一、strcpy
在这里我们需要科普一个东西:断言
何为断言?如果你是字面理解,没错就是断定一句话是不是真的。简单吧?当然我们C语言的断言是以函数assert()来判断一个表达式或者一个值是否是我们需要的,此外使用这个函数需要引用一下assert.h这个头文件。assert断言的用法很简单,就是在一个表达式内判断所需的表达式要判断的值是否是我们需要的。如有以下的函数体
void My_strcat(char *src,char *desc)
{
......
}
上面的函数是自定义的字符串连接函数,我们要认知分析已知条件:接收进来两个指向字符类型的指针,分别是原串和要添加的串,但是我们一定要注意,接收进来的src和desc是不能为空的,至少src在这个后面要连接后面的字符串,所以它不能为空,如果为空,后面的字符串连在一个空指针后面,啥情况???,后面如果要打印连接后的字符串,是不是就发生空指针异常了?是吧。所以src不能为空,我们要如何判断它吧为空呢?回想刚刚的断言,在这个时候是不是能够用上?我们只需在进入函数体的第一时间使用assert(src!=NULL),为了确保安全,我们把desc也使用断言,来个双保险。
回到assert,num为0?assert(num!=0); p不为空指针?assert(p!=NULL)
细节不用说,assert只在条件成立的情况下才能继续执行,如果说条件不成立,那么就会在此报错,并且会暂停程序。
接着我们回来实现一下strcmp();下面是它的声明(在linux中使用 man strcpy可以看到,百度也有)
它是一个返回值为char*类型的(为什么要返回值???),接收两个字符串的函数,注意第二个参数使用了const修饰符,现在表示指向内存单元的内容不可变。当然第一个肯定是要变的。ca
我们先思考它的是如何实现字符串拷贝的,既然是字符串,那只能一个一个来,也就是src中的字符逐个复制到了dest里面,当然dest也是逐个接收的。这里你也许有点想法了,使用个for循环,dest和src逐个赋值。这样写代码有点多,这里我们使用while循环,减少代码行数。
char *My_strcpy(char *desc, const char *src)
{
assert(desc!=NULL && src!=NULL);
char *p = desc;
while (*desc++ = *src++);
return p;
}
来头就断言,保证我们的复制活动内正确的同时,也为以后访问提高安全。
我们要注意:src必须有足够的空间存储desc,想一想,如果不能,是不是多余的字符就被复制到未被分配的内存中,称为非法的内存访问。
接着我们用一个暂时性标记记住现在desc的地址,因为待会它要与src生死相依,直到同赴\0字符结束循环,最终由标记重新带回“最初的原点”,到里这个函数就结束了。再看strcat的自我实现。
二、strcat的自我实现
还是先看看strcat的声明
跟strcpy差不多,所以我们先分析思路,desc先绕到\0处,接着从src逐个复制过来
char *My_strcat(char *desc, const char *src)
{
assert(src != NULL);
char *p = desc;
while (*desc++);
desc--;
while (*desc++=*src++);
return p;
}
三、strcmp的自我实现
strcmp是字符串比较函数,通过逐个对比两个字符串的每个字符,遇上不相等的就返回字符间的ASCII值,又一次逐个比较,最后返回的还是字符间的ASCII值,因此,我们可以借鉴上面的思路。写出如下函数
int my_strcmp(const char *desc, const char *src)
{
assert(src != NULL && desc != NULL);
//desc和src相同的就后移,其中一个当前指向存贮‘\0'时,停止循环
while (*desc++ == *src++ && *desc != '\0' && *src != '\0');
if (*desc == '\0'&& *src == '\0'){
return 0;
}
return *desc-*src ;
}
但是还是麻烦了,因为我们对于字符串的比较又返回他们之间的差值,完全可以用一个临时变量和while循环来解决嘛,于是有了下面的优化版
int My_strcmp_1(const char *str1, const char *str2)
{//
assert(str1 != NULL && str2 != NULL);
int tmp;//*str - *str2
while ((tmp = *str1 - *str2) == 0); //当某个字符串到\0后 循环退出
return tmp;
}
是不是设计的超级简单?哈哈,这里的tmp变量和==0的条件用的非常好,tmp一旦不等于零,循环就结束,并且现在tmp的值刚刚好是差值,直接返回。这个设计思路很棒,以后大家可以借鉴借鉴,减少代码冗余。
再补充一个strlen的自我实现,strlen计算是不包含\0这个元素的。所以灵活使用这个条件。我们可以写出如下代码
int My_strlen(const char *str)
{
int length = 0;
while (*str)
{
length++;
str++;
}
return length;
}
最后给大家可以试着去实现strncpy,strncmp等等函数,它们只是对复制和比较的字符进行了限制。