模拟实现字符串拷贝函数小细节

 大家经常在对字符串操作的时候使用字符串库的一些函数,

 

像对字符串的拷贝,之前我也有写过一篇博客是专门把一些经常用的字符串函数介绍了一下简单的用法。大家在考试的时候或者说,在面试的时候经常会遇到一个问题,经常让你自己来写一个函数来模仿函数库中得字符串拷贝函数,今天我就对这个问题来说一些我目前了解的内容。

 

#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

#include<string.h>

#include<stdlib.h>

void my_strcpy(char *dest,char *str )

{

while (*str != NULL)

{

 

*dest = *str;

*dest++;

*str++;

}

}

int main()

{

char arr[5] = { 0 };

my_strcpy(arr, "hello");

printf("%s", arr);

   system("pause");

 

 

}

 

大家可以看到,我写的这个函数已经成功的模仿了字符串的拷贝函数,将hello成功复制到了arr数组中,有的人可能注意到了,我的数组定义了6个元素,hello明明只有五个元素,为什么要定义六个呢?这里并不是没有他的道理,在字符串数组进行拷贝的时候,五个元素你的目标数组,必须要有6个或以上的元素位置,因为大家都知道,字符串在电脑中储存的时候在他的字符后边会有一个\0,这个元素的标志着当前字符串的结束,所以大家,也就很容易明白为什么要定义6个元素了,因为字符串复制的时候他也会复制这个结束符,所以你的目标位置就一定要比这个原字符串大,如果将这地方定义成大小为5 的呢?

 

这就是定义成5之后的程序,程序还是能够将hello成功复制过来不过后边会出现一堆烫烫烫....

 

大家看这段代码,我将arr2中的内容拷到arr中,这时候运行就发现程序崩溃了,这就是因为arr2中没有\0你的代码就会一直的走啊走走啊走,走出了你当前程序的内存范围之后就会发生错误。

#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

#include<string.h>

#include<stdlib.h>

void my_strcpy(char *dest,char *str )

{

while (*str != '\0')

{

 

*dest = *str;

*dest++;

*str++;

}

*dest = *str;

}

int main()

{

char arr[7] = { 0 };

//char arr2[] = { 'a', 'b' };

my_strcpy(arr, "hello");

printf("%s", arr);

   system("pause");

 

 

}

所以你就需要在while循环停止之后再将你的\0复制到新的字符串中。

  如果考试或者面试的时候,程序写到这你发现我的功能已经实现了,那就交卷吧,这时候,10分的题你只能获得两分,确实这个功能已经实现了,但是这段代码还有很多很多可以优化的地方。

while (*str != '\0')

{

 

*dest++ = *str++;

//*dest++;

//*str++;

}

*dest = *str;

首先 你的++位置可以放到等式里边的后置++,这样代码看起来就更加的整洁,简单。*dest++ = *str++;这个的意思大家应该都能明白,先对dest和str进行使用,将str赋值给dest之后两个值再进行++;

现在再看这个代码,还有可以改进的地方大家看,最后的这个语句,是因为我的str为\0的时候就会跳出循环,那我能不能把这个语句加入到循环里边呢?

while (*dest++ = *str++)

{

;

}

大家这样改进之后的代码,是不是更加的简洁,而且同样实现了你的所有功能呢?先让你的dest等于你的str然后将两个都++,在最后一次加完之后再看代码,str变成了\0,进入循环之后,先将你的表达式执行,str赋值给了dest,然后++,++结束之后再去判断你这个表达式的值,此时你的表达式为0,那这个循环就不再执行了。

 看了现在的代码,写过的人都会发现他还是会有一点点的缺陷,比如我的str或者说我的dest是空指针的时候怎么办,这个时候不能再进行拷贝了,这时候

if ((dest == NULL) || (str == NULL))

return;

while (*dest++ = *str++)

{

;

}

代码就写成了这个样子,这时候你去看,如果你的两个指针其中有一个是NULL的话你就直接返回,这样就不会再去执行剩下的语句了,确实这个语句实现了你的功能,但是,这个语句这段代码,他并不够好,因为,首先如果有一天你的指针真的出现问题之后,它之后的语句确实不会执行,但是,这时候你发现你的程序出现了问题,却不知道你的程序问题出在那里,这时候你的程序在编译的时候没有任何问题,执行的时候也没有任何的异常,但是却不能输出正确的值。这个时候如果是一个大程序,你就需要去下功夫发现你的程序到底哪里出现了问题,这里我有一个更好的语句,可以代替你这里你的if判断语句,那就是assert断言语句。

assert(表达式)这个函数,如果函数之后的表达式为真,那什么事情都不发生,如果当前的表达式为假,程序就会终止。

void my_strcpy(char *dest,char *str )

{

//if ((dest == NULL) || (str == NULL))

//return;

assert(dest != NULL);

while (*dest++ = *str++)

{

;

}

//*dest = *str;

}

程序修改成这样之后,如果这时候你的dest为NULL,那么你的程序将会终止,很多人说那既然这个也是终止return也是终止,这个有什么好处呢?

大家看程序的运行结果,

 

程序会提示你,你写的代码挂掉了,甚至还会告诉你你的问题出在了那,甚至你出错的行数都告诉你了。

那这段代码在改成这样之后,你会得到几分呢?6分。还不能得到满分的原因依然有两个。

第一个

 

这是查询函数功能之后出来的,char * strcpy ( char * destination, const char * source );

大家注意这一句话,strcpy这个函数他的返回值并不是我们所写的void,而是char*。

林锐的《高质量C++编程指南》中写了

【建议6-2-1】有时候函数原本不需要返回值,但为了增加灵活性如支持链式表达,
可以附加返回值。
例如字符串拷贝函数strcpy 的原型:
char *strcpy(char *strDest,const char *strSrc);
strcpy 函数将strSrc 拷贝至输出参数strDest 中,同时函数的返回值又是strDest。
这样做并非多此一举,可以获得如下灵活性:
char str[20];
int length = strlen( strcpy(str, “Hello World”) );

最初在接触链式表达的时候我不太明白链式表达是什么意思int length = strlen( strcpy(str, “Hello World”) );看了这段话之后我就明白了,我不能用准确的语言表达出来,但是我想大家看了之后也能明白为什么要返回一个char* 类型的返回值

char* my_strcpy(char *dest,char *str )

{

//if ((dest == NULL) || (str == NULL))

//return;

char * ret = dest;

assert((dest != NULL) && (dest != NULL));

while (*dest++ = *str++)

{

;

}

return ret;

//*dest = *str;

}

这个时候代码就变成了这个样子,有人问,为什么还需要一个ret而不是直接去返回dest呢,这个很容易理解, 你再while循环中dest在不断的++,在最后你的dest指向的已经不是你最初的初始地址了,而是复制结束之后你的终止地址。所以这里需要一个ret。

那不能获得满分的另外一个理由是什么呢?

char* my_strcpy(char *dest,const char *s)

这样就可以获得满分了,那为什么要加这个const呢?

 


这是const的作用,那么加在这里的作用是什么呢?这里其实就是理解的他的第三个作用,保护被修饰的东西,这个拷贝函数大家都清楚,你是将str指向的空间来赋值到dest指向的空间,那么如果有一天你在编写程序的时候出现了失误,你写反了你写成了*str=*dest那这时候你的程序就有了错误,如果你不加入const的话,程序运行起来并没有什么错误,但是最终结果却是错的,这应该怎么办,和assret一样,如果你是一个很大的工程的话,这时候你检查起来可就是真的麻烦了,如果加上了你的const呢?

 

当你写反的时候你的程序编译都不会编译过去,下边会给你报出一个str常量不能够赋值的错误。

这个时候你的模拟实现字符串函数的程序就能获得满分了。

看了这些,才发现即使是计算机语言他也是一个很高深的东西,在学习语言上,如果想将你的程序写的很美写的像诗一样,路还很长。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值