将指向数组的指针传递给函数

我将我的信息存储在一个指向结构的指针数组中。 换句话说,数组的每个元素都是指向链表的指针。

我不知道数组应该有多长,所以不是在main()函数中初始化数组,而是初始化双指针

struct graph** graph_array; 

然后,一旦我获得数组的长度,我尝试使用函数GraphInitialize初始化graph_array的每个元素:

 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; } 

但由于某种原因,这并没有将更新的graph_array返回给main()。 基本上,此函数在本地更新graph_array,并且不进行任何更改。 因此,每次我尝试访问graph_array的元素时,它都会因为未初始化而出现故障。 我究竟做错了什么?

编辑:在跟Tom Ahh进行convo之后,我应该添加一些让这更令人困惑的东西。

我不直接从main()调用GraphIntialize。 相反,我从main调用getdata(),并将指向graph_array的指针传递给getdata,如下所示。

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

然后getdata从我的输入文件中获取顶点数,并使用它来调用GraphInitialize:

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

这会导致错误:“预期’结构图3ASTERISKS’,但参数类型为’struct graph 4ASTERISKS’。

当您为graph_array分配graph_array ,只需将其分配给其本地副本即可。 调用者无法看到函数中对其所做的更改。 您需要通过指针值传递它才能更改其值。 将函数原型更改为int GraphInitialize(struct graph ***graph_array,int vertices) ,当您调用它时,请使用GraphInitialize(&graph_array, 42)

代码中的第二个问题是当您创建graph_array2 ,您将其声明为GraphInitialize()函数的本地。 因此,退出函数时,即使您将其分配给*graph_array ,graph_array2也会被销毁。 (星号取消引用指针以将其指定给它指向的值)。

将您的分配更改为*graph_array = malloc(sizeof(*graph_array) * vertices); 你会没事的

内存分为两部分,堆栈和堆。 Malloc将从堆中返回一大块内存,它存在于函数之间,但必须被释放。 因此,您的程序必须小心跟踪malloced()内存并在其上调用free()。

声明变量graph_array2 [vertices + 1]会在堆栈上分配一个局部变量。 当函数返回时,堆栈指针弹出“释放”函数调用中分配的内存。 您不必手动管理内存,但是当函数调用结束时,它不再存在。

有关两种分配方式的一些讨论,请参见此处: http : //www.ucosoft.com/stack-vs-heap.html

您正在使用C99样式的本地arrays分配。 函数返回时,数组消失。 相反,您需要使用malloc()来分配将在函数之后保留的内存。 您可以使用typedefs使代码更具可读性:

 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; } 

你有两个问题。

首先, graph_array2具有自动范围 ,这意味着它只存在于其封闭范围内,该范围是GraphInitialize函数的主体; 一旦函数退出,释放内存, graph_array不再指向任何有意义的内容。

其次,对参数graph_array任何更改都是函数的局部变量; 更改将不会反映在调用方中。 请记住,所有参数都按值传递; 如果您将指针传递给函数,并且您希望函数修改指针的值,则必须将指针传递给指针,如下所示:

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

如果您打算让InitializeGraph为您的数组分配内存,您需要执行以下操作:

 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. } ... } 

[]这样的后缀运算符比*类的一元运算符具有更高的优先级,因此表达式*arr[i]被解释为*(arr[i]) ; 我们取消引用数组的第i个元素。 在GraphInitialize ,我们需要graph_array之前取消引用graph_arraygraph_array不是数组,它指向数组),因此我们需要编写(*graph_array)[i]