为什么对于长度为 k 的字符串需要 char[k + 1] 而不是 char[k] ?

Why do I need char[k + 1] instead of char[k] for a string with length k?

所以我有一组简单的代码:

#include <stdio.h>

int main()
{
  char x[3] = "ABC"; // (*)
  puts(x);
  return 0;
}

它returns一个奇怪的输出:

ABC¬ a

使用 的最佳答案,我发现当我将 x[3] 更改为 x[4] 时一切正常。

但是为什么呢?为什么我在 x[3] 上得到一个奇怪的输出,为什么 x[4] 没问题?

终止[=12=]没有space。事实上,我预计在这种情况下编译会失败。

尝试

char x[4] = "ABC";

或者,正如 @Zeta 建议的那样,

char x[] = "ABC";

您的字符串应该 终止 [=11=]

使用

char x[] = "ABC";

相反。

Using the top answer from this question, I found that when I change x[3] to x[4] everything runs fine.

BUT WHY? What is going on that x[3] is giving such a strange output?

puts() 继续前进,直到遇到 终止 [=11=] 字节。因此,如果您不在字符串末尾提供一个,它会将 运行 保留在字符串后面,直到找到 [=11=]crashes..

puts() description:

The function begins copying from the address specified (str) until it reaches the terminating null character ('[=16=]'). This terminating null-character is not copied to the stream.

一个字符串以空字符结束 - 你还没有为它分配 space。

char x[] = "ABC";

让编译器为您完成工作!

既然你已经问过 "why" 这会产生 ABC -a,这里有一个解释:你的 char x[3] = "ABC" 不适合 putsputs 需要一个以零结尾的字符串。但是,您的 x 基本上是:

char x[3] = {'A', 'B', 'C'};

如您所知,无法获取(动态)数组的长度:

char * allocate(){
   return malloc(rand() + 1);
}

char * mem = allocate(); // how large is mem??

你无法知道它有多长。然而,要打印一个字符串,它只不过是内存中的连续字符序列,函数需要知道字符串(也称为字符序列)何时结束。

这就是 American Standard Code for Information Interchange (ASCII) and many other character sets contain the null character 的原因。它基本上是 char 的值 0:

char wrong_abc[3]   = {'A', 'B', 'C'};     // when does it end?
char correct_abc[4] = {'A', 'B', 'C', 0 }; // oh, there's a zero!

现在像 puts 这样的函数可以简单地检查 0:

// Simplified, actual "puts" checks for errors and returns
// EOF on error or a non-negative int on succes.
void puts(const char * str){
   int i = 0;

   while(str[i] != 0){
      putchar(str[i]);
      i++;
   }

   putchar('\n');
}

这就是为什么你

  • 需要记忆字符序列+1中的所有字符,
  • 当您忘记 0 时会出现未定义的行为。

上面 puts 的实现永远不会找到 0 并意外地离开你拥有的内存(或访问其他数据),这通常会导致段错误或其他错误(或更糟的是,不会'被长时间检测到然后产生严重错误)。这种情况下的实际行为是不确定的。

请注意,字符串文字(例如 "ABC")自动在末尾有一个 '[=28=]'。此外,编译器足够聪明,可以为您计算文字的长度,因此您可以简单地使用

char x[] = "ABC";

这样一来,以后更改字面量就不用担心了。

每次你声明一个字符串变量时,只要在你需要的结束字符的基础上再增加一个字符'[=10=]'就可以了。