首先理解:
strcat(s1, s2): 连接字符串 s2 到字符串 s1 的末尾。
就是拼接俩个字符串, 但仅仅这样么??????????????
看我的代码:
#include <stdio.h>
#include <string.h>
int main(){
char s1[] = "hello";
char s2[] = "world";
char s3[] = "cokie";
printf("strlen(s1) s1: %d\n", strlen(s1));
printf("strcat(s2, s3) s2: %s\n", strcat(s2, s3));
printf("strlen(s1) s1: %d\n", strlen(s1));
printf("s1: %s\n", s1);
return 0;
}
再看执行结果
strlen(s1) s1: 5
strcat(s2, s3) s2: worldcokie
strlen(s1) s1: 4
s1: okie
请按任意键继续. . .
我去, 我的s1的长度咋变了, 值也变了???????????????
来看讲解(来自[文心一言]):
在C语言中,执行上述代码时,strlen(s1)
两次获取的长度不一致,并且最后打印s1
时,s1
的值发生了变化,这主要是由于strcat
函数的特性以及字符数组在内存中的布局所导致的。
首先,让我们看看strcat
函数的工作原理。strcat
函数用于连接两个字符串。它将第二个字符串(及其终止的null字符)追加到第一个字符串的结尾,直到第一个字符串的\0
字符为止。这意味着strcat
会修改其第一个参数指向的字符串。
在你的代码中:
char s1[] = "hello";
char s2[] = "world";
char s3[] = "cokie";
你定义了三个字符数组,并分别初始化为"hello"、"world"和"cokie"。
接下来,你调用strcat(s2, s3)
:
printf("strcat(s2, s3) s2: %s\n", strcat(s2, s3));
这会将s3
的内容("cokie")追加到s2
的内容("world")的末尾,所以s2
现在包含"worldcokie"。重要的是,strcat
会修改s2
的内容,而s2
和s3
的内容在内存中是相邻的(尽管没有直接的保证,但在大多数实现中是这样)。
问题出在strcat
可能无意中覆盖了s1
的内容。由于s1
、s2
和s3
都是在栈上分配的,并且可能相邻,strcat
在寻找s2
的结束位置(即\0
字符)时可能会越过s2
的边界,进入s3
的内存区域,然后继续在栈上寻找\0
。如果在这个过程中它覆盖了s1
的结束null字符,那么s1
的字符串就会变长,因为它不再以null字符结尾。
因此,当你第一次调用strlen(s1)
时,s1
仍然以null字符结尾,所以长度是5(对应"hello"的长度)。但是,在调用strcat(s2, s3)
后,s1
的结束null字符可能已经被覆盖,导致strlen(s1)
在寻找新的null字符时越过了"hello"的范围,得到了一个更大的长度。
最后,当你打印s1
时:
printf("s1: %s\n", s1);
printf
会使用%s
格式化说明符,该说明符期望一个以null字符结尾的字符串。由于s1
现在可能不再以null字符结尾,或者null字符的位置已经改变,printf
会继续打印内存中的字符,直到它偶然遇到一个null字符为止。这可能导致输出包含s2
和s3
的部分内容,或者其它栈上的内存内容,造成未定义行为。
为了避免这种问题,你应该确保在使用strcat
时,目标字符串(在这里是s2
)有足够的空间来容纳源字符串(在这里是s3
)的内容,包括额外的null字符。通常,这意味着你应该为目标字符串分配足够的空间,或者在调用strcat
之前检查是否有足够的空间。在实际编程中,更安全的做法是使用strncat
函数,它允许你指定一个最大字符数来避免缓冲区溢出。
此外,为了避免未定义行为,你应该总是确保字符串以null字符结尾,并且在访问或打印字符串之前检查它们是否确实以null字符结尾。这通常是在分配或修改字符串后通过显式设置null字符来完成的。
我知道,我偷懒了, 但是问题找到了, 不是吗,哈哈哈哈
解决方法:
1. 确保在使用strcat
时,目标字符串(在这里是s2
)有足够的空间来容纳源字符串(在这里是s3
)的内容, 包括null字符