C语言中的常量字符字符串是否总是以空字符结尾?

13

C语言中的常量字符字符串是否总是以空字符结尾,没有例外?

例如,下面这段C代码是否总会输出"true":

const char* s = "abc";
if( *(s + 3) == 0 ){
   printf( "true" );
} else {
   printf( "false" );
} 

7
回答是肯定的。 - user3700562
我认为你的意思是if( *(s + 3) == '\0' ) - Aditi Rawat
1
是的 - 尽管你的问题听起来像你怀疑否则... - Steve
是的,在C语言中,所有字符串都由以0结尾的字符串表示。 - Sir Jo Black
3
"\0" 是一个值为0的字符,可以与0进行比较。 - Unh0lys0da
4个回答

19

只有包含空字符的字符串才能被称作字符串

字符串是由连续字符序列组成的,以第一个空字符结尾并包含该空字符。C11 §7.1.1 1

"abc"字符串字面值。它总是包含一个空字符。一个字符串字面值可能包含多个空字符。

"def\0ghi"  // 2 null characters.

然而,在接下来的内容中,x不是一个字符串(它是一个没有null字符char数组)。yz都是char数组且都是字符串。

char x[3] = "abc";
char y[4] = "abc";
char z[] = "abc";
使用 OP 的代码,变量 s 指向一个字符串字面值 "abc"。表达式 *(s + 3)s[3] 的值为0。试图修改 s[3] 是未定义的行为,原因是 1)s 是一个 const char * 类型;2)s 指向的数据是一个字符串字面值。试图修改一个字符串字面值也是未定义行为。
const char* s = "abc";
更深入:C语言不定义“常量字符串”。该语言定义了一个“字符串字面量”,如"abc",它是一个大小为4的字符数组,值为'a''b''c''\0'。试图修改这些内容是未定义行为(UB)。这在使用上取决于上下文。
标准C库定义了“字符串”。
对于const char* s = "abc";s是指向类型为char的数据的指针。作为一个const some_type* 指针,使用s来修改数据是UB。 s被初始化为指向“字符串字面量” "abc"s 本身不是一个“字符串”。 s 最初指向的内存是一个“字符串”。

我认为在上面的第一种情况中,x不能保证以null结尾。(请参见下面Felix的答案) - Tyler Durden
1
@TylerDurden 这里写着这样一句话。x 不是一个字符串,因为它保证不被终止 - Eugene Sh.
@TylerDurden 是的,x[] 不是以空字符结尾,因此不是一个“字符串”,但是"abc"仍然以空字符结尾。当然,在 char x[3] = "abc"; 中使用它使得那个 "abc" 的空字符变得不必要,因为它没有被使用。 - chux - Reinstate Monica

13
简而言之,是的。一个字符串常量当然是一个字符串,而且根据定义,字符串是以0结尾的。
如果您像这样使用字符串常量作为数组初始化程序:
char x[5] = "hello";

由于没有空间,x 中不会有 0 终止符。

但是使用

char x[] = "hello";

它将在那里,x 的大小为6。


只是在第一个例子中,没有终止符的不是字符串常量,而是生成的数组。 - Eugene Sh.
好的,这种编程语言规定常量字符字符串必须以空字符结尾,还是仅仅是一种约定俗成的做法? - Tyler Durden
1
这是语言标准。没有任何未被定义语言行为的惯例 - Eugene Sh.
@EugeneSh。但这不是我写的吗? - user2371524
@FelixPalmen 是的。我的意思是问题实际上是关于字符串常量的。所以实际答案在第一行。其他的只是有用的补充。 - Eugene Sh.

2

字符串的概念被定义为由零字符终止的字符序列。重要的是,该序列是否可修改,即相应声明是否具有修饰符const并不重要。

例如,在C语言中,字符串字面量具有非常数字符数组类型。因此,您可以编写如下代码:

char *s = "Hello world";

在这个声明中,标识符s指向字符串的第一个字符。
您可以使用字符串字面量自己初始化字符数组。例如:
char s[] = "Hello world";

这个声明等同于:
char s[] = { 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '\0' };

然而在C语言中,你可以在字符数组的初始化中排除终止零。

例如:

char s[11] = "Hello world"; 

虽然字符串文字作为初始化器包含终止零,但它被排除在初始化之外。结果,字符数组s不包含字符串。


1
在C语言中,没有像C++和Java中的“字符串”数据类型。
每个有能力的计算机科学学位课程都应该提到的重要原则是:信息是符号加解释。
“字符串”通常被定义为以空字节('\0')结尾的任何字符序列。
正在发布的“陷阱”(具有中间值为0的字符/字节数组)只是一种不同的解释方式。将字节数组视为字符串与将其视为字节([0,255]中的数字)具有不同的应用程序。显然,如果您要打印到终端,则可能要打印字符,直到达到空字节。如果您要保存文件或在数据块上运行加密算法,则需要支持字节数组中的0。
还可以将“字符串”作为字节数组进行可选解释。

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