在字符串中不使用空终止的后果是什么?

时间:2018-10-09 12:22:35

标签: c string char

以下面的代码为例:

int main(){
    char string[] = { 'h' , 'e', 'l', 'l', 'o' };
    printf(string);
    printf("\n%d", strlen(string));
}

输出将是:

hello
6

所以从一开始我就可以看到strlen的值偏离了1,但是如果考虑到这一点,这似乎并不是一个障碍。

什么时候不终止字符串会造成问题?

3 个答案:

答案 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。在第二种情况下,优化器实际上 did 意识到它不知道字符串的长度,因此需要调用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