何时使用 NULL 以及何时在 C 的链表中使用 '\0'?
When to use NULL and when to use '\0' in linked list in C?
我在C里学的:null char == '[=12=]' == NULL
,下面写了一个循环,在C里从头到尾读取一个char[]
// case #1
char buf[32];
while (buf[i] != NULL){
//do something...
}
但是,我的 gcc 编译器给了我一个警告:指针和整数之间的比较。有人提到我混淆了两个不同的概念:NULL 用于指针,而 '\0' 用于字符。因此,为了消除警告,我应该使用“\0”,因为我的循环测试的是一个字符。
现在我正在写一个链表,测试头指针是否指向节点。因为它是结构,所以使用 if (h1 == NULL)
是合理的,但显然当我使用 if (h1 == '[=14=]')
时编译器也会编译,即使节点是结构而不是字符。有人可以提供一些帮助,为什么在这种情况下可以同时使用 '\0' 和 NULL 而在第一种情况下不能同时使用它们?
// case #2
struct ListNode {
int val;
struct ListNode *next;
};
根据编译器的不同,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)
'[=24=]'
字符文字在 C 中是 int
,在 C++ 中可隐式转换为 int
。所以'[=24=]'
也可以用在指针比较中。
您应该使用 '[=24=]'
(或只是 0
)进行字符比较,不要使用 NULL
:
while (buf[i] != '[=16=]') // or 0
或更简单:
while (buf[i])
NULL
有效地用作链表或指针数组的空终止符。 '[=12=]'
用作字符串的空终止符(即 char 数组)
如果您有一个结构数组,您可能希望遍历它们直到到达末尾:
MyStruct** things = ...
for(int i = 0; things[i] != NULL; i++) {
// Do something with things[i]
}
当指向最后一个结构的指针为NULL
时,此循环将结束。
这是一个很常见的混淆。 "null character"(出于历史原因,通常拼写为 NUL,只有一个 L)是一个 字符,比较等于零。 "null pointer" 是比较等于零的 指针 。区别仅在于类型——但这是一个重要的区别。允许编译器反对您的程序,但不是必需的,因为您正在将 character 值与 null pointer 常量进行比较。
C 有一个相当松散的类型系统,尤其是涉及到整型常量时,因此您可以逃避 很多时候使用形式上不正确类型的常量。当涉及到零时尤其如此:整数文字 0
可以在任何可以安全使用宏 NULL
或字符文字 '[=12=]'
的地方使用。事实上,在 C 标准的所有版本中都明确允许实现使用 #define NULL 0
。因此,有一小部分上下文绝对必须对某些具体类型 T 使用 (T*)0
, 而不是 裸 0
或 NULL
,例如将空指针传递给参数数量可变的函数(例如 execl
)。
作为混淆蛋糕上的进一步锦上添花,在 C 中,字符文字的类型为 int
,而不是 char
,并且 '[=12=]'
是一个合法的 空指针常量。 (在 C++ 中,这些都不是真的。)
C 中的最佳实践,恕我直言,是使用 '[=12=]'
作为空 字符 ,并且 0
— not NULL
— 对于 null pointer.
我在C里学的:null char == '[=12=]' == NULL
,下面写了一个循环,在C里从头到尾读取一个char[]
// case #1
char buf[32];
while (buf[i] != NULL){
//do something...
}
但是,我的 gcc 编译器给了我一个警告:指针和整数之间的比较。有人提到我混淆了两个不同的概念:NULL 用于指针,而 '\0' 用于字符。因此,为了消除警告,我应该使用“\0”,因为我的循环测试的是一个字符。
现在我正在写一个链表,测试头指针是否指向节点。因为它是结构,所以使用 if (h1 == NULL)
是合理的,但显然当我使用 if (h1 == '[=14=]')
时编译器也会编译,即使节点是结构而不是字符。有人可以提供一些帮助,为什么在这种情况下可以同时使用 '\0' 和 NULL 而在第一种情况下不能同时使用它们?
// case #2
struct ListNode {
int val;
struct ListNode *next;
};
根据编译器的不同,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)
'[=24=]'
字符文字在 C 中是 int
,在 C++ 中可隐式转换为 int
。所以'[=24=]'
也可以用在指针比较中。
您应该使用 '[=24=]'
(或只是 0
)进行字符比较,不要使用 NULL
:
while (buf[i] != '[=16=]') // or 0
或更简单:
while (buf[i])
NULL
有效地用作链表或指针数组的空终止符。 '[=12=]'
用作字符串的空终止符(即 char 数组)
如果您有一个结构数组,您可能希望遍历它们直到到达末尾:
MyStruct** things = ...
for(int i = 0; things[i] != NULL; i++) {
// Do something with things[i]
}
当指向最后一个结构的指针为NULL
时,此循环将结束。
这是一个很常见的混淆。 "null character"(出于历史原因,通常拼写为 NUL,只有一个 L)是一个 字符,比较等于零。 "null pointer" 是比较等于零的 指针 。区别仅在于类型——但这是一个重要的区别。允许编译器反对您的程序,但不是必需的,因为您正在将 character 值与 null pointer 常量进行比较。
C 有一个相当松散的类型系统,尤其是涉及到整型常量时,因此您可以逃避 很多时候使用形式上不正确类型的常量。当涉及到零时尤其如此:整数文字 0
可以在任何可以安全使用宏 NULL
或字符文字 '[=12=]'
的地方使用。事实上,在 C 标准的所有版本中都明确允许实现使用 #define NULL 0
。因此,有一小部分上下文绝对必须对某些具体类型 T 使用 (T*)0
, 而不是 裸 0
或 NULL
,例如将空指针传递给参数数量可变的函数(例如 execl
)。
作为混淆蛋糕上的进一步锦上添花,在 C 中,字符文字的类型为 int
,而不是 char
,并且 '[=12=]'
是一个合法的 空指针常量。 (在 C++ 中,这些都不是真的。)
C 中的最佳实践,恕我直言,是使用 '[=12=]'
作为空 字符 ,并且 0
— not NULL
— 对于 null pointer.