模拟实现strcpy函数(怎么写出优秀的代码?)(C语言)

1.strcpy库函数函数的应用

#include<stdio.h>
#include<string.h>
int main()
{
   char arr1[20] = "XXXXXXXXXXXX";
   char arr2[] = "hello bit";
   printf("%s\n", strcpy(arr1,arr2)); 
   return 0;
}

strcpy使用前需要引用头文件string.h
strcpy的使用:strcpy(目标空间,源数据)
strcpy拷贝数据的时候会把源字符串的\0也拷贝过去

请添加图片描述

2.模拟实现strcpy函数功能

主函数

#include<stdio.h>
#include<string.h>
int main()
{
   char arr1[20] = "XXXXXXXXXXXX";
   char arr2[] = "hello bit";
   my_strcpy(arr1,arr2);
   printf("%s\n", arr1); 
   return 0;
}

my_strcpy函数

void my_strcpy(char* dest,char* src)
{
   while(*src != '\0')
   {
       *dest = *src;
       dest++;
       src++;
   }
   *dest = *src;
}

src不是\0的时候进入循环,当src是\0的时候退出循环
最后再把\0给*dest。
这样写看着没什么问题,但这种代码如果总分是10分只能
给5分,想想这样写会不会太啰嗦了呢?while的时候进行
拷贝,退出while的时候又拷贝一次,太啰嗦了。
下面对其进行改进

3.改进一

void my_strcpy(char* dest,char* src)
{
   while(*dest++ = *src++)
   {
       ;//空语句
   }
}

这样写会不会觉得眼前一亮?先说明一下后置加加在这里的意思
比如:*dest++的意思是先对dest解引用,再对dest加加,通俗来讲
就是,先找到dest中的数据,再对dest这个指针(也就是地址)+1。

那么*dest++ = *src++,当拷贝的不是\0的时候,是真,就进入循环,
当拷贝的是\0的时候就不进入循环,注意这里是先拷贝再看是否进入
循环,所以\0已经拷贝上了。
但是这样的代码还不够完美,还会有出现bug的可能。

4.改进二

#include<assert>
void my_strcpy(char* dest,const char* src)
{
   //断言
   assert(src != NULL);
   assert(dest != NULL);
   while(*dest++ = *src++)
   {
       ;//空语句
   }
}
int main()
{
	char arr1[20] = "XXXXXXXXXXXXXXXXX";
	char arr2[] = "hello bit";
	char* p = NULL;
	my_strcpy(arr1, p);
	printf("%s\n", arr1);
	return 0;
}

如果把空指针传过去,对其解引用是很危险的,所以这里我们就要
使用断言assert,看一下具体效果

这样就避免了空指针的危险

const char* src这里加const也是为了减少bug的出现
如果我们在写while语句的时候这样写

    //err
	while (*src++ = *dest++)
	{
		;//空语句
	}
	//ok
	while (*dest++ = *src++)
	{
		;//空语句
	}

如果我们写成err的代码的话,编译器会直接报错的

关于const的解释

int main()
{
   const int m = 10;
   m = 100;
   printf("%d\n", m);
   return 0;
}

在这里插入图片描述
const的作用就是保护源数据
但我们可以通过取地址,再对地址指向的对象进行改变的方法更改m的值

int main()
{
   const int m = 10;
   int* p = &m;
   *p = 100;
   printf("%d\n", m);
   return 0;
}

在这里插入图片描述
这里是绕过const的语法限制
取m的地址,去改变m的值
属于翻窗户的行为


下面是对const放在 * 左边和 * 右边的解释
1.const放在 * 左边,不能改变p指向的对象,但可以改变p本身

int main()
{
   const int m = 10;
   const int* p = &m;//const int*等价于int const*
   int n = 20;
   *p = 100;//err
   p = &n;//ok
   printf("%d\n", m);
   return 0;
}

在这里插入图片描述

2.const放在 * 右边,可以改变p指向的对象,但不能改变p本身

int main()
{
   const int m = 10;
   int* const p = &m;
   int n = 20;
   *p = 100;//ok
   p = &n;//err
   printf("%d\n", m);
   return 0;
}

在这里插入图片描述

3. * 两边都加const 都不能改变
const int* const p

5.完美代码

注意到strcpy函数,其函数原型为
char* strcpy(char* destination, const char* source);
但是我们写的模拟函数没有返回,所以是不够完美的

#include<stdio.h>
#include<assert>
//为什么返回char*呢?
//是为了实现链式访问(就是把一个函数的返回值作为另一个函数的参数)
//strcpy函数返回的是目标空间的首元素地址
char* my_strcpy(char* dest,const char* src)
{
   //保存起始地址
   char* ret = dest;
   //断言
   assert(src != NULL);
   assert(dest != NULL);
   while(*dest++ = *src++)
   {
       ;//空语句
   }
   //return dest;//err
   return ret;
}
int main()
{
	char arr1[20] = "XXXXXXXXXXXXXXXXX";
	char arr2[] = "hello bit";
	printf("%s\n", my_strcpy(arr1, arr2));
	return 0;
}

到了这里我们才明白原来写一个几乎没有bug的代码需要考虑这么多
那么怎样才能写出优秀的代码呢?
在这里插入图片描述

请添加图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值