字符串
1. 字符串处理函数
1. strlen:长度
作用:测量字符串长度
语法:
size_t strlen(const char *s);
参数:
- s:要测量的字符指针变量
返回值:
- 字符串长度
注意:不包含 ‘\0’
sizeof
是个关键字,测量数据的占用内存空间大小
。
- 如果测量的是数组的名字,则测的是数组占多少个字节
- 如果 sizeof 测的是指针变量,则测的是指针变量本身占几个字节, 32 平台下结果为 4G
strlen
是个库函数,它测的是字符指针指向的字符串中字符的个数,不管指针是数组的名字,还是个指针变量。
示例:
#include <stdio.h>
#include <string.h>
void fun01()
{char *str01 = "hell0";int len = strlen(str01);printf("str01的长度为:%d\n", len);
}
int main(int argc, char const *argv[])
{fun01();return 0;
}
//str01的长度为:5
2. strcpy:拷贝
语法:
char *strcpy(char *dest, const char *src);
参数:
- dest:目标地址
- src:要拷贝的字符串
返回值:
- 目的内存地址
作用:拷贝 src 指向的字符串到 dest 指针指向的内存中, ’\0’ 也会拷贝
注意:
- 必须保证
dest
指向的内存空间足够大,否则会出现内存污染- 要注意 拷贝与赋值的区别
示例1:
#include <string.h>
#include <stdlib.h>void fun02()
{char *str01 = "hello world!";char *str02 = (char *)malloc(strlen(str01) + 1);if (str02 == NULL){printf("内存开辟失败");return;}strcpy(str02, str01);printf("str02=%s\n", str02);if (str02 != NULL){free(str02);str02 = NULL;}
}
int main(int argc, char const *argv[])
{fun02();return 0;
}
//str02=hello world!
示例2: 拷贝与赋值的区别
void fun03()
{char str01[] = "hello";/*将str01的地址赋值给了str02此时不管str01还是str02对其进行修改,另外一个也将被修改*/char *str02 = str01;str01[0] = 'H';printf("str02=%s\n",str02); //str02=Hellostr02[1] = 'E';printf("str01=%s\n",str01); //str01=HEllo
}void fun04()
{char str01[] = "hello";char *str02 = (char *)malloc(strlen(str01) + 1);/*strcpy会将str01的值拷贝一份给str02此时str01修改不会影响str02反之str02修改也不会影响str01*/strcpy(str02,str01);str01[0] = 'H';printf("str02=%s\n",str02); //str02=hello
}
3. strncpy:拷贝前n个字节
语法:
char *strncpy(char *dest, const char *src, size_t n);
参数:
- dest:目标地址
- src:要拷贝的字符串
返回值:
- 目的内存 的 首地址
作用:将 src
指向的字符串前 n 个字节
,拷贝到 dest
指向的内存中
注意:
- 不拷贝 ‘\0’
- 如果 **n 大于 src **指向的字符串中的字符个数,则在 dest 后面填充 n-strlen(src)个 ’\0’
示例:
void fun05()
{char *str01 = "hello";char *str02 = (char *)calloc(5, 1);strncpy(str02, str01, 3);printf("str02=%s\n", str02); //str02=hel
}
示例2:
void fun06()
{int len,i,len02;char buf[100]="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";len=strlen(buf);printf("buf长度:%d\n",len); //buf长度:38strncpy(buf,"helloworld",15); printf("buf=%s\n",buf); //buf=helloworldlen02=strlen(buf);printf("buf拷贝后长度:%d\n",len02); //buf拷贝后长度:10for(i=0;i<len;i++)printf("%c",buf[i]); printf("\n");//注意:遍历后发现,a还在字符串中 helloworldaaaaaaaaaaaaaaaaaaaaaaa,只是字符串以 '\0'结尾,长度和打印没显示
}
4. strcat:追加
语法:
char *strcat(char *dest, const char *src);
参数:
- dest:目标地址
- src:要追加的字符串
注意:
- 会追加 ’\0’
- 保证 dest 指向的内存
空间足够大
。
作用: 追加 src 字符串到 dest 指向的字符串的后面。
示例:
void fun08()
{char str01[100] = "hello";char str02[] = "world";strcat(str01,str02);printf("str01=%s\n",str01); //str01=helloworld
}
5. strncat:追加前n个字符
语法:
char *strncat(char *dest, const char *src, size_t n);
参数:
- dest:目标地址
- src:要追加的字符串
- n:要追加字符的个数
注意:
- 会追加 ’\0’
- 如果
n 大于 src 的字符个数
,则只将 src 字符串追加到 dest 指向的字符串的后面追加的时候会追加’\0’ 。
作用: 追加 src 字符串 的前n个字符 到 dest 指向的字符串的后面。
示例:
void fun07()
{char str01[100] = "hello";char str02[] = "world";strncat(str01,str02, 3);printf("str01=%s\n",str01); //str01=hellowor
}
6. strcmp:比较
语法:
int strcmp(const char *s1, const char *s2);
参数:
- s1:要比较的字符串1
- s2:要比较的字符串2
作用:比较 s1 和 s2 指向的字符串的大小,
- 比较的方法:逐个字符去比较 ascII 码,一旦比较出大小返回。
返回值:
- 返回 0 ,表示所有字符都一样
- 返回 1 ,s1 指向的字符串大于 s2 指向的字符串
- 返回-1 ,s1 指向的字符串小于 s2 指向的字符串
void fun10()
{char *str01 = "hello";char str02[100];strcpy(str02, str01);int num = strcmp(str01, str02);if (num == 0){printf("str01和str02相同\n");}else{printf("str01和str02不相同\n");}
}
//str01和str02相同
7. strncmp:比较前n个字符
比较 s1 和 s2 指向的字符串中的前 n 个字符
小练习示例:
int fun11()
{/*用户输入账号与密码如果账号为admin,密码为123456显示登录成功否则显示登录失败*/for(int i= 0; i < 3; i++){printf("请输入账号:\n");char uname[100];scanf("%s",uname);printf("请输入密码:\n");char pword[100];scanf("%s",pword);if (strcmp(uname,"admin") == 0 && strcmp(pword,"123456") == 0){printf("登录成功\n");return 1;}else{printf("账号密码不匹配\n");if (2 - i == 0){printf("账号已被锁定\n");}else{printf("还有%d次机会\n",(2-i));}}}return 0;
}
8. strchr:字符查找函 首次匹配
语法:
char *strchr(const char *s, int c);
参数:
- s:字符串
- c:要查的字符
作用:在字符指针 s 指向的字符串中,找 ascii 码为 c 的字符
注意:
是首次匹配,如果说 s 指向的字符串中有
多个
AScII 为 c 的字符,则找的是第 1 个字符
返回值:
- 找到了,返回 找到字符第一次出现的地址;
- 找不到,返回 NULL。
示例:
void fun11()
{char *str01 = "hello";char *p1 = strchr(str01, 'l');if (p1 != NULL){printf("p1=%p\n", p1); //p1=0x400f46printf("o 的下标为:%ld\n", p1 - str01); //o 的下标为:2,计算字符在字符串中的第一次出现的下标}}
9. strrchr:字符查找函 末次匹配
作用:在 s 指向的字符串中,找最后一次出现的 AScII 为 c 的字符,
返回值:末次匹配的字符的地址
示例:
void fun12()
{char *str01 = "hello";char *p1 = strrchr(str01, 'l');if (p1 != NULL){printf("p1=%p\n", p1); //p1=0x400ff7printf("o 的下标为:%ld\n", p1 - str01); //o 的下标为:3,计算字符在字符串中的第一次出现的下标}}
10. strstr 字符串匹配 首次匹配
语法:
char *strstr(const char *haystack, const char *needle);
参数:
- haystack:被匹配的字符串
- needle:需要匹配的字符串
作用:在 haystack
指向的字符串中查找 needle
指向的字符串,也是首次匹配
返回值:
- 找到了:找到的字符串的首地址
- 没找到:返回 NULL
示例:
void fun13()
{char *str = "abcddefcde";char *p = strstr(str,"cde");printf("%ld\n",p - str); //7
}
11. atoi/atol/atof 字符串转数字
语法:
int atoi(const char *nptr); long atol(const char *nptr); double atof(const char *nptr);
参数:
- nptr:被转的字符串
作用:将 nptr 指向的字符串转换成整数、长整形、浮点型(小数默认是double)
void fun14()
{int num01 = atoi("123");printf("%d\n",num01+1); //124long num02 = atol("1111111");printf("%ld\n",num02+1); //1111112double f03 = atof("1.23");printf("%.2lf\n",f03+1); //2.23
}
12. strtok 字符串切割
语法:
char *strtok(char *str, const char *delim);
参数:
- str:被切割的字符串
- delim:切割的字符串
返回值:
- 切割出的字符串首地址
- 切割失败返回NULL
作用:字符串切割,按照 delim 指向的字符串中的字符,切割 str 指向的字符串。
其实就是在 str 指向的字符串中发现了 delim 字符串中的字符,就将其变成’\0’,调用一次 strtok 只切割一次,切割一次之后,再去切割的时候 strtok 的第一个参数传 NULL,意思是接着上次切割的位置继续切 。
注意:
如果 str 字符串中出现了连续的几个 delim 中的字符,则只将第一个字符变成’\0’
示例1:
void fun15()
{char s[] = "123,,,...456##..789,,..";char *str = s;char *delim = ",.#";char *p = strtok(str,delim);printf("%s\n",p); //123char *p1 = strtok(NULL,delim);printf("%s\n",p1); //456char *p2 = strtok(NULL,delim);printf("%s\n",p2); //789char *p3 = strtok(NULL,delim);printf("%p\n",p3); //(nil)
}
示例2:优化重复代码,并将切割出来的字符串写入数组
void fun16()
{char s[] = "123,,,...456##..789,,..";char *str = s;char *d = ",.#";char *buf[3];char *p = strtok(str, d);int i = 0;while(1){buf[i] = p;i++;p = strtok(NULL, d);if (p == NULL){break;}}for (int j = 0; j < 3; j++){printf("buf[%d]=%s\n", j, buf[j]);}
}
// buf[0]=123
// buf[1]=456
// buf[2]=789
示例3:再优化
void fun17()
{char s[] = "123,,,...456##..789,,..";char *d = ",.#";char *buf[3] = {s, NULL};int i = 0;while((buf[i] = strtok(buf[i], d)) != NULL && (++i));for (int j = 0; j < 3; j++){printf("buf[%d]=%s\n", j, buf[j]);}
}
// buf[0]=123
// buf[1]=456
// buf[2]=789
2. 组包
13. sprintf:格式化输出
语法:
int sprintf(char *buf, const char *format, … );
参数:
- buf:输出到指定的内存,首地址
- format:输出的格式
- 值:输出的内容
作用:将 值
按照 format
格式 输出到 指定的 buf内存中
示例:
void fun18()
{char *str[100];sprintf(str, "%d年%d月%d日\n", 2023, 11, 06);printf("str=%s\n", str); //str=2023年11月6日
}
扩展使用如下:
13.1 数字转字符串
void fun19()
{char *str[100];sprintf(str, "%d", 2023);printf("str=%s\n", str); //str=2023
}
13.2 字符串拼接
void fun20()
{//字符串拼接char *str01 = "hello";char *str02 = "world";char str[100];sprintf(str,"%s%s",str01,str02);printf("%s\n",str); //helloworld
}
3. 解包
14. sscanf:格式化输入
语法:
int sscanf(const char *buf,const char *format, … );
参数:
- buf:从指定的内存,首地址,读入信息
- format:输入的格式
- 值:输入的内容
作用:将 值
按照 format
格式 从 buf 指定的内存
区域中读入信息
示例:
void fun21()
{char *str = "2023年11月6日 20:33:58";int y = 0;int m = 0;int d = 0;int h = 0;int min = 0;int s = 0;sscanf(str,"%d年%d月%d日 %d:%d:%d",&y,&m,&d,&h,&min,&s);printf("y=%d\n",y);printf("m=%d\n",m);printf("d=%d\n",d);printf("h=%d\n",h);printf("min=%d\n",min);printf("s=%d\n",s);
}
// y=2023
// m=11
// d=6
// h=20
// min=33
// s=58
14.1 读指定宽度的数据:%[width]s
格式化 占位符 前面可以加宽度:%2d
,一般用于数字
%s 前面一般不会加宽度。
void fun22()
{char *str = "1234567890";int num = 0;char c = 0;char s[3];sscanf(str, "%2d%c%s", &num, &c, s);printf("num=%d\n", num); //12printf("c=%c\n", c); //3printf("s=%s\n", s); //4567890 因为取得是首地址,所以会拿到4,没有遇到'\0',所以会直接取到结束printf("s=%c\n", *s); //4
}
14.2 跳过数据: %*s 或 %*d
void fun23()
{//跳过前两个数据,再取两个地址char *str = "1234567890";int num = 0;sscanf(str, "%*2d%2d", &num);printf("num=%d\n", num); //num=34
}
14.3 %[a-z] 表示匹配 a 到 z 中任意字符(贪婪性:尽可能多的匹配)
void fun24()
{//char *str = "acdeAZ123abcd";char p[100];sscanf(str, "%[a-z]", p);printf("%s\n", p); //acde
}
14.4 %[aBc] 匹配aBc中一员,贪婪性
void fun26()
{char *str = "aaaBccBaedf";char p[100];sscanf(str,"%[aBc]",p);printf("%s\n",p); //aaaBccBa
}
14.5 %[^aFc] 匹配非 aFc 的任意字符,贪婪性
void fun27()
{char *str = "dsssaFcvrdf";char p[100];sscanf(str,"%[^aFc]",p);printf("%s\n",p); //dsss
}
14.6 %[^a-z]表示读取除 a-z 以外的所有字符
void fun25()
{char *str = "abcdedfA123abc";char p1[100];char p2[100];sscanf(str,"%[^a-z]",p1);printf("%s\n",p1); //结果啥也没有,所以得先跳过前面的小写sscanf(str,"%*[a-z]%[^a-z]",p2);printf("%s\n",p2); //A123
}
14.7 练习
使用 sscanf 两个#号之间的字符串 abc#def@ghi
void fun28()
{char buf[20];sscanf("abc#def@ghi","%*[^#]%*c%[^@]",buf);printf("%s\n",buf); //def
}