目录
- 前言
- 字符函数和字符串函数
- 1.字符分类函数
- 2.字符转换函数
- 3.strlen的使用和模拟实现
- 3.1 代码演示
- 3.2 strlen返回值http://www.devze.com
- 3.3 strlen的模拟实现
- 4.strcpy的使用和模拟实现
- 4.1 代码演示
- 4.2 模拟实现
- 5.strcat的使用和模拟实现
- 5.1 代码演示
- 5.2 模拟实现
- 6.strcmp的使用和模拟实现
- 6.1 代码演示:
- 6.2 模拟实现:
- 7.strncpy函数的使用
- 7.1 代码演示
- 7.2 ⽐较strcpy和strncpy函数
- 8.strncat函数的使用
- 8.1 代码演示
- 8.2 strcat和strncat对比
- 9.strncmp函数的使用
- 9.1 代码演示
- 9.2 strcmp和strncmp⽐较
- 10.strstr的使用和模拟实现
- 10.1 代码演示
- 10.2 strstr的模拟实现
- 11.strtok函数的使用
- 11.1 代码演示
- 11.2 注意事项
- 12.strerror函数的使用
- 12.1 代码演示
- 12.2 perror
- 总结
前言
在编程的过程中,我们经常要处理字符和字符串,为了⽅便操作字符和字符串,C语⾔标准库中提供了 ⼀系列库函数,接下来我们就学习⼀下这些函数。
字符函数和字符串函数
1.字符分类函数
C语⾔中有⼀系列的函数是专⻔做字符分类的,也就是⼀个字符是属于什么类型的字符的。 这些函数的使⽤都需要包含⼀个头⽂件是 ctype.h
这些函数的使⽤⽅法⾮常类似,我们就讲解⼀个函数的事情,其他的⾮常类似:
int islower ( int c );
islower 是能够判断参数部分的 c 是否是⼩写字⺟的。 通过返回值来说明是否是⼩写字⺟,如果是⼩写字⺟就返回⾮0的整数,如果不是⼩写字⺟,则返回 0。
练习:
写⼀个代码,将字符串中的⼩写字⺟转⼤写,其他字符不变。
#include <stdio.h> #include <ctype.h> int main () { int i = 0; char str[] = "Test String.\n"; char c; while (str[i]) { c = str[i]; if (islower(c)) c -= 32; putchar(c); i++; } return 0; }
也可以写成
while(str[i]!='\0') { if(islower(str[i])) { str[i]=toupper(str[i]); } i++; }
2.字符转换函数
C语⾔提供了2个字符转换函数:
int tolower ( int c ); //将参数传进去的⼤写字⺟转⼩写 int toupper ( int c ); //将参数传进去的⼩写字⺟转⼤写
上⾯的代码,我们将⼩写转⼤写,是-32完成的效果,有了转换函数,就可以直接使⽤ tolower 函 数。
#include <stdio.h> #include <ctype.h> int main () { int i = 0; char str[] = "Test String.\n"; char c; while (str[i]) { c = str[i]; if (islower(c)) c = toupper(c); putchar(c); i++; } return 0; }
3.strlen的使用和模拟实现
size_t strlen ( const char * str );//size_t是无符号整型
功能:统计参数 str 指向的字符串的⻓度。统计的是字符串中 ‘\0’ 之前的字符的个数。
参数:
• str :指针,指向了要统计⻓度的字符串。 返回值:返回了 str 指向的字符串的⻓度,返回的⻓度不会是负数,所以返回类型是 size_t 。
if((strlen("abc")-strlen("abcdef"))>0)//size_t为无符号整型,所以3-6一定大于0 { printf(">\n");//所以输出> } else { printf("<=\n"); }
解决方案
(int)strlen("abc")-(int)strlen("abcdef")
3.1 代码演示
#include <stdio.h> #include <string.h> int main() { const char* str = "abcdef"; printf("%zd\n", strlen(str)); return 0; }
使⽤注意事项:
• 字符串以 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前⾯出现的字符个数(不包 含 ‘\0’ )。
• 参数指www.devze.com向的字符串必须要以 ‘\0’ 结束。
• 注意函数的返回值为 size_t ,是⽆符号的( 易错 )
• strlen的使⽤需要包含头⽂件
3.2 strlen返回值
#include <stdio.h> #include <string.h> int main() { const char* str1 = "abcdef";http://www.devze.com const char* str2 = "bbb"; if(strlen(str2) - strlen(str1) > 0)//size_t类型恒大于0 { printf("str2 > str1\n"); } else { printf("srt1 > str2\n"); } return 0; }
3.3 strlen的模拟实现
⽅式1:
//计数器⽅式 int my_strlen(const char * str) { int count = 0; assert(str);//assert断言 头文件<assert.h> while(*str) { count++; str++; } return count; }
⽅式2:
//不能创建临时变量计数器 int my_strlen(const char * str) { assert(str); if(*str == '\0') return 0; else return 1 + my_strlen(str+1);//str+1是下一个字符的地址 }
比如 my_strlen("abcdef")=1+my_strlen("bcdef")
⽅式3:
//指针-指针的⽅式 int my_strlen(char *s) { assert(str); char *p = s; while(*p != '\0') p++; return p - s; }
4.strcpy的使用和模拟实现
string copy
char* strcpy(char * destination, const char * source );
功能:字符串拷⻉,拷⻉到源头字符串中的 \0 为⽌
参数:
destination :指针,指向⽬的地空间
source :指针,指向源头数据
返回值:
strcpy 函数返回的⽬标空间的起始地址
4.1 代码演示
#include <stdio.h> #include <string.h> int main() { char arr1[10] = {0}; char arr2[] = "hello"; strcpy(arr1, arr2);//\0也会拷贝进去 printf("%s\n", arr1); return 0; }
使⽤注意事项:
•源字符串必须以 ‘\0’ 结束.。
• 会将源字符串中的 ‘\0’ 拷⻉到⽬标空间。
• ⽬标空间必须⾜够⼤,以确保能存放源字符串。
• ⽬标空间必须可修改。(不能是常量字符串,因为常量字符串不可以修改)
4.2 模拟实现
#include <stdio.h> #include <assert.h> //1.参数顺序 //2.函数的功能,停⽌条件 //3.assert //4.const修饰指针 //5.函数返回值 char* my_strcpy(char *dest, const char*src)//src不能修改 { char *ret = dest;//dest++后变了 所以先存起来 assert(dest != NULL); assert(src != NULL); while((*dest++ = *src++))//先用再++,当*src为\0时,终止循环 { ; } return ret; } int main() { char arr1[10] = {0}; char arr2[] = "hello"; my_strcpy(arr1, arr2); printf("%s\n", arr1); return 0; }
void my_strcpy(char* dest,char* src) { //拷贝\0前面的内容 while(*src!='\0') { *dest=*src; dest++; src++; } *dest=*src;//拷贝\0 }
5.strcat的使用和模拟实现
连接字符串
char * strcat ( char * destination, const char * source );
功能:字符串追加,把 source 指向的源字符串中的所有字符都追加到 destination 指向的空间 中。
参数:
destination :指针,指向⽬的地空间
source :指针,指向源头数据
返回值:
strcat 函数返回的⽬标空间的起始地址
5.1 代码演示
#include <stdio.h> #include <string.h> int main() { char arr1[20] = "hello "; char arr2[] = "world"; strcat(arr1, arr2); printf("%s\n", arr1); return 0;//输出hello world }
使用注意事项:
• 源字符串必须以 ‘\0’ 结束。
• ⽬标字符串中也得有 \0 ,否则没办法知道追加从哪⾥开始。
• ⽬标空间必须有⾜够的⼤,能容纳下源字符串的内容。
• ⽬标空间必须可修改。
5.2 模拟实现
#include <stdio.h> #include <assert.h> char* my_strcat(char *dest, const char*src) { char *ret = dest; assert(dest != NULL); assert(src != NULL);//这两行等价于assert(dest&&src) //1.找到目标空间中的\0 while(*dest)//while(*dest!='\0') { dest++; } while((*dest++ = *src++)) { ; } return ret; } int maandroidin() { char arr1[20] = "hello "; char arr2[] = "world"; my_strcat(arr1, arr2); printf("%s\n", arr1); return 0; }
那如果是自拼接呢
my_strcat(arr1,arr1) //自拼接会:1.死循环2.系统崩溃
6.strcmp的使用和模拟实现
两个字符串比较应用场景 登录: 输入 :用户名 密码
数据库 用户名 密码
int strcmp ( const char * str1, const char * str2 );
功能:⽤来⽐较 str1 和 str2 指向的字符串,从两个字符串的第⼀个字符开始⽐较,如果两个字符 的ASCII码值相等,就⽐较下⼀个字符。直到遇到不相等的两个字符,或者字符串结束。
参数:
str1 :指针,指向要⽐较的第⼀个字符串
str2 :指针,指向要⽐较的第⼆个字符串
返回值:
• 标准规定:
◦ 第⼀个字符串⼤于第⼆个字符串,则返回⼤于0的数字
◦ 第⼀个字符串等于第⼆个字符串,则返回0
◦ 第⼀个字符串⼩于第⼆个字符串,则返回⼩于0的数字
6.1 代码演示:
#include <stdio.h> #include <string.h> int main() { char arr1[] = "abcdef"; char arr2[] = "abq"; int ret = strcmp(arr1, arr2); printf("%d\n", ret); if(ret > 0) printf("arr1 > arr2\n"); else if(ret == 0) printf("arr1 == arr2\n"); else printf("arr1 < arr2\n"); return 编程0; }
6.2 模拟实现:
int my_strcmp (const char * str1, const char * str2) { int ret = 0 ; assert(str1 != NULL); assert(str2 != NULL); while(*str1 == *str2) { if(*str1 == '\0') return 0; str1++; str2++; } return *str1-*str2;//最后比较的ASII码值的差 }
7.strncpy函数的使用
strcpy strcat strcmp 是长度不受限的字符串比较 不安全
strncpy strncat strncmp 长度受限函数char * strncpy ( char * destination, const char * source, size_t num );
功能:字符串拷⻉;将 source 指向的字符串拷⻉到 destination 指向的空间中,最多拷⻉ num 个字符。
参数:
destination :指针,指向⽬的地空间
source :指针,指向源头数据
num :从source指向的字符串中最多拷⻉的字符个数
返回值:
strncpy 函数返回的⽬标空间的起始地址
7.1 代码演示
#include <stdio.h> #include <string.h> int main() { char arr1[20] = {0}; char arr2[] = "abcdefghi"; char* str = strncpy(arr1, arr2, 5); printf("%s\n", arr1); printf("%s\n", str); return 0; }
长度足够,让拷贝几个就几个,长度小于num补\0
7.2 ⽐较strcpy和strncpy函数
strcpy 函数拷⻉到 \0 为⽌,如果⽬标空间不够的话,容易出现越界⾏为。
strncpy 函数指定了拷⻉的⻓度,源字符串不⼀定要有 \0 ,同时在设计参数的时候,就会多⼀层 思考:⽬标空间的⼤⼩是否够⽤, strncpy 相对 strcpy 函数更加安全。
8.strncat函数的使用
char * strncat ( char * destination, const char * source, size_t num );
功能:字符串追加;将 source 指向的字符串的内容,追加到 destination 指向的空间,最多追 加 num 个字符。
参数:
destination :指针,指向了⽬标空间
source :指针,指向了源头数据
num :最多追加的字符的个数
返回值:返回的是⽬标空间的起始地址
8.1 代码演示
#include <stdio.h> #include <string.h> int main() { char arr1[20] = "hello "; char arr2[] = "world"; char* str = strncat(arr1, arr2, 5);//从\0开始追加,追加万还加\0 printf("%s\n", arr1); printf("%s\n", str);//若num>长度,则追加\0 return 0; }
8.2 strcat和strncat对比
• 参数不同, strncat 多了⼀个参数
• strcat 函数在追加的时候要将源字符串的所有内容,包含 \0 都追加过去,但是 strncat 函 数指定了追加的⻓度。
• strncat 函数中源字符串中不⼀定要有 \0 了。
• strncat 更加灵活,也更加安全。
9.strncmp函数的使用
int strncmp ( const char * str1, const char * str2, size_t num );
功能:字符串⽐较;⽐较 str1 和 str2 指向的两个字符串的内容,最多⽐较 num 字符。
参数:
str1 :指针,指向⼀个⽐较的字符串
str2 :指针,指向另外⼀个⽐较的字符串
num :最多⽐较的字符个数
返回值:
• 标准规定:
◦ 第⼀个字符串⼤于第⼆个字符串,则返回⼤于0的数字
◦ 第⼀个字符串等于第⼆个字符串,则返回0
◦ 第⼀个字符串⼩于第⼆个字符串,则返回⼩于0的数字
9.1 代码演示
#include <stdio.h> #include <string.h> int main() { char arr1[] = "abcdef"; char arr2[] = "abcqw"; int ret1 = strncmp(arr1, arr2, 3); printf("%d\n", ret1); int ret2 = strncmp(arr1, arr2, 4); printf("%d\n", ret2); return 0; }
9.2 strcmp和strncmp⽐较
• 参数不同
• strncmp可以⽐较任意⻓度了
• strncmp函数更加灵活,更加安全
10.strstr的使用和模拟实现
char * strstr ( const char * str1, const char * str2);
功能:strstr 函数,查找 str2 指向的字符串在 str1 指向的字符串中第⼀次出现的位置。 简⽽⾔之:在⼀个字符串中查找⼦字符串。 strstr 的使⽤得包含<string.h>
参数:
str1 :指针,指向了被查找的字符串
str2 :指针,指向了要查找的字符串
返回值:• 如果str1指向的字符串中存在str2指向的字符串,那么返回第⼀次出现位置的指针
• 如果str1指向的字符串中不存在str2指向的字符串,那么返回NULL(空指针)
10.1 代码演示
/* strstr example */ #include <stdio.h> #include <string.h> int main () { char str[] ="This is a simple string"; char * pch; pch = strstr (str,"simple"); if (pch != NULL) printf("%s\n", pch); else printf("查找的字符串不存在\n"); return 0; }
int main() { char arr1[]="this is an apple\n"; const char* p="is";//放的是i的地址 char* ret = strstr(arr1,p); printf("%s\n",ret); return 0; }
10.2 strstr的模拟实现
char * strstr (const char * str1, const char * str2)//str1 str2不希望被修改 { char *cp = (char *) str1; char *s1, *s2; //特殊情况:str2是空字符串时,直接返回str1 if ( !*str2 ) return((char *)str1); while (*cp) { s1 = cp; s2 = (char *) str2; while ( *s1 && *s2 && !(*s1-*s2) ) s1++, s2++; if (!*s2) return(cp); //返回第⼀次出现的起始 cp++; } return(NULL); //找不到则返回NULL }
先来一种简单情况 在abcdef 中找 bcd
str1指向a时,不符合,所以++指向b,此时与*str2相等,然后str2++,再str1++,直到str2指向\0时结束
再来一种复杂情况
从第一个b开始时没有 可能存在多次匹配 还得有两个指针变量 存放他们两个的起始变量 然后对他们++ 让起始位置向后平移
char* my_strstr(const char* str1,const char* str2) { const char* s1=NULL; const char* s2=NULL; const char* cur=str1; while(*cur) { s1=cur; s2=str2; while(*s1!='\0'&&*s2!='\0'&&*s1==*s2) { s1++; s2++; } if(*s2=='\0') { return char* cur; } cur++; } return NULL; }
strstr函数的实现有多种,可以暴⼒查找,也有⼀种⾼效⼀些的算法:KMP,有兴趣的可以去学习。
11.strtok函数的使用
char *strtok(char *str, const char *delim); //delim参数指向了一个字符串,定义了用作分隔符的字符的集合
功能
• 分割字符串:根据delim 参数中指定的分隔符,将输⼊字符串str 拆分成多个⼦字符串。
• 修改原始字符串: strtok 会直接在原始字符串中插⼊’\0’ 终⽌符,替换分隔符的位置,因 此原始字符串会被修改。
参数
1.str :⾸次调⽤时传⼊待分割的字符串;后续调⽤传⼊NULL ,表⽰继续分割同⼀个字符串。
2.delim :包含所有可能分隔符的字符串(每个字符均视为独⽴的分隔符)。
返回值
• 成功时返回指向当前⼦字符串的指针。
• 没有更多⼦字符串时返回NULL 。
使⽤步骤
- ⾸次调⽤:传⼊待分割字符串和分隔符。
- 后续调⽤:传⼊NULL 和相同的分隔符,继续分割。
- 结束条件:当返回NULL 时,表⽰分割完成。
11.1 代码演示
int main() { char arr[]="fnianxu@yeah.net"; char arr2[30]={0};//"fnianxu\0yeah\0net" strcpy(arr2,arr); const char* sep="@.";//传入NULL在\0之后继续进行 char* ret=NULL;//初始化 ret = strtok(arr2,sep); printf("%s\n",ret); ret = strtok(NULL,sep); printf("%s\n",ret); ret = strtok(NULL,sep); printf("%s\n",ret); }
运行结果如下:
但一直传入空指针有些麻烦,所以看以下示例
#include <stdio.h> #include <string.h> int main() { char arr[] = "192.168.6.111"; const char* sep = "."; const char* str = NULL; char buf[30] = {0}; strcpy(buf, arr); //将arr中的字符串拷⻉到buf中,对buf的内容进⾏切割 for (str = strtok(buf, sep); str != NULL; str = strtok(NULL, sep)) { printf("%s\n", str); } return 0; }
11.2 注意事项
• 破坏性操作: strtok 会直接修改原始字符串,将其中的分隔符替换为’\0’ 。如果需要保留原字符串,应先拷⻉⼀份。
• 连续分隔符:多个连续的分隔符会被视为单个分隔符,不会返回空字符串。
• 空指针处理:如果输⼊的str 为NULL 且没有前序调⽤,⾏为未定义。
12.strerror函数的使用
char* strerror ( int errnum );
功能
1.strerror 函数可以通过参数部分的errnum 表示错误码,得到对应的错误信息,并且返回这个错误信息字符串⾸字符的地址。
2.strerror 函数只针对标准库中的函数发⽣错误后设置的错误码的转换。
3.strerror 的使⽤需要包含<string.h>
在不同的系统和C语⾔标准库的实现中都规定了⼀些错误码,⼀般是放在 errno.h 这个头⽂件中说 明的,C语⾔程序启动的时候就会使⽤⼀个全局的变量 errno 来记录程序的当前错误码,只不过程序启动的时候errno 是0,表⽰没有错误,当我们在使⽤标准库中的函数的时候发⽣了某种错误, 就会将对应的错误码,存放在 errno 中,⽽⼀个错误码的数字是整数,很难理解是什么意思,所 以每⼀个错误码都是有对应的错误信息的。strerror函数就可以将错误码对应的错误信息字符串的地 址返回。
参数:
errnum :表示错误码
这个错误码⼀般传递的是 errno 这个变量的值,在C语⾔有⼀个全局的变量叫: errno ,当库函数 的调⽤发⽣错误的时候,就会讲本次错误的错误码存放在 errno 这个变量中,使⽤这个全局变量需要 包含⼀个头⽂件 errno.h 。
返回值:
函数返回通过错误码得到的错误信息字符串的⾸字符的地址。
12.1 代码演示
#include <errno.h> #include <string.h> #include <stdio.h> //我们打印⼀下0~10这些错误码对应的信息 int main() { int i = 0; for (i = 0; i <= 10; i++) { printf("%d: %s\n", i, strerror(i)); } return 0; }
在Windows11+VS2022环境下输出的结果如下:
0: No error 1: Operation not permitted 2: No such file or directory 3: No such process 4: Interrupted function call 5: Input/output error 6: No such device or address 7: Arg list too long 8: Exec format error 9: Bad file descriptor 10: No child processes
举例:
#include <stdio.h> #include <string.h> #include <errno.h> int main () { FILE * pFile = NULL; //fopen函数以读的形式打开⽂件,如果⽂件不存在,则打开失败。 pFile = fopen ("unexist.ent", "r"); if (pFile == NULL) { printf ("错误信息是:%s\n", strerror(errno)); return 1;//错误返回 }//读文件 fclose(pf);//关闭文件 return 0;//空指针不能解引用 }
输出:
错误信息是:No such file or directory
12.2 perror
也可以了解⼀下 perror 函数, perror 函数相当于⼀次将上述代码中的第11⾏完成了,直接将错误 信息打印出来。 perror 函数打印完参数部分的字符串后,再打印⼀个冒号和⼀个空格,再打印错误 信息。
perror有能力直接打印错误信息,打印的时候,先打印传给perror的字符串,然后打印冒号,再打印空格,最后打印错误码对应信息
perrpr=printf+strerror
#include <stdio.h> #include <string.h> #include <errno.h> int main () { FILE * pFile = NULL; pFile = fopen ("unexist.ent", "r"); if (pFile == NULL) { perror("错误信息是"); return 1; } return 0; }
输出:
错误信息是: No such file or directory
总结
到此这篇关于C/C++字符函数和字符串函数的文章就介绍到这了,更多相关C/C++字符函数和字符串函数内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
精彩评论