C语言 - 结构体中指针的默认值是什么?

4

我有一个非常简单的C语言单向链表实现如下:

typedef struct Node{
        int data;
    struct Node *next;  
} node;


void printLL(node * start);
void addNode(node * head, node * add);

int main()
{
    node first;
    first.data = 99;
    first.next = NULL;

    node second;
    second.data = 11;

    addNode(&first, &second);   
    printLL(&first);    
}

void addNode(node * head, node * add)
{
    if(head->next)
    {
        addNode(head->next, add);
    }
    else 
    {
        head->next = add;
    }
}

void printLL(node * start)
{
    printf("Data is %d\n", start->data);
    if (start->next) {
        printLL(start->next);
    }
}

我感到困惑的是,如果我不明确设置first.next = NULL,就会出现EXE_BAD_ACCESS错误。当我尝试检查该属性是否已设置或未设置以确定是否应递归调用时,它会发生。另一件我不理解的事情是,如果我将first.next指向“second”,即使对于“second”,我没有明确设置其下一个为NULL,所有函数都能正常工作。因此,在结构体中定义的指针的默认值似乎存在某些不一致性。当然,我可能做错了什么,但如果有人能阐明这个问题,我会非常感激。总之,我的问题是:
  1. 在结构体中定义的指针的默认值是什么?
  2. 假设没有默认值,是否有一种简单的方法在结构体定义中设置默认值?(我查阅了一些C书籍,但没有找到答案)
8个回答

3
看起来结构体中指针的默认值存在一些不一致性。
这正是问题所在——编译器不会将自动(局部)变量设置为任何默认值。因此,您可能会得到导致“EXE_BAD_ACCESS”错误的结果,或者您可能会得到似乎可以工作的结果。这是随机的(即使它似乎可以工作,也是一个错误)。
C语言的缺点之一是您需要确保正确初始化变量。编译器可以通过警告来协助,但并非所有编译器在这方面都同样出色。
在结构体定义中没有设置默认值的简单方法。但是,在声明该类型的变量时,您可以初始化结构体:
node first = { 99, NULL };

如果我调用了一个库,它返回一个像节点一样的结构体,但作者很懒,忘记为指针设置默认值。然后我来检查是否有东西存在,但它会崩溃,还有其他安全的方法来检查该指针是否已初始化吗? - user398746
你说得没错,但有一点需要注意。对于所有未明确提及的字段,都有默认初始化。再加上指定初始化器,这样处理起来就比你所表述的要简单得多。请看我的回答。 - Jens Gustedt
@user398746:简短的回答是否定的,更长的回答是,找一个更好的库。如果你向库传递数据,请在调用之前初始化(无论文档如何都是一个好习惯)。如果库没有初始化数据或分配内存,那么你就会遇到问题。 - mattnz

1

指针没有默认值,它包含一个垃圾值。除非您使用自己的默认值初始化所有指针。


0

默认值可能取决于C编译器,因此最好提供它们。

在创建结构体实例后,您必须对其进行初始化,例如second.next = NULL


没有默认值不依赖于编译器。C标准规定了变量初始化的确切方式。 - Jens Gustedt
其他一些答案说没有默认值,我有点记得有一些C编译器会将某些东西设置为0,但是有几个不会。但也许我把这个和另一种语言混淆了,我不确定了。 - ZoolWay

0

结构体中没有任何默认值(除非它是静态创建的)。也没有提供一种方式来提供默认值。如果您需要这样做,应该使用 C++,它提供了构造函数来实现这一点。如果坚持使用 C,您需要显式地初始化结构体。


1
当然有。请看我的回答。 - Jens Gustedt
@Jens 您的答案似乎是关于显式初始化的。 - user2100815
1
你说“结构体中没有任何默认值”,这是不正确的。如果它隐式地被初始化,无论是静态的还是具有省略该字段的初始化程序,其默认值都为0 - Jens Gustedt

0

在调用 addNode(&first, &second); 函数时,在 if 语句中你正在执行 head->next,这是导致问题的原因。默认情况下,next 没有初始化并且会在运行时导致 EXE_BAD_ACCESS 错误。

但当你将其设置为 NULL 时,if 语句中的条件将失败,并且会让你进入 else 语句块,在那里你实际上分配了指针。


有没有比较“安全”的检查方法来确定它是否已初始化?似乎最好的方法是在结构体中初始化所有值,但假设我从某个我没有编写的调用中获得了一个结构体,我该如何进行防御性编程呢?我想不行,因为它可能看起来像节点的有效地址,也可能不是。 - user398746
据我所知,这很难确定。因为未初始化的指针具有未定义的行为。它可能有时会指向有效的位置并且表现得好像没有任何问题。因此,最好的方法是将其设置为“null”。还要检查@Michael Burr的解决方案,这是您需要做的。 - Mahesh

0
如果您想要默认指针值,可以创建一个工厂方法,返回一个新的结构体实例,并将其值设置为所需的默认值。

0

没有默认值。每个内存位置将保留它所拥有的任何值,除非明确修改。虽然这种行为本身取决于编译器。最重要的是,您不能假设它将包含特定值。

为了设置默认值,一个好的做法是在创建实例时显式地为struct属性分配值。

如果您使用的是C++,则应该在构造函数中设置成员的默认值。


0

在C语言中,自动变量无论是否为struct类型都不会被初始化,需要手动进行初始化。

但与大多数回答所暗示的相反,对于任何数据类型,包括指针,都有一个默认值。这个默认值是将所有组件都显式初始化为普通值'0'。例如:

node first = { .data = 99 };

可以使用以下代码来完成此操作:struct myStruct next = {0};。这将使next正确初始化。(如果您没有C99,则省略.data =并希望您永远不会更改struct的布局 :))

还要注意,这可能与使用memset或类似方法清零struct是不同的。在某些体系结构中,全0位模式可能不是空指针或double的正确初始化方式。因此最好坚持使用语言本身提供的初始化机制。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接