求字符串长度
strlen
函数功能
求一个字符串的长度,计算的是’\0’之前出现的字符个数
函数参数
size_t strlen( const char *string ); # size_t 是函数的返回类型 # char* string 是函数参数
模拟实现
size_t my_strlen(char *str) { int count = 0; while (*str != '\0') { count++; str++; } return count; }
注意事项
1.strlen的结束标志是’\0’,因此要求传给strlen的参数必须带’\0’,否则strlen的结果就是随机值。(因为strlen会一直向后访问,直到找到’\0’。可以说是一个大情种了(手动滑稽))。
2.strlen的返回值是无符号整形,如果用两个strlen相减的话得到的结果始终是非负数。
长度不受限制的字符串函数
strcpy
函数功能
字符串拷贝,将一个字符串的内容拷贝到另一个字符串中(包括’\0’)
函数参数
char* strcpy(char * destination, const char * source ); # char* 是函数的返回值,返回的是目标空间的起始地址 # source 是要拷贝的字符串 # destination 是目标空间
模拟实现
char* my_strcpy(char* dest, char* src) { assert(dest&&src);//assert断言,保证dest和src不为空指针,头文件为#include<assert.h> char* ret = dest;//函数要求返回目标空间的起始地址 while (*dest++ = *src++) { ; } return ret; }
while循环里的语句是将src指向的内容拷贝到dest当前指向的位置,再用拷贝的结果来作为判断,最后对两个指针进行自增操作。
注意事项
源字符串必须要是以"\0"结束
目标空间要足够大
目标空间必须可修改。
strcat
函数功能
字符串追加,在一个字符串的末尾追加另一个字符串(包含’\0’)
函数参数
char * strcat ( char * destination, const char * source ); # char* 是函数的返回值,返回的是目标空间的起始地址 # source 是要追加的字符串 # destination 是目标空间
模拟实现
char* my_strcat(char* dest, char* src) { assert(dest&&src); char* ret = dest; //先找到dest的末尾,再字符串拷贝 while (*dest != '\0') { dest++; } while (*dest++ = *src++) { ; } return ret; }
注意事项
1.源字符串必须以’\0’结束
2.目标空间必须足够大,能够放下追加后的字符
3.目标空间必须是可修改的
4.strcat不能自己给自己追加。(因为自己给自己追加会覆盖掉末尾的’\0’,导致死循环)
strcmp
函数功能
字符串比较,比较两个字符串大小,如果相等则往后移,直到’\0’结束
函数参数
int strcmp ( const char * str1, const char * str2 ); # int 函数返回值 # char* str1 char* str2 用于比较的两个字符串 #返回值 >0 : str1 大于 str2; =0 : str1 等于 str2; <0 : str1 小于 str2
模拟实现
int my_strcmp(const char* str1, const char* str2) { assert(str1 && str2); //如果相等就往后比较 while (*str1 != '\0' && *str2 != '\0' && *str1 == *str2) { //相等的情况在这里,如果进来循环并且有一个为\0,那就说明两个字符串都到结尾了 if (*str1 == '\0') return 0; str1++; str2++; } /*if (*str1 > *str2) return 1; else return -1;*/ return(*str1 - *str2);//第一个字符串大于第二个字符串,则返回大于0的数字,第一个字符串小于第二个字符串,则返回小于0的数字。既然它们不相等,那么直接作差就能得到大小 }
注意事项
字符在内存中是以ASCII码值存储的,因此比较的也是每一对字符的ASCII码值
长度受限制的字符串函数
由于strcpy,strcat,strcmp等字符串函数不受长度的限制,容易造成越界的问题存在安全隐患。因此C语言还给我们提供了另外几种相对安全的字符串函数,即strncpy,strncat,strncmp。它们比原字符串函数多了一个参数,这个参数是用于指定操作的字节数。因为受到长度的限制,不会无脑梭哈,因此也相对更安全。(不是绝对安全,毕竟我要写bug谁也拦不住(斜眼笑))。
strncpy
函数功能
字符串拷贝,把一个字符串中指定的字节数的内容拷贝到另一个字符串中
函数参数
char * strncpy ( char * destination, const char * source, size_t num ); # char* 是函数的返回值,返回的是目标空间的起始地址 # source 是要拷贝的字符串 # destination 是目标空间 # num 是要拷贝的字节数
模拟实现
char* my_strncpy(char* dest, const char* src, size_t num) { assert(dest && src); char* ret = dest; //记录目标空间的起始地址 while (num--) { *dest = *src; if (*dest == '\0') //如果*dest为0,说明将src的结束字符赋给了dest,这种情况下源字符串的长度小于num { while (num--) { //如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。(与库函数的实现方式保持一致) *dest++ = 0; } break; } dest++; src++; } *dest = '\0'; //在dest的末尾补上结束字符 return ret; }
注意事项
可以看到,如果源字符串中的内容不够num个,会把用’\0’来补足。
strncat
函数功能
字符串追加,将一个字符串中num个字节的内容拷贝到另一个字符串的末尾,并在末尾补充’\0’。
函数参数
char * strncat ( char * destination, const char * source, size_t num ); # char* 是函数的返回值,返回的是目标空间的起始地址 # source 是要追加的字符串 # destination 是目标空间 # num 是要追加的字节数
模拟实现
char* my_strncat(char* dest, const char* src, size_t num) { assert(dest && src); char* ret = dest; //记录目标空间的起始地址 //找到dest末尾 while (*dest != '\0') { dest++; } //strncpy while (num--) { *dest = *src; if (*dest == '\0') //如果*dest为0,说明将src的结束字符赋给了dest,这种情况下源字符串的长度小于num { //如果源字字符串的长度小于num,则只复制到终止空字符的内容。(与库函数的实现方式保持一致) return ret; //直接返回 } dest++; src++; } *dest = '\0'; //则在dest的末尾补上结束字符 return ret; }
注意事项
如果源字符串的内容少于num个字节,也只复制到终止空字符的内容,也就是说并不会再去补’\0’。
strncmp
函数功能
字符串比较,比较两个字符串中前num个字节内容的大小
函数参数
int strncmp ( const char * str1, const char * str2, size_t num ); # int 函数返回值 # char* str1 char* str2 用于比较的两个字符串 # num 要比较的字节数 #函数返回值 >0 : str1 大于 str2; =0 : str1 等于 str2; <0 : str1 小于 str2
模拟实现
int my_strncmp(const char* str1, const char* str2, int num) { assert(str1 && str2); for(int i=0;i<num;i++)//库中使用的是for循环,因此我们也用for循环 { if (*str1 == *str2) { str1++; str2++; } else { return(*str1 - *str2); } } return 0; }
注意事项
比较的是每一对字符中的ASCII码值。
对前num个字节逐一比较,除非遇到’\0’或者不相等字符。
字符串查找函数
strstr
函数功能
查找子串,在一个字符串中查找是否包含该子串
函数参数
char * strstr ( const char *str1, const char * str2); # char* 函数返回值,返回字符串中子串的起始地址,若找不到,则返回NULL; # char* str1 要搜索的字符串; # char* str2 子串
模拟实现
分析:
代码实现:
char* my_strstr(const char* str1, const char* str2) { assert(str1 && str2); //根据分析,至少要三个指针 const char* s1 = str1; const char* s2 = str2; const char* p = str1; while (*p) { s1 = p;// s2 = str2; while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2) { s1++; s2++; } if (*s2 == '\0') return (char*)p; p++;//p记录的是上次匹配的起始位置,匹配失败要从上次的位置的下一个位置开始匹配 } return NULL; }