=========================================================================
相关代码gitee自取:C语言学习日记: 加油努力 (gitee.com)
=========================================================================
接上期:
学C的第二十七天【指针的进阶(三)】_高高的胖子的博客-CSDN博客
=========================================================================
(1).
C语言中对于字符和字符串的处理很是频繁,但是C语言本身没有字符串类型,字符串通常放在 常量字符串 中或者 字符数组 中。
(2).
字符串常量 适用于那些对其不做修改的字符串函数。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(1). strlen()函数:求字符串(字符数组)长度
函数返回值类型和相关参数:
size_t strlen ( const char * str );
(接收 常量字符指针 ,返回 无符号整数 )
注意事项:
(1).
字符串是以 '\0' 作为结束标志,需要 string.h 头文件,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包 含 '\0' )。
(2).
参数指向的字符串必须要以 '\0' 结束(不然统计个数为随机值)。
(3).
注意函数的返回值为size_t,是无符号的( 易错 ),如下:
(4).
学会strlen函数的模拟实现(下面第2个模块有)
(2). strcpy()函数:拷贝字符串
函数返回值类型和相关参数:
char* strcpy(char * destination, const char * source );
(接收 目标空间指针 和 内容不能被修改的源字符串指针 ,返回 目标空间指针)
注意事项:
(1).
将 源字符串指针 指向的 字符串 复制到 目标空间指针 指向的空间 中,
包括 终止空字符,即 \0 ,并在该点停止。
(2).
源字符串必须以 '\0' 结束。
(3).
会将源字符串中的 '\0' 拷贝到目标空间。
(4).
目标空间必须足够大,以确保能存放源字符串。
(5).
目标空间必须可变。
(6).
学会strcpy函数的模拟实现(下面第2个模块有)
(3). strcat()函数:追加字符串到另一字符串后
函数返回值类型和相关参数:
char * strcat ( char * destination, const char * source );
(接收 目标空间指针 和 内容不能被修改的源字符串指针 ,返回 目标空间指针)
注意事项:
(1).
将源字符串的副本追加到目标字符串。
目的地中的 '\0' 被源字符串的第一个字符覆盖,
并且 '\0' 会在新字符串的末尾。
需要
头文件。
(2).
源字符串必须以 '\0' 结束。
(3).
目标空间必须有足够的大,能容纳下源字符串的内容。
(4).
目标空间必须可修改。
(5).
学会strlen函数的模拟实现(下面第2个模块有)
(4). strcmp()函数:比较两个字符串的大小
函数返回值类型和相关参数:
int strcmp ( const char * str1, const char * str2 );
(接收 两个常量字符串的首字符指针,返回 一个整数)
注意事项:
(1).
此函数开始比较时会比较每个字符串的第一个字符。
如果它们彼此相等,则继续比较下一对,
直到 字符不同 或 比较完所有字符都相同 为止。
(2). 标准规定:
第一个字符串的字符 大于 第二个字符串的字符,则返回 大于0 的数字
(假设 “abcdef” 和 “abc” 比较,abc都相等,第四次比较时 e>\0,那么"abcdef"更大,返回 大于0 的数字)
第一个字符串的字符 等于 第二个字符串的字符,则 返回0
(假设 “abc” 和 “abc” 比较,abc都相等,第四次比较时 \0==\0,返回 0)
第一个字符串的字符 小于 第二个字符串的字符,则返回 小于0 的数字
(假设 “abcdef” 和 “abq” 比较,a和b都相等,第三次比较时 c
,那么"abq"更大,返回小于0 的数字)
(3).
学会strlen函数的模拟实现(下面第2个模块有)
(5). strncpy()函数:拷贝字符串的num个字符
函数返回值类型和相关参数:
char * strncpy ( char * destination, const char * source, size_t num );
(和 strcpy()函数 相同,只是参数多了个 拷贝的字符个数)
注意事项:
(1).
将 源字符串指针 指向的 字符串前num个字符 复制到 目标空间指针 指向的空间 中,
包括 终止空字符,即 \0 ,并在该点停止。(和strcpy()函数类似,但限制了拷贝个数)
(2).
从源字符串拷贝num个字符到目标空间。
(3).
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的空间后边追加0,直到num个。
(6). strncat()函数:追加字符串的num个字符到另一字符串
函数返回值类型和相关参数:
char * strncat ( char * destination, const char * source, size_t num );
(和 strcat()函数 相同,只是参数多了个 拷贝的字符个数)
注意事项:
(1).
将源字符串的副本的num个字符追加到目标字符串。
目的地中的 '\0' 被源字符串的第一个字符覆盖,
并且 '\0' 会在新字符串的末尾。
(和strcat()函数类似,但限制了追加个数)
(2).
如果源字符串的长度小于num,也只追加 源字符串 的字符串,
不会像strncpy一样补0。
(7). strncmp()函数:在num个字符内比较两个字符串
函数返回值类型和相关参数:
int strncmp ( const char * str1, const char * str2, size_t num );
(和 strcmp()函数 相同,只是参数多了个 限定在num个字符中比较)
注意事项:
(1).
比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。
(8). strstr()函数:在字符串中找子字符串
函数返回值类型和相关参数:
char * strstr ( const char *str1, const char * str2);
(参数接收 两个常量字符串,返回 字符指针)
注意事项:
(1).
在 str1 中 找 str2 首次出现的地址,如果 str2 中没有 str1 则返回 空指针NULL。
(4).
学会strstr函数的模拟实现(下面第2个模块有)
(9). strtok()函数:使用自定义分隔符对字符串进行分割
函数返回值类型和相关参数:
char * strtok ( char * str, const char * sep );
(参数接收 被分割的字符串首字符地址 和 指定的分隔符指针,
返回 被分割的子字符串指针 )
注意事项:
(1).
sep参数是个字符串,定义了用作分隔符的字符集合
(2).
str参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
(3).
strtok函数找到str中的下一个标记,并将其用 \0 结尾(把找到的标记变为 \0 ),
返回一个指向这个标记的指针。
(注: strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容 并且可修改。)
(4).
strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
(5).
strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
(6).
如果字符串中不存在更多的标记,则返回 NULL 指针。
(10). strerror()函数:将错误码以字符串形式提供出来
函数返回值类型和相关参数:
char * strerror ( int errnum );
(参数接收 错误码,返回 错误码的字符串信息地址)
注意事项:
(1).
库函数在执行时,发生了错误,会将一个错误码存放在 errno 这个变量中,
errno 是C语言提供的一个全局变量。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(1). 模拟实现strlen()函数:
方法1:计数器方式
对应代码:
#include
//方法1:计数器方式 size_t my_strlen(const char* str) //和库函数的strlen函数一样 //返回值为无符号整型,参数为常量字符指针 { int count = 0; //计数器 while (*str != '\0') //还没到结束符就继续统计 { count++;//没到结束符就统计+1 str++;//判断下一位 } return count;//返回计数器 } int main() { size_t sz = my_strlen("abc"); //使用模拟实现的strlen函数返回一个size_t(无符号整数)的数 //进行打印: printf("%u\n", sz); //%u:打印无符号的数 return 0; }
方法2:指针方式
对应代码:
#include
//方法2:指针方式 size_t my_strlen(const char* str) //和库函数的strlen函数一样 //返回值为无符号整型,参数为常量字符指针 { char* p = str; while (*p != '\0') //还没到结束符就继续统计 { p++;//没指向结束符就判断下一位 } return p-str;//用移动后的指针 - 原来的指针 == 字符串长度 } int main() { size_t sz = my_strlen("abc"); //使用模拟实现的strlen函数返回一个size_t(无符号整数)的数 //进行打印: printf("%u\n", sz); //%u:打印无符号的数 return 0; }
方法3:迭代方式
对应代码:
#include
//方法3:迭代方式 size_t my_strlen(const char* str) //和库函数的strlen函数一样 //返回值为无符号整型,参数为常量字符指针 { if (*str == '\0') { return 0;//如果第一个就指向\0,说明长度是0 } else { return 1 + my_strlen(str + 1); } } int main() { size_t sz = my_strlen("abc"); //使用模拟实现的strlen函数返回一个size_t(无符号整数)的数 //进行打印: printf("%u\n", sz); //%u:打印无符号的数 return 0; }
(2). 模拟实现strcpy()函数:
主函数:
模拟实现strcpy()函数:
对应代码:
//模拟strcpy函数: #include
#include char* my_strcpy(char* dest, const char* src) //返回值类型 和 参数 与库函数strcpy相同 //返回值设置为char*,是为了能够使用链式访问,把返回值作为其它函数的参数 { //保存目标空间指针原位置,方便最后进行返回 char* ret = dest; //进行断言,两个指针都不为空指针,需要头文件 assert(dest != NULL); assert(src != NULL); //只要 源字符串 还没指向 \0 就继续循环拷贝 while (*src != '\0') { *dest = *src; //将源字符串的一位赋给目标空间 //下次赋值下一位,所以要移动两个指针: dest++; src++; } //循环中没有将 \0 赋给目标空间,所以要加上: *dest = *src; //循环完后,dest移向了新位置,src在\0位置,所以直接赋值即可 //返回拷贝后的目标指针原地址: return ret; } int main() { //目标空间(字符数组): char arr1[20] = "xxxxxxxxxxxxxxxx"; //源字符串: char arr2[] = "hello world"; my_strcpy(arr1, arr2); //使用模拟的函数来拷贝 //arr1为目标空间指针,arr2为源字符串指针 //将arr2指向的内容 拷贝到 目标空间指针中 //打印拷贝结果: printf("%s\n", arr1); return 0; }
可进行化简:
对应代码:
//模拟strcpy函数: #include
#include char* my_strcpy(char* dest, const char* src) //返回值类型 和 参数 与库函数strcpy相同 //返回值设置为char*,是为了能够使用链式访问,把返回值作为其它函数的参数 { //保存目标空间指针原位置,方便最后进行返回 char* ret = dest; //进行断言,两个指针都不为空指针,需要头文件 assert(dest != NULL); assert(src != NULL); //只要 源字符串 还没指向 \0 就继续循环拷贝 while (*dest++ = *src++) { ; } //返回拷贝后的目标指针原地址: return ret; } int main() { //目标空间(字符数组): char arr1[20] = "xxxxxxxxxxxxxxxx"; //源字符串: char arr2[] = "hello world"; my_strcpy(arr1, arr2); //使用模拟的函数来拷贝 //arr1为目标空间指针,arr2为源字符串指针 //将arr2指向的内容 拷贝到 目标空间指针中 //打印拷贝结果: printf("%s\n", arr1); return 0; }
(3). 模拟实现strcat()函数:
对应代码:
//模拟strcat函数: #include
#include #include char* my_strcat(char* dest, const char* src) { //进行断言,两个字符串都不为\0 (空) assert(dest); assert(src); //保存目标地址的原位置 char* ret = dest; //找到目标字符串的\0,作为连接的起点: while (*dest) { dest++; } //开始连接字符串,和strcpy是一样的 while (*dest++ = *src++) { ; } //返回连接后的目标空间指针: return ret; } int main() { //目标空间(数组): char arr1[20] = "hello"; //源字符串: char arr2[] = " world"; //使用模拟的自定义函数,将arr2连接到arr1后 my_strcat(arr1, arr2); //打印连接后的新字符串: printf("%s\n", arr1); return 0; }
(4). 模拟实现strcmp()函数:
对应代码:
//模拟strcmp函数: #include
int my_strcmp(const char* str1, const char* str2) { while (*str1 == *str2) //两字符串同位置上的值相同的情况 { if (*str1 == '\0') //同位置上都是\0说明两个字符串相同 { return 0; //相同则返回 0 } //不是\0,是其它值相同,则判断下一位 str1++; str2++; } if (*str1 > *str2) //当前位置,字符串1的字符大于字符串的字符 { return 1; //大于则返回大于0的数 } else //当前位置,字符串1的字符小于字符串的字符 { return -1; //小于则返回小于0的数 } } int main() { //使用自定义函数进行比较: int ret = my_strcmp("abq", "abc"); printf("%d\n", ret); return 0; }
(5). 模拟实现strstr()函数:
模拟的自定义函数:
主函数:
对应代码:
//模拟strncmp函数: #include
#include char* my_strstr(char* str1, char* str2) { char* cp = str1; //开始进行判断的初始位置指针 char* s1 = cp; //在arr1中的cp位置开始逐位进行匹配的指针 char* s2 = str2; //在arr2中逐位进行匹配的指针 //如果要找的子字符串为空指针,则返回str1: if (*str2 == '\0') { return str1; } while (*cp != '\0') // \0之后不可能找到arr2的内容 { //开始匹配: s1 = cp; //让s1在初始位置开始进行逐位判断 s2 = str2; while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2) //两字符串都未到\0,如果当前位置的内容相同,则再循环判断下一位 { s1++; s2++; } if (*s2 == '\0') //如果子字符串已经到了\0, //说明arr1中有arr2,匹配成功 { return cp; //匹配成功,则返回子字符串的初始位置 } cp++; //判断arr1下一个初始位置 } return NULL; //未找到则返回空指针 } int main() { char arr1[] = "abbbcdef"; char arr2[] = "bbc"; //使用自定义函数进行查找: char* ret = my_strstr(arr1, arr2); if (ret != NULL) { printf("%s\n", ret); } else { printf("未找到"); } return 0; }