文章图片
文章目录
- 前言
- 一、求字符串长度的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 基本语法
①处理字符和字符串的库函数的使用和注意事项;
②部分库函数的模拟。
文章图片
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,输出值为<,但是输出值为>,不符合预期。
文章图片
这就是因为函数的返回值为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;
}
文章图片
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 基本语法
文章图片
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:
文章图片
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 基本语法
文章图片
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;
}
引发异常:
文章图片
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 基本语法
文章图片
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;
}
文章图片
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
}
※※※源码的思路大概为:长度受限制的字符串函数:(五、六、七) 五、复制字符串strncpy函数 5.1 基本语法
当两个指针所指位置的字符相同且不为’\0’时,两个指针同时后移,当不满足该循环条件(①两指针所指位置的字符不同;②两指针所指位置的字符均为’\0’;③某个指针所指字符为’\0’,此时两指针所指字符必不相同),先将不满足循环条件时的两指针内容相减的结果赋值给ret变量,然后退出循环,返回ret,此时ret就记录了最后退出循环时的两字符比较结果。
文章图片
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’结束。
#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’。六、追加字符串strncat函数 6.1 基本语法
但是,自己测试当count大于源字符串长度和大于目标字符串长度时有点问题。待解决。
文章图片
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步骤:
文章图片
- 特殊情况②:当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;
}
文章图片
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);
}
源码分析:七、字符串比较strncmp函数 7.1 基本语法 【C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】】
先找到目标空间的’\0’,然后循环count次,中途如果遇到源字符串中的’\0’则说明count大于源字符长度,追加完毕,返回;
如果循环count次中途没有退出,则说明count小于源字符长度,追加count个字符,完毕后,返回。
文章图片
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;
}
文章图片
- 特殊情况②说明:如果如下两个字符串相比较(前面的字符都相同,字符串长短不同):
#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;
}
文章图片
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 基本语法
文章图片
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;
}
文章图片
代码②(所查找的字符串连续但不完整):
#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’仅是打印结果不同。
#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 基本语法
文章图片
9.2 注意事项
- str2参数是个字符串,定义了用作分隔符的字符集合;
- 第一个参数指定一个字符串,它包含了0个或者多个由str2字符串中一个或者多个分隔符分割的标记。
- strtok函数找到str1中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
- strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。(strtok函数找第一个标记的时候,函数的第一个参数不是NULL)
- strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。(strtok函数找非第一个标记的时候,函数的第一个参数是NULL)
- 如果字符串中不存在更多的标记,则返回 NULL 指针。
#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;
}
文章图片
代码②:(代码①的基础上优化)
#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;
}
文章图片
错误信息报告:(十) 十、返回错误信息strerror函数 10.1 基本语法
文章图片
10.2 注意事项
- C语言中规定了一些信息,strerror函数返回错误码所对应的错误信息;
#include
#include int main()
{
int i = 0;
for (i = 0;
i < 10;
i++) {
printf("%s\n", strerror(i));
}
return 0;
}
文章图片
10.4 补充用法 10.4.1 补充用法使用说明
- 当库函数使用的时候,发生错误会把errno这个全局的错误变量设置为本次执行库函数产生的错误码;
- errno是C语言提供的一个全局变量,可以直接使用,放在errno.h文件中的,使用时需包含头文件:#include
文章图片
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;
}
文章图片
字符操作:(十一) 十一、字符分类函数
函数 | 如果他的参数符合下列条件就返回真 |
---|---|
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 ); | 小写转换大写 |
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
希望大家一起坚持学习,共同进步。梦想一旦被付诸行动,就会变得神圣。
欢迎各位大佬批评建议,分享更好的方法!!!
推荐阅读
- c语言学习|c语言深入浅出,玩爆常见字符串,内存操作库函数(爆肝最长时间之作)
- C入门|指针与字符串,读取字符串,字符串库函数举例 C语言入门
- java|35个小妙招优化Java性能——精简篇
- C语言|C语言课程设计|学生成绩管理系统(含完整代码)
- c++|程序员怎么提高代码编写的速度()
- 启发式|元启发式如何跳出局部最优()
- C语言|C 语言与指针 , 指针部分笔试题目及解析
- c语言|每天一练——牛客网基础语法(10)
- c语言|这可能是最全最详细的C语言指针基础教程