【问题标题】:When to use NULL and when to use '\0' in linked list in C?在 C 的链表中何时使用 NULL 以及何时使用 '\0'?
【发布时间】:2015-12-17 11:07:47
【问题描述】:

我在 C 中了解到这一点:null char == '\0' == NULL,然后我在下面编写了一个循环来读取 C 中 char[] 的开头到结尾。

// case #1
char buf[32];
while (buf[i] != NULL){
    //do something...
}  

但是,我的 gcc 编译器给了我一个警告:指针和整数之间的比较。有人提到我混淆了两个独立的概念:NULL 用于指针,而 '\0' 用于字符。所以为了摆脱警告,我应该使用'\0',因为我的循环测试了一个字符。

现在我正在编写一个链表,并测试一个头指针是否指向一个节点。由于它是结构,因此使用if (h1 == NULL) 是合理的,但显然当我使用if (h1 == '\0') 时编译器也会编译,即使节点是结构而不是字符。有人可以提供一些帮助,为什么在这种情况下可以同时使用 '\0' 和 NULL 而在第一种情况下不能同时使用它们?

// case #2
struct ListNode {
    int val;
    struct ListNode *next;
};

【问题讨论】:

  • 在需要时在字符串中使用 \0 作为终止符。将 NULL 用于不指向任何内容的指针(例如,链表的末尾。它们并不相同,即使它们在某些情况下可以互换。

标签: c pointers linked-list


【解决方案1】:

这是一个很常见的混淆。 “空字符”(由于历史原因,通常拼写为 NUL,只有一个 L)是比较等于零的 字符。 “空指针”是一个比较等于零的指针。区别只是类型——但这是一个重要的区别。编译器允许但不是必须反对您的程序,因为您将 character 值与空 pointer 常量进行比较。

C 有一个相当松散的类型系统,尤其是在涉及整数常量时,因此您可以避免在很多时候使用具有形式上不正确类型的常量。当涉及到零时尤其如此:整数文字0 可以在任何可以安全使用宏NULL 或字符文字'\0' 的地方使用。事实上,在 C 标准的所有版本中,都明确允许实现使用#define NULL 0。因此,在少数情况下,对于某些具体类型 T,绝对必须使用(T*)0而不是0NULL,例如在传递空指针时到一个接受可变数量参数的函数(例如execl)。

进一步让混淆蛋糕锦上添花,在 C 中,字符文字的类型为 int,而不是 char,而 '\0' 是合法的空指针常量。 (在 C++ 中,这些都不是真的。)

C 中的最佳实践,IMNSHO,是使用'\0' 作为空字符0 - not NULL - 作为空指针

【讨论】:

  • 更好的是使用术语“NULL”来指代指针和“nul”来指代字符,就像在典型的 ASCII 表中一样。另外我知道NULL 不一定是0(在MPU 中),所以最好使用定义的值NULL。请注意0'\0' 在语法上是等价的:两者都是int 类型并且都具有值0。
  • @WeatherVane 在 C 中,在我看来,NULL 只是整数常量 0 的另一个名称,使用 0 几乎总是更好。特别是,人们可能会误以为他们不需要在例如execl 的参数列表,而实际上它们确实如此。
  • @WeatherVane 我不知道您所说的“在 MPU 中 NULL 不一定为 0”是什么意思,但在 C 中,空指针总是比较等于零,即使空指针的位表示并非全为零。
  • 这就是我想说的:0 可能是一个有效的地址,如果使用NULL,它就会被处理。
  • @WeatherVane 不过不是这样。 NULL 只是一个宏,它需要扩展为一个整数文字值为零。反之,any 整型常量表达式,其值为 0 时,在转换为指针类型时会转换为空指针。换句话说,C 标准完全禁止零成为有效地址。
【解决方案2】:

根据编译器的不同,NULL 的定义方式可能不同:

#define NULL ((char *)0)

#define NULL ((void *)0)

#define NULL 0L

#define NULL 0

NULL 用于指针比较。但是,整数0 是允许进行指针比较的特殊情况,这就是为什么您可以直接将ListNode* 指针与0 进行比较(否则上面的NULL 定义了不存在指针类型转换的位置不会工作):

if (h1 == 0)

或者更简单:

if (!h1)

'\0' 字符文字是 C 中的 int,并且可以隐式转换为 C++ 中的 int。所以'\0'也可以用于指针比较。

你应该使用'\0'(或只是0)进行字符比较,不要使用NULL

while (buf[i] != '\0') // or 0

或者更简单:

while (buf[i])

【讨论】:

  • 抱歉有点挑剔,但'\0' 中没有隐式的 char-to-int 转换。字符常量在 C 中的类型为 int,与 C++ 中的类型为 char 不同。在实践中,C 中的'\0'0 之间没有类型或值的区别,但我完全同意你的观点,如果在处理字符时使用一个,而在处理数值时使用另一个,则可读性会大大提高。同样,NULL 应该用于指针,即使 0 正确但可读性较差。
【解决方案3】:

NULL 有效地用作链表或指针数组的空终止符。 '\0' 用作字符串(即字符数组)的空终止符

如果你有一个结构数组,你可能想循环它们直到你到达终点:

MyStruct** things = ...
for(int i = 0; things[i] != NULL; i++) {
    // Do something with things[i]
}

当指向最后一个结构的指针为NULL时,此循环将结束。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-20
    • 1970-01-01
    • 2012-02-20
    • 2012-06-07
    • 1970-01-01
    • 2011-07-01
    • 2016-06-06
    相关资源
    最近更新 更多