#include <stdio.h>
int main() {
char a = 5;
char b[2] = "hi"; // No explicit room for `\0`.
char c = 6;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
每当我们编写一个用双引号括起来的字符串时,C 都会自动为我们创建一个字符数组,其中包含该字符串,并以 \0 字符结尾 http://www.eskimo.com/~scs/cclass/notes/sx8。 html
在上面的示例中,b只有 2 个字符的空间,因此空终止字符没有位置可放置,但编译器正在重新组织内存存储指令,以便将a和c存储b在内存中,以便为 a 腾出\0空间数组的末尾。
这是预期的还是我遇到了未定义的行为?
假设我有以下c char数组:
char okaysize4[5] = "four"; // line 5
char toosmall4[4] = "four"; // line 6
char toosmall3[3] = "four"; // line 7
Run Code Online (Sandbox Code Playgroud)
当我使用gcc 4.4.7编译时,我收到以下错误:
array.c:7:警告:chars数组的初始化字符串太长
第7行预计会出现此错误,因为我试图将5个字符填充("four" + \0)到3个元素数组中.第5行也没有错误,因为5元素数组足够大.
然而,我很惊讶第6行没有类似的错误.最终初始化的toosmall4是未终止的字符串,这可能会导致各种麻烦.
我的理解是"four",由于null终止符,c字符串文字应该是五个字符长.实际上sizeof("four")是5.那么为什么编译器不会在这里给出错误?
有没有什么方法可以改变我的声明/定义/初始化,以便在这种情况下标记错误?
我知道C中的字符串只是字符数组。因此,我尝试了以下代码,但给出了奇怪的结果,例如垃圾输出或程序崩溃:
#include <stdio.h>
int main (void)
{
char str [5] = "hello";
puts(str);
}
Run Code Online (Sandbox Code Playgroud)
为什么不起作用?
它可以用干净地编译gcc -std=c17 -pedantic-errors -Wall -Wextra。
注意:对于在声明字符串时未能为NUL终止符分配空间而引起的问题,本帖子旨在用作规范的FAQ。
C18标准指出6.7.9/2:
初始化程序不得尝试为未包含在正在初始化的实体中的对象提供值。
目前还不清楚这意味着什么。有一个相关主题:用于字符串初始化的Incretent gcc诊断。我引用的子句用于解释以下初始化产生的错误:
//error: excess elements in array initializer char a[5]
char a[5] = {'h','e','l','l','o','\0'};
Run Code Online (Sandbox Code Playgroud)
其中的initializer-list长度超过正在初始化的数组的大小。
但是考虑更简单的例子:
int main(void){
int a;
int b = (a = 3);
}
Run Code Online (Sandbox Code Playgroud)
这里的初始值设定项(a = 3)是assignment-expression。并且初始化程序为另一个对象分配一个值,这将导致违反约束。
为什么不打印任何诊断信息?
#include<stdio.h>
void main()
{
int i;
char str[4] = "f4dfkjfj";
char str2[3] = "987";
char str3[2] = {'j','j','\0'};
//printf("%c\n",str[1]);
//printf("%c\n",1[str]);
puts(str);
puts(str2);
puts(str3);
}
Run Code Online (Sandbox Code Playgroud)
产出观察:
str2打印无论从内容str2和str.str3打印件str3,str2和str.为什么这个行为在打印非nul时结束了字符串,它与先前定义的字符串连接,直到puts()函数遇到"\ 0"字符(此函数打印直到遇到nul)?
(注意:我故意用太长的初始化字符串初始化它们)
虽然我声明了两个char字符串,其内容相同,但输出不同.
#include <stdio.h>
int main(void)
{
/* Initialization of two different array that We deal with */
char arr1[10]={'0','1','2','3','4','5','6','7','8','9'};
char arr2[10]="0123456789";
/* Initialization End */
for(int i = 0 ; i < 11 ; ++i)
{
printf("arr1[%d] is %c \t\t",i,arr1[i]);
printf("arr2[%d] is %c\n",i,arr2[i]);
if(arr1[i]=='\0')
printf("%d . character is \\0 of arr1 \n",i);
if(arr2[i]=='\0')
printf("%d . character is \\0 of arr2 \n",i);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我预计,对于'i'的任何值,两个if语句都是正确的.无论'我'是什么都没关系.
我知道如何用两种不同的方式初始化 C 中的字符串。
char str[] = "abcd";
char str[] = {'a','b','c','d','\0' };
Run Code Online (Sandbox Code Playgroud)
清晰地书写"abcd"而不是{'a','b','c','d','\0' }节省时间且舒适。
是否有任何特殊原因可以让我们像最后一行那样初始化字符串?它在某些情况下有用还是多余?
在编写c代码时,我尝试编写strcpy自己的代码,并且遇到了这个问题.
#include <stdio.h>
#include <string.h>
void strcpy2(char *s, char *t);
int main() {
char a[10] = "asds";
char b[10] = "1234567890";
strcpy2(a, b);
printf("Copy completed! : %s", a);
return 0;
}
void strcpy2(char *s, char *t) {
while ((*s++ = *t++));
}
Run Code Online (Sandbox Code Playgroud)
错误代码:已完成退出代码-1073741819(0xC0000005)
感谢这个问题,我学会了字符串应该以'\ 0'结尾,但为什么上面的代码不起作用,即使它在声明时不会导致错误?(当char b [10] ="123456789"时效果很好)
那么,'\ 0'究竟如何影响这个过程并最终导致错误?(运行时?编译时间?等)(我只知道'\ 0'应该是字符串的结尾)