strcat()正在复制它的第二个参数

时间:2014-08-29 13:43:50

标签: c string

自学C充满了惊喜。我做了这个简短的片段来测试strcat(),它应该将第二个参数附加到第一个参数:

#include <stdio.h>
#include <string.h>

char s1[4] = "Foo ";
char s2[] = "Bar";

int main(void) {

    strcat(s1, s2);

    printf("%s %d %d \n", s1, strlen(s1), strlen(s2));
    return 0; 
}

我期待一些溢出错误,因为s1是一个包含4个字符的数组,但我得到了这个:

Foo BarBar BarBar 10 6

我是在Windows上使用MS Visual Studio Express 2013完成此操作(顺便说一下,它提出了一些关于使用strcat的警报)。那么......为什么strcat重复了s2的值?这不在文档中。

3 个答案:

答案 0 :(得分:2)

char s1[4] = "Foo ";

创建一个没有零终结符的字符序列s1。这意味着s1不是字符串,将其传递给strcat是违法的。行为未定义。

(在上面的初始化声明中,你使用的是C语言的一个不起眼的特性,它允许零终结符“脱落”正在初始化的char数组的末尾。在C ++中,这个初始化将是错误的,因为初始化字符串需要大小为5的缓冲区,而不是4。)

实际上,这会导致strcats1数组的末尾运行并进入s2(显然意外地位于内存附近),在第一个参数中寻找零终止符。因此,最后您将s2添加到内存中s1+s2的组合中,这会产生s2重复的效果。不用说,结果毫无意义。

当然,即使大小为s1的代码,代码仍然会显示未定义的行为,因为目标缓冲区中没有连接结果的空间。 s1的大小必须至少为8才能使结果适合它。

答案 1 :(得分:0)

首先:s1不是以空值终止的

第二:你为s1和s2分配静态内存。编译器通常将它们打包到可执行文件的共享数据块中。如果你正在阅读s1的边界,你正在阅读这个区块,因为你的程序“拥有”这个记忆,操作系统不会抱怨它。

答案 2 :(得分:0)

首先要注意的是C字符串是“空终止” - 即它以空字节(“\ 0”)结束(因此不能包含多个空字节)。所以字符串“Foo”实际上是五个个字符{'F', 'o', 'o', ' ', '\0'}

您定义一个4个字符的数组,并用五个元素填充它。 char s1[4] = "Foo "; 这意味着下一个可能放在第一个数组旁边的数组s2将覆盖s1的空字节。

因为C字符串定义为空字节,strcat将从第一个字符串复制字符,直到达到nullbyte。但是,因为s2覆盖了空字节,strcat遇到的第一个空是来自s2的空值。 因此,从strcat的角度来看,s1看起来像"Foo Bar\0";