C中的字符串声明

时间:2017-01-17 06:21:10

标签: c arrays string initialization undefined-behavior

下面显示的代码1和代码2之间有什么区别。在这两种情况下,我都是相同的。内部有什么不同吗?

代码1

char test[30]="KEL";
strcat (test,"DATA");

代码2

char test[]="KEL"
strcat (test,"DATA");

4 个答案:

答案 0 :(得分:6)

在您的第一个代码示例中,test将有30个字符的空格 前4个将是字符串"KEL" + nul终结符(如果我的内存服务,其余的也将初始化为0,感谢chux)。将"DATA"连接到它是明确定义的。

在第二个样本中,它只有4个空格,因为缓冲区的长度是从字符串文字推导出来的。当您将"DATA"连接到它时,您将超出缓冲区的边缘进行写入。这是未定义的行为。

如果标准显式未定义行为,那么编译器和运行时的实现可以做任何事情。你的程序会崩溃。或者它可以运行险恶的代码。它也可以出现,就像你的情况一样。但这不是你可以依赖的东西。

答案 1 :(得分:2)

让我们从C标准开始。根据它(6.7.9初始化)

  

14字符串数组可以用字符串初始化   文字或UTF-8字符串文字,可选择用大括号括起来。   字符串文字的连续字节(包括终止空值)   字符,如果有空间或数组的大小未知)   初始化数组的元素。

  

19初始化应在初始化程序列表顺序中进行,每个顺序   初始化程序为特定的子对象提供覆盖任何子对象   以前列出的同一子对象的初始值设定项; 151)全部   未初始化的子对象应初始化   隐含地与具有静态存储持续时间的对象相同。

如何将这些引号应用于字符数组初始化?

在此代码段中

char test[30]="KEL";
strcat (test,"DATA");

数组test被声明为具有30个元素。数组的前四个元素由字符串文字的元素显式初始化,可以表示为{ 'K', 'E', 'L', '\0' }。所有其他元素都隐式初始化为具有静态存储持续时间值'\0'的对象。

所以在声明内部的数组测试内部看起来像是

{ 
'K', 'E', 'L', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0' 
}

在第二段代码中

char test[]="KEL"
strcat (test,"DATA");

声明了一个未知大小的数组,其大小根据初始值设定项的数量计算。由于字符串文字有四个字符{ 'K', 'E', 'L', '\0' },因此数组将具有完全相同的四个字符。

在第一个代码段中,您可以更改值为'\0'的数组元素。例如,你可以写

test[3] = 'D';
test[4] = 'A';
test[5] = 'T';
test[6] = 'A';

,数组看起来像

{ 
'K', 'E', 'L', 'D', 'A', 'T', 'A', '\0', '\0', '\0', '\0', '\0', '\0', 
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0' 
}

结果它将包含字符串"KELDATA"。而不是带有赋值的几个语句,编写

更简单
strcat (test,"DATA");

并获得相同的结果。

然而,第二个代码片段呢?因为它被认为没有任何"免费"除了由字符串文字"KEL"初始化的元素之外的元素。所以你可以改变的只是他的四个要素。您不能将新数据附加到存储在数组中的字符串文字。你只能覆盖它们。

因此这句话

strcat (test,"DATA");

将导致覆盖数组之外的内存,并且程序将具有未定义的行为。

答案 2 :(得分:1)

char test[30]="KEL";

在这种情况下,编译器在堆栈中分配30个字节。只要最终字符串的大小不超过30个字节(包括空终止符),就可以使用strcat连接字符串。

char test[]="KEL"

但是,在这种情况下,编译器本身决定为给定的字符串分配足够的内存。它是3个字节加上' \ 0'(空终止符)所以没有足够的空间来容纳另一个字符。

尝试编写超出编译器分配的内容,正如StoryTeller已经说明的那样,未定义的行为,这意味着程序可能正确执行或可能会崩溃。或者可以两次做。未定义的行为也是非常特定于编译器的属性。 gcc,clang或任何其他编译器编译的完全相同的源代码可能会产生不同的结果。

注意:字符类型(char)的大小为1个字节。

答案 3 :(得分:-1)

代码1 char test[30]="KEL"; //不允许输入大于30个字符但小于30个字符的值。

代码2 char test[]="KEL" //免费提供您无需输入任何固定大小的值。