文章目录
一、分类
- 求字符长度:strlen
- 长度不受限制的字符串函数:strcpy 、strcat 、strcmp
- 长度受限制的字符串函数:strncpy 、strncat 、strncmp
- 字符串查找:strstr、strtok
- 错误信息报告:strerror
- 字符操作
- 内存操作函数:memcpy、memmove、memset、memcmp
二、函数实现过程
1.strlen
作用:strlen 计算字符串 str 的长度,直到空结束字符,但不包括空结束字符。
头文件:
声明:
size_t strlen(const char *str)
注意
- 字符串以‘\0’作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包 含 ‘\0’ )。
- 参数指向的字符串必须要以 ‘\0’ 结束。
- 注意函数的返回值为size_t,是无符号的。
模拟实现
- 计数器
size_t My_strlen(const char* str) { assert(str != NULL); int count = 0; while (*str ) { count++; str++; } return count; }
- 递归(不创建临时变量)
size_t My_strlen(const char* str) { if (*str == '\0') { return 0; } else return 1 + My_strlen(str + 1); }
- 指针减指针
size_t My_strlen(const char* str) { const char* star = str; const char* end = str; while (*end != '\0') { end++; } return end - star; }
2、strcpy和strncpy
作用:strcpy:把 src 所指向的字符串复制到 dest。
strncpy: 把 src 所指向的字符串复制到 dest,最多复制 n 个字符。
头文件:
声明
char* strcpy(char * destination, const char * source );
char * strncpy ( char * destination, const char * source, size_t num );
注意:
- 源字符串必须以 ‘\0’ 结束。
- 会将源字符串中的 ‘\0’ 拷贝到目标空间。
- 目标空间必须足够大,以确保能存放源字符串。
- 目标空间必须可变。
- strncpy
- 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
模拟实现
strcpy
char* My_strcpy(char* dest, const char* src) { assert(dest != NULL && src != NULL); char* res = dest; while ( *res==*src ) { *res++; *src++ } return res; }
strncpy
char * My_strncpy(char * dest, const char *src, size_t num) { assert(dest); assert(src); char *ret = dest; while (num--) { *dest++ = *src++; } return ret; }
3、strcat和strncat
作用
strcat:把 src 所指向的字符串追加到 dest 所指向的字符串的结尾。
strncat:把 src 所指向的字符串追加到 dest 所指向的字符串的结尾,直到 n 字符长度为止。
头文件
声明
char *strcat(char *dest, const char *src)
char *strncat(char *dest, const char *src, size_t n)
注意
- dest – 指向目标数组,该数组包含了一个 C 字符串,且足够容纳追加后的字符串。
- src – 指向要追加的字符串,该字符串不会覆盖目标字符串。
- 源字符串必须以 ‘\0’ 结束。
- 目标空间必须有足够的大,能容纳下源字符串的内容。
- 目标空间必须可修改。
- 模拟实现
strcat
char* My_strcat(char* dest, const char* src) { assert(dest != NULL && src != NULL); while (*dest != '\0') { dest++; } while (*dest = *src) { dest++; src++; } return dest; }
strncat
char* My_strncat(char* dest, char* src, size_t n) { char* ret = dest; assert(dest && src); while (*dest != '\0') { dest++; } while (count && (*des++ = *src++)) { n--; } *dest = '\0'; return ret; }
4、 strcmp和strncmp
作用
strcmp:把 str1 所指向的字符串和 str2 所指向的字符串进行比较.
strncmp:把 str1 和 str2 进行比较,最多比较前 n 个字节。
头文件
声明
int strcmp(const char *str1, const char *str2)
int strncmp(const char *str1, const char *str2, size_t n)
注意
- 第一个字符串大于第二个字符串,则返回大于0的数字
- 第一个字符串等于第二个字符串,则返回0
- 第一个字符串小于第二个字符串,则返回小于0的数字
模拟实现
strcmp
int My_strcmp(const char* str1, const char* str2) { assert(str1 && str2); while (*str1 == *str2) { if (*str1 == '\0') { return 0; } str1++; str2++; } return *str2 - *str1; }
strncmp
int my_strncmp(const char *str1, const char *str2, size_t n) { assert(str1); assert(str2); while (*str1&&*str2&&(*str1 == *str2)&&n--) { str1++; str2++; } return *str1 - *str2; }
5、strstr
作用
在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 ‘\0’,如果未找到则返回 null。
声明
char *strstr(const char *haystack, const char *needle)
头文件
模拟实现
char* My_strstr(const char* string, const char* strCharSet) { assert(string&&strCharSet); const char* dest =NULL; const char* src =strCharSet; const char* cp = string; if (*strCharSet == '\0') { return (char*)string; } while (*cp) { dest = cp; src = strCharSet; while ((*dest == *src) && *dest != '\0' && *src != '\0') { dest++; src++; } if (*src == '\0') { return (char*)cp; } else { cp++; } } return NULL; }
6、strtok
作用
分解字符串 str 为一组字符串,delim 为分隔符
头文件
声明
char *strtok(char *str, const char *delim)
参数
- str – 要被分解成一组小字符串的字符串。
- delim – 包含分隔符的 C 字符串。
- 返回值
- 该函数返回被分解的第一个子字符串,如果没有可检索的字符串,则返回一个空指针。
注意
strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
7、strerror
返回错误码,所对应的错误信息。
char * strerror ( int errnum );
字符分类函数:
iscntrl 任何控制字符
isspace 空白字符:空格‘ ’,换页‘\f’,换行’\n’,回车‘\r’,制表符’\t’或者垂直制表符’\v’
isdigit 十进制数字 0~9
isxdigit 十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A-F
islower 小写字母a~z
isupper 大写字母A~Z
isalpha 字母a~z或A-Z
isalnum 字母或者数字,a~z,A-Z,0-9
ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph 任何图形字符
isprint 任何可打印字符,包括图形字符和空白字符
二、内存函数
1、memset
作用
复制字符 c(一个无符号字符)到参数 str 所指向的字符串的前 n 个字符。
头文件
声明
void *memset(void *str, int c, size_t n)
参数
- str – 指向要填充的内存块。
- c – 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式。
- n – 要被设置为该值的字符数。
- 返回值
- 该值返回一个指向存储区 str 的指针。
- 实现
2、memcmp
作用
存储区 str1 和存储区 str2 的前 n 个字节进行比较。
头文件
声明
int memcmp(const void *str1, const void *str2, size_t n)
参数
- str1 – 指向内存块的指针。
- str2 – 指向内存块的指针。
- n – 要被比较的字节数。
- 返回值
- 如果返回值 < 0,则表示 str1 小于 str2。
- 如果返回值 > 0,则表示 str1 大于 str2。
- 如果返回值 = 0,则表示 str1 等于 str2。
- 注意
- memcmp函数作用与strcmp作用相同,而strcmp只适用于字符串。
**3、memcpy与memmove
作用
两者作用都是从 str2 复制 n 个字符到 str1。
头文件
声明
void *memcmp(void *str1, const void *str2, size_t n)
void *memmove(void *str1, const void *str2, size_t n)
参数
- str1 – 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
- str2 – 指向要复制的数据源,类型强制转换为 void* 指针。
- n – 要被复制的字节数。
- 返回值
该函数返回一个指向目标存储区 str1 的指针。
模拟实现
void* my_memmove(void* dest, const void* src, size_t count) { assert(dest && src); char* pdest = (char*)dest; const char* psrc = (char*)src; if (pdest < psrc || *pdest >= *psrc + count)//没有发生内存重叠 { while (count--) { *pdest++ = *psrc++; } } else//发生内存重叠 { pdest = pdest + count - 1; psrc = psrc + count - 1; while (count--) { *pdest-- = *psrc--; } } return dest; }
但是在重叠内存块这方面,memmove() 是比 memcpy() 更安全的方法。什么是内存重叠?
内存重叠就是拷贝的目的地址和源地址有重叠
蓝色部分为内存重叠区。