• 真嘟假嘟?!这么清晰简单的字符函数和字符串函数!!!


    目录​​​​​​​

    1. 字符分类函数

    1.1 小练习

    1.1.1 方法一

    2. 字符转换函数

    2.1 小练习的方法二

    3. strlen的使⽤和模拟实现

    3.1 注意事项

    3.1.1 注意事项2的练习

    3.2 strlen函数的模拟实现

    3.2.1 方法一

    3.2.2 方法二(指针—指针)

    3.2.3 方法三(递归方式)

    3.2.3.1 注意事项

    4. strcpy的使⽤和模拟实现

    4.1 注意事项

    4.2 使用举例

    4.2.1 注意点!!!

    4.3 stcpy函数的模拟实现

    4.3.1 版本一(先拷贝\0之前的字符,再拷贝\0之后的字符)

    4.3.2 版本二(拷贝\0前的字符包括\0)

    4.3.3 版本三 (assert,防止死循环)

    4.3.4 版本四 (dest指向的空间是需要改变的,但是src指向的空间是不被期望改变的)

    4.3.5 版本五 (返回目标空间的起始地址)

    5. strcat的使⽤和模拟实现

    5.1 注意事项

    5.2 使用举例

    5.3 strcat函数的模拟实现

    5.4 自己追加拼接自己可以吗?

    6. strcmp的使⽤和模拟实现

    6.1 使用举例

    6.2 strcmp的模拟实现

    7. strncpy函数的使⽤和模拟实现

    7.1 使用举例

    7.2 strncpy函数的模拟实现

    8. strncat函数的使⽤和模拟实现

    8.1 使用举例

    8.2 strncat函数的模拟实现

    9. strncmp函数的使⽤和模拟实现

    9.1 使用举例

    9.2 strncmp函数的模拟实现

    10. strstr的使⽤和模拟实现

    10.1 使用举例

    10.2 strstr函数的模拟实现

    10.2.1 模拟实现思路

    10.2.2 模拟实现思路优化

    10.2.3 代码实现

    11. strtok函数的使⽤

    11.1 用途介绍

    11.2 使用举例

    ​编辑

    11.2.1 方法优化

    12. strerror函数的使⽤

    12.1 使用举例

    12.2 相关函数perror的使用


    1. 字符分类函数

    C语⾔中有⼀系列的函数是专⻔做字符分类的,也就是⼀个字符是属于什么类型的字符的。

    这些函数的使⽤都需要包含⼀个头⽂件是 ctype.h

    这可以让我们更加方便的判断⼀个字符是属于什么类型的字符的

    接下来,我们以islower举例,其他函数使用的规则一样

    int islower ( int c );

    islower是用来返回参数是否是小写字母的,如果是小写字母就返回非零的值,如果不是小写字母就返回零

    1. #include
    2. #include
    3. int main()
    4. {
    5. int ret = islower('Q');
    6. printf("%d\n", ret);
    7. return 0;
    8. }

    1.1 小练习

    接下来,让我们写一个代码,将字符串中的小写字母转大写,其他字符不变

    1.1.1 方法一

    思路:大小写字母相差32

    1. #include
    2. #include
    3. #include
    4. int main()
    5. {
    6. char arr[] = "i AM A Student.";
    7. int i = 0;
    8. int len = strlen(arr);
    9. for (i = 0; i < len; i++)
    10. {
    11. if (islower(arr[i]))
    12. {
    13. arr[i] -= 32;
    14. }
    15. }
    16. printf("%s", arr);
    17. return 0;
    18. }

    但是,这种方法有点麻烦,让我们介绍完字符转换函数再来实现方法二

    2. 字符转换函数

    int tolower(int c);//将参数传进去的小写字母转大写

    int toupper(int c);//将参数传进去的大写字母转小写

    由此,我们可以得到方法二

    2.1 小练习的方法二

    1. #include
    2. #include
    3. #include
    4. int main()
    5. {
    6. char arr[] = "i AM A Student.";
    7. int i = 0;
    8. int len = strlen(arr);
    9. for (i = 0; i < len; i++)
    10. {
    11. if (islower(arr[i]))
    12. {
    13. arr[i]=toupper(arr[i]);
    14. }
    15. }
    16. printf("%s", arr);
    17. return 0;
    18. }

    3. strlen的使⽤和模拟实现

    size_t strlen ( const char * str );

    3.1 注意事项

    注意事项:
    1.strlen函数要正确获得字符串长度的话,字符串中必须要有\0
    2.要注意strlen的返回值是size_t(字符串长度没有负数- - ->无符号整型)

    3.1.1 注意事项2的练习

    观察以下代码,判断输出符号:

    1. #include
    2. #include
    3. #include
    4. int main()
    5. {
    6. if (strlen("abc") - strlen("abcdef") > 0)
    7. printf(">");
    8. else
    9. printf("<=");
    10. return 0;
    11. }

    可是,结果不是-3吗?为什么结果却是>呢?

    返回类型觉得结果———>-3———>3
    2个无符号类型相减得到的也是无符号整型

    3.2 strlen函数的模拟实现

    仿照strlen函数的参数,返回值,功能,写一个类似的函数

    3.2.1 方法一

    1. #include
    2. #include
    3. #include
    4. size_t my_strlen(char* str)
    5. {
    6. int count = 0;//计数
    7. while (*str != '\0')
    8. {
    9. count++;
    10. str++;
    11. }
    12. return count;
    13. }
    14. int main()
    15. {
    16. char arr[] = "abcdef";
    17. size_t ret = my_strlen(arr);
    18. printf("%zd\n", ret);
    19. return 0;
    20. }


    3.2.2 方法二(指针—指针)

    1. #include
    2. #include
    3. #include
    4. #include
    5. size_t my_strlen(const char* str)
    6. {
    7. const char* p = str;
    8. assert(str != NULL);
    9. while (*str != '\0')
    10. str++;
    11. return str - p;
    12. }
    13. int main()
    14. {
    15. char arr[] = "abcdef";
    16. size_t ret = my_strlen(arr);
    17. printf("%zd\n", ret);
    18. return 0;
    19. }


    3.2.3 方法三(递归方式)

    1. #include
    2. #include
    3. #include
    4. #include
    5. size_t my_strlen(const char* str)
    6. {
    7. if (*str == 0)
    8. return 0;
    9. else
    10. return 1 + my_strlen(str + 1);
    11. }
    12. int main()
    13. {
    14. char arr[] = "abcdef";
    15. size_t ret = my_strlen(arr);
    16. printf("%zd\n", ret);
    17. return 0;
    18. }

    3.2.3.1 注意事项

    可能会有人问str++可不可以?不行!!!

    str++为什么不行?
    后置++:先使用再++,str传址过去再++  ——>永远都传str的地址,str++或者++str导致str改变
    str+1:str不变
    但是,++str可以运行成功,但是str会改变,有隐患

    4. strcpy的使⽤和模拟实现

    char* strcpy(char * destination, const char * source );

    4.1 注意事项

    注意事项:
    1.原字符串必须包含\0;同时\0也会被拷贝到目标空间
    2.要保证目标空间要足够大,能放得下拷贝来的数据
    3.还要保证目标空间可修改

    4.2 使用举例

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include
    4. #include
    5. #include
    6. int main()
    7. {
    8. char s1[] = "hello world";
    9. char s2[20] = "xxxxxxxxxxxxx";
    10. strcpy(s2, s1);
    11. printf("%s\n", s2);
    12. return 0;
    13. }

    按理来说,应该输出:hello worldxx

    调试可以看到:拷贝的时候会将原字符串中的\0也拷进去,\0也拷贝过来后拷贝就结束了

    4.2.1 注意点!!!

    常量字符串---不可以修改

    4.3 stcpy函数的模拟实现

    4.3.1 版本一(先拷贝\0之前的字符,再拷贝\0之后的字符)

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include
    4. #include
    5. void my_strcpy(char* dest, char* src)
    6. {
    7. while (*src != 0)
    8. {
    9. *dest = *src;
    10. dest++;
    11. src++;
    12. }
    13. //拷贝\0
    14. *dest = *src;
    15. }
    16. int main()
    17. {
    18. char s1[] = "hello world";
    19. char s2[20] = { 0 };
    20. my_strcpy(s2, s1);
    21. printf("%s\n", s2);
    22. return 0;
    23. }


    4.3.2 版本二(拷贝\0前的字符包括\0)

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include
    4. #include
    5. char* my_strcpy(char* dest, char* src)
    6. {
    7. char* ret = dest;
    8. while (*dest++ = *src++)
    9. {
    10. ;
    11. }
    12. return ret;
    13. }
    14. int main()
    15. {
    16. char s1[] = "hello world";
    17. char s2[20] = { 0 };
    18. printf("%s\n", my_strcpy(s2, s1));
    19. return 0;
    20. }


    4.3.3 版本三 (assert,防止死循环)

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include
    4. #include
    5. #include
    6. char* my_strcpy(char* dest, char* src)
    7. {
    8. assert(dest);
    9. assert(src);
    10. char* ret = dest;
    11. while (*dest++ = *src++)
    12. {
    13. ;
    14. }
    15. return ret;
    16. }
    17. int main()
    18. {
    19. char s1[] = "hello world";
    20. char s2[20] = { 0 };
    21. printf("%s\n", my_strcpy(s2, s1));
    22. return 0;
    23. }


    4.3.4 版本四 (dest指向的空间是需要改变的,但是src指向的空间是不被期望改变的)

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include
    4. #include
    5. #include
    6. char* my_strcpy(char* dest, const char* src)
    7. {
    8. assert(dest);
    9. assert(src);
    10. char* ret = dest;
    11. while (*dest++ = *src++)
    12. {
    13. ;
    14. }
    15. return ret;
    16. }
    17. int main()
    18. {
    19. char s1[] = "hello world";
    20. char s2[20] = { 0 };
    21. printf("%s\n", my_strcpy(s2, s1));
    22. return 0;
    23. }


    4.3.5 版本五 (返回目标空间的起始地址)

    strcpy的功能是将原字符串的内容拷贝到目标空间,希望目标空间的内容发生改变
    所以返回目标空间的起始地址,方便观察目标空间的内容

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include
    4. #include
    5. #include
    6. char* my_strcpy(char* dest, const char* src)
    7. {
    8. assert(dest);
    9. assert(src);
    10. char* ret = dest;
    11. while (*dest++ = *src++)
    12. {
    13. ;
    14. }
    15. return ret;
    16. }
    17. int main()
    18. {
    19. char s1[] = "hello world";
    20. char s2[20] = { 0 };
    21. printf("%s\n", my_strcpy(s2, s1));
    22. return 0;
    23. }

    5. strcat的使⽤和模拟实现

    char *my_strcat(char *dest, const char*src)

    5.1 注意事项

    注意事项:
    1.从末尾追加拼接,末尾是\0,拼接结束末尾也是\0——>源头字符串要有\0(从哪里开始);目标空间中要有\0(到哪里结束)
    2.目标空间要足够大,目标要可修改

    5.2 使用举例

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include
    4. #include
    5. #include
    6. int main()
    7. {
    8. char s[20] = "hello ";
    9. const char* p = "world";
    10. strcat(s, p);
    11. printf("%s\n", s);
    12. return 0;
    13. }

    5.3 strcat函数的模拟实现

    模拟实现步骤:
    1.找到目标空间\0
    2.拷贝数据——strcpy函数

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include
    4. #include
    5. #include
    6. char* my_strcat(char* dest,const char* src)
    7. {
    8. char* ret = dest;
    9. while (*dest != '\0')
    10. {
    11. dest++;
    12. }
    13. while (*dest++ = *src++)
    14. {
    15. ;
    16. }
    17. return ret;
    18. }
    19. int main()
    20. {
    21. char s[20] = "hello ";
    22. const char* p = "world";
    23. printf("%s\n", my_strcat(s, p));
    24. return 0;
    25. }

    5.4 自己追加拼接自己可以吗?

    不可以❌

    不行❌会自己把\0不断覆盖掉——>越界访问

    6. strcmp的使⽤和模拟实现

    比较2个字符串的大小

    比较两个字符串中对应位置上的字符按照字典顺序比较

    • 标准规定:

    ◦ 第⼀个字符串⼤于第⼆个字符串,则返回⼤于0的数字

    ◦ 第⼀个字符串等于第⼆个字符串,则返回0

    ◦ 第⼀个字符串⼩于第⼆个字符串,则返回⼩于0的数字

    ◦ 那么如何判断两个字符串? ⽐较两个字符串中对应位置上字符ASCII码值的⼤⼩。

    6.1 使用举例

    1. #include
    2. #include
    3. #include
    4. #include
    5. int main()
    6. {
    7. char s1[] = "abcdef";
    8. char s2[] = "abcq";
    9. int ret=strcmp(s1, s2);
    10. printf("%d\n", ret);
    11. return 0;
    12. }

    6.2 strcmp的模拟实现

    1. #include
    2. #include
    3. #include
    4. int my_strcmp(const char* str1, const char* str2)//只是比较大小,不用修改值
    5. {
    6. assert(str1 != NULL);//确保指针有效性
    7. assert(str2 != NULL);
    8. while (*str1 == *str2)
    9. {
    10. if (*str1 == '\0')//只需要比较其中一个是否是\0,成立则都是\0
    11. return 0;
    12. str1++;
    13. str2++;
    14. if (*str1 > *str2)
    15. return 1;
    16. else
    17. return 1;
    18. }
    19. }
    20. int main()
    21. {
    22. int ret = my_strcmp("abcdef", "abcdg");
    23. printf("%d\n", ret);
    24. return 0;
    25. }

    7. strncpy函数的使⽤和模拟实现

    char * strncpy ( char * destination, const char * source, size_t num ); 

    • 拷⻉num个字符从源字符串到⽬标空间。

    • 如果源字符串的⻓度⼩于num,则拷⻉完源字符串之后,在⽬标的后边追加0,直到num个

    7.1 使用举例

    1. #include
    2. #include
    3. int main()
    4. {
    5. char arr1[10] = "xxxxxxxxxx";
    6. char arr2[] = "ab";
    7. strncpy(arr1, arr2, 5);
    8. printf("%s\n", arr1);
    9. return 0;
    10. }

    我们可以通过调试看见,多余的位置用\0来凑​​​​​​​

    7.2 strncpy函数的模拟实现

    8. strncat函数的使⽤和模拟实现

    8.1 使用举例

    提供参数大于传输全部个数,则全部传输,并且无论长短传输\0不变

    1. #include
    2. #include
    3. int main()
    4. {
    5. char s1[20] = "abc\0xxxxxxxx";
    6. char s2[] = "def";
    7. strncat(s1, s2,5);
    8. printf("%s\n", s1);
    9. return 0;
    10. }

    8.2 strncat函数的模拟实现

    9. strncmp函数的使⽤和模拟实现

    int strncmp ( const char * str1, const char * str2, size_t num );

    9.1 使用举例

    1. #include
    2. #include
    3. int main()
    4. {
    5. char s1[15] = "abcdef";
    6. char s2[] = "abcg";
    7. int ret = strncmp(s1, s2, 3);
    8. printf("%d\n", ret);
    9. return 0;
    10. }

    ​​​​​​​

    9.2 strncmp函数的模拟实现

    10. strstr的使⽤和模拟实现

    char * strstr ( const char *, const char * );

    strstr函数的功能:

    在字符串中找一个字符串

    返回str2在str1中第一次出现的位置;如果str2在str1中没有出现,就返回NULL

    10.1 使用举例

    1. #include
    2. #include
    3. #include
    4. int main()
    5. {
    6. char s1[] = "abcdefabcdef";
    7. char s2[] = "efabc";
    8. char* ret = strstr(s1, s2);
    9. if (ret != 0)
    10. printf("找到了,是%s\n", ret);
    11. else
    12. printf("找不到\n");
    13. return 0;
    14. }

    10.2 strstr函数的模拟实现

    10.2.1 模拟实现思路

    首先,我们会想到遍历,当我们成功找到字符串时,却发现没有记住匹配成功的首个字符位置,无法返回首元素的地址,而且这只是最简单一种情况,我们直接就找到了

    10.2.2 模拟实现思路优化

    我们要考虑到多次查找和首元素的地址确定

    10.2.3 代码实现

    11. strtok函数的使⽤

    char * strtok ( char * str, const char * sep);

    11.1 用途介绍


    解析:

    • sep参数指向⼀个字符串,定义了⽤作分隔符的字符集合

    • 第⼀个参数指定⼀个字符串,它包含了0个或者多个由sep字符串中⼀个或者多个分隔符分割的标记//第一个参数指向的字符串是由sep指向的第二个参数指向的字符串分割的

    • strtok函数找到str中的下⼀个标记,并将其⽤ \0 结尾,返回⼀个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使⽤strtok函数切分的字符串⼀般都是临时拷⻉的内容并且可修改。)//将分割符变成\0,并返回标记的起始地址,打印的时候到\0停止

    • strtok函数的第⼀个参数不为 NULL ,函数将找到str中第⼀个标记,strtok函数将保存它在字符串中的位置//记住\0的位置

    • strtok函数的第⼀个参数 NULL ,函数将在同⼀个字符串中被保存的位置开始,查找下⼀个标记

    • 如果字符串中不存在更多的标记,则返回 NULL 指针

    11.2 使用举例

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include
    4. #include
    5. int main()
    6. {
    7. char s[] = "iCiWVorwbnvvj@163.com";//字符串
    8. char* p = "@.";//分隔符
    9. char *ret = strtok(s, p);
    10. printf("%s\n", ret);
    11. return 0;
    12. }

    11.2.1 方法优化

    如果分割符过多的话,则上面的方法过于冗长,需要我们一次次的运行,那我们可以将字符串拷贝到目标空间,再目标空间里进行循环输出,并且不改变源空间的字符串

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include
    4. #include
    5. int main()
    6. {
    7. char s[] = "iCiWVorwbnvvj@163.com.yuHjC.ieia";//字符串
    8. char* p = "@.";//分隔符
    9. char buf[100] = { 0 };
    10. strcpy(buf, s);
    11. char* r = NULL;
    12. for (r = strtok(s, p); r != NULL; r = strtok(NULL, p))
    13. {
    14. printf("%s\n", r);
    15. }
    16. return 0;
    17. }

    12. strerror函数的使⽤

    char * strerror ( int errnum );

    strerror函数可以把参数部分错误码对应的错误信息的字符串地址返回来

    在不同的系统和C语⾔标准库的实现中都规定了⼀些错误码,⼀般是放在 errno.h 这个头⽂件中说明的,C语⾔程序启动的时候就会使⽤⼀个全局的变量errno来记录程序的当前错误码,只不过程序启动的时候errno是0,表⽰没有错误,当我们在使⽤标准库中的函数的时候发⽣了某种错误,就会将对应的错误码,存放在errno中,⽽⼀个错误码的数字是整数很难理解是什么意思,所以每⼀个错误码都是有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。

    在 C语言的库函数中设计了一些错误码,当我们库函数在调用的过程中发生的各种错误,要记录下来,这时候记录的就是错误码
    例如:404———>该网页不存在

    12.1 使用举例

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include
    4. #include
    5. int main()
    6. {
    7. int i = 0;
    8. for (i = 0; i < 10; i++)
    9. {
    10. char* ret = strerror(i);
    11. printf("%d:%s\n", i, ret);
    12. }
    13. return 0;
    14. }

    但是,我们怎么知道代码运行失败的原因是什么呢?

    我们可以举个例子,来看看库函数在C语言中的作用,也可以看看错误的原因是什么

    当库函数调用失败的时候,会将错误码记录到errno这个变量中

    errno是C语言的一个全局变量

    例如,我们要读取一个文件,读取文件前,我们要打开文件,打开成功,前提是文件存在,反之,则打开失败

    我们看一下界面:

    我想读区test_9_7这个文件,看看我们能不能成功

    1. #include
    2. #include
    3. #include
    4. #include
    5. int main()
    6. {
    7. FILE* pf = fopen("test_9_7", "r");
    8. if (pf == NULL)
    9. {
    10. printf("打开文件失败,失败的原因是:%s\n", strerror(errno));
    11. return 1;
    12. }
    13. else
    14. {
    15. printf("打开文件成功\n");
    16. }
    17. return 0;
    18. }

    虽然我们看到了错误原因,但是为什么打开失败呢?明明我的界面上就有这个文件啊!

    那是因为,我们没有显示文件拓展名

    通过拓展名,我们发现原来我们输入的文件名不对

    这样之后,就可以打开成功了

    12.2 相关函数perror的使用

    perror函数是打印错误信息的

    1. #include
    2. #include
    3. #include
    4. int main ()
    5. {
    6. FILE * pFile;
    7. pFile = fopen ("unexist.ent","r");
    8. if (pFile == NULL)
    9. perror("Error opening file unexist.ent");
    10. return 0;
    11. }

    本次的分享到这里就结束了!!!

    PS:小江目前只是个新手小白。欢迎大家在评论区讨论哦!有问题也可以讨论的!

    如果对你有帮助的话,记得点赞👍+收藏⭐️+关注➕

  • 相关阅读:
    ctfhub技能树---http协议
    数仓建模,什么是宽表?如何设计?好处与不足
    野火霸天虎 STM32F407 学习笔记_1 stm32介绍;调试方法介绍
    2022.7.19 模拟赛
    面向对象设计模式实例
    VirtualBox安装RockyLinux并使用ssh访问
    并发编程-线程池ForkJoinPool
    【第01天】A + B | 基础输入输出,开启学习Java旅程
    Spring之aop
    思维导图怎么变成ppt?4个思维导图一键生成ppt的方法
  • 原文地址:https://blog.csdn.net/2301_79184587/article/details/132782452