字符数组(char*)应该以'\0'或"\0"结尾?

17
假设我们有一个字符指针数组。
char* array[] = { "abc", "def" };

现在该在末尾放什么?

char* array[] = { "abc", "def", '\0' };
或者
char* array[] = { "abc", "def", "\0" };

虽然两者都可以,但我们只需要根据情况检查结尾即可。

例如:

array[ index ] != '\0';
或者
array[ index ] != "\0";

我的问题是哪种方式更好?大多数程序员使用哪种方式?

编辑

大多数答案都说NULL优于'\0'和"\0"。 但我一直认为

NULL与'\0'相同,'\0'与0x0或0相同

这错了吗?


1
关于修改,在 C 语言中 NULL 是指针(通常定义为 (void*)0),'\0' 是一个字符常量。因此,在期望指针的位置使用字符常量时,会发生隐式转换。正如它发生在任何整数零的转换结果为 NULL 指针一样,但这并不清楚你是否打算使用指针。我认为最好简单地使用文字常量整数零。事实上,在 C++ 中这是首选方法,但在 C++ 中,NULL 宏也是以此方式定义的(请查看您编译器的标准头文件)。 - Clifford
6个回答

30

我会以NULL结束它。为什么?因为你不能做以下任何一件事:

array[index] == '\0'
array[index] == "\0"

第一个错误是将char *char进行比较,这不是你想要的。你需要这样做:

array[index][0] == '\0'
第二个代码片段根本就不起作用。虽然您正在比较两个char *,但这种比较毫无意义。只有当这两个指针指向同一块内存时,它才会通过。在C语言中,您不能使用==来比较两个字符串,必须使用strcmp()函数,因为C语言没有内置的字符串支持,除了一些(我是说很少)语法糖之外。与此相反的是:
array[index] == NULL

这很好地发挥作用并传达了您的观点。


我知道它可能会工作,但这绝不是保证能够工作的,因此永远不能依赖它,也因此毫无意义。如果它能工作,那是因为你有一个聪明的编译器,或者你很幸运。 - Chris Lutz
1
NULL和'\0'不是一样的吗?我的理解是NULL == '\0' == 0x0。这是不正确的吗? - Andrew-Dufresne
1
通常情况下,NULL 是 ((void*)0)……尽管值相等,但类型是不同的。 - fortran
10
Nitpick - 第一个比较实际上是没问题的- ‘\0’ 是整数值零,在这个上下文中被评估为空指针常量。不过这并不是一个好主意,因为它传达了作者感到混乱的感觉。如果你的意思是 NULL,就说 NULL - caf
4
@caf正是我想写的,点赞+1。@Chris,请注意,在C语言中,字符字面量实际上具有类型“int”,而不是“char”(但这并不会改变其成为空指针常量的能力 -“char”也是整数类型)。修正它,我也会给你点赞xD。 - Johannes Schaub - litb
显示剩余6条评论

8
根据C99规范:
- NULL 扩展为一个空指针常量,不要求但通常是类型为void * - '\0' 是一个字符常量;字符常量的类型为int,因此等价于普通的0 - "\0" 是一个以空字符结尾的字符串字面量,并等价于复合文字(char [2]){ 0, 0 } NULL, '\0'0 都是空指针常量,因此在转换时它们都会产生空指针;而"\0"则产生一个非空的char *(修改是未定义的,应该视作const);由于每个该字面量的出现都可能有不同的指针,因此它不能用作标志值。
尽管您可以使用值为0的任何整数常量表达式作为空指针常量(例如'\0'sizeof foo - sizeof foo + (int)0.0),但您应使用NULL来明确您的意图。

虽然有些吹毛求疵,但是NULL只有在被定义为(void*)0时才会被展开为一个空指针(此时它既是空指针常量又是空指针)。如果它是0或者类似的值,则它仅仅是一个空指针常量,还需要转换成一个空指针。 - Johannes Schaub - litb
@litb:实际上,'\0' 可能不是一个有效的空指针常量,因为它是一个字符常量(C99 6.4.4.4),而不是整数常量(C99 6.4.4.1);字符常量有时被称为整数字符常量,但这是否使它们成为 C99 6.3.2.3 所要求的 "整数常量表达式" 呢? - Christoph
@litb:谢谢 - 不知道为什么我没有自己搜索这个术语。 - Christoph

6

这两个例子中,第一个是类型错误:'\0'是一个字符,不是指针。编译器仍然接受它,因为它可以将其转换为指针。

第二个例子只是巧合“起作用”。"\0"是一个由两个字符组成的字符串字面量。如果在源代码中多次出现这些字符,编译器可能会但不一定会使它们相同。

因此,正确的写法应该是:

char* array[] = { "abc", "def", NULL };

你正在测试 array[index]==NULL。测试第二个条件的正确方法是array[index][0]=='\0';你也可以在字符串中省略 '\0'(即将其拼写为""),因为这已经包含了一个空字节。


我发现这个问题有两个可行的答案,但都不是技术上正确的,也不是出题人认为的原因。 - Chris Lutz

1

从技术上讲,'\0'是一个字符,而"\0"是一个字符串,因此如果您正在检查空终止字符,则前者是正确的。然而,正如Chris Lutz在他的答案中指出的那样,您目前的比较方式是不起作用的。


使用 '\0' 进行比较是将 char *char 进行比较,这就像将苹果与橙子进行比较一样。实际上,两者都不正确。 - Chris Lutz
1
@Chris: <nitpick>使用 '\0' 是将 char *int 进行比较</nitpick>。 - Christoph
@Christoph - 这就是Chris Lutz指出的。我没有更新我的答案,而是将我的答案指向了他的答案。 - ChrisF

0
字符数组以空字符结尾只是在C中用于字符串的一种惯例而已。你所处理的是完全不同的东西——字符指针数组,所以它与C字符串的惯例没有任何关系。当然,你可以选择用空指针来结束它;这或许可以成为你对指针数组的惯例。还有其他方法可以实现相同的效果。你不能问别人它应该如何工作,因为你假设了某种并不存在的惯例。

变长数组的惯例是使用NULL作为哨兵值。 - u0b34a0f6ae

0

空终止是一种糟糕的设计模式,最好留在历史书籍中。C字符串背后仍然有很多惯性,所以在那里无法避免。但在OP的示例中没有使用它的理由。

不要使用任何终止符,并使用sizeof(array)/ sizeof(array [0])来获取元素数量。


1
+1 是为了获取数组大小,sizeof array/sizeof array[0]。但是你认为这足以不使用终止符吗? - Andrew-Dufresne
2
只有在数组被声明在作用域内时,此方法才有效。如果它是通过指针传递的,则无法使用 sizeof(array),您只能通过参数传递大小或搜索空终止符来获取长度。 - Carson Myers
我应该更加明确。在数组旁边传递元素的数量,比使用终止符更安全和更清晰。 - Alan

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