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

时间:2019-01-22 09:03:30

标签: c pointers struct malloc 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;

可以,但是显然不能。

我还要指出,我知道直接在struct中创建指针或双指针通常被认为是不好的做法,但这是分配的一部分,并且给出了struct定义,必须按原样使用。最终目标是制作一个数组或链接列表。根据我的理解,可以找到链接列表部分,但这就是问题所在。

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

我已将代码更改为此:

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

但是我的程序仍然崩溃。

3 个答案:

答案 0 :(得分:1)

如果您坚持使用双指针,则应按以下步骤操作:

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中使用双指针(我建议您告诉您的教授访问stackoverflow.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的值在此并不重要;它仅用于向编译器指示要使用数组元素)。

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

答案 1 :(得分: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 pointers 指针数组的第一个元素的指针,但是由于您使用{{1 }}数组中所有这些指针将为 calloc 。取消引用NULL指针无效,并导致undefined behavior

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

根据经验:切勿将指针隐藏在类型别名后面。它使代码更难以阅读,理解和维护。

答案 2 :(得分:0)

其他人回答了这个问题,但是如果有人遇到这个问题并且对如何正确执行此操作感兴趣:

  • 永远不要将指针隐藏在typedef后面。
  • 当您实际需要2D数组时,切勿使用type**。那只能用于诸如可变长度的字符串表之类的东西,它不是2D数组。有关详细信息,请参见Correctly allocating multi-dimensional arrays
  • 始终free() malloc()您的free()。当然,在大多数情况下,操作系统都会为您执行此操作。但是通过调用free(),我们可以在代码中的其他地方暴露和检测错误,例如内存泄漏,悬空指针等,这些都会在调用#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; } 时表现为程序崩溃。

以下是适当代码的示例,其中一个示例使用1D数组,另一个示例使用2D数组:

sizeof *nodeList2D

请注意,调用malloc / calloc时的3 * sizeof(Node)技巧适用于所使用的类型。对于2D数组,这将为我们提供一个1D数组的大小(与var a = Url.Action(action: "GetContentByFileId", values: new { fileId = 1 }); var b = _linkGenerator.GetUriByAction(HttpContext, action: "GetContentByFileId", controller: "FileController", values: new { fileId = 1 }); var c = _linkGenerator.GetUriByAction(_httpContextAccessor.HttpContext, action: "GetContentByFileId", controller: "FileController", values: new { fileId = 1 }); 相同),然后使用calloc分配2个这样的内存块。