size_t strlen ( const char * str );
'\0'
作为结束标志。strlen
函数返回的是 '\0'
前面出现的字符个数,不包含 '\0'
。size_t
,即无符号整型。
//计数器
int my_strlen1(const char* str)
{
assert(str != NULL);
int cnt = 0;
while (*str++ != '\0')
{
cnt++;
}
return cnt;
}
//递归
int my_strlen2(const char* str)
{
assert(str != NULL);
if (*str != NULL)
return 1 + my_strlen2(str + 1);
else
return 0;
}
//指针相减
int my_strlen3(const char* str)
{
assert(str != NULL);
const char* start = str;
while (*++str != '\0')
;
return str - start;
}
char* strcpy(char * destination, const char * source );
'\0'
结束。'\0'
拷贝到目标空间。char* my_strcpy(char* dest, const char* src)
{
assert(dest != NULL && src != NULL);
const char* start = dest;
while (*dest++ = *src++)
;
return start;
}
char * strcat ( char * destination, const char * source );
'\0'
开始,这个 '\0'
会被源字符串的第一个字符替换。'\0'
为止,所以源字符串必须以 '\0'
结束。'\0'
追加到目标空间。char* my_strcat(char* dest, const char* src)
{
assert(dest != NULL && src != NULL);
char* start = dest;
while (*++dest != '\0')
;
while (*dest++ = *src++)
;
return start;
}
int strcmp ( const char * str1, const char * str2 );
ASCII
码。strcmp
从第一个字符开始,逐字符比较大小,直到遇到第一个不相等的字符或者'\0'
停止。大于0
的数。小于0
的数。0
。int my_strcmp(const char* str1, const char* str2)
{
assert(str1 != NULL && str2 != NULL);
while (*str1 == *str2)
{
if (*str1 == '\0')
return 0;
str1++;
str2++;
}
return *str1 - *str2;
}
char * strncpy ( char * destination, const char * source, size_t num );
strcpy
。num
。num
,则拷贝完源字符串之后,继续追加'\0'
直到num
个为止。char* my_strncpy(char* dest, const char* src, size_t num)
{
assert(dest != NULL && src != NULL);
const char* start = dest;
while (num--)
{
if (*src == '\0')
{
*dest++ = '\0';
}
else
{
*dest++ = *src++;
}
}
return start;
}
char * strncat ( char * destination, const char * source, size_t num );
strcat
。num
。num
,则追加完源字符串之后,继续追加'\0'
直到num
个为止。char* my_strncat(char* dest, const char* src, size_t num)
{
assert(dest != NULL && src != NULL);
char* start = dest;
while (*++dest != '\0')
;
while (num--)
{
if (*src == '\0')
{
*dest++ = '\0';
}
else
{
*dest++ = *src++;
}
}
return start;
}
int strncmp ( const char * str1, const char * str2, size_t num );
strcmp
。num
个字符全部比较完为止。int my_strncmp(const char* str1, const char* str2, size_t num)
{
assert(str1 != NULL && str2 != NULL);
while (num--)
{
if (*str1 == *str2)
{
str1++;
str2++;
}
else
{
return *str1 - *str2;
}
}
return 0;
}
char * strstr ( const char *str1, const char * str2);
BF算法,即暴力枚举。
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 != NULL && str2 != NULL);
if (*str2 == '\0')
return (char*)str1;
const char* s1, * s2;
const char* cp = str1;
while (*cp != '\0')
{
s1 = cp;
s2 = str2;
while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
return (char*)cp;
cp++;
}
return NULL;
}
进阶:KMP算法
char * strtok ( char * str, const char * sep );
sep
是所有分隔符组成的字符串。strtok
找到一个分隔符后,会将其覆盖为'\0'
,并返回该分隔符的前一个子串。strtok
每次找到一个分隔符后都会自动保存该位置。
strtok
会从上一次保存的位置开始往后找。来看一个例子:
/* strtok example */
#include
#include
int main ()
{
char str[] ="- This, a sample string.";
char* p;
printf ("Splitting string \"%s\" into tokens:\n",str);
p = strtok (str," ,.-");
while (p != NULL)
{
printf ("%s\n", p);
p = strtok (NULL, " ,.-");
}
return 0;
}
运行结果如下:
char * strerror ( int errnum );
errno
中。strerror
函数把错误码翻译成错误信息。strerror
函数返回的就是包含错误信息的字符串的地址。来看一个例子:
#include
#include //strerror函数
#include //errno变量
int main ()
{
FILE * pFile = fopen ("unexist.ent","r");
if (pFile == NULL)
printf ("%s\n",strerror(errno));
return 0;
}
运行结果如下:
如果只想要打印错误信息,可以使用perror
函数。
void * memcpy ( void * destination, const void * source, size_t num );
source
的位置开始,向后拷贝num
个字节的数据到destination
的内存位置。'\0'
的时候并不会停下来。source
和destination
有重叠,结果是未定义的。strncpy
只能拷贝字符串不同,memcpy
可以拷贝任意类型的数据。void* my_memcpy(void* dest, const void* src, size_t num)
{
assert(dest != NULL && src != NULL);
void* start = dest;
while (num--)
{
*(char*)dest = *(char*)src;
++(char*)dest;
++(char*)src;
}
return start;
}
void * memmove ( void * destination, const void * source, size_t num );
memcpy
。memcpy
的不同在于:memmove
处理的源内存块和目标内存块是可以重叠的。void* my_memmove(void* dest, const void* src, size_t num)
{
assert(dest != NULL && src != NULL);
void* start = dest;
//考虑到源内存块和目标内存块的重叠问题
if (dest < src)//从前向后拷贝
{
while (num--)
{
*(char*)dest = *(char*)src;
++(char*)dest;
++(char*)src;
}
}
else//从后向前拷贝
{
while (num--)//利用num--往前,dest和src不动
{
*((char*)dest + num) = *((char*)src + num);
}
}
return start;
}
注:现在很多库里的memcpy
函数已经优化解决了源内存块和目标内存块的重叠问题,但还是建议能用memmove
就用memmove
。
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
strncmp
类似,逐字节比较从 ptr1
开始和从 ptr2
开始的num
个字节。strncmp
只能比较字符不同,memcmp
可以比较任意类型。int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{
assert(ptr1 != NULL && ptr2 != NULL);
while (num--)
{
if (*(char*)ptr1 == *(char*)ptr2)
{
++(char*)ptr1;
++(char*)ptr2;
}
else
{
return *(char*)ptr1 - *(char*)ptr2;
}
}
return 0;
}
void * memset( void * ptr, int value, size_t num );
ptr
是目标内存的地址,value
是要设置的值,num
是要设置多少个字节。