以下面的代码为例:
int main(){
char string[] = { 'h' , 'e', 'l', 'l', 'o' };
printf(string);
printf("\n%d", strlen(string));
}
输出将是:
hello
6
所以从一开始我就可以看到strlen
的值偏离了1,但是如果考虑到这一点,这似乎并不是一个障碍。
什么时候不终止字符串会造成问题?
答案 0 :(得分:10)
在字符串中不使用空终止有什么影响?
从技术上讲没有,因为C字符串-by definition-以空字符终止:
字符串是连续的字符序列,以第一个空字符结尾并包含第一个空字符。
因此,如果未正确终止,则它不是字符串。
如果将非字符串传递给需要字符串的代码,则会调用未定义的行为。
答案 1 :(得分:3)
根据C中的定义,字符串必须以null termination character
结尾,否则不是字符串。
如果不使用终止符而您尝试输出内容,则会有未定义的行为,这取决于分配数组后内存中包含的内容。
因此您可能很幸运,并且终止符为空,因为内存中已经有该字符了,或者您最终可能会在控制台上打印乱码,甚至崩溃(如果在找到{{{1 }}。
例如:
termination character
在代码中,我将分配给数组的内存之后的字符设置为字符#include <stdio.h>
#include <string.h>
int main(){
char string[5];
memset(string, 'z', 6);
string[0] = 'h';
string[1] = 'e';
string[2] = 'l';
string[3] = 'l';
string[4] = 'o';
printf("%s\n", string);
printf("%d\n", (int)strlen(string));
}
。如果运行此命令,则大多数情况下它将崩溃,因为z
开始打印,直到找到一个空终止符为止(并且printf
之后有hello
并且没有终止!)。
答案 2 :(得分:3)
好的,让我们考虑一个更简单的程序,它没有任何未定义的行为。这是打印 5 。
#include <stdio.h>
#include <string.h>
int main(void) {
char string[6] = "hello";
printf("%zu\n", strlen(string));
}
该程序具有不确定的行为
#include <stdio.h>
#include <string.h>
int main(void) {
char string[5] = "hello";
printf("%zu\n", strlen(string));
}
因为空终止符不适合string
,并且strlen
要求输入必须以空终止。 C11 7.1.1
[...]字符串是一个连续的字符序列,由第一个空字符终止,包括第一个空字符。[...]
和
C11 7.24.6.3 The strlen function:
说明
2
strlen
函数计算由指向的字符串的长度返回
3
strlen
函数返回前面的字符数 终止的空字符。
这里的实践有什么区别?当我使用-S -O3
进行编译以生成程序集时,在第一种情况下,数字 5 被硬编码,而不是被调用strlen
。在第二种情况下,优化器实际上strlen
。但是,它不是在内存中提供字符串,而是通过以下方式创建的:
movl $1819043176, 2(%rsp)
即将一个64位常量值0x6c6c6568
移到了堆栈上……对于hello\0\0\0
来说,它是低位优先的。然后代码再次打印出5。但是,编译器可以对此进行了诊断,并完全拒绝编译您的程序,因为它毫无意义,而且行为不确定。
猜猜下面的程序在执行gcc -O3 -Werror
编译后会说什么?
#include <stdio.h>
#include <string.h>
int main(){
char string[5];
strcpy(string, "Hello world!!!");
printf("%zu\n", strlen(string));
}
没事!因为它不编译,所以吐出来
In file included from /usr/include/string.h:494:0,
from strcpyexample.c:2:
In function ‘strcpy’,
inlined from ‘main’ at strcpyexample.c:6:5:
/usr/include/x86_64-linux-gnu/bits/string_fortified.h:90:10: error: ‘__builtin___memcpy_chk’ writing 15 bytes into a region of size 5 overflows the destination [-Werror=stringop-overflow=]
return __builtin___strcpy_chk (__dest, __src, __bos (__dest));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors