Pasando punteros a matrices a funciones

Estoy almacenando mi información en una serie de punteros a estructuras. En otras palabras, cada elemento de la matriz es un puntero a una lista vinculada.

No sé cuánto debería durar la matriz, así que en lugar de inicializar la matriz en mi función main (), en lugar de eso, intialize el puntero doble

struct graph** graph_array; 

Luego, una vez que obtengo la longitud de la matriz, trato de inicializar cada elemento de graph_array usando una función GraphInitialize:

 int GraphInitialize(struct graph* *graph_array,int vertices) { struct graph* graph_array2[vertices+1]; graph_array = graph_array2; int i; for (i=0;i<vertices+1;i++) { graph_array[i] = NULL; } return 0; } 

Pero por alguna razón esto no está devolviendo el graph_array actualizado a main (). Básicamente, esta función está actualizando graph_array localmente, y no se está haciendo ningún cambio. Como resultado, cada vez que bash acceder a un elemento de graph_array it seg faults porque no está inicializado. ¿Qué estoy haciendo mal?

Edit: Siguiendo la conversación con Tom Ahh, debería agregar algo más que haga esto más confuso.

No llamo a GraphIntialize directamente desde main (). En su lugar, llamo a getdata () desde main, y paso un puntero a graph_array para obtenerdata como se muestra a continuación.

  getdata(argc, argv, vertpt, edgept, &graph_array) int getdata(int argc, char *argv[], int *verts, int *edges, struct graph* **graph_array) 

Luego, getdata obtiene el número de vértices de mi archivo de entrada y lo usa para llamar a GraphInitialize:

  if ((GraphInitialize(&graph_array, *verts)) == -1) { printf("GraphCreate failed"); return 0; } 

Esto da como resultado un error: “se esperaba ‘struct graph 3ASTERISKS’ pero el argumento es de tipo ‘struct graph 4ASTERISKS’.

Cuando asigna algo a graph_array , simplemente lo asigna a su copia local. Los cambios realizados en la función no podrán ser vistos por la persona que llama. Debe pasarlo por un valor de puntero para poder cambiar su valor. Cambie el prototipo de su función a int GraphInitialize(struct graph ***graph_array,int vertices) y cuando lo llame, use GraphInitialize(&graph_array, 42) .

El segundo problema en su código es cuando crea graph_array2 , declara que es local a su función GraphInitialize() . Por lo tanto, al salir de su función, graph_array2 se destruye, incluso si la asignó a *graph_array . (la estrella hace referencia al puntero para asignarlo al valor al que apunta).

cambie su asignación a *graph_array = malloc(sizeof(*graph_array) * vertices); y deberías estar bien

La memoria se divide en dos partes, la stack y el montón. Malloc le devolverá una porción de memoria del montón, que vive entre las funciones, pero debe ser liberada. Por lo tanto, su progtwig debe tener cuidado de no perder de vista la memoria malloced () y llamar a free ().

Al declarar una variable graph_array2 [vertices + 1] asigna una variable local en la stack. Cuando la función regresa, el puntero de la stack se abre “liberando” la memoria asignada en la llamada de la función. No tiene que administrar la memoria manualmente, pero cuando finaliza la llamada a la función ya no existe.

Vea aquí para una discusión de los dos estilos de asignación: http://www.ucosoft.com/stack-vs-heap.html

Está utilizando la asignación de matriz local de estilo C99. La matriz desaparece cuando la función vuelve. En su lugar, debe usar malloc() para asignar memoria que persistirá después de la función. Puede usar typedefs para hacer que su código sea más legible:

 typedef struct graph_node_s { // linked list nodes struct graph_node_s *next; ... } GRAPH_NODE; typedef GRAPH_NODE *NODE_REF; // reference to node typedef NODE_REF *GRAPH; // var length array of reference to node GRAPH AllocateGraph(int n_vertices) { int i; GRAPH g; g = malloc(n_vertices * sizeof(NODE_REF)); if (!g) return NULL; for (i = 0; i < n_vertices; i++) g[i] = NULL; return g; } 

Tienes dos problemas.

Primero, graph_array2 tiene una extensión automática , lo que significa que solo existe dentro de su ámbito de envolvente, que es el cuerpo de la función GraphInitialize ; una vez que la función sale, esa memoria se libera y graph_array ya no apunta a ningún lugar significativo.

Segundo, cualquier cambio en el parámetro graph_array es local a la función; Los cambios no se reflejarán en la persona que llama. Recuerde, todos los parámetros se pasan por valor ; Si pasa un puntero a una función, y desea que el valor del puntero sea modificado por la función, debe pasar un puntero al puntero, de esta manera:

 void foo(int **p) { *p = some_new_pointer_value(); return; } int main(void) { int *ptr = NULL; foo(&ptr); ... } 

Si pretende que InitializeGraph asigne la memoria a su matriz, deberá hacer algo como esto:

 int InitializeGraph(struct graph ***graph_array, int vertices) { *graph_array = malloc(sizeof **graph_array * vertices); if (*graph_array) { int i; for (i = 0; i < vertices; i++) { (*graph_array}[i] = NULL; // parentheses matter here! } } else { return -1; } return 0; } int main(void) { int v; struct graph **arr; ... if (GraphInitialize(&arr, v) == 0) { // array has been allocated and initialized. } ... } 

Los operadores de Postfix como [] tienen mayor prioridad que los operadores unarios como * , por lo que la expresión *arr[i] se interpreta como *(arr[i]) ; estamos desviando la referencia al elemento i 'th de la matriz. En GraphInitialize , necesitamos graph_array referencia a graph_array antes de suscribir ( graph_array no es una matriz, apunta a una matriz), por lo que necesitamos escribir (*graph_array)[i] .