C语言–模拟实现库函数strcpy

目录

  • 前言
  • strcpy实现的基本原理
  • 函数的模拟实现
    • 代码优化
      • assert–断言
      • const关键字
  • strcpy的返回值
  • 结语

前言

本章内容我们将通过相关函数来实现库函数中的strcpy。

strcpy实现的基本原理

C语言 strcpy()函数用于对字符串进行复制(拷贝)。需要的头文件为 <string.h>。原理如下

char* strcpy(char* strDestination, const char* strSource);

其中的strSource为源字符串,strDestination为目的字符串,strcpy的作用就是将 strSource 指向的字符串复制到 strDestination。

我们举个例子

int main()
{
	char arr1[20] = "xxxxxxxxxxxxxxx";
	char arr2[] = "hello";
	strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

打印结果如图1
图1
我们知道字符串arr2实际上是”hello\0“,那么我们在打印字符串的时候有没有打印这个\0呢,我们用监视的方法来看一下,如图2
图2
我们发现实际上\0也是被拷贝过来了的。

函数的模拟实现

我们来写一个函数my_strcpy实现字符串的拷贝,框架如下

void my_strcpy(char* dest, char* src)
{

}
int main()
{
	char arr1[20] = "xxxxxxxxxxxxxxx";
	char arr2[] = "hello";
	my_strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

图3

当’\0’也被拷贝过去时函数停止运行,我们可以用一个循环来实现代码

void my_strcpy(char* dest, char* src)
{
	while (*src != '\0')
	{
		*dest = *src;
		dest++;
		src++;
	}//当src解引用为'\0'时跳出循环,但'\0'还并没有被复制过去
	*dest = *src;//将最后的'\0'也复制过去
}
int main()
{
	char arr1[20] = "xxxxxxxxxxxxxxx";
	char arr2[] = "hello";
	my_strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

代码优化

上述函数只是我们按照基本思路一步步写出来的,肯定不是最优解,看下面这段代码

void my_strcpy(char* dest, char* src)
{
	while (*dest++=*src++)
	{
		;
	}
}

这段代码才是大师级别的书写格式,它将我们上述的个步骤融为一体,下面我们来分析这段代码。
首先我们将解引用的src的值赋给dest,然后后置++,各自都跳到下一个位置再进行赋值,当最后一次src解引用为’\0’并赋值给dest时,由于’\0’的ascll码值为0,当0被赋值给dest,判断结果也为0,0为假,就会跳出循环,这样既把\0复制了过去,还借此跳出了循环,可谓是一举两得。

assert–断言

假设arr1或arr2为空指针会发生什么呢?显然,空指针是不能解引用的,程序会报错。可是这种情况也是难以避免的,为了避免程序崩溃,我们在函数开头添加一个assert(断言),通过一个判断来选择继续执行或中止代码。

void my_strcpy(char* dest, char* src)
{
	assert(src != NULL);//若为真则继续执行,若为假则终止代码
	while (*dest++=*src++)
	{
		;
	}
}
int main()
{
	char arr1[20] = "xxxxxxxxxxxxxxx";
	char arr2[] = "hello";
	my_strcpy(arr1,NULL);
	printf("%s\n", arr1);
	return 0;
}

我们假定arr2为空指针,代码运行结果就会如下
图4
这样,我们既可以有效防止程序崩溃,还可以很清晰的在代码中锁定出问题的地方(比如途中出问题的地方就为源.c line27)。

const关键字

如果我们在函数书写中把拷贝对象和被拷贝对象写反了,会发生什么呢?

void my_strcpy(char* dest, char* src)
{
	assert(src != NULL);
	while (*src++=*dest++)
	{
		;
	}
}
int main()
{
	char arr1[20] = "xxxxxxxxxxxxxxx";
	char arr2[] = "hello";
	my_strcpy(arr1,arr2);
	printf("%s\n", arr1);
	return 0;
}

代码运行结果如图5
图5
我们会发现程序崩溃了,原因在于arr2字符串长度放不下arr1。但如果我们加入const关键字修饰就能很好的规避这个问题。

const关键字的作用在于修饰变量,这个变量就被称为常变量,它具备了常量的属性,但本质上还是一个变量。
但我们来看一段代码

int main()
{
    const int num = 10;
	int* p = &num;
	*p = 20;

	printf("%d\n",num);
}

运行结果如图6
图6
我们发现,被const修饰的变量num还是被修改了,我么要想保持num不变,就需要修饰指针变量

int main()
{
    int num = 10;
	const int* p = &num;
	*p = 20;

	printf("%d\n",num);
}

这样* p=20这段代码将无法实行。这是因为const如果放在* 左边,修饰的是*p,表示的是指针指向的内容,是不能通过指针来改变的,但是指针变量本身( p )是可以修改的,如果放在 *右边,修饰的就是p,和放在左边完全相反,指针变量本身将无法被修改,但指针指向的内容却可以被修改,num还是会被修改为20

strcpy的返回值

strcpy这个库函数的执行原理实际上是会返回目标空间的起始地址

char* my_strcpy(char* dest, const char* src)
{
	assert(src != NULL);
	assert(dest != NULL);
	char* ret = dest;
	while (*dest++=*src++)
	{
		;
	}
	return ret;
}
int main()
{
	char arr1[20] = "xxxxxxxxxxxxxxx";
	char arr2[] = "hello";
	//目标空间的起始地址 源空间的起始地址
	my_strcpy(arr1,arr2);
	printf("%s\n", my_strcpy(arr1,arr2);//链式访问
	return 0;
}

结语

以上就是标准的库函数strcpy的模拟实现流程,如有出入,欢迎指正。

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
xiaoxingxing的头像xiaoxingxing管理团队
上一篇 2023年12月15日
下一篇 2023年12月15日

相关推荐