0


超详解,让你C语言成功入门(四)——数组

目录

数组

数组是一组具有相同类型元素组成的集合。

1.一维数组

1.1一维数组的创建和初始化

数组的创建方式:

type_t   arr_name   [const_n];//type_t 是指数组的元素类型//const_n 是一个常量表达式,用来指定数组的大小// [] - 下标操作符, 用于访问数组的操作符。

例:

int arr[10]
char ch[12]
float date[30]

注: 在C99标准之前,数组的大小必须是常量或者常量表达式;在C99标准之后,数组大小可以是变量,是为了支持变长数组。(

char ch[

n

]

这种数组是不能初始化的)

1.2数组的初始化

数组的初始化,指在创建数组时给数组的内容一些合理的值。
例:

int arr[10]={1,2,3};//不完全初始化,剩余元素默认初始化为 0int arr2[]={1,2,3,4,5,6};char ch[4]={'a','b','c','d'};char ch2[]={'a',99,'d'};char ch3[]="abcdef";

数组在创建的时候如果想不指明数组的确定大小就得初始化。数组的元素个数根据初始化的内容来确定。

但是对于下面的代码要区分,内存中如何分配。

char ch1[]="abc";// a b c \0char ch2[]={'a','b','c'};// a b c

在这里插入图片描述

int arr[10]={1,2,3,4,5,6,7,8,9,10};

在内存中栈区找了一块连续的空间来存放1,2,3,4,5,6,7,8,9,10。
我们给这块空间取名为arr。
就像在酒店排了十个连续的房间,而每个房间都有一个编号,在C语言中,这个编号从0开始,这里的编号就是数组的下标。
在这里插入图片描述
通过数组的下标访问数组的元素,每个下标对应一个元素。

1.3一维数组的使用

#include<stdio.h>intmain(){int arr[10]={0};//数组的不完全初始化//计算数组的元素个数int sz =sizeof(arr)/sizeof(arr[0]);//对数组内容赋值,数组是使用下标来访问的,下标从0开始。所以:int i =0;//做下标for(i=0; i<10; i++){
         arr[i]= i;}//输出数组的内容for(i=0; i<10;++i){printf("%d ", arr[i]);}return0;}
sizeof(arr)

,计算的是整个数组的大小;

sizeof(arr[0])

,计算的是一个元素所占字节数。

例1.3.1:用数组实现Fibonacci数列问题。

#include<stdio.h>intmain(){int i =0;int f[20]={0};//对前两个元素赋值为1
    f[0]= f[1]=1;//依次求出f[2]~f[19]的值for(i =2; i <20; i++){
        f[i]= f[i -2]+ f[i -1];}for(i =0; i <20; i++){printf("%d ", f[i]);}printf("\n");return0;}

在这里插入图片描述

此题还可拓展到求第n个元素的值。

#include<stdio.h>intmain(){int n =0;int i =0;scanf("%d",&n);int f[n]={0};
    f[0]= f[1]=1;for(i =2; i < n; i++){
        f[i]= f[i -2]+ f[i -1];}for(i =0; i < n; i++){printf("%d ", f[i]);}printf("\n");return0;}

例1.3.2:对数组元素进行排序。

#include<stdio.h>intmain(){int arr[10]={0};int i =0, j =0;printf("输入:");//对数组元素进行赋值for(i =0; i <10; i++){scanf("%d",&arr[i]);}for(j =0; j <9; j++){for(i =0; i <9- j; i++){//比较大小if(arr[i]> arr[i+1]){int tmp = arr[i];
                arr[i]= arr[i+1];
                arr[i+1]= tmp;}}}printf("输出:");for(i =0; i <10; i++){printf("%d ",arr[i]);}printf("\n");return0;}

在这里插入图片描述

1.4 数组名

数组名确实能表示首元素的地址
但是,有两个例外:

  • sizeof(数组名),这里的数组名表示的是整个数组,计算的是整个数组的大小,单位是字节
  • &数组名,这里的数组名表示整个数组,取出的是整个数组的地址

1.5一位数组在内存中的存储

#include<stdio.h>intmain(){int arr[10]={1,2,3,4,5,6,7,8,9,10};int i =0;int sz =sizeof(arr)/sizeof(arr[0]);for(i =0; i <10; i++){//打印数组元素的地址printf("&arr[%d] = %p\n", i,&arr[i]);}return0;}

在这里插入图片描述

地址是用十六进制表示的,从结果中看出,每个整型数组元素占了四个字节。且随着数组下标的增长,元素的地址,也在有规律的递增。
由此可以得出:数组在内存中是连续存放的。
在这里插入图片描述

2.二维数组

二维数组通常叫矩阵。把二维数组写成行(row)和列(column)的排列形式。

2.1二维数组的创建

把多组数据都存储起来,用二维数组。

//1 2 3 4//2 3 4 5//3 4 5 6int arr[3][4];//三行四列的数组char arr[2][5];float arr[4][3];double arr[3][3];

在这里插入图片描述

2.2二维数组的初始化

int arr1[3][4]={1,2,3,4,2,3,4,5,3,4,5,6};int arr2[3][4]={1,2,3,4,5};int arr3[3][4]={{1,2},{3,4},{5}};//1,2放第一行,3,4放第二行,5放第三行 int arr4[][4]={{1,2},{3}};//二维数组如果有初始化,行可以省略,列不能省略

在这里插入图片描述
当数据不够时,自动补零。

2.3二维数组的使用

二维数组的使用也是通过下标的方式。

#include<stdio.h>intmain(){int arr[3][4]={0};int i =0;for(i=0; i<3; i++){int j =0;for(j=0; j<4; j++){scanf("%d",&arr[i][j]);}}for(i=0; i<3; i++){int j =0;for(j=0; j<4; j++){printf("%d ", arr[i][j]);}printf("\n");}return0;}

可以将二维数组看做是一维数组,即可理解为一维数组的数组
在这里插入图片描述

2.4二维数组在内存中的存储

二维数组在内存中也是连续存储的。

在这里插入图片描述

#include<stdio.h>intmain(){int arr[3][4];int i =0;for(i=0; i<3; i++){int j =0;for(j=0; j<4; j++){printf("&arr[%d][%d] = %p\n", i, j,&arr[i][j]);}}return0;}

在这里插入图片描述

2.5二维数组的数组名的理解

intmain(){int arr[3][4];printf("%p\n",arr);//二维数组的数组名也表示数组首元素的地址return0;}

在这里插入图片描述
求数组一行或一列的大小

printf("%d\n",sizeof(arr)/sizeof(arr[0]));//一行printf("%d\n",sizeof(arr[0])/sizeof(arr[0][0]));//一列

3.数组越界

数组的下标是有范围限制的。
数组的下标规定从0开始,如果有n个元素,那数组的最后一个元素的下标就是n-1。
故,数组的下标小于零,或大于n-1,就是数组越界访问,超出了数组合法空间的访问。
C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的,所以程序员写代码时,最好自己做越界的检查

#include<stdio.h>intmain(){int arr[10]={1,2,3,4,5,6,7,8,9,10};int i =0;for(i =0; i <=13; i++){printf("%d\n", arr[i]);}return0;}

在这里插入图片描述

二维数组的行和列也可能存在越界。

4.字符数组和字符串

4.1字符数组的创建

第一个入门篇中介绍了,字符型数据是以ASCII码存储在内存单元中的,一个数组元素占一个字节单位。
一维字符数组:

char ch[10];

二维字符数组:

char ch[5][5];

4.2字符数字的初始化及使用

4.2.1一维字符数组

char ch1[10]={'H','e','l','l','o','w','o','r','l','d'};char ch2[]={'H','e','l','l','o','w','o','r','d'};char ch3[15]={'H','e','l','l','o','w','o','r','l','d'};//未初始化的字符数组元素,自动补‘\0’char ch4[]="Helloworld";

在这里插入图片描述

4.2.2二维字符数组

char arr[5][5]={{' ',' ','*'},{' ','*','*','*'},{'*','*','*','*','*'},{' ','*','*','*'},{' ',' ','*'}};
#include<stdio.h>intmain(){char arr[5][5]={{' ',' ','*'},{' ','*','*','*'},{'*','*','*','*','*'},{' ','*','*','*'},{' ',' ','*'}};//做出来一个菱形。for(int i =0; i <5; i++){for(int j =0; j <5; j++){printf("%c", arr[i][j]);}printf("\n");}return0;}

在这里插入图片描述

4.3字符串

在C语言中,将字符串作为字符数组来处理。
字符串的有效长度并不是数组的长度。
字符串是以 ’ \0 ’ 作为结束标志的。字符串遇到 ’ \0 ’ 则结束。
C语言中,在字符数组存储字符串常量时会自动补上 ’ \0 ’ 作为结束符。

4.3.1字符串的创建和初始化

char d[]={'H','e','l','l','o',' ','W','o','r','l','d','!','\0'};/这样表示字符串过于繁杂。
char arr[]={"Hello World!"};char ch[]="Hello World!";

4.3.2字符串函数

重点掌握!!!:

  • 求字符串长度strlen
  • 长度不受限的字符串长度strcpy``````strcat``````strcmp
  • 长度受限的字符串长度strncpy``````strncat``````strncmp
  • 字符串查找strstr``````strtok
  • 错误信息报告strerror

字符串函数的模拟实现如有错误,还望指出。仅做为参考实现代码 ,并不唯一。

1.gets()和puts()——输入和输出字符串

puts()

将字符串输出到终端。
用puts()函数输出的字符串中可以包含转义字符。
char str[] = {“Hello\nWorld”};

Hello
World

在用 puts 输出时将字符串结束标志 ’ \0 ’ 转换成 ’ \n ’ ,即输出完字符串后换行。

gets()

从终端输入字符串到字符数组。
一般利用 gets 函数的目的是向字符数组输入一个字符串,而不太关心起函数值。

注意:
用 puts 和 gets 函数只能输出或输入一个字符串。

在这里插入图片描述

#include<stdio.h>intmain(int argc,constchar* argv[]){char a[100];gets(a);puts(a);return0;}

2.strlen——求字符串长度

size_tstrlen(constchar*str);
  • 字符串以\0作为结束标志,求字符串长度时,只求\0之前的所有字符数,不包含’ \0 ‘。
#include<stdio.h>#include<string.h>//字符串函数的头文件intmain(){char arr[]="abcdef";int len =strlen(arr);printf("len = %d\n", len);return0;}//len = 6
  • 参数指向的字符串必须要以 ‘\0’ 结束。
#include<stdio.h>#include<string.h>//字符串函数的头文件intmain(){char arr[]={'a','b','c','d','e','f'};int len =strlen(arr);printf("len = %d\n", len);return0;}//len = 19   ? ? ?

这里为什么是输出19,而不是6呢?

在内存中,数组是连续存储的,而字符串以\0为结束标志,内存中不知道哪里放置了\0,故数组会越界查找,直到遇上\0才停止。

正确写法:

char arr[]={'a','b','c','d','e','f','\0'};
  • 注意函数的返回值为size_t,是无符号的整型unsigned int( 易错 )
#include<stdio.h>#include<string.h>intmain(){constchar*str1 ="abcdef";constchar*str2 ="bbb";if(strlen(str2)-strlen(str1)>0)// 3 - 6 = -3{printf("str2>str1\n");}else{printf("srt1>str2\n");}return0;}

在这里插入图片描述
运行程序时,发生了错误,无法正常运行。

就是因为strlen返回类型是size_t,是一个无符号的,-3被当做是无符号数来处理时,就是一个非常大的正数。

  • strlen函数的模拟实现:
#include<stdio.h>#include<string.h>#include<assert.h>//断言头文件size_tmy_strlen(constchar* str){assert(*str);//断言,用于判断指针是否为空int count =0;while(*str !='\0'){
        count++;
        str++;}return count;}intmain(){char arr[]="abcdef";size_t len =my_strlen(arr);printf("%u\n", len);return0;}// 6

长度不受限制的字符串函数:

3.strcpy ——字符串拷贝

char*strcpy(char* destination,constchar* source );

将字符串 str2 拷贝到 str1 中去。

#include<stdio.h>#include<string.h>intmain(){char str1[20]={0};char str2[]="zhangsan";strcpy(str1, str2);printf("%s\n", str1);return0;}// zhangsan

注意:
切不可写成

arr1 = "zhangsan"

arr1 数组名是地址,地址是一个常量值,不能被赋值。 而 “zhangsan” 要存放到空间里去。

  • 源字符串必须以 ‘\0’ 结束。
#include<stdio.h>#include<string.h>intmain(){char str1[20]={0};char str2[]={'b','y','t','e'};strcpy(str1, str2);printf("%s\n", str1);return0;}

在这里插入图片描述
由于不知何时会遇见\0,所以数组很有可能会进行越界访问。

  • 会将源字符串中的 ‘\0’ 拷贝到目标空间。
#include<stdio.h>#include<string.h>intmain(){char name[20]={0};strcpy(name,"zhang\0san");printf("%s\n",name);return0;}

在这里插入图片描述

那是否真的将\0拷贝到目标空间内了呢?
测试一下:

#include<stdio.h>#include<string.h>intmain(){char name[20]="xxxxxxx";strcpy(name,"zhang\0san");printf("%s\n",name);return0;}

拷贝前:

在这里插入图片描述

拷贝后:

在这里插入图片描述

事实证明,确实将\0拷贝到了目标空间内。

  • 目标空间必须足够大,以确保能存放源字符串。
#include<stdio.h>#include<string.h>intmain(){char str1[2]={0};char str2[]="abcdef";strcpy(str1, str2);printf("%s\n", str1);return0;}

在这里插入图片描述
str1 放不下,但非要放进去,就形成了越界访问。

  • 目标空间必须可变。

错误代码:

char*p ="abcdef";//目标区域不可修改char arr[]="byte";strcpy(p,arr);
  • 学会模拟实现。

版本1:

#include<stdio.h>#include<string.h>#include<assert.h>char*my_strcpy(char* dest,char* src){assert(dest);assert(src);char* ret = dest;while(*src){*dest++=*src++;}*dest =*src;//拷贝 \0return ret;}intmain(){char str1[20]={0};char str2[]="abcdef";my_strcpy(str1, str2);printf("%s\n", str1);return0;}

版本2:

#include<stdio.h>#include<string.h>#include<assert.h>char*my_strcpy(char* dest,char* src){assert(dest && src);char* ret = dest;while(*dest++=*src++);return ret;}intmain(){char str1[20]={0};char str2[]="abcdef";my_strcpy(str1, str2);printf("%s\n", str1);return0;}

4.strcat——字符串追加

char*strcat(char* destination,constchar* source );

例:在字符数组 arr1 后追加 “world” 。

#include<stdio.h>#include<string.h>intmain(){char arr1[20]="hello ";strcat(arr1,"world");printf("%s\n", arr1);return0;}//hello world

strcat 与strcpy相似,同样有以下要求:

  • 源字符串必须以 ‘\0’ 结束。
  • 目标空间必须有足够的大,能容纳下源字符串的内容。
  • 目标空间必须可修改。
  • 模拟实现 strcat 函数:
  1. 找到目标字符串的结尾\0
  2. 拷贝 – strcpy
#include<stdio.h>#include<string.h>#include<assert.h>char*my_strcat(char* dest,constchar* src){assert(dest && src);char* ret = dest;//1.找到目标空间的末尾 \0while(*dest !='\0'){
        dest++;}//2.拷贝字符串while(*dest++=*src++){;}return ret;}intmain(){char arr1[20]="hello ";my_strcat(arr1,"world");printf("%s\n", arr1);return0;}

思考:字符串自己给自己追加会如何?

程序崩溃,原因是在找尾时,第一次拷贝字符将\0给覆盖了,然后目标空间没有\0无法停下来,会陷入死循环。

5.strcmp——字符串内容比较

intstrcmp(constchar* str1,constchar* str2 );

错误代码:

#include<stdio.h>#include<string.h>intmain(){char arr1[20]="helloworld";char arr2[]="helloworld!!!";if(arr1 == arr2){printf("==\n");}else{printf("!=\n");}return0;}

可能编译器出来的结果是 != ,但这个代码依旧是错的,即使 arr1 和 arr2 的内容一模一样。

因为,arr1 和 arr2 是数组名,数组名是首元素的地址,两个数组名的地址肯定不相等啊,地址是一个常量值。

比较两个字符串相等应该使用strcmp函数。

  • 标准规定:
  1. 第一个字符串大于第二个字符串,则返回大于0的数字
#include<stdio.h>#include<string.h>intmain(){char arr1[20]="helloworld!!!";char arr2[]="helloworld";int ret =strcmp(arr1, arr2);printf("%d\n", ret);return0;}// 1
  1. 第一个字符串等于第二个字符串,则返回0
#include<stdio.h>#include<string.h>intmain(){char arr1[20]="helloworld";char arr2[]="helloworld";int ret =strcmp(arr1, arr2);printf("%d\n", ret);return0;}// 0
  1. 第一个字符串小于第二个字符串,则返回小于0的数字
#include<stdio.h>#include<string.h>intmain(){char arr1[20]="helloworld";char arr2[]="helloworld!!!";int ret =strcmp(arr1, arr2);printf("%d\n", ret);return0;}// -1

注意以下代码:

#include<stdio.h>#include<string.h>intmain(){
    cha
    r arr1[20]="abcdef";char arr2[]="abx";int ret =strcmp(arr1, arr2);if(ret <0){printf("<\n");}elseif(ret ==0){printf("==\n");}else{printf(">\n");}return0;}// <
#include<stdio.h>#include<string.h>intmain(){
    cha
    r arr1[20]="abxdef";char arr2[]="abc";int ret =strcmp(arr1, arr2);if(ret <0){printf("<\n");}elseif(ret ==0){printf("==\n");}else{printf(">\n");}return0;}// >

两种代码产生差异的原因是:strcmp比较的是字符的ASCII码值。

  • 模拟实现 strcmp 函数:
#include<stdio.h>#include<string.h>#include<assert.h>intmy_strcmp(constchar* str1,constchar* str2){assert(str1 && str2);while(*str1 ==*str2){if(*str1 =='\0')return0;//相等
        str1++;
        str2++;}if(*str1 >*str2)return1;elsereturn-1;}intmain(){char arr1[20]="abcdef";char arr2[]="abc";int ret =my_strcmp(arr1, arr2);if(ret <0){printf("<\n");}elseif(ret ==0){printf("==\n");}else{printf(">\n");}return0;}

简化版:

#include<stdio.h>#include<string.h>#include<assert.h>intmy_strcmp(constchar* str1,constchar* str2){assert(str1 && str2);while(*str1 ==*str2){if(*str1 =='\0')return0;//相等
        str1++;
        str2++;}return(*str1 -*str2);}intmain(){char arr1[20]="abcdef";char arr2[]="abc";int ret =my_strcmp(arr1, arr2);if(ret <0){printf("<\n");}elseif(ret ==0){printf("==\n");}else{printf(">\n");}return0;}

长度受限制的字符串长度:

6.strncpy——拷贝src中num个字符

char*strncpy(char* destination,constchar* source,size_t num );
  • 拷贝num个字符从源字符串到目标空间。
#include<stdio.h>#include<string.h>intmain(){char arr1[20]="abcdef";char arr2[]="hello world";strncpy(arr1, arr2,5);printf("%s\n", arr1);return0;}//hellof

在这里插入图片描述

  • 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
#include<stdio.h>#include<string.h>intmain(){char arr1[20]="abcdef";char arr2[]="xyz";strncpy(arr1, arr2,5);printf("%s\n", arr1);return0;}//xyz

在这里插入图片描述

  • 模拟实现strncpy函数:
#include<stdio.h>#include<string.h>#include<assert.h>char*my_strncpy(char* dest,constchar* src,size_t num){assert(dest && src);char* ret = dest;int len =strlen(src);if(len >= num){int i =0;while(*src !='\0'&& i < num){*dest++=*src++;
            i++;}}else{int j =0;while(*src !='\0'){*dest++=*src++;
            j++;}while(num - j !=0){*dest++='\0';
            j++;}}return ret;}intmain(){char arr1[20]="abc";char arr2[]="xyzdef";my_strncpy(arr1, arr2,5);printf("%s\n", arr1);return0;}

7.strncat——追加src中num个字符

char*strncat(char* destination,constchar* source,size_t num );
#include<stdio.h>#include<string.h>intmain(){char str1[20]="hello ";char str2[20]="world";strncat(str1, str2,3);puts(str1);return0;}//hello wor

在这里插入图片描述
在这里插入图片描述

追加后末尾\0是否补上了呢?

#include<stdio.h>#include<string.h>intmain(){char str1[20]="hello \0xxxx";char str2[20]="world";strncat(str1, str2,3);puts(str1);return0;}

在这里插入图片描述

在这里插入图片描述

由此可知,在追加之后,补上了一个\0。

  • 模拟实现 strncat 函数:
#include<stdio.h>#include<string.h>#include<assert.h>char*my_strncat(char* dest,constchar* src,size_t num){assert(dest && src);char* ret = dest;//1.找到目标空间的末尾 \0while(*dest !='\0'){
        dest++;}//2.拷贝字符串int i =0;while(*src !='\0'&& i < num){*dest++=*src++;
        i++;}*dest ='\0';return ret;}intmain(){char arr1[20]="hello ";char arr2[20]="world";my_strncat(arr1, arr2,6);puts(arr1);return0;}//hello world

8.strncmp——比较num个字符内容

intstrncmp(constchar* str1,constchar* str2,size_t num );

比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。

#include<stdio.h>#include<string.h>intmain(){char arr1[]="helloworld";char arr2[]="hellq";int ret =strncmp(arr1, arr2,5);//printf("%d\n",ret);  //1if(ret ==0)printf("==\n");elseif(ret <0)printf("<\n");elseprintf(">\n");return0;}// <
  • 模拟实现 strncmp 函数:
#include<stdio.h>#include<string.h>#include<assert.h>intmy_strncmp(constchar* str1,constchar* str2,size_t num){assert(str1 && str2);int ret =0;while(num !=0){
        ret =*str1 -*str2;if(ret !=0)break;//相等
        str1++;
        str2++;
        num--;}return ret;}intmain(){char arr1[]="abcdef";char arr2[]="abc";int ret =my_strncmp(arr1, arr2,3);if(ret <0){printf("<\n");}elseif(ret ==0){printf("==\n");}else{printf(">\n");}return0;}

9.strstr——查找子串

char*strstr(constchar*str1,constchar* str2);

返回一个指向str1中第一次出现的str2的指针,或者如果str2不是str1的子串,则返回一个空指针。

#include<stdio.h>#include<string.h>intmain(){char arr1[]="abcdefghijklmn";char arr2[]="defghi";char* ret =strstr(arr1, arr2);if(ret ==NULL){printf("子串不存在\n");}else{printf("%s\n", ret);}return0;}// defghijklmn
  • 模拟实现 strstr 函数:
#include<stdio.h>#include<string.h>#include<assert.h>char*my_strstr(constchar* str1,constchar* str2){assert(str1 && str2);constchar* s1 = str1;constchar* s2 = str2;constchar* p = str1;while(*p){
        s1 = p;
        s2 = str2;while(*s1 !='\0'&&*s2 !='\0'&&* s1 ==*s2){
            s1++;
            s2++;}if(*s2 =='\0'){return(char*)p;}
        p++;}returnNULL;}intmain(){char arr1[]="abcdefghijklmn";char arr2[]="defghi";char* ret =my_strstr(arr1, arr2);if(ret ==NULL){printf("子串不存在\n");}else{printf("%s\n", ret);}return0;}

10.strtok——切割字符串

char*strtok(char* str,constchar* sep );

[email protected]

为例:

  • sep参数是个字符串,定义了用作分隔符的字符集合
constchar* sep ="@.";
  • 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
constchar* sep ="@.";char arr[]="[email protected]";char* ret =strtok(arr, sep);
  • strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)

在这里插入图片描述

constchar* sep ="@.";char arr[]="[email protected]";char cp[35]={0};strcpy(cp, arr);char* ret =strtok(cp, sep);
  • strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
#include<stdio.h>#include<string.h>intmain(){constchar* sep ="@.";char arr[]="[email protected]";char cp[35]={0};strcpy(cp, arr);char* ret =strtok(cp, sep);printf("%s\n", ret);return0;}//1234
  • strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。

在这里插入图片描述

#include<stdio.h>#include<string.h>intmain(){constchar* sep ="@.";char arr[]="[email protected]";char cp[35]={0};//"[email protected]"strcpy(cp, arr);char* ret =strtok(cp, sep);printf("%s\n", ret);
    
    ret =strtok(NULL, sep);printf("%s\n", ret);
    
    ret =strtok(NULL, sep);printf("%s\n", ret);
    
    ret =strtok(NULL, sep);printf("%s\n", ret);return0;}//1234//asdf//csin//com
  • 如果字符串中不存在更多的标记,则返回 NULL 指针。
#include<stdio.h>#include<string.h>intmain(){constchar* sep ="@.";char arr[]="[email protected]";char cp[35]={0};//"[email protected]"strcpy(cp, arr);char* ret =strtok(cp, sep);printf("%s\n", ret);
    
    ret =strtok(NULL, sep);printf("%s\n", ret);
    
    ret =strtok(NULL, sep);printf("%s\n", ret);
    
    ret =strtok(NULL, sep);printf("%s\n", ret);
    
    ret =strtok(NULL, sep);printf("%s\n", ret);return0;}//1234//asdf//csin//com//(null)

以上代码过于繁琐,可以用循环来简化代码:

#include<stdio.h>#include<string.h>intmain(){constchar* sep ="@.";char arr[]="[email protected]";char cp[35]={0};//"[email protected]"strcpy(cp, arr);char* ret =NULL;for(ret =strtok(cp, sep); ret !=NULL; ret =strtok(NULL, sep)){printf("%s\n", ret);}return0;}
  • 模拟实现 strtok 函数:
#define_CRT_SECURE_NO_WARNINGS1#include<stdio.h>#include<string.h>#include<assert.h>char*my_strtok(char* str,constchar* sep){assert(sep);staticchar* s1 =NULL;char* s2 = sep;while(s1 !=NULL&&*s1 !='\0'){int cnt =0;char* ret =(char*) sep;while(*ret !='\0'){if(*s1 ==*ret){
                cnt =1;
                s1++;}
            ret++;}if(cnt ==0)break;}if(str ==NULL){if(s1 ==NULL){returnNULL;}
        str = s1;}char* ans = str;while(*ans !='\0'){char* res =(char*)sep;while(*res !='\0'){if(*ans ==*res){*ans ='\0';
                s1 = ans +1;return str;}
            res++;}
        ans++;}staticint num =0;
    num++;if(num ==1){return str;}else{returnNULL;}}intmain(){constchar* sep ="@.";char arr[]="[email protected]";char cp[35]={0};//"[email protected]"strcpy(cp, arr);char* ret =NULL;for(ret =my_strtok(cp, sep); ret !=NULL; ret =my_strtok(NULL, sep)){printf("%s\n", ret);}return0;}//1234//asdf//csin//com

11.strerror——返回错误码所对应的错误信息

C语言的库函数,在执行失败的时候,都会设置错误码,如:0 1 2 3 4 5 6 …
要将这些错误码转换为错误信息,就用到了 strerror 函数。

strerror 函数:返回错误码,所对应的错误信息。

char*strerror(int errnum );
#include<stdio.h>#include<string.h>intmain(){printf("%s\n",strerror(0));printf("%s\n",strerror(1));printf("%s\n",strerror(2));printf("%s\n",strerror(3));return0;}//No error//Operation not permitted//No such file or directory//No such process

一般用于文件操作中:

#include<stdio.h>#include<string.h>#include<errno.h>// errno的头文件intmain(){
    FILE* pf =fopen("test.txt","r");//读取这个文件if(pf ==NULL)//文件不存在{//errno - C语言设置的一个全局的错误码存放的变量printf("%s\n",strerror(errno));//输出错误信息return1;}else{//....文件存在,执行其他操作}return0;}//No such file or directory

如有多个错误,且在继续执行程序,那么记录的始终是最新错误,即新错误将前一个错误所覆盖掉。

文件操作,后期会详说。这里可做了解。

字符转换函数:

12.strlwr、tolower——大写字母转小写字母

char *strlwr(char *str);
#include<stdio.h>#include<string.h>#include<ctype.h>intmain(){char arr[]="ASDFGHJKL";char* a =strlwr(arr);printf("%s\n", a);return0;}//asdfghjkl
int tolower ( int c );
#include<stdio.h>#include<string.h>intmain(){int a =tolower('W');printf("%c\n", a);return0;}//w

13.strupr、toupper——小写字母转大写字母

char *strupr(char *str);
#include<stdio.h>#include<string.h>intmain(){char arr[]="asdfghjkl";char* a =strupr(arr);printf("%s\n", a);return0;}//ASDFGHJKL
int toupper (int c );
#include<stdio.h>#include<string.h>intmain(){int a =toupper('b');printf("%c\n", a);return0;}//B

字符分类函数

函数如果他的参数符合下列条件就返回真iscntrl任何控制字符isspace空白字符:空格‘ ’,换页‘\f’,换行’\n’,回车‘\r’,制表符’\t’或者垂直制表符’\v’isdigit十进制数字 09isxdigit十六进制数字,包括所有十进制数字,小写字母af,大写字母A ~ Fislower小写字母azisupper大写字母AZisalpha字母a ~ z或AZisalnum字母或者数字,a ~ z,A ~ Z,09ispunct标点符号,任何不属于数字或者字母的图形字符(可打印)isgraph任何图形字符isprint任何可打印字符,包括图形字符和空白字符

标签: c语言

本文转载自: https://blog.csdn.net/qq_68162134/article/details/124483428
版权归原作者 Audery867 所有, 如有侵权,请联系我们删除。

“超详解,让你C语言成功入门(四)&mdash;&mdash;数组”的评论:

还没有评论