面试题:实现strcpy,strlen,strcmp,strcat,memcpy 之c-style字符串
哪里可以看到c库函数的源码?
gnu的c运行库glibc,但是源码的实现却是复杂的,需要考虑效率,stlen源码分析。
c-style字符串有个约定,以空字符结尾,即 '\0' 。
1 char ch[] = { '1', '2' }; 2 char ch1[] = { "12" }; 3 char ch2[] = "12";
ch存了2个字符,ch1与ch2一样,存了3个字符,即结尾含有 '\0' 。
1 char *c = "djawj\0p";
c不会存字符p,\0标识了结尾。
1 strlen(ch);//stlen沿着ch的内存一直扫描,直到遇到空字符,这就导致了错误
1 size_t strlen(const char *src) 2 { 3 assert(src!=NULL);//if (src == NULL) return 0; 发生意外情况不返回,直接结束 4 const char *temp = src; 5 while (*temp++); 6 return (temp - src - 1); 7 }
1 char* strcpy(char* dst, const char* src) 2 { 3 assert((dst != NULL) && (src != NULL));//断言,如果条件为false,停止程序运行
char 4 while ((*dst++ = *src++) != '\0'); 5 return dst; 6 }
1 char* strcpy(char* dst, const char* src) 2 { 3 assert((dst != NULL) && (src != NULL)); 4 char *tmp = dst; 5 while ((*dst++ = *src++) != '\0'); 6 return tmp; //返回目的地址,支持链式操作strlen(dst2,strlen(dst1,src)) 7 }
下面代码的问题是返回值不是1,0,-1,有多种值
int strcmp(const char *src, const char *dst) { assert((src != NULL) && (dst != NULL)); int result = 0; while (*src != '\0'&& *dst != '\0') { if (*src == *dst) { src++; dst++; //相等就比较下一个字符 } else if (*src > *dst) return result = 1;//src>dst else return result = -1; //src<dst } return *src - *dst; //三种情况,"abc" "abc" "abcd" }
修改为为用result存两个字符之差来进行循环检测
1 int strcmp(const char *src, const char *dst) 2 { 3 assert((src != NULL) && (dst != NULL)); 4 int result = 0; 5 6 while (!(result = (*src - *dst)) && (*src != '\0'&& *dst != '\0')) 7 { //修改为(!(result = (*src - *dst)) && ( *dst != '\0'))比较简洁 8 dst++; 9 src++; } 10 if (result < 0) return -1; 11 else if(result > 0) return 1; 12 else return 0; 13 }
参考:http://www.cnblogs.com/xuhj001/archive/2013/11/17/3428088.html
C标准库strcmp实现
1 int Strcmp2(char *str1, char *str2) 2 { 3 assert(str1 != NULL&&str2 != NULL); 4 for (; *str1 == *str2; str1++, str2++) 5 if (*str1 == '\0') return 0; 6 return *str1 < *str2 ? -1 : 1; 7 }
自己写的麻烦的实现:
1 int Strcmp(char *s1, char *s2) 2 { 3 assert(s1 != NULL&& s2 != NULL); 4 int ret; 5 while (*s1 != '\0'&&*s2 != '\0') 6 { 7 //while (*s1++ == *s2++); 8 if (*s1 == *s2) { s1++; s2++; } 9 else { 10 ret = *s1 - *s2; 11 cout << ret << endl; 12 return ret <0 ? -1 : 1;//不等<会返回1,大于则返回0,而不是-1 13 14 } 15 } 16 ret = *s1 - *s2; 17 if (ret < 0) return -1; 18 else return ret == 0 ? 0 : 1; 19 }
char *strcat(char *s1,const char *s2) 可以用strcpy(s1+=strlen(s1),s2)实现
1 char *Strcat(char *s, const char *s2)// Strcat不会另申请空间,而是需要s1有足够的空间可以容纳原s1与s2的字符 2 { 3 char *p = s; 4 while (*s++) //s的递增不影响实参指针的值,为了返回字符串的首地址,用p存下来 5 { 6 cout <<1<< *s << " "; 7 } 8 s--; 9 while (*s++ = *s2++);//‘\0'的ascii值为0,结果为假,即表达式的值会转换为真或假 10 return p; 11 }
由于strcat一次拼接返回的是首指针,频繁拼接需要再次从开始位置扫描,找字符串的尾部,这样效率就低了

浙公网安备 33010602011771号