1

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

我不知道数组应该有多长,所以不是在我的 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 的会议之后,我应该添加一些其他的东西,让这更加混乱。

我不直接从 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;
    }

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

4

4 回答 4

4

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

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

将您的分配更改为*graph_array = malloc(sizeof(*graph_array) * vertices);,您应该没问题。

于 2012-11-28T01:15:36.820 回答
2

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

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

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

于 2012-11-28T01:22:41.230 回答
1

您正在使用 C99 风格的本地数组分配。函数返回时数组消失。相反,您需要用于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;
}
于 2012-11-28T01:26:28.603 回答
1

你有两个问题。

首先,graph_array2auto extent,意味着它只存在于它的封闭范围内,也就是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.
  }
  ...
}

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

于 2012-11-28T01:44:33.750 回答