C语言 day12 | 我的日常分享

C语言 day12

字符串处理

  1. 测字符串长度函数
  2. 字符串拷贝函数
  3. 格式化字符串操作函数
  4. const 关键字

对字符串的处理,在嵌入式编程、应用编程、网络编程中会有大量的使用

字符串的拷贝、连接、比较、切割、变换…

要求熟练使用常见字符串处理函数,并且会自己编写典型的字符串操作函数

字符串操作函数

1
2
3
4
5
头文件:#include<string.h>
1strlen //长度测量函数
2strcpy/strncpy //字符串拷贝
3strcat/strncat //字符串拼接
4strcmp/strncmp //字符串比较

注意:只要是 str 开头的函数,都是遇到 '\0' 结束


strlen 函数

  • 函数原型:unsigned int strlen(const char *str);
  • 函数功能:测量字符串的长度,不包含'\0'
  • 函数参数:存放字符串的内存空间的首地址
  • 注意:遇到'\0'结束测量

案例 1:请说出下面代码的运行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include<stdio.h>
#include<string.h>
int main(int argc,char *argv[]){
char str1[128]="hello";
char str2[]="hello";
char str3[]="hel\0lo";
char str4[]="hel\123\\lo";//八进制转义 \hhh h:0~7
char str5[]="hel\x2flo";//十六进制转义 \xdd d:0~9~a~f
char str6[]="\0he\0llo";

printf("%d\n",sizeof(str1));
printf("%d\n",strlen(str1));

printf("%d\n",sizeof(str2));
printf("%d\n",strlen(str2));

printf("%d\n",sizeof(str3));
printf("%d\n",strlen(str3));

printf("%d\n",sizeof(str4));
printf("%d\n",strlen(str4));
printf("%s\n",str4);

printf("%d\n",sizeof(str5));
printf("%d\n",strlen(str5));
printf("%s\n",str5);

printf("%d\n",sizeof(str6));
printf("%d\n",strlen(str6));//不要认为测量的长度为0,字符串就真的没有内容了
return 0;
}

运行结果:
图片

分析:
第 9、10 行,因为定义的数组元素个数为 128,为 char 类型,所以占的字节数为 128,但是 str1 中的字符串为hello只有 5 个字符,所以打印的分别是 128、5;
第 12、13 行,因为数组的长度没有定义,数组的长度有初始化的元素个数决定,然而字符串hello实际上最后面系统会自动添加一个'\0',所以共有 6 个元素,而字符串的长度为 5,因此打印分别为 6、5;
第 15、16 行,数组长度没有定义,有初始化元素个数决定,而"hel\0lo"系统在末尾会添加一个'\0',所以数组总元素个数为 7,而hel后面有个\0,strlen 函数遇到\0就会结束,所以测量出的长度为 3;
第 18,19 行,'\123'代表一个字符,'\\'为一个'\'

作业:自定义一个 my_strlen 函数测量字符串的长度

1
int my_strlen(const char *s);

字符串拷贝函数 strcpy/strncpy

strcpy 函数

  • 函数原型:char *strcpy(char *dest,const char *src);
  • 函数功能:把 src 所指向的字符串复制到 dest 所指向的空间中
  • 返回值:返回 dest 字符串的首地址
  • 注意:遇到\0会结束拷贝,但是\0也会被拷贝过去

案例 2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<stdio.h>
#include<string.h>
int main(int argc,char *argv[]){
char src1[] = "hello world";
char dest1[128]="";//要保证dest足够大
char src2[] = "hello\0 wo\0rld";
char dest2[128]="";
char src3[] = "\0hello world";
char dest3[128]="";

strcpy(dest1,src1);
strcpy(dest2,src2);
strcpy(dest3,src3);

printf("%s\n",dest1);
printf("%s\n",dest2);
printf("##%s##\n",dest3);
return 0;
}

运行结果:
图片

案例 3:自己实现一个 strcpy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<stdio.h>
#include<string.h>
char *my_strcpy(char *dest,const char *src){

while(*src!='\0'){
*dest=*src;
src++;
dest++;
}
*dest='\0';

//优化
//while(*dest++=*src++);
}
int main(int argc,char *argv[]){
char src1[] = "hello world";
char dest1[128]="";
char src3[] = "\0hello world";
char dest3[128]="";

my_strcpy(dest1,src1);
my_strcpy(dest3,src3);

printf("%s\n",dest1);
printf("##%s##\n",dest3);
return 0;
}

运行结果:
图片

strncpy 函数

  • 函数原型:char *strncpy(char *dest,const char *src,int num);
  • 函数功能:把 src 所指向的字符串的前 num 个复制到 dest 所指向的空间中
  • 返回值:返回 dest 字符串的首地址
  • 注意:\0不会被拷贝过去,但是遇到\0结束

    复制多少由num的值决定。如果src的前n个字符不含NULL字符,则结果不会以NULL字符结束。如果n<src的长度,只是将src的前n个字符复制到dest的前n个字符,不自动添加’\0’,也就是结果dest不包括’\0’,需要再手动添加一个’\0’。如果src的长度小于n个字节,则以NULL填充dest直到复制完n个字节。

案例4:

1
2
3
4
5
6
7
8
9
10
#include<stdio.h>
#include<string.h>
int main(int argc,char *argv[]){
char src[]="hello world";
char dest[128]="";

strncpy(dest,src,3);
printf("%s",dest);
return 0;
}

运行结果:
图片


strcat 函数 字符串拼接

  • 函数原型:char *strncat(char *dest,const char *src);
  • 函数功能:把 src 所指向的字符串拼接到到 dest 所指向的字符串的末尾(第一个\0后面)

案例5:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include<stdio.h>
#include<string.h>
int main(int argc,char *argv[]){
char s1[128]="hello";
char s2[128]="world";

char a1[128]="hel\0lo";
char a2[128]="world";

char c1[128]="hello";
char c2[128]="wor\0ld";

strcat(s1,s2);
strcat(a1,a2);
strcat(c1,c2);
printf("%s\n",s1);
printf("%s\n",s2);

printf("%s\n",a1);//并不是拼接成这样hel\0loworld然后只输出hel而是拼接成helworld
printf("%s\n",a2);

printf("%s\n",c1);
printf("%s\n",c2);
return 0;
}

运行结果:
图片

作业:自定义my_strcat函数


strcmp/strncmp 字符串比较函数

strcmp 函数 (整个字符串比较)

  • 函数原型:int strcmp(const char *s1,const char *s2);
  • 函数功能:将s1、s2指向的字符串,逐个字符比较(ASCII码)
  • 返回值:
    • >0 表示s1>s2;
    • <0 表示s1<s2;
    • =0 表示s1=s2;
  • 两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇’\0’为止

    案例6:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #include<stdio.h>
    #include<string.h>
    int main(int argc,char *argv[]){
    char s1[128]="aaahello";
    char s2[128]="aaaworld";
    int res=0;

    res=strcmp(s1,s2);

    if(res>0){
    printf("s1>s2");
    }else if(res<0){
    printf("s1<s2");
    }else if(res == 0){
    printf("s1==s2");
    }
    return 0;
    }
    运行结果:
    图片

问题:如果两个字符串的长度不相等会发生什么?

strncmp 函数 (局部字符串比较)

  • 函数原型:int strcmp(const char *s1,const char *s2,unsigned int num);
  • 函数功能:将s1、s2指向的字符串的前num个,逐个字符比较(ASCII码)
  • 返回值:
    • >0 表示s1>s2;
    • <0 表示s1<s2;
    • =0 表示s1=s2;

案例7:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<stdio.h>
#include<string.h>
int main(int argc,char *argv[]){
char s1[128]="aaahello";
char s2[128]="aaaworld";
int res=0;

// res=strncmp(s1,s2,4);//小于0
res=strncmp(s1,s2,3);//==0

if(res>0){
printf("s1>s2");
}else if(res<0){
printf("s1<s2");
}else if(res == 0){
printf("s1==s2");
}
return 0;
}

运行结果:
图片


strchr 函数

  • 函数原型:char *strchr(const char *str, int c);
  • 功能:在参数str所指向的字符串中搜索第一次出现字符c(一个无符号字符)的位置(地址)。
  • 返回值:该函数返回在字符串 str 中第一次出现字符 c 的位置(地址),如果未找到该字符则返回 NULL。

案例8:将str中所有的o替换成*

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<stdio.h>
#include<string.h>
int main(int argc, char* argv[]) {
char str[] = "www.yuencode.cn";
char *res = NULL;

while (1) {
res = strchr(str, 'o');
if (res == NULL) {
break;
}
*res = '*';
}
// printf("%p\n",res);//返回值为位置(地址)
printf("%s\n", str);
return 0;
}

运行结果:
图片


strstr函数

  • 函数原型:char *strstr(const char *haystack, const char *needle)
  • 函数参数:
    • haystack – 要被检索的 C 字符串。
    • needle – 在 haystack 字符串内要搜索的小字符串。
  • 返回值:该函数返回在 haystack 中第一次出现 needle 字符串的位置,如果未找到则返回 NULL。

案例9:将str中所有的cnm替换成*

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<stdio.h>
#include<string.h>
int main(int argc, char* argv[]) {
char str[] = "www.yucnmencode.ccnmn";
char *res = NULL;
int i=0;
while (1) {
res = strstr(str, "cnm");
if (res == NULL) {
break;
}
//for(i=0;i<strlen("cnm");i++){
// *(res+i) = '*';
//}
memset(res,'*',strlen("cnm"));
}
printf("%s\n", str);
return 0;
}

运行结果:
图片


memset函数

  • 函数原型:void *memset(void *str, int c, size_t n)
  • 参数:
    • str – 指向要填充的内存块。
    • c – 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式。
    • n – 要被设置为该值的字节数。
  • 返回值:该值返回一个指向存储区 str 的指针。