C语言str系列库函数在不同的库中有不同的实现方法,但原理都是一样的。因为库函数都是没有进行入口参数检查的,并且str系列库函数在面试中经常容易被面试官喊在纸上写某一个函数的实现,因此本文参考了OpenBSD和vc++ 8.0库中的代码,结合自己的编程习惯,部分整理如下:
char * strcpy(char *dst, const char *src) { char *d; if (dst == NULL || src == NULL) return dst; d = dst; while (*d++ = *src++) // while ((*d++ = *src++) != '\0') ; return dst; }
//copy at most n characters of src to dst //Pad with '\0' if src fewer than n characters char *strncpy(char *dst, const char*src, size_t n) { char *d; if (dst == NULL || src == NULL) return dst; d = dst; while (n != 0 && (*d++ = *src++)) /* copy string */ n--; if (n != 0) while (--n != 0) *d++ == '\0'; /* pad out with zeroes */ return dst; }
while (n-- != 0 && (*d++ = *src++)) ; while (n-- != 0) *d++ = '\0';第一个while循环中,当n变为0时,仍然会执行n--一,此时n等于经由-1变成的大正数,导致后面对n的使用出错。
char *strcat(char *dst, const char *src) { char *d; if (dst == NULL || src == NULL) return dst; d = dst; while (*d) d++; //while (*d++ != 0); //d--; while (*d++ = *src++) ; return dst; }
//concatenate at most n characters of src to the end of dst //terminates dst with '\0' char *strncat(char *dst, const char *src, size_t n) { if (NULL == dst || NULL == src) return dst; if (n != 0) { char *d = dst; do { if ((*d = *src++) == '\0' ) return dst; //break d++; } while (--n != 0); *d = '\0'; } return dst; }写法2:
char *strncat(char *dst, const char *src, size_t n) { char *d; if (dst == NULL || src == NULL) return dst; d = dst; while (*d) d++; //(1) while (n != 0) { if ((*d++ = *src++) == '\0') return dst; n--; } //(2) //while (n--) //这种方式写最后n的值不为0,不过这个n后面不会再被使用 // if ((*d++ == *src++) == '\0') // return dst; *d = '\0'; return dst; }
int strcmp(const char *s1, const char *s2) { if (s1 == NULL || s2 == NULL) return 0; //(1) //while (*s1 == *s2++) // if (*s1++ == '\0') // return 0; //(2) for (; *s1 == *s2; s1++, s2++) if (*s1 == '\0') return 0; return *(unsigned char*)s1 - *(unsigned char*)s2; }
int strncmp(const char *s1, const char *s2, size_t n) { if (s1 == NULL || s2 == NULL) return 0; if (n == 0) return 0; do { if (*s1 != *s2++) return *(unsigned char*)s1 - *(unsigned char*)--s2; if (*s1++ == '\0') break; } while (--n != 0); //do //{ // if (*s1 != *s2) // return *(unsigned char*)s1 - *(unsigned char*)s2; // if (*s1 == '\0') // break; // s1++; // s2++; //} while (--n != 0); return 0; }
//return pointer to first occurrence of find in s //or NULL if not present char *strstr(const char *s, const char *find) { char *cp = (char*)s; char *s1, *s2; if (s == NULL || find == NULL) return NULL; while (*cp != '\0') { s1 = cp; s2 = (char*)find; while (*s1 && *s2 && *s1 == *s2) s1++, s2++; if(*s2 == '\0') return cp; cp++; } return NULL; }
char *strstr(const char *s, const char *find) { int i = 0, j = 0; while (*(s + i) != '\0' && *(find + j) != '\0') { if (*(s + i + j) == *(find + j)) j++; //继续比较后一字符 else { i++; //开始新一轮比较 j = 0; } } return *(find + j) == '\0' ? (char*)(s + i) : NULL; }
//return pointer to first occurrence of ch in str //NULL if not present char *strchr(const char*str, int ch) { while (*str != '\0' && *str != (char)ch) str++; if(*str == (char)ch) return (char*)str; return NULL; }
//return pointer to last occurrence of ch in str //NULL if not present char *strrchr(const char *str, int ch) { if (str == NULL) return NULL; char *s = (char*)str; while (*s++) ; /* find end of string */ while (--s != str && *s != (char)ch) ; /* search towards front */ if(*s == (char)ch) return (char*)s; return NULL; }
size_t strlen(const char *str) { if (str == NULL) return 0; const char *eos = str; while (*eos++) ; return (eos - 1 - str); }