目录
一:字符串长度不受限的函数
(1)strlen( )函数
功能:计算一个字符串的长度。(不包含结尾的'\0')
实现原理:我们都知道一个字符串的结束标志是'\0',strlen( )函数就是通过字符串首地址来遍历整个数组,遇到'\0'就结束。
调用:传入字符串首地址,如下图
实现思路:
【1】有很多种方法,但大致都是依靠指针来遍历。我们可以定义一个函数my_strlen( ),函数参数为字符串首地址(char*)。(因为只是要计算长度,要防止字符串内容被改变,可以在char*见面加上const进行修饰)
【2】我们可以设计一个计数器,使用while循环来遍历字符串,如果没遇到'\0',计数器加一,循环继续,否则结束循环,返回计数器数值。(也可以设计一个头指针和尾指针,两个指针相减得到的是指针间的元素个数)
图解:
代码:
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <assert.h> #include <string.h> /长度加测试 //注意const修饰,防止改变原字符串内容 int my_strlen(const char* str) { //断言,不传空指针 assert(str); //计数器 int count = 0; //如果走到'\0',结束 while (*str) { str++; count++; } return count; } int main() { char str[20] = "hello"; printf("%u\n", strlen(str)); return 0; }
(2)strcpy( )函数
功能:将一个字符串的所有内容拷贝到目标字符串。(包括'\0')
实现原理:传入目标字符串和源字符串的首地址,以'\0'为结束标志依次把源字符串的内容拷贝到目标字符串中,最后返回修改后的字符串首地址。
调用:传入两个字符串的首地址,第一个参数为目标字符串首地址,第二个参数为源字符串首地址,如下图
实现思路:
【1】定义一个函数my_strcpy( ),函数的参数为两个字符串的首地址。(注:要修改的是目标字符串,为了防止源字符串被修改,可以加上const进行修饰)
【2】遍历源字符串,把源字符串的内容赋给目标字符串,一直到把'\0'也赋给目标字符串,最后返回修改后的字符串首地址。图解:
代码:
//复制加测试 char* my_strcpy(char* dest, const char* src) { //断言,不传空指针 assert(dest&&src); char* cmp = dest; //如果遇到'\0',*dest++='\0',结束循环 //*dest++的值为*dest,结束后dest指针加1 while (*dest++=*src++) { ; } return cmp; } int main() { char str1[20] = "bayuhao"; char str2[20] = "hello"; printf("%s\n", str1); printf("%s\n", my_strcpy(str1, str2)); return 0; }
(3)strcat( )函数
功能:在一个字符串后面追加另一个字符串的内容。
实现原理:strlen( )函数加strcpy( )函数,先遍历目标字符串到'\0',然后把源字符串的内容赋给目标字符串后面的内容。
调用:传入两个字符串的首地址,第一个参数为目标字符串首地址,第二个参数为源字符串首地址,如下图
代码:
//追加和测试 //为了避免修改源字符串,用const修饰 char* my_strcat(char* dest,const char* src) { char* ret = dest; //断言,不传空指针 assert(dest && src); while (*dest) { dest++; } while (*dest++=*src++) { ; } return ret; } int main() { char str1[20] = "hello "; char str2[] = "world"; printf("%s\n", str1); printf("%s\n", my_strcat(str1, str2)); return 0; }
(4)strcmp( )函数
功能:进行字符串比较,前大与后就返回1,后大于前就返回-1,相同返回-1(也可以返回大于0,小于0的数来表示大小关系,不同平台实现有所不同)。
字符串比较:从第一个字符开始,依次进行比较,遇到不同的字符就比较两者的ASCLL码,大的一方就为大的字符串,小的就为小的字符串,如果两方同时走到'\0',就代表两个字符串相同。
实现原理:通过两个字符串指针进行遍历,依次比较。
调用:传入两个要比较的字符串首地址,如下图
代码:
//比较和测试 //只是进行比较,用const进行修饰防止修改字符串内容 int my_strcmp(const char* s1,const char* s2) { //断言,不传空指针 assert(s1 && s2); //以单个字符不相同为循环结束条件 while (*s1 == *s2) { if (*s1 == '\0') return 0; s1++; s2++; } //返回两者相差的ASCLL码 return *s1 - *s2; } int main() { char str1[20] = "hello"; char str2[20] = "hellp"; char str3[20] = "hello"; int ret = strcmp(str1, str2); int ret1 = strcmp(str1, str3); printf("ret:%d\n", ret); printf("ret1:%d\n", ret1); return 0; }
二:字符长度受限的函数
(1)strncmp( )函数
功能:也是进行字符串的比较,但多了一个参数,只比较固定的n位。
实现原理:依据传入的参数来进行固定次数的比较。
调用:给两个字符串首地址,再加一个整型,如下图
代码:
//固定比较n位 int my_strncmp(const char* str1, const char* str2, int num) { //断言,不传空指针 assert(str1 && str2); for (int i = 0; i < num; i++) { //如果不同,就计算相差的大小 if (*str1 != *str2) { return *str1 - *str2; } //迭代,往后走 str1++; str2++; } return 0; } int main() { char str1[20] = "helloq"; char str2[20] = "hellop"; int ret=my_strncmp(str1, str2, 5); if (ret > 0) printf("str1大于str2\n"); else if (ret < 0) printf("str1小于str2\n"); else printf("str1和str2相同\n"); return 0; }
(2)strncpy( )函数
功能:和strcpy( )函数类似,但多了一个参数,将一个字符串的固定n位拷贝到目标字符串。(包括'\0')
实现原理:依据传入的参数来进行固定次数的拷贝。
调用:给两个字符串首地址,再加一个整型,如下图
代码:
//固定复制n位 //用const修饰源字符串,防止修改 char* my_strncpy(char* dest,const char* src,int num) { //断言,不传空指针 assert(dest&&src); //保存首地址 char ret = dest; for (int i = 0; i < num; i++) { *dest++ = *src++; } return ret; } int main() { char str1[20] = "666666666"; char str2[20] = "bayuhao"; printf("%s\n", str1); my_strncpy(str1, str2,7); printf("%s\n", str1); return 0; }
(3)strncat( )函数
功能:和strcat( )函数类似,但是多了一个参数,只进行n个字符的追加。
实现原理:找到'\0'的位置,然后固定追加n个字符。(注:如果源字符串的字符数小于n,我们应该再'\0'追加完毕后就直接结束循环,避免越界访问)
调用:给两个字符串首地址,再加一个整型,如下图
代码:
//固定追加n位 //用const修饰,避免修改源字符串 char* my_strncat(char* dest,const char* src,int num) { //断言,不传空指针 assert(dest&&src); //保存首地址 char* ret = dest; while (*dest) { dest++; } for (int i = 0; i < num; i++) { //如果源字符串已经走到空,结束循环 if (*src == '\0') break; *dest++ = *src++; } //给目标字符串尾加上'\0' *dest = '\0'; return ret; } int main() { char str1[20] = "hello "; char str2[20] = "world"; printf("%s\n", str1); printf("%s\n", my_strncat(str1, str2, 4)); return 0; }
三:另外的几个函数
(1)strstr( )函数
功能:在一个字符串中查找另一个字符串
实现原理:
【1】传入两个字符串的首地址。(待查找的字符串和母字符串)
【2】从头遍历母字符串,如果找到了与待查找字符串首字符相同的字符,就从这个位置开始依次向后比较,如果待查找的字符串走到'\0',就代表母字符串里面有待查找字符串,返回第一个相同字符的地址,否则就返回NULL。
【3】如果遍历的过程中存在不同,我们要将指向母字符串的指针复位到原先开始遍历的位置的下一个位置,指向待查找字符串的指针复位到首地址。所以两者进行遍历比较前要记录指向母字符串的指针。
看不懂没关系,上图解:
调用:第一个参数为母字符串首地址,第二个参数为待查找字符串首地址,如下图
代码:
//一个字符串里面找另一个字符串 //只是查找,为了避免修改,用const修饰 char* my_strstr(const char* str1,const char* str2) { //断言,不传空指针 assert(str1&&str2); char* s1 = str1; char* s2 = NULL; char* cp = s1; //如果为空,直接返回 if(*str2=='\0') return (char*)str1; while (*cp) { s1 = cp; s2 = str2; //如果两者都没有走到空并且相同就继续 while (*s1&&*s1 == *s2) { s1++; s2++; //如果待查找字符串走到空,返回 if (*s2 == '\0') return (char*)cp; } cp++; } return NULL; } int main() { char str1[20] = "hebbitel"; char str2[] = "bitel"; char* ret = my_strstr(str1, str2); if (ret == NULL) printf("没找到\n"); else printf("找到了\n"); return 0; }
(2)strerror( )函数
功能:传入错误码,返回错误信息(字符串)的首地址。
错误码:其实每次我们调用库函数时都会生成一个错误码errno(int 类型,声明在头文件errno.h中,是一个全局变量)。
调用:
(3) strtok( )函数
功能:进行字符串的分割。
实现原理:
【1】第一次调用传入两个字符串首地址,其中一个为原字符串的首地址(如"[email protected]")
,另一个为分割符号字符串的首地址(如"@.")。
【2】函数第一次只会找到'@'的位置然后把它修改成'\0',为了让我们继续分割,函数会帮我们记录下原来@的下一个位置(静态变量)。
【3】除了第一次调用,为了让函数知道我们是要继续进行分割,我们需要改变第一个传入的参数,如果我们传入NULL,即告诉这个函数我们要继续分割。
【4】函数如果全部分割完毕,会返回一个空指针,否则就返回进行本次分割的这部分字符串的首地址。
调用: