本章重点:重点介绍处理字符和字符串的库函数的使用和注意事项
求字符串长度
- strlen
长度不受限制的字符串函数
- strcpy
- strcat
- strcmp
长度受限制的字符串函数介绍
- strncpy
- strncat
- strncmp
字符串查找
- strstr
- strtok
错误信息报告
- strerror
字符操作
内存操作函数
- memcpy
- memmove
- memset
- memcmp
1、函数介绍
1.1、strlen
size_t strlen ( const char * str );
- 字符串已经 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包 含 '\0' )。
- 参数指向的字符串必须要以 '\0' 结束。
- 注意函数的返回值为size_t,是无符号的( 易错 )
- 学会strlen函数的模拟实现
首先先来看一段代码:
#include <stdio.h> #include <string.h> int main() { //注意返回值类型 - 无符号整型 const char* str1 = "abcdef"; const char* str2 = "bbb"; if (strlen(str2) - strlen(str1) > 0) { printf("str2>str1\n"); } else { printf("srt1>str2\n"); } return 0; }
运行结果:
解释:在这段代码中,比较的是两个字符串的长度,而不是字符串本身的内容。因为 strlen()函数用于计算字符串的长度,而不会考虑字符串中的具体字符。在这里,"abcdef" 的长度为 6,"bbb" 的长度为 3,strlen(str2) - strlen(str1)相减的结果是-3,但是由于strlen的返回值是无符号整型,两个无符号整型相减结果也会被当作无符号整型看待,无符号整型的结果必定大于0,-3的补码:11111111111111111111111111111101,用无符号看待结果大于0,所以输出结果将是 "str1
模拟实现strlen
方式一:计数器方式
size_t my_strlen(const char* str) { int count = 0; while (*str != '\0') { count++; str++; } return count; }
方式二:递归方法
size_t my_strlen(const char* str) { const char* start = str; while (*str != '\0') { str++; } return str - start; }
方式三:指针-指针的方式
size_t my_strlen(const char* str) { if (*str == '\0') return 0; else return my_strlen(++str) + 1; }
1.2、strcpy
char* strcpy(char * destination, const char * source );
- Copies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point).(将由源指针指向的C字符串复制到由目标指针指向的数组中,包括终止空字符(并在那一点停止复制))
- 源字符串必须以 '\0' 结束。
- 会将源字符串中的 '\0' 拷贝到目标空间。
- 目标空间必须足够大,以确保能存放源字符串。
- 目标空间必须可变。
- 学会模拟实现。
#include<stdio.h> #include<string.h> int main() { //char* strcpy(char* destination, const char* source); char arr1[20] = { 0 }; char arr2[] = "hello!"; char *arr3 = strcpy(arr1, arr2);//接受返回值 printf("%s\n", arr1);//不接受返回值打印 printf("%s\n", arr3);//接受返回值打印 return 0; }
运行结果:
注意1:strcpy拷贝会将'\0'拷贝至目的地
注意2:strcpy的源头必须保证有'\0'字符
模拟实现strcpy
char* my_strcpy(char* destination, const char* source) { char* dest = destination; assert(source != '\0' && destination != '\0');//头文件<assert.h> while (*source) { *destination = *source; destination++; source++; } *destination = *source;//拷贝'\0' //return destination;//error,此时destination地址已经被改变 return dest; }
优化
char* my_strcpy(char* destination, const char* source) { char* dest = destination; assert(source != '\0' && destination != '\0');//头文件<assert.h> while (*destination++ = *source++) { ;//后置++,先使用后++ //'\0'的ASCII码值为0,while(0)为假退出循环 } //return destination;//error,此时destination地址已经被改变 return dest; }
1.3、strcat
char * strcat ( char * destination, const char * source );
- Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source, and a null-character is included at the end of the new string formed by the concatenation of both in destination.(将源字符串的副本追加到目标字符串中。目标字符串中的终止空字符会被源字符串的第一个字符覆盖,并且在目标字符串中形成的新字符串的末尾包含一个空字符,用于表示字符串的结束。)
- 源字符串必须以 '\0' 结束。
- 目标空间必须有足够的大,能容纳下源字符串的内容。
- 目标空间必须可修改。
#include<stdio.h> #include<string.h> int main() { char arr1[20] = "i"; char arr2[] = "love you"; strcat(arr1, arr2);//追加字符串 printf("%s\n", arr1); return 0; }
运行结果:
模拟实现strcat:
char* my_strcat(char* destination, const char* source) { char* dest = destination; assert(source != '\0' && destination != '\0');//头文件<assert.h> while (*destination!='\0') { destination++;//找到目标空间的\0 } while (*destination++ = *source++) { ;//把目标空间\0及以后的空间拷贝上源头的字符串 } return dest; }
那我们字符串自己给自己追加,如何?
解释:很明显,程序崩溃了。因为在追加字符串的时候,首先就要找到目标空间的\0,然后把它修改成源字符串的第一个字母,但是由于是自己给自己追加字符串,导致把源字符串的\0也修改掉了,字符串就会一直拷贝去找\0,但是源字符串的\0已经被修改,导致一直追加字符串,最后空间不足程序崩溃。
1.4、strcmp
int strcmp ( const char * str1, const char * str2 );
- This function starts comparing the first character of each string. If they are equal to each other, it continues with the following pairs until the characters differ or until a terminating null-character is reached.(这个函数从两个字符串的第一个字符开始比较。如果它们相等,它会继续比较后续的字符对,直到找到不同的字符或者遇到终止空字符为止。)
- 标准规定:
- 第一个字符串大于第二个字符串,则返回大于0的数字
- 第一个字符串等于第二个字符串,则返回0
- 第一个字符串小于第二个字符串,则返回小于0的数字
那么如何判断两个字符串?
#include<stdio.h> #include<string.h> int main() { //比较的是字母的ASCII码值,a - 97,b - 98 //int strcmp(const char* str1, const char* str2); char arr1[] = "hello"; char arr2[] = "hellc"; if (strcmp(arr1, arr2) > 0) { printf("arr1 > arr2"); } else if (strcmp(arr1, arr2) < 0) { printf("arr1 < arr2"); } else { printf("arr1 = arr2"); } return 0; }
运行结果:
模拟实现strcmp:
int my_strcmp(const char* str1, const char* str2) { assert(str1 != '\0' && str2 != '\0');//头文件<assert.h> while (*str1 == *str2)//字符串相等 { if (*str1 == '\0')//两个字符串相等 return 0; str1++; str2++; } //两个字符串不相等 if (*str1 > *str2) return 1; else return -1; }
优化:
int my_strcmp(const char* str1, const char* str2) { assert(str1 != '\0' && str2 != '\0');//头文件<assert.h> while (*str1 == *str2)//字符串相等 { if (*str1 == '\0')//两个字符串相等 return 0; str1++; str2++; } //两个字符串不相等 return (*str1-*str2);//繁返回他们之间的差值 }
【编织代码之纵横字符与绚丽字符串](中):https://developer.aliyun.com/article/1424777