C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】

C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片


文章目录

  • 前言
  • 一、求字符串长度的strlen函数
    • 1.1 基本语法
    • 1.2 注意事项
    • 1.3 模拟实现strlen函数
      • 1.3.1 计数器方法实现
      • 1.3.2 递归方法实现
      • 1.3.3 指针相减的方法实现
    • 1.4 strlen库函数源码查看
  • ==长度不受限制的字符串函数:(二、三、四)==
  • 二、复制字符串strcpy函数
    • 2.1 基本语法
    • 2.2 注意事项
    • 2.3 模拟实现strcpy函数
    • 2.4 strcpy库函数源码查看
  • 三、追加字符串strcat函数
    • 3.1 基本语法
    • 3.2 注意事项
    • 3.3 模拟实现strcat函数
    • 3.4 strcat库函数源码查看
  • 四、字符串比较strcmp函数
    • 4.1 基本语法
    • 4.2 注意事项
    • 4.3 模拟实现strcmp函数(和特殊②结果不同)
      • 4.3.1 版本1
      • 4.3.2 版本2
    • 4.4 strcmp库函数源码查看
  • ==长度受限制的字符串函数:(五、六、七)==
  • 五、复制字符串strncpy函数
    • 5.1 基本语法
    • 5.3 注意事项
    • 5.4 模拟实现strncpy函数
    • 5.5 strncpy库函数源码查看
  • 六、追加字符串strncat函数
    • 6.1 基本语法
    • 6.2 注意事项
    • 6.3 模拟实现strncat函数(有变动,允许==源==字符串不以'\0'结束)
    • 6.4 strncat库函数源码查看
  • 七、字符串比较strncmp函数
    • 7.1 基本语法
    • 7.2 注意事项
    • 7.3 模拟实现strncmp函数(不考虑特殊情况②)
    • 7.4 strncmp库函数源码查看
  • ==字符串查找函数:(八、九)==
  • 八、字符串查找strstr函数
    • 8.1 基本语法
    • 8.2 注意事项
    • 8.3 模拟实现strstr函数
      • 8.3.1 版本1(两个指针来控制)
      • 8.3.2 版本2(三个指针来控制,前提str1和str2都完整)
      • 8.3.3 版本3(KMP算法)
  • 九、分隔字符串strtok函数
    • 9.1 基本语法
    • 9.2 注意事项
    • 9.3 使用举例
  • ==错误信息报告:(十)==
  • 十、返回错误信息strerror函数
    • 10.1 基本语法
    • 10.2 注意事项
    • 10.3 使用举例
    • 10.4 补充用法
      • 10.4.1 补充用法使用说明
      • 10.4.2 fopen函数基本语法说明
      • 10.4.3 补充用法使用举例
  • ==字符操作:(十一)==
  • 十一、字符分类函数
  • 总结

前言
本文主要介绍:
①处理字符和字符串的库函数的使用和注意事项;
②部分库函数的模拟。
一、求字符串长度的strlen函数 1.1 基本语法 C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

1.2 注意事项
  • 字符串以’\0’作为结束标志,strlen函数返回的是在字符串中’\0’前面出现的字符个数(不包含’\0’);
  • 参数指向的字符串必须要以’\0’结束,否则strlen函数无法找到所需计算位置的结束标志,则会在内存继续向后读取,直到遇到’\0’;
  • 注意:函数的返回值为size_t,是无符号的,例:
#include #include int main() { if (strlen("abc") - strlen("abcdef") > 0) { printf(">"); } else { printf("<="); } return 0; }

我们预期:“abc”的长度明显更小,所以strlen(“abc”) - strlen(“abcdef”)<0,输出值为<,但是输出值为>,不符合预期。
C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

这就是因为函数的返回值为size_t,是无符号的,所以误将-3识别为无符号整数,所以识别为一个非常大的正整数,输出值为>。
解决方案:(将strlen函数的返回值强制转换为int(int默认为有符号整形unsigned int))
#include #include int main() { if ((int)strlen("abc") - (int)strlen("abcdef") > 0) { printf(">"); } else { printf("<="); } return 0; }

C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

1.3 模拟实现strlen函数 1.3.1 计数器方法实现
#include #include #include // 方法1:(计数器方法)int My_Strlen(const char* str) // const保护str所指内容不被改变 { assert(str); int sum = 0; // 相当while ('\0' != *str) while (*str) { sum++; str++; } return sum; }int main() { char str[20] = {0}; scanf("%s", str); int len = My_Strlen(str); printf("%d\n", len); return 0; }

1.3.2 递归方法实现
#include #include #include // 方法2:(递归方法) // 限定条件为首指针所指内容不为'\0',每次通过字符串首指针的后移一位来接近限定条件int My_Strlen(const char* str) // const保护str所指内容不被改变 { assert(str); char* top = str; // 相当if ('\0' != *top) if (*top) { return 1 + My_Strlen(top + 1); } else { return 0; } }int main() { char str[20] = {0}; scanf("%s", str); int len = My_Strlen(str); printf("%d\n", len); return 0; }

1.3.3 指针相减的方法实现
// 方法3:(指针相减的方法)int My_Strlen(const char* str) // const保护str所指内容不被改变 { assert(str); char* end = str; // 相当while ('\0' != *end) while (*end) { end++; } // 最后end指向'\0' return end - str; // 或者: //while (*mask++) {//方法2,这样的话指针会指向‘\0’的后面, ////画图分析即可,所以return后额外减去1 //; //} //return mask - arr - 1; }int main() { char str[20] = {0}; scanf("%s", str); int len = My_Strlen(str); printf("%d\n", len); return 0; }

1.4 strlen库函数源码查看
/*** *strlen.c - contains strlen() routine * *Copyright (c) Microsoft Corporation. All rights reserved. * *Purpose: *strlen returns the length of a null-terminated string, *not including the null byte itself. * *******************************************************************************/#include #pragma function(strlen)/*** *strlen - return the length of a null-terminated string * *Purpose: *Finds the length in bytes of the given string, not including *the final null character. * *Entry: *const char * str - string whose length is to be computed * *Exit: *length of the string "str", exclusive of the final null byte * *Exceptions: * *******************************************************************************/size_t __cdecl strlen ( const char * str ) { const char *eos = str; while( *eos++ ) ; return( eos - str - 1 ); }

和指针相减方法实现的模拟函数思路基本相同。
长度不受限制的字符串函数:(二、三、四) 二、复制字符串strcpy函数 2.1 基本语法 C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

2.2 注意事项
  • 字符串必须以’\0’结束;
  • 会将字符串中的’\0’拷贝到目标空间;
  • 目标空间必须足够大,以确保能存放源字符串;
  • 目标空间必须可变(不能为const,否则会引发异常:访问冲突);
  • 目标字符串可以已经有内容,源字符串可以放入已有内容的字符空间内。例:
#include #include int main() { char arr1[] = "abcdef"; char arr2[] = "xxxxxxxxx"; strcpy(arr2, arr1); // 调试到该步骤查看监视arr2 printf("%s\n", arr2); return 0; }

调试到代码提示的位置,查看监视arr2:
C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

2.3 模拟实现strcpy函数
#include #include #include // 模拟实现strcpy函数char* My_Strcpy(char* to, const char* from)// const保护from所指内容不被改变 { assert(to && from); // 代替to指针移动,因为最后要返回to指针 char* mask = to; // 因为to字符串的长度一定是足够容纳from字符串的, // 所以只需判断from指针是否后移到'\0' // 当*from为'\0'时先赋值给*mask,然后循环条件整体为假退出 while (*mask++ = *from++) { //相当while ('\0' != (*mask++ = *from++)) ; } return to; }int main() { char from[] = "abcdef"; char to[] = "xxxxxxxxx"; My_Strcpy(to, from); printf("%s\n", to); return 0; }

2.4 strcpy库函数源码查看
/* **Copy the string contained in the second argument to the ** buffer specified by the first argument. */ void strcpy( char *buffer, char const *string ) { /* ** Copy characters until a NUL byte is copied. */ while( (*buffer++ = *string++) != '\0' ) ; }

和实现的模拟函数代码思路基本相同。
三、追加字符串strcat函数 3.1 基本语法 C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

3.2 注意事项
  • 字符串必须以’\0’结束;
  • 目标空间必须足够大,能容纳下源字符串的内容;
  • 目标空间必须可修改;
  • 目标字符串必须以’\0’结束(因为源代码根据目标空间的’\0’作为追加的位置,char str1[20] = "abcdef\0aaaaaaa"和char str1[20] = {‘a’,‘b’,‘c’,‘d’,‘e’,‘f’},都以’\0’结尾,因为空间必须保证足够大,未初始化的部分自动初始化为’\0’)
  • 字符串自己给自己追加:
#include #include int main() { char from[20] = "abcdef"; printf("%s\n", strcat(from, from)); return 0; }

引发异常
C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

3.3 模拟实现strcat函数
#include #include #include // 模拟实现strcat函数char* My_Strcat(char* to, const char* from)// const保护from所指内容不被改变 { assert(to && from); // 代替to指针移动,因为最后返回to指针 char* mask = to; while (*mask) { mask++; } // mask指针此时指向to字符串中的'\0' // 因为to字符串空间一定足以容纳,所以我们仅需判断from后移过程是否指向'\0' // 当*from为'\0'时,先赋值给*mask,然后循环条件整体为假,退出循环 while (*mask++ = *from++) { //相当while ('\0' != (*mask++ = *from++)) ; } return to; }int main() { char from[] = "abcdef"; char to[20] = "xxxxxxxxx"; char* ret = My_Strcat(to, from); printf("%s\n", ret); return 0; }

3.4 strcat库函数源码查看
/*** *char *strcat(dst, src) - concatenate (append) one string to another * *Purpose: *Concatenates src onto the end of dest.Assumes enough *space in dest. * *Entry: *char *dst - string to which "src" is to be appended *const char *src - string to be appended to the end of "dst" * *Exit: *The address of "dst" * *Exceptions: * *******************************************************************************/char * __cdecl strcat ( char * dst, const char * src ) { char * cp = dst; while( *cp ) cp++; /* find end of dst */while((*cp++ = *src++) != '\0') ; /* Copy src to end of dst */return( dst ); /* return dst */}

源码思路和模拟函数代码基本相同。
四、字符串比较strcmp函数 4.1 基本语法 C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

4.2 注意事项
  • 字符串比较的是对应位置上的字符大小,该位置相同情况下则比较下个字符,直到有大小之分,或者最后比较结束均相同,则返回0;
  • 比较字符比较的是该字符对应的ASCII码
  • 在VS下底层通过返回-1,0,1来实现返回负数,零,整数,而标准规定返回正负零,而不是-1,0,1,所以在模拟时需注意;
  • 特殊情况①说明:如果如下两个字符串相比较(前面的字符都相同,字符串长短不同):
char str1[] = "abcdef"; char str2[] = "abcde";

则当str1指针指向’f’时,实际str2指针指向的是字符串最后的’\0’,’\0’的ASCII码值为0,所以‘f’的ASCII一定大于0,所以最终比较结果是str1大于str2。
  • 特殊情况②说明:如果如下两个字符串相比较(前面的字符都相同,字符串长短不同):
#include #include int main() { char str1[] = { 'a','b','c','d','e'}; char str2[] = {'a','b','c','d'}; printf("%d\n", strcmp(str1, str2)); return 0; }

C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

4.3 模拟实现strcmp函数(和特殊②结果不同)
在VS下底层通过返回-1,0,1来实现返回负数,零,整数,而标准规定返回正负零,而不是-1,0,1,所以在模拟时需注意
4.3.1 版本1
#include #include #include // 模拟实现strcmp函数 int My_Strcmp(const char* str1, const char* str2) // const保护二者字符串内容都不能被改变 { assert(str1 && str2); while (*str1 == *str2) { if ('\0' == *str1) { return 0; } str1++; str2++; } return *str1 - *str2; }int main() { char str1[] = "abcde"; char str2[] = "abcdef"; int ret = My_Strcmp(str1, str2); if (ret > 0) { printf("str1字符串较大\n"); } else if (ret < 0) { printf("str2字符串较大\n"); } else { printf("二者相同\n"); } return 0; }

4.3.2 版本2
#include #include #include // 模拟实现strcmp函数// 通过返回-1,0,1来实现返回负,零,正值 int My_Strcmp(const char* str1, const char* str2) // const保护二者字符串内容都不能被改变 { assert(str1 && str2); while (*str1 || *str2) { // 相当while (('\0' != *str1) || ('\0' != *str2)) if ((*str1 == *str2) && '\0' != *str1) { str1++; str2++; } else if (*str1 > *str2) { return 1; } else { return -1; } } // 如果循环结束还没有退出,则说明二者完全相同 return 0; }int main() { char str1[] = "abcde"; char str2[] = "abcdef"; int ret = My_Strcmp(str1, str2); if (ret > 0) { printf("str1字符串较大\n"); } else if (ret < 0) { printf("str2字符串较大\n"); } else { printf("二者相同\n"); } return 0; }

4.4 strcmp库函数源码查看
/*** *strcmp.c - routine to compare two strings (for equal, less, or greater) * *Copyright (c) Microsoft Corporation. All rights reserved. * *Purpose: *Compares two string, determining their ordinal order. * *******************************************************************************/#include #pragma function(strcmp)/*** *strcmp - compare two strings, returning less than, equal to, or greater than * *Purpose: *STRCMP compares two strings and returns an integer *to indicate whether the first is less than the second, the two are *equal, or whether the first is greater than the second. * *Comparison is done byte by byte on an UNSIGNED basis, which is to *say that Null (0) is less than any other character (1-255). * *Entry: *const char * src - string for left-hand side of comparison *const char * dst - string for right-hand side of comparison * *Exit: *returns -1 if src dst * *Exceptions: * *******************************************************************************/int __cdecl strcmp ( const char * src, const char * dst ) { int ret = 0 ; while((ret = *(unsigned char *)src - *(unsigned char *)dst) == 0 && *dst) { ++src, ++dst; }return ((-ret) < 0) - (ret < 0); // (if positive) - (if negative) generates branchless code }

※※※源码的思路大概为:
当两个指针所指位置的字符相同且不为’\0’时,两个指针同时后移,当不满足该循环条件(①两指针所指位置的字符不同;②两指针所指位置的字符均为’\0’;③某个指针所指字符为’\0’,此时两指针所指字符必不相同),先将不满足循环条件时的两指针内容相减的结果赋值给ret变量,然后退出循环,返回ret,此时ret就记录了最后退出循环时的两字符比较结果。
长度受限制的字符串函数:(五、六、七) 五、复制字符串strncpy函数 5.1 基本语法 C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

5.3 注意事项
  • 拷贝count个字符从字符串到目标空间;
  • 如果字符串的长度小于count,则拷贝完源字符串之后,在目标后追加0,直到count个
  • 如果字符串的长度大于count,则拷贝源字符串中的count个字符。
  • count不能大于目标字符串的长度(如果目标字符串是通过初始化赋值字符串来定义大小的,类似char str[] = “abc”,则count最大值为字符串长度加1(加的是最后的’\0’);如果类似char str[20] = “abc”,初始化时已规定大小,则count最大值为20,否则会溢出,总之,count最大值为sizeof(str) / sizeof(str[0]));
  • 目标空间必须可变(不能为const,否则会引发异常:访问冲突,例const char* str1 = “abcdef”);
  • 目标字符串可以已经有内容,源字符串可以放入已有内容的字符空间内;
  • 字符串不需要必须以’\0’结束。
5.4 模拟实现strncpy函数
#include #include #include // 模拟实现strncpy函数char* My_Strncpy(char* str1, const char* str2, size_t count, int max1, int max2) { assert(str1 && str2); char* mask = str1; // 判断count和目标空间大小关系,条件合法再执行代码 if (count <= max1) {// 判断count和源字符串长度关系,两种方式来复制字符串 if (count > max2) { int i = 0; for (i = 0; i < count; i++) { if (i < max2) { *mask++ = *str2++; } else { *mask++ = '\0'; } } } else { int j = 0; for (j = 0; j < count; j++) { *mask++ = *str2++; } } } return str1; }int main() { char str1[] = "abcdef"; char str2[] = {'x', 'x', 'x'}; int count = 4; int max1 = sizeof(str1) / sizeof(str1[0]); int max2 = sizeof(str2) / sizeof(str2[0]); char* ret = My_Strncpy(str1, str2, count, max1, max2); printf("%s\n", ret); return 0; }

5.5 strncpy库函数源码查看
/*** *strncpy.c - copy at most n characters of string * *Copyright (c) Microsoft Corporation. All rights reserved. * *Purpose: *defines strncpy() - copy at most n characters of string * *******************************************************************************/#include #if defined _M_ARM #pragma function(strncpy) #endif/*** *char *strncpy(dest, source, count) - copy at most n characters * *Purpose: *Copies count characters from the source string to the *destination.If count is less than the length of source, *NO NULL CHARACTER is put onto the end of the copied string. *If count is greater than the length of sources, dest is padded *with null characters to length count. * * *Entry: *char *dest - pointer to destination *char *source - source string for copy *unsigned count - max number of characters to copy * *Exit: *returns dest * *Exceptions: * *******************************************************************************/char * __cdecl strncpy ( char * dest, const char * source, size_t count ) { char *start = dest; while (count && (*dest++ = *source++) != '\0')/* copy string */ count--; if (count)/* pad out with zeroes */ while (--count) *dest++ = '\0'; return(start); }

源码先通过count && (*dest++ = *source++) != ‘\0’来将源字符串、目标字符串长度都小于count,且都不为’\0’的字符段完成复制,然后剩余的count如果大于0,则再目标字符串后加剩余count数量个’\0’。
但是,自己测试当count大于源字符串长度和大于目标字符串长度时有点问题。待解决
六、追加字符串strncat函数 6.1 基本语法 C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

6.2 注意事项
  • 目标空间必须足够大,能容纳下源字符串的内容;
  • 目标空间必须可修改;
  • 目标字符串必须以’\0’结束(因为源代码根据目标空间的’\0’作为追加的位置,char str1[20] = "abcdef\0aaaaaaa"和char str1[20] = {‘a’,‘b’,‘c’,‘d’,‘e’,‘f’},都以’\0’结尾,因为空间必须保证足够大,未初始化的部分自动初始化为’\0’)
  • 字符串必须以’\0’结束;
  • 特殊情况①:当count小于字符串长度时,复制源字符串的count个字符到目标空间,并在最后追加一个’\0’,见下;
#include #include int main() { // 用字符串中间的\0模拟一个局部字符串的结尾,从而调试观察如何追加 char str1[20] = "abcdef\0aaaaaaa"; char str2[] = "xxxx"; int count = 2; char* ret = strncat(str1, str2, count); printf("%s\n", ret); return 0; }

调试到printf步骤:
C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

  • 特殊情况②:当count大于字符串长度时,复制源字符串的所有到目标空间,并在最后追加一个’\0’目标后续其他字符不变动,见下;
#include #include int main() { // 用字符串中间的\0模拟一个局部字符串的结尾,从而调试观察如何追加 char str1[20] = "abcdef\0aaaaaaa"; char str2[] = "xxxx"; int count = 7; char* ret = strncat(str1, str2, count); printf("%s\n", ret); return 0; }

C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

6.3 模拟实现strncat函数(有变动,允许字符串不以’\0’结束)
#include #include #include // 模拟实现strncat函数char* My_Strncat(char* str1, const char* str2, size_t count, int len2) { assert(str1 && str2); // 代替str来移动 char* mask = str1; while (*mask) { mask++; } // mask指向str1中的'\0' // 找到len2和count的较小值,将源字符串的min个字符来追加到目标空间 int min = len2 < count ? len2 : count; while (min) { *mask++ = *str2++; min--; } // 如果此时*(mask - 1)不为'\0',需要追加'\0', // 因为当源字符串如果自带'\0',例char str[20] = "abc",追加之后的*(mask - 1)已经为'\0', // 而当源字符串如果没有'\0',例char str[20] = {'a','b','c'},追加之后的*(mask - 1)不为'\0',则需要*mask追加'\0' if (*(mask - 1)) { *mask = '\0'; } return str1; }int main() { // 用字符串中间的\0模拟一个局部字符串的结尾,从而调试观察如何追加 char str1[25] = "abcdef\0aaaaaaaa"; char str2[] = "xxxx"; int count = 3; int len2 = sizeof(str2) / sizeof(str2[0]); char* ret = My_Strncat(str1, str2, count, len2); printf("%s\n", ret); return 0; }

6.4 strncat库函数源码查看
/*** *strncat.c - append n chars of string to new string * *Copyright (c) Microsoft Corporation. All rights reserved. * *Purpose: *defines strncat() - appends n characters of string onto *end of other string * *******************************************************************************/#include /*** *char *strncat(front, back, count) - append count chars of back onto front * *Purpose: *Appends at most count characters of the string back onto the *end of front, and ALWAYS terminates with a null character. *If count is greater than the length of back, the length of back *is used instead.(Unlike strncpy, this routine does not pad out *to count characters). * *Entry: *char *front - string to append onto *char *back - string to append *unsigned count - count of max characters to append * *Exit: *returns a pointer to string appended onto (front). * *Uses: * *Exceptions: * *******************************************************************************/char * __cdecl strncat ( char * front, const char * back, size_t count ) { char *start = front; while (*front++) ; front--; while (count--) if ((*front++ = *back++) == 0) return(start); *front = '\0'; return(start); }

源码分析:
先找到目标空间的’\0’,然后循环count次,中途如果遇到源字符串中的’\0’则说明count大于源字符长度,追加完毕,返回;
如果循环count次中途没有退出,则说明count小于源字符长度,追加count个字符,完毕后,返回。
七、字符串比较strncmp函数 7.1 基本语法 【C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】】C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

7.2 注意事项
  • 比较到出现一个字符不一样,或者一个字符串结束,或者count个字符全部比较完;
  • 字符串比较的是对应位置上的字符大小,该位置相同情况下则比较下个字符,直到有大小之分,或者count个字符比较结束均相同,则返回0;
  • 比较字符比较的是该字符对应的ASCII码
  • 在VS下底层通过返回-1,0,1来实现返回负数,零,整数,而标准规定返回正负零,而不是-1,0,1,所以在模拟时需注意;
  • 特殊情况①说明:如果如下两个字符串相比较(前面的字符都相同,字符串长短不同):
#include #include int main() { char str1[] = "abcde"; char str2[] = "abcd"; printf("%d\n", strncmp(str1, str2, 5)); return 0; }

C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

  • 特殊情况②说明:如果如下两个字符串相比较(前面的字符都相同,字符串长短不同):
#include #include int main() { char str1[] = { 'a','b','c','d','e'}; char str2[] = {'a','b','c','d'}; printf("%d\n", strncmp(str1, str2, 5)); return 0; }

C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

7.3 模拟实现strncmp函数(不考虑特殊情况②)
#include #include #include // 模拟实现strncmp函数int My_Strncmp(const char* str1, const char* str2, size_t count) { // 当该位置两字符相同,且count-1大于0时,进入循环指针向后移动继续比较下一个字符 while ((count-1) && (*str1++ == *str2++)) { // 因为*str1和2相同,所以二者如果都为'\0'则说明字符比较完毕,返回0 if ('\0' == *str1) { return 0; } count--; } // 之前未返回,说明要么count-1不大于0,或者该位置两字符不同,返回(*str1 - *str2)即可(不考虑特殊情况②) return (*str1 - *str2); } int main() { char str1[] = "abcde"; char str2[] = "abcd"; int count = 5; int ret = My_Strncmp(str1, str2, count); if (ret > 0) { printf("str1字符串较大\n"); } else if (ret < 0) { printf("str2字符串较大\n"); } else { printf("二者相同\n"); } return 0; }

7.4 strncmp库函数源码查看
/*** *strncmp.c - compare first n characters of two strings * *Copyright (c) Microsoft Corporation. All rights reserved. * *Purpose: *defines strncmp() - compare first n characters of two strings *for ordinal order. * *******************************************************************************/#include #ifdef _M_ARM #pragma function(strncmp) #endif/*** *int strncmp(first, last, count) - compare first count chars of strings * *Purpose: *Compares two strings for ordinal order.The comparison stops *after: (1) a difference between the strings is found, (2) the end *of the strings is reached, or (3) count characters have been *compared. * *Entry: *char *first, *last - strings to compare *unsigned count - maximum number of characters to compare * *Exit: *returns <0 if first < last *returns0 if first == last *returns >0 if first > last * *Exceptions: * *******************************************************************************/int __cdecl strncmp ( const char *first, const char *last, size_tcount ) { size_t x = 0; if (!count) { return 0; }/* * This explicit guard needed to deal correctly with boundary * cases: strings shorter than 4 bytes and strings longer than * UINT_MAX-4 bytes . */ if( count >= 4 ) { /* unroll by four */ for (; x < count-4; x+=4) { first+=4; last +=4; if (*(first-4) == 0 || *(first-4) != *(last-4)) { return(*(unsigned char *)(first-4) - *(unsigned char *)(last-4)); }if (*(first-3) == 0 || *(first-3) != *(last-3)) { return(*(unsigned char *)(first-3) - *(unsigned char *)(last-3)); }if (*(first-2) == 0 || *(first-2) != *(last-2)) { return(*(unsigned char *)(first-2) - *(unsigned char *)(last-2)); }if (*(first-1) == 0 || *(first-1) != *(last-1)) { return(*(unsigned char *)(first-1) - *(unsigned char *)(last-1)); } } }/* residual loop */ for (; x < count; x++) { if (*first == 0 || *first != *last) { return(*(unsigned char *)first - *(unsigned char *)last); } first+=1; last+=1; }return 0; }

不懂- -待补充
字符串查找函数:(八、九) 八、字符串查找strstr函数 8.1 基本语法 C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

8.2 注意事项
  • 无法查找空字符串,如果查找的str2是空字符串,则返回的就是str1指针;
  • 如果找到,函数返回的指针是字符串str2首次出现在字符串str1中的位置,如果没有找到,则返回NULL。
  • 查找的是连续、完整的子串(说明见下),例见下;
代码①(所查找的字符串连续且完整):
#include #include int main() { char str1[] = "abcde"; char str2[] = "bcde"; // char str2[] = {'b','c','d','e'}; char* ret = strstr(str1, str2); if (NULL == ret) { printf("没找到\n"); } else { printf("%s\n", ret); } return 0; }

C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

代码②(所查找的字符串连续但不完整):
#include #include int main() { char str1[] = "abcde"; //char str2[] = "bcde"; char str2[] = {'b','c','d','e'}; char* ret = strstr(str1, str2); if (NULL == ret) { printf("没找到\n"); } else { printf("%s\n", ret); } return 0; }

代码③(所查找的字符串连续且完整):
#include #include int main() { char str1[] = "abcde"; //char str2[] = "e"; char str2[] = {'b','c','d','e','\0'}; char* ret = strstr(str1, str2); if (NULL == ret) { printf("没找到\n"); } else { printf("%s\n", ret); } return 0; }

综上:完整代表该字符串包含结尾处的’\0’。
  • str1字符串无特殊要求,如果查找成功即返回首次出现在字符串str1中的位置,结尾有无’\0’仅是打印结果不同。
8.3 模拟实现strstr函数 8.3.1 版本1(两个指针来控制)
#include #include #include // 模拟实现strstr函数char* My_Strstr(const char* str1, const char* str2, int len2) { assert(str1 && str2); if('\0' == *str2){ return (char*)str1; // 因为str1为const char*类型,避免编译器警告 } int i = 0; // 通过len2来控制循环上限 for (i = 0; i < len2; i++) { // 如果对比二者的此位置字符内容不同且str1未执行完(*str1 != '\0'), // 则将str1向后移动一位继续比较,将循环变量重置为0,从新位置的首字符开始比较 if ((*(str1 + i) != *(str2 + i)) && (*str1 != '\0')) { str1++; i = 0; } } // 如果执行完i

8.3.2 版本2(三个指针来控制,前提str1和str2都完整)
#include #include #include // 模拟实现strstr函数// (前提:str1和str2必须完整) char* My_Strstr(const char* str1, const char* str2) { assert(str1 && str2); if ('\0' == str2) { return (char*)str1; } // s1和s2代替str1和str2来移动 const char* s1 = str1; const char* s2 = str2; // cur记录本轮比较时s1的首位置,因为s1查找时会移动,如果成功查找需返回该首位置 const char* cur = str1; // 相当while ('\0' != *cur) while (*cur) { // 每轮循环重置s1,s2位置 s1 = cur; s2 = str2; while ((*s1 == *s2) && '\0' != *s2) { s1++; s2++; } // 如果上述循环执行完毕后将s2所有字符都进行比较,和s1对应相同,则此时s2应指向字符串最后的'\0' if ('\0' == *s2) { return cur; } // 每轮循环执行完毕后如果没有返回,则cur后移一位 cur++; } // 在上述循环内未返回,则说明查找失败,返回NULL return NULL; }int main() { char str1[] = "abcde"; char str2[] = "cd"; char* ret = My_Strstr(str1, str2); if (NULL == ret) { printf("没找到\n"); } else { printf("%s\n", ret); } return 0; }

8.3.3 版本3(KMP算法)
待补充
九、分隔字符串strtok函数 9.1 基本语法 C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

9.2 注意事项
  • str2参数是个字符串,定义了用作分隔符的字符集合;
  • 第一个参数指定一个字符串,它包含了0个或者多个由str2字符串中一个或者多个分隔符分割的标记。
  • strtok函数找到str1中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。
  • strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。(strtok函数找第一个标记的时候,函数的第一个参数不是NULL)
  • strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。(strtok函数找非第一个标记的时候,函数的第一个参数是NULL)
  • 如果字符串中不存在更多的标记,则返回 NULL 指针。
9.3 使用举例 代码①:
#include #include int main() { char str1[] = "abcde@!sdasd@!feef"; char str2[] = "@!"; char tmp[30] = { 0 }; // 因为strtok会改变被操作的字符串,所以将str1临时拷贝到tmp中 strcpy(tmp, str1); char* p = strtok(tmp, str2); printf("%s\n", p); p = strtok(NULL, str2); printf("%s\n", p); p = strtok(NULL, str2); printf("%s\n", p); return 0; }

C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

代码②:(代码①的基础上优化)
#include #include int main() { char str1[] = "abcde@!sdasd@!feef"; char str2[] = "@!"; char tmp[30] = { 0 }; // 因为strtok会改变被操作的字符串,所以将str1临时拷贝到tmp中 strcpy(tmp, str1); char* p = NULL; for (p = strtok(tmp, str2); p != NULL; p = strtok(NULL, str2)) { printf("%s\n", p); } return 0; }

C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

错误信息报告:(十) 十、返回错误信息strerror函数 10.1 基本语法 C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

10.2 注意事项
  • C语言中规定了一些信息,strerror函数返回错误码所对应的错误信息
10.3 使用举例
#include #include int main() { int i = 0; for (i = 0; i < 10; i++) { printf("%s\n", strerror(i)); } return 0; }

C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

10.4 补充用法 10.4.1 补充用法使用说明
  • 当库函数使用的时候,发生错误会把errno这个全局的错误变量设置为本次执行库函数产生的错误码;
  • errno是C语言提供的一个全局变量,可以直接使用,放在errno.h文件中的,使用时需包含头文件:#include
10.4.2 fopen函数基本语法说明
C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

10.4.3 补充用法使用举例
使用举例:
说明
#include #include #include int main() { // 打开文件,如果test.txt已创建则没有错误 FILE* pf = fopen("test.txt", "r"); // 如果文件出错会返回NULL if (NULL == pf) { // 打印出错原因 printf("%s\n", strerror(errno)); // 出错直接结束main函数 return 0; } // 读文件。。。 // 关闭文件 fclose(pf); pf = NULL; return 0; }

C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
文章图片

字符操作:(十一) 十一、字符分类函数
函数 如果他的参数符合下列条件就返回真
iscntrl 任何控制字符
isspace 空白字符:空格‘ ’,换页‘\f’,换行’\n’,回车‘\r’,制表符’\t’或者垂直制表符’\v’
isdigit 十进制数字 0-9(字符)
isxdigit 十六进制数字(字符),包括所有十进制数字(字符),小写字母a-f,大写字母A-F
islower 小写字母a-z
isupper 大写字母A-Z
isalpha 字母a-z或A-Z
isalnum 字母或者数字(字符),a-z,A-Z,0-9
ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph 任何图形字符
isprint 任何可打印字符,包括图形字符和空白字符
int tolower ( int c ); 大写转换小写
int toupper ( int c ); 小写转换大写
对于isdigit函数:
int main() { char c = '3'; // 判断字符数字是否为十进制0-9 // 方法1 if (c > '0' && c < '9') { printf("bingo\n"); } // 方法2(更好) if (isdigit(c)) { printf("bingo\n"); } return 0; }

对于大小写转换函数(tolower和toupper):
int main() { char c = 'a'; if (islower(c)) { c = toupper(c); } else { c = tolower(c); } printf("%c\n", c); return 0; }

总结 这里对文章进行总结:
以上就是今天总结的内容,本文包括了C语言字符和字符串的库函数的使用注意事项和模拟,分享给大家。
真欢迎各位给予我更好的建议,欢迎访问!!!小编创作不易,觉得有用可以一键三连哦,感谢大家。peace
希望大家一起坚持学习,共同进步。梦想一旦被付诸行动,就会变得神圣。
欢迎各位大佬批评建议,分享更好的方法!!!

    推荐阅读