Pregunta

Estoy tratando de crear una función que tome una matriz como argumento, le agregue valores (aumentando su tamaño si es necesario) y devuelva el recuento de elementos. Hasta ahora tengo:

int main(int argc, char** argv) {
    int mSize = 10;
    ent a[mSize];
    int n;
    n = addValues(a,mSize);

    for(i=0;i<n;i++) {
       //Print values from a
    }
}

int addValues(ent *a, int mSize) {
    int size = mSize;

    i = 0;

    while(....) { //Loop to add items to array
        if(i>=size-1) { 
            size = size*2;
            a = realloc(a, (size)*sizeof(ent));
        }
        //Add to array
        i++;
    }
    return i;
}

Esto funciona si mSize es lo suficientemente grande como para contener todos los elementos potenciales de la matriz, pero si necesita cambiar el tamaño, aparece un error de segmentación.

También he intentado:

int main(int argc, char** argv) {
    ...
    ent *a;
    ...
}

int addValues(ent *a, int mSize) {
    ...
    a = calloc(1, sizeof(ent);
    //usual loop
    ...
}

En vano.

Supongo que esto se debe a que cuando llamo a realloc, la copia de 'a' apunta a otra parte: ¿cómo es posible modificar esto para que 'a' siempre apunte a la misma ubicación?

¿Estoy haciendo esto correctamente? ¿Hay mejores formas de lidiar con las estructuras dinámicas en C? ¿Debo implementar una lista vinculada para tratar con estos?

¿Fue útil?

Solución

El principal problema aquí es que está intentando usar realloc con una matriz asignada por pila. Tienes:

ent a[mSize];

Esa es la asignación automática en la pila. Si quisiera usar realloc () en esto más adelante, crearía la matriz en el montón usando malloc (), así:

ent *a = (ent*)malloc(mSize * sizeof(ent));

Para que la biblioteca malloc (y, por lo tanto, realloc (), etc.) conozca su matriz. Por lo que parece, puede ser confuso matrices de longitud variable C99 con verdaderos arrays dinámicos , así que asegúrese de comprender la diferencia allí antes de intentar solucionar esto.

Realmente, sin embargo, si está escribiendo matrices dinámicas en C, debe intentar usar el diseño OOP-ish para encapsular información sobre sus matrices y ocultarla al usuario. Desea consolidar información (por ejemplo, puntero y tamaño) sobre su matriz en una estructura y operaciones (por ejemplo, asignación, agregar elementos, eliminar elementos, liberar, etc.) en funciones especiales que funcionan con su estructura. Entonces es posible que tenga:

typedef struct dynarray {
   elt *data;
   int size;
} dynarray;

Y podría definir algunas funciones para trabajar con dynarrays:

// malloc a dynarray and its data and returns a pointer to the dynarray    
dynarray *dynarray_create();     

// add an element to dynarray and adjust its size if necessary
void dynarray_add_elt(dynarray *arr, elt value);

// return a particular element in the dynarray
elt dynarray_get_elt(dynarray *arr, int index);

// free the dynarray and its data.
void dynarray_free(dynarray *arr);

De esta manera, el usuario no tiene que recordar exactamente cómo asignar las cosas o qué tamaño tiene la matriz actualmente. Espero que te ayude.

Otros consejos

Intente volver a trabajarlo para que pase un puntero a un puntero a la matriz, es decir, ent ** a . Entonces podrá actualizar la persona que llama en la nueva ubicación de la matriz.

esta es una buena razón para usar OOP. sí, puedes hacer POO en C, e incluso se ve bien si se hace correctamente.

en este caso simple no necesita herencia ni polimorfismo, solo los conceptos de encapsulación y métodos:

  • define una estructura con una longitud y un puntero de datos. tal vez un tamaño de elemento.
  • escribir funciones getter / setter que operan en punteros a esa estructura.
  • la función 'grow' modifica el puntero de datos dentro de la estructura, pero cualquier puntero de estructura sigue siendo válido.

Si cambió la declaración de variable en main para que sea

ent *a = NULL;

el código funcionaría más como lo imaginó al no liberar una matriz asignada a la pila. Establecer a NULL funciona porque realloc trata esto como si el usuario llamara malloc (tamaño). Tenga en cuenta que con este cambio, el prototipo para agregar valor debe cambiar a

int addValues(ent **a, int mSize)

y que el código necesita manejar el caso de falla de realloc. Por ejemplo

while(....) { //Loop to add items to array
    tmp = realloc(*a, size*sizeof(ent));
    if (tmp) {
        *a = tmp;
    } else {
        // allocation failed. either free *a or keep *a and
        // return an error
    }
    //Add to array
    i++;
}

Esperaría que la mayoría de las implementaciones de realloc asignen internamente el doble de memoria si es necesario cambiar el tamaño del búfer actual para hacer el código original

size = size * 2;

innecesario.

Está pasando el puntero de matriz por valor. Lo que esto significa es:

int main(int argc, char** argv) {
    ...
    ent *a; // This...
    ...
}

int addValues(ent *a, int mSize) {
    ...
    a = calloc(1, sizeof(ent); // ...is not the same as this
    //usual loop
    ...
}

por lo que cambiar el valor de a en la función addValues ?? no cambia el valor de a en main. Para cambiar el valor de un in main, debe pasarle una referencia a addValues ??. En este momento, el valor de a se está copiando y pasando a addValues ??. Para pasar una referencia a un uso:

int addValues (int **a, int mSize)

y llámalo así:

int main(int argc, char** argv) {
    ...
    ent *a; // This...
    ...
    addValues (&a, mSize);
}

En el addValues ??, acceda a los elementos de este tipo:

(*a)[element]

y reasignar la matriz de esta manera:

(*a) = calloc (...);

Xahtep explica cómo su interlocutor puede lidiar con el hecho de que realloc () podría mover la matriz a una nueva ubicación. Mientras hagas esto, deberías estar bien.

realloc () puede resultar costoso si comienza a trabajar con matrices grandes. Es entonces cuando es hora de comenzar a pensar en usar otras estructuras de datos: una lista vinculada, un árbol binario, etc.

Como se indicó, debe pasar el puntero al puntero para actualizar el valor del puntero.
Pero sugeriría rediseñar y evitar esta técnica, en la mayoría de los casos puede y debe evitarse. Sin saber qué es exactamente lo que está tratando de lograr, es difícil sugerir un diseño alternativo, pero estoy 99% seguro de que es factible de otra manera. Y como Javier triste - piensa orientado a objetos y siempre obtendrás un mejor código.

¿Realmente debe usar C? Esta sería una gran aplicación de '' std :: vector '' de C ++, que es precisamente una matriz de tamaño dinámico (fácilmente redimensionable con una sola llamada que no tiene que escribir y depurar usted mismo).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top