函数声明:char* strcat(char* strdestination, const char* strsource);
提示:源字符串在函数实现过程中不修改其内容,所以加const修饰更安全!
strdestination: 目标字符串
strsource:源字符串
函数介绍:strcat是连接/追加字符串的函数,两个形参都是指针,函数最终返回一个指向目标字符串首元素地址的指针。
函数实现:
- 首先strcat函数会一直在目标字符串中往后数,直到指针指向目标字符串中的'\0'
- 源字符串赋值给目标字符串,源字符串的第一个字符将目标字符串中指针指向的'\0'替代掉,并将自己的‘\0’赋值到目标字符串当中
- 打印目标字符串
应用举例:
#include
#include
#include
int main()
{
char dest[20] = "Hello ";//定义目标字符串空间可修改
char src[] = "world";
printf("%s\n",strcat(dest,src));
system("pause");
return 0;
}
模拟实现:
#include
#include
#include
char* my_strcat(char* strdestination,const char* strsource)//源字符串不用修改,加const防止其被意外修改
{
assert(strdestination != NULL && strsource != NULL);//对源字符串和目标字符串进行断言,防止空指针
char* reverse_back = strdestination;//提前记录保存目标字符串首地址
while (*strdestination)//让指针指向目标字符串的'\0',当指针指向‘\0’的地址时,再解引用后为0,跳出循环
{
strdestination++;
}
while (*strdestination++ = *strsource++);//将源字符串赋值给目标字符串,当源字符串的‘\0’赋值给目标字符串后跳出循环
return reverse_back;//返回目标字符串的首地址
}
int main()
{
char dest[20] = "Hello ";//定义目标字符串
char src[] = "world";//定义源字符串
printf("%s\n", my_strcat(dest, src));//调用函数并打印
return 0;
}
反向验证:1.
int main()
{
char arr1[5] = "Hello ";//定义字符串,内存太小,无法容纳两个字符串连接后的大小
char arr2[] = "world";
printf("%s\n",strcat(arr1,arr2));
return 0;
}
由此,不难看出,当目标空间太小会发生数组溢出,导致程序出错!
在反向验证2前,首先我们要学会strcat是如何追加/连接字符串的:
int main()
{
char arr1[20] = "Hello \0*********";//巧妙定义字符串,可以观察到源字符串在目标字符串当中的赋值情况
char arr2[] = "world";
printf("%s\n", strcat(arr1, arr2));
return 0;
}
以上代码的调试监视窗口:
观察图片就可以明白,源字符串会将目标字符串的‘\0’替代掉,并且会将自己的‘\0’赋值到目标字符串,那么如果源字符串没有将‘\0’赋值给目标字符串会出现什么情况呢?接下来就开始验证!
反向验证:2.
int main()
{
char arr1[20] = "Hello \0*********";
char arr2[] = "world";
char* pa = strcat(arr1, arr2);
arr1[11] = '#';//当我们把从arr2赋值给arr1的'\0'修改成字符'#',后观察调试结果
printf("%s\n",arr1);
return 0;
}
从上面的运行结果就不难看出,函数会持续往后读取,所以源字符串必须要有‘\0’,否则在打印字符串的时候就会发生非法越界访问,导致出错!
反向验证:3.
int main()
{
char *ps = "Hello ";//定义目标字符串空间不可修改
char arr2[] = "world";
printf("%s\n",strcat(ps, arr2));
return 0;
}
不难发现,当目标空间无法修改的时候,程序就会挂掉!
反向验证:4.
int main()
{
char arr1[20] = "abcdef";
printf("%s\n", strcat(arr1, arr1));//自己追加自己
return 0;
}
调试过程:
追加字符串时函数要在源字符串当中寻找‘\0’来结束追加,而这里的源字符串其实就是目标字符串,结合上述图片内容就不难发现,源字符串在追加过程当中用字符‘a’覆盖了‘\0’,之后在追加过程当中就无法在源字符串当中寻找到‘\0’,程序就会持续运行,最终导致程序崩溃!
这时凸显出另一个库函数 strncat 的作用了.......
函数声明:char* strncat(char* strdestination, const char* strsource, size_t num);
提示1:源字符串在函数实现过程中不修改其内容,所以加const修饰更安全!
提示2:使用size_t目的是因为num只代表个数,不代表正负!
函数介绍:strncat函数将源字符串的前num个字符连接到目标字符串的末端,连接后的结果放在目标字符串当中,函数有三个形参,两个指针,一个无符号整型,函数返回一个指向目标字符串首元素地址的指针。
函数实现:
- 首先strncat函数会一直在目标字符串中往后数,直到指针指向目标字符串中的'\0'
- 把源字符串的前num个字符连接到目标字符串的末端,然后加上‘\0’
- 打印目标字符串
应用举例:
#include
#include
int main()
{
char arr1[20] = "Hello ";//定义目标字符串
char arr2[] = "world";//定义源字符串
printf("%s\n", strncat(arr1, arr2, 3));//追加字符串并打印
return 0;
}
模拟实现:
#include
#include
#include
char* my_strncat(char* strdestination, const char* strsource, size_t num)//源字符串不用修改,加const防止其被意外修改
{
assert(strdestination != NULL && strsource != NULL);//对源字符串和目标字符串进行断言,防止引入空指针
char* reverse_back = strdestination;//提前记录保存目标字符串的首地址
while (*strdestination)//让指针指向目标字符串的'\0'
{
strdestination++;
}
while (num--)//追加字符的个数
{
if ((*strdestination++ = *strsource++) == 0)//当追加字符的个数大于源字符串中字符的个数时,函数只会追加到源字符串的'\0',防止越界
{
return reverse_back;//返回目标字符串首元素的地址
}
}
*strdestination = '\0';//当没有追加到源字符串的'\0'时,给目标字符串末尾添加一个'\0',防止打印越界
return reverse_back;//返回目标字符串首元素的地址
}
int main()
{
char dest[20] = "Hello ";//定义目标字符串
char src[] = "world";//定义源字符串
printf("%s\n", my_strncat(dest, src, 3));//调用函数并打印
return 0;
}
注意:
以上注意事项在strcat函数部分都已举例,请返回参考!
验证3.
#include
#include
int main()
{
char arr1[20] = "Hello ";
printf("%s\n", strncat(arr1, arr1,5));
return 0;
}
从运行结果可知,strncat函数是可以实现自己给自己追加,但会报一个警告!
因为strncat函数的两个指针都指向同一个数组,在函数运算过程当中,该数组内存储的字符一直在变化,所以函数会认为运用的这个字符串数组没有初始化变量!
本人大一新生一枚,写的不好和错的地方,大家可以指正出来,我们共同进步 。希望大家谅解!
如果大家觉得我写的还行,帮小编点一个免费的赞和关注,我会持续更新出更好的博客,谢谢大家!