为什么对于长度为 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..
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"
不适合 puts
。 puts
需要一个以零结尾的字符串。但是,您的 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=]'
就可以了。
所以我有一组简单的代码:
#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..
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"
不适合 puts
。 puts
需要一个以零结尾的字符串。但是,您的 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=]'
就可以了。