当我引用双指针时代码不起作用

Code doesn't work when I reference double pointer

为什么我不能正确存储和引用双指针?

此代码有效:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct _node{
    int nodeNumber;
    int weight;
}* Node;

int main(int argc, char **argv){
    Node nodeList = calloc(3, sizeof(struct _node));

    // Used for testing
    nodeList->nodeNumber = 9;
    printf("Node Number: %d\n", nodeList->nodeNumber);

    return 0;
}

但是当我尝试使结构成为双指针并像这样引用时:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct _node{
        int nodeNumber;
        int weight;
}** Node;



int main(int argc, char **argv){
        Node nodeList = calloc(3, sizeof(struct _node));

        // Used for testing
        nodeList[0]->nodeNumber = 9;
        printf("Node Number: %d\n", nodeList[0]->nodeNumber);

        return 0;
}

我的程序运行了一秒钟然后崩溃了。没有错误或任何东西。我认为用

引用结构
nodeList[0]->nodeNumber = 9;

可以,但显然不行。

我还想指出,我知道直接在结构中创建指针或双指针通常被认为是不好的做法,但这是赋值的一部分并且给出了结构定义并且必须使用 "as is".最终目的是做一个数组或者链表。链接列表部分会被找到,因为我想我明白了,但这就是问题所在。

----------------------------编辑------------ ----------------------

我已将我的代码更改为:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct _node{
        int nodeNumber;
        int weight;
}** Node;



int main(int argc, char **argv){
        Node nodeList = malloc(sizeof(struct _node *));

        // Used for testing
        nodeList[0]->nodeNumber = 9;
        printf("Node Number: %d\n", nodeList[0]->nodeNumber);

        return 0;
}

但我的程序仍然崩溃。

typedef struct _node{
    int nodeNumber;
    int weight;
}* Node;

Node nodeList = calloc(3, sizeof(struct _node));

你让 nodeList 指向 struct _node 元素数组的第一个元素。

typedef struct _node{
        int nodeNumber;
        int weight;
}** Node;

然后nodeList将是指向指针数组第一个元素的指针struct _node ,但由于您使用 calloc,数组中的所有这些指针都将是 NULL。取消引用 NULL 指针是无效的,会导致 undefined behavior.

此外,您的分配是错误的,因为您仍然为三个 struct _node 个元素而不是 struct _node * 个元素分配了内存。

作为经验法则:永远不要将指针隐藏在类型别名后面。它使代码更难阅读、理解和维护。

如果你坚持使用双指针,那么你应该进行如下操作:

typedef struct _node{
    int nodeNumber;
    int weight;
} Node;

在你的函数中:

    Node **nodelist = malloc(3 * sizeof(Node *));
    for (int i=0; i<3; i++)
        nodelist[i]= calloc(1,sizeof(Node));

请注意,我没有在 typedef 中使用指针,因为它很容易混淆。相反,我将 nodelist 声明为双指针。


所以你教授坚持在 typedef 中使用双指针(我建议你告诉你的教授访问 whosebug.com.....)。然后进行如下操作:

typedef struct _node{
    int nodeNumber;
    int weight;
} **Node;

在你的函数中:

    Node nodelist = malloc(3 * sizeof(*nodelist));
    for (int i=0; i<3; i++)
        nodelist[i]= calloc(1,sizeof(*nodelist[i]));

这里我不使用类型名而是使用变量名来确定要分配的大小:*nodelist 将节点列表取消引用为 struct _node **nodelist[i] 将其取消引用为实际的 struct _node (注意 i 的值在这里并不重要;它仅用于向编译器指示数组元素是预期的)。

人们甚至更喜欢使用变量名而不是类型名,这样当将来变量引用另一种类型时,分配会随之自动改变。

其他人已经回答了这个问题,但如果有人遇到这个问题并对如何正确地做到这一点感兴趣:

  • 切勿将指针隐藏在 typedef 后面。
  • 当您确实需要二维数组时,切勿使用 type**。这应该只用于可变长度字符串的 table 之类的东西,它不是二维数组。有关详细信息,请参阅
  • 总是free()malloc()。当然,在大多数情况下 OS 会为您完成此操作。但是通过调用 free(),我们可以暴露和检测代码中其他地方的错误,例如内存泄漏、悬空指针等,这些都会在调用 free().[=29 时表现为程序崩溃。 =]

以下是正确代码的示例,一个示例使用一维数组,另一个示例使用二维数组:

#include <stdio.h>
#include <stdlib.h>

typedef struct {
  int nodeNumber;
  int weight;
} Node;

int main (void)
{
  Node* nodeList = calloc(3, sizeof *nodeList);

  nodeList[0].nodeNumber = 9;
  printf("Node Number: %d\n\n", nodeList->nodeNumber);

  free(nodeList);


  /****************************************************************************/

  const size_t x = 2;
  const size_t y = 3;
  Node (*nodeList2D)[y] = calloc(x, sizeof *nodeList2D);

  int count = 0;
  for(int i=0; i<x; i++)
  {
    for(int j=0; j<y; j++)
    {
      nodeList2D[i][j].nodeNumber = count++;
      printf("Node (%d, %d): %d\n", i, j, nodeList2D[i][j].nodeNumber);
    }
  }

  free(nodeList2D);

  return 0;
}

请注意,调用 malloc/calloc 时的 sizeof *nodeList2D 技巧适用于所使用的类型。对于二维数组,这将为我们提供一个一维数组的大小(与 3 * sizeof(Node) 相同),然后我们使用 calloc 分配 2 个这样的内存块。