目录
1.字符分类函数
2.字符转换函数
3.strlen函数的使用和模拟实现
4.strcpy函数的使用和模拟实现
5.strcat函数的使用和模拟实现
6.strcmp函数的使用和模拟实现
7.strcnpy函数的使用和模拟实现
8.strcnat函数的使用和模拟实现
9.strncmp函数的使用
10.strstr的函数使用和模拟实现
11.strtok函数的使用
12.strerror函数的使用
12.1 perror
1.字符分类函数
C语言中有一系列函数是专门做字符串分类的,也就是一个字符是属于什么类型的字符,这些函数的使用需要包含一个头文件ctype.h
我们介绍其中的一个函数,其余函数类似:
int islower ( int c );
islower是 可以判断参数部分的c是否是小写字母,如果是小写字母,则返回非0的整数,如果不是小写字母,则返回0;
练习:写一个代码,将字符串中的小写字母转成大写,其余字符不变。
#include<stdio.h>
#include<ctype.h>
int main()
{char arr[] = "hello BIT";int i = 0;while (arr[i]){if (islower(arr[i])){arr[i] -= 32;}i++;}printf("%s\n", arr);return 0;
}
2.字符转换函数
C语言提供了2个字符转换函数:
int tolower ( int c) ;//将参数传进去的大写字母转成小写字母int toupper ( int c);//将参数传进去的小写字母转大写字母
学习了上面的字符转换函数,我们就可以改写上面的练习代码:
#include<stdio.h>
#include<ctype.h>
int main()
{char arr[] = "hello BIT";int i = 0;while (arr[i]){if (islower(arr[i])){arr[i]=toupper(arr[i]);}i++;}printf("%s\n", arr);return 0;
}
3.strlen函数的使用和模拟实现
//函数原型
size_t strlen ( const char* str );
功能:统计参数str指向的字符串的长度,统计的是字符串中\0之前的字符个数。
参数: str :指针,指向了要统计长度的字符串(一般传字符的首地址)
返回值:返回了str指向的字符串的长度,返回的长度不可能是负数,所以返回类型是size_t。
代码演示:
#include<stdio.h>
#include<string.h>
int main()
{char arr[] = "hello bit";printf("%zu\n", strlen(arr));//%zu是打印无符号类型的整数return 0;
}
模拟实现:
//方式一 创建第三变量
size_t my_strlen(const char* str)
{const char* strat = str;while (*str){str++;}return str - strat;
}
int main()
{char arr[] = "hello bit";size_t ret = my_strlen(arr);printf("%zu\n", ret);return 0;
}//方式二 不创建其余变量
size_t my_strlen(const char* str)
{if (*str=='\0'){return 0;}else{return 1 + my_strlen(str + 1);}
}
int main()
{char arr[] = "hello bit";size_t ret = my_strlen(arr);printf("%zu\n", ret);return 0;
}
使用注意事项:
字符串必须以‘\0’作为结束标志,strlen函数返回的是在字符串中的'\0'之前的字符个数(不包含\0).
参数指向的字符串必须以'\0'结束。
注意函数的返回类型是size_t类型,是无符号类型。
strlen函数在使用的时候需要包含头文件string.h。
练习题:
#include<string.h>
int main()
{if (strlen("abc") - strlen("abcdef") > 0){printf(">\n");}else{printf("<\n");}return 0;
}
strlen("abc")的结果是3,strlen("abcdef")的结果是6,很明显3-6<0,那strlen("abc") - strlen("abcdef")的结果就是小于0的吗?我么通过编译器运行可以发现最终打印出的是 >,这是什么原因呢?
我们知道strlen函数的返回类型是size_t类型,也就是无符号整型,计算机在进行运算的时候,是对二进制的补码进行加减运算,size_t类型它认为内存中存的(补码)就是无符号整型,32位二进制全是有效位,所以最终结果是大于0的。
4.strcpy函数的使用和模拟实现
//函数原型
char* strcpy(char* destination ,const char* source);
功能:字符串拷贝,将源头数据拷贝到目标空间,直到遇见源头数据中的 '\0'时停止拷贝。
参数:
destination : 指针,指向目的地空间;
source:指针,指向源头数据。
返回值:
strcpy函数返回目标空间的起始地址(注意:可以是destination,也可以用变量来接收这个返回值)
代码演示:
//strcpy
int main()
{char src[] = "hello bit";char dest[20] = { 0 };strcpy(dest, src);printf("%s\n", dest);return 0;
}
模拟实现:
//模拟实现
#include<assert.h>
char* my_strcpy(char* dest, const char* src)
{assert(src);while (*dest++ = *src++)//1.*dest=*str 2.dest++,str++ 3.判断循环条件{;}return dest;
}
int main()
{char src[] = "hello bit";char dest[20] = { 0 };my_strcpy(dest, src);printf("%s\n", dest);return 0;
}
while (*dest++ = *src++)
{
;
} 这段代码的意思是:1.执行赋值语句*dest=*src 2. dest++ src++ 3.条件判断 赋值表达式的结果是被复制的值(即赋值的字符),看赋值表达式的结果是否为0.
使用注意事项:
源字符串必须以 ‘\0’结束;
会将源字符串中的‘\0’拷贝到目标空间;
目标空间必须足够大,以保证能存放原字符串,并且必须是可以修改的 ;
遇见‘\0’停止拷贝,‘\0’后面的数据不拷贝。
5.strcat函数的使用和模拟实现
//函数原型
char* strcat(char* destination , const char* source);
功能:字符串追加,将source指向的源头字符串中的所有字符串都追加到destination指向的空间里。从目标空间中的‘\0’位置开始追加,追加到源头数据的‘\0’停止追加(如果源头数据中存在多个‘\0’则遇到最靠前的停止追加),并且将源头数据中的‘\0’也追加到目的地。
参数:
destination : 指针。指向目的地空间;source : 指针,指向源头数据。
返回值:
strcat函数返回的是目标空间的起始地址。(该返回值可以是destination,也可以用变量来接收返回值)
代码演示:
//strcat
int main()
{char dest[20] = "hello";char str[] = "world";//方式一//strcat(dest, str);//printf("%s\n", dest);//方式二char* ret= strcat(dest, str);printf("%s\n", ret);return 0;
}
模拟实现:
#include<assert.h>
char* my_strcat(char* dest, const char* str)
{assert(dest && str);char* ret = dest;while (*dest){dest++;}while (*dest++ = *str++){;}return ret;
}
int main()
{char dest[20] = "hello";char str[] = "world";char* ret = my_strcat(dest, str);printf("%s\n", ret);return 0;
}
使用注意事项:
源字符串必须以‘\0’结束;
目标字符串中也必须要有‘\0’,否则没办法直到从哪里开始追加;
目标空间必须足够大,能容下源字符串的内容;
目标空间必须是可修改的。
6.strcmp函数的使用和模拟实现
//函数原型
int strcmp(const char* str1, const char* str2);
功能 :用来比较str1和str2指向的字符串,从两个字符串的第一个字符开始比较,如果两个字符的ASCII码值相等,就比较下一个字符。直到遇见不相等的两个字符,或者是字符串结束。
参数:
str1: 指针,指向的是要比较的第一个字符串;
str2: 指针,指向的是要比较的第二个字符串。
返回值:
如果第一个字符串大于第二个字符串,则返回大于0的数字;
如果第一个字符串小于第二个字符串,则返回小于0的数字;
如果第一个字符串等于第二个字符串,则返回0。
代码演示:
int main()
{char arr1[] = "extravgant";char arr2[] = "arrogant";int ret=strcmp(arr1, arr2);if (ret > 0){printf(">\n");}else if (ret == 0)printf("==\n");elseprintf("<\n");return 0;
}
模拟实现:
//模拟实现
#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
{assert(str1 && str2);while(*str1 == *str2){if (*str1){return 0;}str1++;str2++;}if (*str1 > *str2){return 1;}elsereturn -1;
}
int main()
{char arr1[] = "extravgant";char arr2[] = "arrogant";int ret = my_strcmp(arr1, arr2);if (ret > 0){printf(">\n");}else if (ret == 0)printf("==\n");elseprintf("<\n");return 0;
}
7.strcnpy函数的使用和模拟实现
//函数原型
char* strncpy(char* destination, const char* source,size_t num);
功能:字符串拷贝,将source指向的字符串拷贝到destination指向的空间中,最多拷贝num个字符。
参数:
destination : 指针,指向目的地空间;
source :指针,指向源头数据;
num : 从source指向的字符串中最多拷贝的字符个数。
返回值:
strncpy函数返回目标空间的起始地址。(可以是destination,也可以用其他变量来接收这个返回值)
代码演示:
int main()
{char arr1[20] = { 0 };char arr2[] = "world you";strncpy(arr1, arr2, 5 * sizeof(char));printf("%s\n", arr1);return 0;
}
模拟实现:
#include<assert.h>
char* my_strncpy(char* dest, const char* str, size_t num)
{assert(str);while (num--){*dest = *str;dest++;str++;}return dest;
}
int main()
{char arr[10] = { 0 };char arr2[] = "hello bit";my_strncpy(arr, arr2, 5);printf("%s\n", arr);return 0;
}
注意事项:
若源头数据中的字符数不足num个,则主动用‘\0’补够num个,若拷贝不够num个,但提前遇到‘\0’,则停止拷贝,不够的用'\0'补齐。
strncpy函数指定了拷贝的长度,源字符串不一定要有'\0'。
8.strcnat函数的使用和模拟实现
//函数原型
char* strncat(char* destination, const char* source,size_t num);
功能:字符串追加,将source指向的字符串的内容,追加到destination指向的空间,最多追加num个字符,追加完成后自动添加'\0',若源头字符串中的字符个数不足num个,则有几个就追加几个。
参数:
destination : 指针,指向目的地空间;
source :指针,指向源头数据;
num : 从source指向的字符串中最多追加的字符个数。
返回值:
strncat函数返回目标空间的起始地址。(可以是destination,也可以用其他变量来接收这个返回值)
代码演示:
//strncat 在末尾追加字符串,限定字符个数
#include<string.h>
int main()
{char str[] = "how are you";char dest[30] = "good morning";strncat(dest, str, 3);printf("%s\n", dest);return 0;
}
模拟实现:
#include<assert.h>
char* my_strncat(char* dest, const char* str, size_t num)
{assert(str);char* ret = dest;while (*dest)dest++;while (num--){*dest = *str;dest++;str++;}return ret;
}
int main()
{char str[] = "how are you";char dest[30] = "good morning";my_strncat(dest, str, 3);printf("%s\n", dest);return 0;
}
9.strncmp函数的使用
//函数原型
int strncmp(const char* str1,const char* str2,size_t num);
功能:字符串的比较,比较str1和str2指向的两个字符串的内容,最多比较num个字符。
参数:
str1 : 指针,指向一个比较的字符串;
str2 :指针,指向一个比较的字符串;
num :最多比较的字符个数。
返回值:
如果第一个字符串大于第二个字符串,则返回大于0的数字;
如果第一个字符串小于第二个字符串,则返回小于0的数字;
如果第一个字符串等于第二个字符串,则返回0。
代码演示:
//strncmp 比较限定前num个字符
#include<string.h>
int main()
{char arr1[] = "abcdcvknf";char arr2[] = "abc";int ret=strncmp(arr1, arr2, 4);if (ret > 0)printf(">");else if (ret < 0)printf("<");elseprintf("=");return 0;
}
10.strstr的函数使用和模拟实现
//函数原型
char* strstr(const char* str1, const char* str2);
功能:查找str2指向的字符串在str1指向的字符串中第一次出现的位置。简而言之:在一个字符串中查找子字符串。
参数:
str1 :指针,指向了被查找的字符串;
str2 :指针,指向了要查找的字符串。
返回值:
如果找到了,则返回第一次在str1中出现的起始地址;如果没找到,就返回NULL。
代码演示:
#include<string.h>
int main()
{char str1[] = "abbcdfe";char str2[] = "bbc";char* ret=strstr(str1, str2);printf("%s\n", ret);return 0;
}
模拟实现:
#include<assert.h>
char* my_strstr(const char* str1, const char* str2)
{assert(str1 && str2);const char* p = str1;const char* s1 = NULL;;const char* s2 = NULL;if (*str2 == '\0')return str1;while (*p)//寻找次数{s1 = p;s2 = str2;//找一次的匹配过程while (*s1 == *s2 && *s2 && *s1){s1++;s2++;}if (*s2 == '\0')return (char*)p;p++;}return NULL;
}
int main()
{char str1[] = "bbc";char str2[] = "abbcdfe";char* ret = my_strstr(str1, str2);if (ret == NULL)printf("找不到\n");elseprintf("找到了,%s\n", ret);return 0;
}
11.strtok函数的使用
//函数原型
cahr* strtok(char* str,const cahr* delim);
功能:
分割字符串:根据delim参数中指定的分隔符,将输入字符串str拆分成多个子字符串。
修改原始字符串:strtok会直接在原始字符串中插入‘\0’终止符,替换分隔符的位置,因此原始字符串会被修改。
参数:
str:首次调用时传入待分割的字符串;后续调用传入NULL,表示继续分割同一个字符串。
delim :包含所有可能分隔符的字符串(每个字符均视为独立的分隔符)。
返回值:
成功时返回指向当前子字符串的指针,若没有更多子字符串时返回NULL。
使用步骤:
1.首次调用:传入待分割字符串和分隔符。
2.后续调用:传入NULL和相同的分隔符,继续分割。
3.结束条件:当返回NULL时,表示分割完成。
代码演示:
#include<stdio.h>
#include<string.h>
int main()
{char str1[] = "3604400378@qq.com";char str2[] = "@.";char str3[30] = { 0 };strcpy(str3, str1);char* ret = NULL;for (ret = strtok(str3, str2); ret != NULL;ret=strtok(NULL,str2)){printf("%s\n", ret);}return 0;
}
注意事项:
破坏性操作:strtok会直接修改原始字符串,将其中的分隔符替换成‘\0’。如果需要保留原始字符串,应先拷贝一份。
连续分隔符:多个连续的分隔符会被视为单个分隔符,不会返回空字符串。
空指针处理:如果输入的str为NULL且没有前序调用,行为未定义。
12.strerror函数的使用
//函数原型
char* strerror(int errnum);
功能:
1. strerror 函数可以通过参数部分的 个错误信息字符串⾸字符的地址。
2. errnum 表示错误码,得到对应的错误信息,并且返回这 strerror 函数只针对标准库中的函数发⽣错误后设置的错误码的转换。
3. strerror 的使⽤需要包含<string.h>
参数:
errnum: 表示错误码
这个错误码一般传递的是errno这个变量的值,在C语言中有一个全局变量叫:errno ,当库函数的调用发生错误的时候,就会将本次错误的错误码存放在errno这个变量中,使用这个全局变量需要包含一个头文件errno.h。
返回值:
函数返回通过错误码得到的错误信息字符串的首字符的地址。
代码演示:
#include<string.h>
int main()
{FILE* pf = fopen("data.txt", "r");if (pf == NULL){printf("%s\n", strerror(errno));return 1;}return 0;
}
strerror函数是将错误码翻译成错误信息,然后通过printf函数将错误信息打印出来,不知道有没有小伙伴感到有一点麻烦?有没有一种函数可以自己找到错误信息,然后自己打印出来呢?当然是有的。
12.1 perror
perror函数可以直接将错误信息打印出来。perror函数打印完参数部分的字符串后,再打印一个冒号和空格,再打印错误信息。
代码演示:
#include<string.h>
int main()
{FILE* pf = fopen("data.txt", "r");if (pf == NULL){perror("fopen");return 1;}return 0;
}
输出:
完结~