一、字符串拷贝strcpy
代码:
char * strcpy(char * des, const char * src){
assert( (des != NULL) && (src != NULL));
char * p = des;
while( (*p++ = *src++) != '\0' );
return des;
}
要注意的点:
- 入参里,为了防止对src的修改,应该使用const,这是一个好习惯;这里要分清 const char * 和 char * const 的区别,因为这个可能会被面试官引申出来问。const char * src里const修饰的是src所指向的内容,不可在该函数中被修改;char * const src是指src只能指向这一地址空间,不能再进行src++的操作。
- assert断言宏的使用,用于检测入参的合法性,算是一种异常处理,如果真,继续运行,如果假,就调用abort终止程序。
- *p++ = *src++ != '\0' 是将*src赋值给*p,再判断是否是遇到结束符,最后各自++。
- 返回 des 的目的是为了方便链式操作。
二、内存拷贝memcpy
代码:
void * memcpy(void * des, const void * src, size_t size){
assert( (des != NULL) && (src != NULL));
char * tmpd = (char *)des;
char * tmps = (char *)src;
while(size-- > 0)
*tmpd++ = *tmps++;
return des;
}
要注意的点:
- const和assert及返回值不再赘述。
- 要用void*型指针来接收入参,因为使用void * 可以接受任何类型的指针。
- 入参多一个size,用来控制复制长度。因为memcpy是内存拷贝,不是以 '\0' 为结尾标志位的。
- 在复制偏移之前,要先将入参转换为char *,因为入参不一定是什么类型,指针偏移都是按照类型占几个字符来自动偏移的,比如int *p = &a;现在p指向a的地址,但是p++后,p指向的地址其实是 (&a) + 4,同理如果p是char * 类型,则指向的是 (&a) + 1。所以要在复制偏移之前,将入参类型强转为char *。
- memcpy有一个很重要的潜在问题,就是内存重叠。解决办法是从后往前拷贝遍历,才能保证des可以得到原汁原味的src
三、字符串比较strcmp
代码
//功能:str1 > str2 返回1,反之返回-1,相等返回0
int strcmp(const char * str1, const char * str2){
assert( (str1 != NULL) && (str2 != NULL));
int ret = 0;
while( *str1 != '\0' && *str2 != '\0' && *str1 == *str2 ){
str1++;
str2++;
}
if( *str1 != '\0' && *str2 == '\0') return 1;//str1比str2长
else if( *str1 == '\0' && *str2 != '\0') return -1;//str1比str2短
else if( *str1 > *str2) return 1;
else if( *str1 < *str2) return -1;
return 0;//如果前面都没return,那就说明都一样
}
要注意的点:
- 入参const,assert不在赘述。
- 在while循环结束后,要使用if else if的结构,避免单独使用多个if,显得代码风格更优雅
四、内存比较memcmp
代码
//功能:比较内存值是否相同
int memcmp(const void *buffer1,const void *buffer2, size_t size){
if (!size) return 0;
char * m1 = (char *)buffer1;
char * m2 = (char *)buffer2;
while ( --size && *m1 == *m2){
m1++;
m2++;
}
if(size == 0) return 0;
else if(*m1 > *m2) return 1;
else return -1;
}
要注意的点:
- https://blog.youkuaiyun.com/watergear/article/details/79531063 对于memcmp的效率问题,这篇文章探究的很清楚,大概意思是做了8字节对齐,用上了并行优化
- 在while循环中,如果使用size--的话,就会造成在buffer1 == buffer2 的情况下,退出循环时size = -1的情况
五、字符串拼接strcat
代码
char * strcat( char * des, const char * src){
assert( (str1 != NULL) && (str2 != NULL));
char * p = des;
while(*p != '\0') p++;//找到des的结尾
while( (*p++ = *src++) != '\0' );//开始往后复制,不用管'\0',会自动添加
return des;
}
要注意的点:
- 先找到des的结尾,然后从其结尾的'\0'开始覆盖,一直到src的'\0'
- 最后的'\0'不用人工添加,会自动添加