在将短语存储在数组中时,是否需要考虑空字符并分配额外的空间,还是只需要提及需要存储的字符数?
是的,您应该计算空字符来分配额外的空间。您必须注意这里的重点:
S[number]= "hello\n";
如果number 值等于(或大于)字符串"hello\n" 的长度,则将\0 附加到S[] 数组中@ 为\0 字符(或者如果您根本不提供大小)如s[] = "hello\n";)。
来自:ISO/IEC 9899:201x 委员会草案,2011 年 4 月 12 日 N1570:
[...]
14:字符类型的数组可以由字符串文字或 UTF-8 字符串文字初始化,可选用大括号括起来。字符串文字的连续字节(包括终止空字符如果有空间或如果数组大小未知)初始化数组的元素。
[..]
示例 8 声明
char s[] = "abc", t[3] = "abc";
定义“普通”字符数组对象 s 和 t,其元素用字符串字面量初始化。此声明等同于:
char s[] = { 'a', 'b', 'c', '\0' },
t[] = { 'a', 'b', 'c' }; // you are missing this point
数组的内容是可以修改的。另一方面,声明
char *p = "abc";
定义p 类型为pointer to char'' and initializes it to point to an object with typearray of char'',长度为4,其元素用字符串字面量初始化。如果尝试使用 p 修改数组的内容,则行为未定义。
正如我对您的问题的评论:这取决于您在声明中给出的 number 的值。它可能添加'\0' char(在大多数情况下)或可能不添加(在一个有效的声明中)。这是非常重要的一点,大多数答案都丢失了。
更珍贵:
注意"hello"是六字符长字符串(包括字符串终止nul char '\0')
S[6]= "hello";
等同于:
S[6]= {'h', 'e', 'l', 'l', 'o', '\0'};
// ^ is 6
但是
S[5]= "hello";
在 C 中有效,但不要附加 nul \0 char。相当于:
S[5]= {'h', 'e', 'l', 'l', 'o'};
// ^ is 5
现在要注意这一点非常重要,在此声明中,如果在声明中给出了 5 = 5,那么您可以使用循环将字符打印为 for(i = 0; i < sizeof(S); i++),但您不能使用 %s 或类似 strcpy 的函数在S[] 上——使用这个调用未定义的行为。
除此之外,我还建议您在编译代码时始终使用 -Wall 和 -pedantic 标志。现在看看它是如何工作的:
让我们编译这段代码,使用char s[4] = "hello";:
int main(){
char s[4] = "hello";
int i = 0;
for (i = 0; i < sizeof s; i++)
printf("%c", s[i]);
printf("\n");
return 0;
}
您将收到如下警告:
$ gcc -Wall -pedantic x.c
x.c: In function ‘main’:
x.c:3:15: warning: initializer-string for array of chars is too long
[enabled by default]
但是代码在 C 中是有效的,char s[5] = "hello"; 编译相同的代码它不会给你任何警告,这也意味着它是一个有效的代码,但显然它没有添加 \0。
#include <stdio.h>
int main(){
char s[5] = "hello";
int i = 0;
for (i = 0; i < sizeof s; i++)
printf("%c", s[i]);
printf("\n");
return 0;
}
检查这个(你应该注意到这次编译器不会发出任何警告):
$ gcc -Wall -pedantic x.c
@:~$ ./a.out
hello
但这一次我们应该使用printf("%s", s);,它会调用未定义的行为。
因此,当您使用字符串字面量创建数组时,最好避免在声明中使用大小,例如:
char s[] = "hello";
但这与char s[6] = "hello"; 相同,并且您不能将新字符附加到s[] 为strcat(s, " world!")。
如果您打算在代码中修改s[],那么您可能希望创建一个足够大的字符串:
char s[100] = "hello";
现在strcat(s, " world!") 是完全有效的代码。