char数组的空终止

考虑以下情况:

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

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

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

C不会阻止你破坏你不拥有的内存。 这导致未定义的行为 。 你的程序可以做任何事情 – 它可能会崩溃,它可以默默地垃圾其他variables,造成混乱的行为,它可能是无害的,或其他任何东西。 请注意,您的程序不能保证可靠地工作或可靠地崩溃。 你甚至不能立即依靠它崩溃。

这是为什么scanf("%s")是危险的,绝对不能使用的一个很好的例子。 它不知道你的数组的大小,这意味着没有办法安全地使用它。 相反,避免scanf和使用更安全,如fgets() :

fgets()最多读入一个小于stream的大小字符,并将它们存储到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和string处理。 这是可以做到的,可以安全地完成,但C会一直踢,尖叫。

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

 scanf("%4s", A); 

为了读取最大值 从标准input4个字符。

没有一个保留的字符,所以你必须小心,不要将整个数组填充到不能空终止的地步。 Char函数依赖于null结束符,如果你发现自己处于你描述的状态,那么你将会得到灾难性的结果。

你会看到很多C代码将使用诸如strncpy之类的函数的“n”派生。 从该手册页你可以阅读:

strcpy()和strncpy()函数返回s1。 stpcpy()和stpncpy()函数返回一个指向s1的终止'\ 0'字符的指针。 如果stpncpy()不是用NUL字符终止s1,而是返回一个指向s1 [n]的指针(这不一定是指有效的内存位置)。

strlen也依赖于空字符来确定字符缓冲区的长度。 如果和当你错过了这个angular色,你会得到不正确的结果。

你会以未定义的行为结束。

正如你所说, A的大小总是5,所以如果你阅读5个或更多的charscanf将尝试写入内存,它不应该修改。

不,没有为\0符号保留空间/字符。

任何长度超过4个字符的string都将导致scanf超出数组边界。 由此产生的行为是不确定的,如果你幸运的话,会导致你的程序崩溃。

如果你想知道为什么scanf不停止写太长而不能存储在数组A中的string,那是因为scanf没有办法知道sizeof(A)是5.当你传递一个数组作为参数时一个C函数,数组衰减到指向数组中第一个元素的指针。 所以,没有办法查询函数内数组的大小。

为了限制读入到数组中的字符的使用

 scanf("%4s", A); 

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

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

请不要把char foo [5]看作一个string。 把它看作放5个字节的地方。 你可以在那里存储5个字符而不是null,但是你必须记住你需要做一个memcpy(otherCharArray,foo,5)而不是使用strcpy。 你也必须知道另一个CharArray有足够的空间来处理这5个字节。

空字符用于终止数组。 它是在数组的末尾,并显示该数组在该点结束。 该数组自动使最后一个字符为空字符,以便编译器可以很容易地理解数组已经结束。

\ 0是一个终止符运算符,当数组满了时,如果数组不满,那么\ 0将在数组的末尾,当你input一个string,它会从数组的末尾读取