C语言str系列库函数在不同的库中有不同的实现方法,但原理都是一样的。因为库函数都是没有进行入口参数检查的,并且str系列库函数在面试中经常容易被面试官喊在纸上写某一个函数的实现,因此本文参考了OpenBSD和vc++ 8.0库中的代码,结合自己的编程习惯,部分整理如下:
1、strcpy
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;
}
2、strncpy
//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;
}
注意
n是unsigned int,在进行n--操作时特别要小心。如果不小心写成下面这样就会出错:
while (n-- != 0 && (*d++ = *src++))
;
while (n-- != 0)
*d++ = '\0';第一个while循环中,当n变为0时,仍然会执行n--一,此时n等于经由-1变成的大正数,导致后面对n的使用出错。
3、strcat
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;
}
4、strncat
写法1:
//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;
}
5、strcmp
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;
}
6、strncmp
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;
}
7、strstr
写法1:
//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;
}
写法2:参照简单模式匹配算法
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;
}
8、strchr
//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;
}
9、strrchr
//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;
}
10、strlen
size_t strlen(const char *str)
{
if (str == NULL)
return 0;
const char *eos = str;
while (*eos++)
;
return (eos - 1 - str);
}
另外两篇str系列库函数:
C语言str系列库函数之strtok():
http://www.voidcn.com/article/p-wqnkttwj-gr.html