空数字符串终止

时间:2012-08-18 15:49:45

标签: c null char

考虑以下案例:

#include<stdio.h>
int main()
{
    char A[5];
    scanf("%s",A);
    printf("%s",A);
}

我的问题是char A[5]是否只包含两个字符。说“ab”,然后是A[0]='a'A[1]='b'A[2]='\0'。 但是如果输入是“abcde”,那么在这种情况下'\0'A[5]'\0'吗? 如果是,为什么? sizeof(A)将始终返回5作为答案。然后,当数组已满时,是否为'\0'保留了sizeof()不计算的额外字节?

8 个答案:

答案 0 :(得分:50)

如果键入超过四个字符,则额外字符和空终止符将写在数组末尾之外,覆盖不属于该数组的内存。这是一个缓冲区溢出。

C不会阻止你破坏你不拥有的记忆。这导致 undefined behavior 。你的程序可以做任何事情 - 它可能会崩溃,它可能会默默地删除其他变量并导致混乱的行为,它可能是无害的,或其他任何东西。请注意,无法保证您的程序可靠运行或可靠运行。你甚至不能立即依赖它崩溃。

这是一个很好的例子,说明为什么scanf("%s")是危险的,永远不应该使用。它不知道你的阵列的大小,这意味着没有办法安全地使用它。相反,请避免使用scanf并使用更安全的内容,例如fgets()

  

fgets()从流中读取最多一个小于字符的字符,并将它们存储到s指向的缓冲区中。读数在EOF或换行符后停止。如果读取换行符,则将其存储到缓冲区中。终止空字节('\ 0')存储在缓冲区中的最后一个字符之后。

示例:

if (fgets(A, sizeof A, stdin) == NULL) {
    /* error reading input */
}

令人讨厌的是,fgets()会在数组的末尾留下一个尾随的换行符('\ n')。所以你可能还想要代码来删除它。

size_t length = strlen(A);
if (A[length - 1] == '\n') {
    A[length - 1] = '\0';
}

唉。一个简单的(但破碎的)scanf("%s")变成了7行怪异。这是当天的第二课:C不擅长I / O和字符串处理。它可以完成,它可以安全地完成,但C会一直踢和尖叫。

答案 1 :(得分:8)

正如已经指出的那样 - 你必须定义/分配一个长度为N + 1的数组,以便正确存储N个字符。可以限制scanf读取的字符数量。在您的示例中,它将是:

scanf("%4s", A);

为了读取最大值来自stdin的4个字符。

答案 2 :(得分:3)

没有保留的字符,因此必须注意不要将整个数组填充到无法终止的位置。 Char函数依赖于null终止符,如果你发现自己处于你描述的情境中,你将会从中获得灾难性的结果。

您将看到的许多C代码将使用strncpy等函数的'n'派生词。从该手册页中,您可以阅读:

  

strcpy()和strncpy()函数返回s1。 stpcpy()和   stpncpy()函数返回一个        指向s1的终止“\ 0”字符的指针。如果stpncpy()没有用NUL终止s1        它返回一个指向s1 [n]的指针(它不一定是指有效的存储器)        ory location。)

strlen还依赖于null字符来确定字符缓冲区的长度。如果您错过了该角色,您将得到不正确的结果。

答案 3 :(得分:3)

您将最终得到未定义的行为

正如你所说,A的大小总是5,所以如果你读了5个或更多char s,scanf会尝试写入内存,那不是应该修改。

不,\0符号没有保留的空格/字符。

答案 4 :(得分:3)

任何长度超过4个字符的字符串都会导致scanf超出数组范围。由此产生的行为是未定义的,如果您很幸运,将导致您的程序崩溃。

如果您想知道为什么scanf不会停止编写太长而无法存储在数组A中的字符串,那是因为scanf无法知道{ {1}}是5.当您将数组作为参数传递给C函数时,数组衰减到指向数组中第一个元素的指针。因此,无法在函数内查询数组的大小。

为了限制读入数组的字符数,请使用

sizeof(A)

答案 5 :(得分:3)

c中的字符数组只是指向内存块的指针。如果你告诉编译器为字符保留5个字节,那就是。如果您尝试在那里放入超过5个字节,它将覆盖超过您保留的5个字节的内存。

这就是为什么c可以有严格的安全实现。你必须知道你只会写4个字符+一个\ 0。 C将允许您覆盖内存,直到程序崩溃。

请不要将char foo [5]视为字符串。可以把它想象成放置5个字节的点。你可以在那里存储5个字符而不是null,但你必须记住你需要做一个memcpy(otherCharArray,foo,5)而不是使用strcpy。您还必须知道otherCharArray有足够的空间容纳这5个字节。

答案 6 :(得分:-1)

空字符用于终止数组。它位于数组的末尾,表明数组在该点结束。数组自动将最后一个字符作为空字符,以便编译器可以很容易地理解数组已结束。

答案 7 :(得分:-3)

\ 0是一个终结符运算符,它在数组已满时终止 如果数组未满,则\ 0将位于数组的末尾 当你输入一个字符串时,它将从数组的末尾读取