C语言中的常量字符字符串是否总是以空字符结尾,没有例外?
例如,下面这段C代码是否总会输出"true":
const char* s = "abc";
if( *(s + 3) == 0 ){
printf( "true" );
} else {
printf( "false" );
}
只有包含空字符的字符串才能被称作字符串。
字符串是由连续字符序列组成的,以第一个空字符结尾并包含该空字符。C11 §7.1.1 1
"abc"
是字符串字面值。它总是包含一个空字符。一个字符串字面值可能包含多个空字符。
"def\0ghi" // 2 null characters.
然而,在接下来的内容中,x
不是一个字符串(它是一个没有null字符的char
数组)。y
和z
都是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)。这在使用上取决于上下文。const char* s = "abc";
,s
是指向类型为char
的数据的指针。作为一个const some_type*
指针,使用s
来修改数据是UB。 s
被初始化为指向“字符串字面量” "abc"
。 s
本身不是一个“字符串”。 s
最初指向的内存是一个“字符串”。x
不是一个字符串,因为它保证不被终止。 - Eugene Sh.x[]
不是以空字符结尾,因此不是一个“字符串”,但是"abc"
仍然以空字符结尾。当然,在 char x[3] = "abc";
中使用它使得那个 "abc"
的空字符变得不必要,因为它没有被使用。 - chux - Reinstate Monicachar x[5] = "hello";
由于没有空间,x
中不会有 0 终止符。
但是使用
char x[] = "hello";
它将在那里,x
的大小为6。
字符串的概念被定义为由零字符终止的字符序列。重要的是,该序列是否可修改,即相应声明是否具有修饰符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
不包含字符串。
if( *(s + 3) == '\0' )
。 - Aditi Rawat