【C语言】strcat、strncat详解并模拟实现

1.库函数strcat: 

函数声明:char* strcat(char* strdestination, const char* strsource);

 提示:源字符串在函数实现过程中不修改其内容,所以加const修饰更安全!

strdestination: 目标字符串

strsource:源字符串

函数介绍:strcat是连接/追加字符串的函数,两个形参都是指针,函数最终返回一个指向目标字符串首元素地址的指针。

 函数实现:

  1. 首先strcat函数会一直在目标字符串中往后数,直到指针指向目标字符串中的'\0'
  2. 源字符串赋值给目标字符串,源字符串的第一个字符将目标字符串中指针指向的'\0'替代掉,并将自己的‘\0’赋值到目标字符串当中
  3. 打印目标字符串

 应用举例:

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

int main()
{
	char dest[20] = "Hello ";//定义目标字符串空间可修改
	char src[] = "world";
	printf("%s\n",strcat(dest,src));
	system("pause");
	return 0;
}

 596bc3b5e63040df9963bc2c056b2cac.png

模拟实现: 

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

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. 指针strdestination所指向的目标空间必须要能容纳下两个字符串连接后的大小。
  2. 源字符串必须以 '\0' 结尾。
  3. 目标空间必须可修改。 
  4. 自己无法直接追加自己。

反向验证:1.

int main()
{
	char arr1[5] = "Hello ";//定义字符串,内存太小,无法容纳两个字符串连接后的大小

	char arr2[] = "world";

	printf("%s\n",strcat(arr1,arr2));

	return 0;
}

 d77d1aad9b424ec09863ac86692fd31b.png

运行结果:094bdc3cadbf427b8f8c90adaeb78fed.png

 由此,不难看出,当目标空间太小会发生数组溢出,导致程序出错!

在反向验证2前,首先我们要学会strcat是如何追加/连接字符串的: 

int main()
{
	char arr1[20] = "Hello \0*********";//巧妙定义字符串,可以观察到源字符串在目标字符串当中的赋值情况

	char arr2[] = "world";

	printf("%s\n", strcat(arr1, arr2));

	return 0;
}

 以上代码的调试监视窗口

2c9f06da6d91465791dd58f344aeaaed.png

 观察图片就可以明白,源字符串会将目标字符串的‘\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;
}

 1cde024d16734d77abe96e6467e4b07d.png

 从上面的运行结果就不难看出,函数会持续往后读取,所以源字符串必须要有‘\0’,否则在打印字符串的时候就会发生非法越界访问,导致出错!

反向验证:3.

int main()
{
	char *ps = "Hello ";//定义目标字符串空间不可修改

	char arr2[] = "world";

	printf("%s\n",strcat(ps, arr2));

	return 0;
}

37310dfc57704a019147f6cc80e5f968.png

 不难发现,当目标空间无法修改的时候,程序就会挂掉!

 反向验证:4.

int main()
{
	char arr1[20] = "abcdef";

	printf("%s\n", strcat(arr1, arr1));//自己追加自己

	return 0;
}

 调试过程:

1632f05c0649423a928b20d2ec073a8a.png

 c209d12e949a4fb8b95554a33b3a08b7.png

 追加字符串时函数要在源字符串当中寻找‘\0’来结束追加,而这里的源字符串其实就是目标字符串,结合上述图片内容就不难发现,源字符串在追加过程当中用字符‘a’覆盖了‘\0’,之后在追加过程当中就无法在源字符串当中寻找到‘\0’,程序就会持续运行,最终导致程序崩溃!

这时凸显出另一个库函数 strncat 的作用了.......


2.库函数strncat:

 函数声明:char* strncat(char* strdestination, const char* strsource, size_t num);

提示1:源字符串在函数实现过程中不修改其内容,所以加const修饰更安全!

提示2:使用size_t目的是因为num只代表个数,不代表正负!

 函数介绍:strncat函数将源字符串的前num个字符连接到目标字符串的末端,连接后的结果放在目标字符串当中,函数有三个形参,两个指针,一个无符号整型,函数返回一个指向目标字符串首元素地址的指针。

 函数实现:

  1. 首先strncat函数会一直在目标字符串中往后数,直到指针指向目标字符串中的'\0'
  2. 把源字符串的前num个字符连接到目标字符串的末端,然后加上‘\0’
  3. 打印目标字符串

应用举例:

#include <stdio.h>

#include <string.h>

int main()
{
	char arr1[20] = "Hello ";//定义目标字符串

	char arr2[] = "world";//定义源字符串

	printf("%s\n", strncat(arr1, arr2, 3));//追加字符串并打印

	return 0;
}

 ca80d5d4b8c446ca98b76f711972b166.png

 模拟实现:

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

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;
}

 注意:

  1. 指针strdestination所指向的目标空间必须要能容纳下目标字符串和所追加的源字符串字符连接后的大小。
  2. 目标空间必须可修改。

以上注意事项在strcat函数部分都已举例,请返回参考!

在strncat函数运用的时,出现的情况:

  1. 当源字符串的长度大于num时,函数只会在目标字符串末尾追加源字符串的前num个字符,并且在这num个字符后面的位置添加一个'\0'字符。
  2. 当源字符串的长度小于num时,函数会检测到源字符串末尾的'\0',自动结束追加!
  3. 可以实现自己追加自己。

 验证3.

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

int main()
{
	char arr1[20] = "Hello ";
	printf("%s\n", strncat(arr1, arr1,5));
	return 0;
}

c7db534ce1d84ac88b7c950b00ed5b14.png

 从运行结果可知,strncat函数是可以实现自己给自己追加,但会报一个警告!

8e10ea6201a74653bd06602e119c0e1c.png

因为strncat函数的两个指针都指向同一个数组,在函数运算过程当中,该数组内存储的字符一直在变化,所以函数会认为运用的这个字符串数组没有初始化变量!


本人大一新生一枚,写的不好和错的地方,大家可以指正出来,我们共同进步 。希望大家谅解!

如果大家觉得我写的还行,帮小编点一个免费的赞和关注,我会持续更新出更好的博客,谢谢大家!

猜你喜欢

转载自blog.csdn.net/m0_73968621/article/details/129033623