构造类型-枚举
建议:如果定义不相干的常量,使用宏定义:如果需要定义一组相关的常量,使用枚举。以后正式开发switch的case后访问的就是枚举。
-
定义
我们一般情况下,定义常量使用宏定义(#define 红名称值),宏定义非常适合没有关联关系的常量;但是有时候我们可能需要对一组拥有关联关系的量进行定义,比如 ==周一周日、1月12月、方向(上下左右中)等,那么使用宏定义,就不是很清晰,这时就需要用到枚举。
枚举的存在就是将多个拥有关系的常量组合到一起,提高代码的可读性。
说明:
- 枚举类型定义了一组常量,我们在开发中直接使用这些常量。(常用)
- 当然枚举类型也可以类似于结构体一样定义变量等操作。(不常用)
- 枚举常量有默认值,从0开始依次+1;我们可以在定义时指定它的默认值,如果个别没有赋值,可以根据赋值依次+1推导。
特点:
定义了一组常量,类似于定义了多个自定义常量(宏定义)。
提供了代码的可读性。
定义语法:
定义枚举类型名以后就可以定义该枚举类型的变量
enum 枚举类型名 变星列表;
在定义枚举类型的同时定义该枚举类型的变量。
enum 枚举类型名{枚举元素列表}变星列表;
直接定义枚举变量
enum{枚举元素列表}变星列表;
案例
#include <stdio.h>
int main()
{// 定义一个枚举类型//枚举类型名一般首字母大写,主要是根枚举变量区分enum Week{//定义枚举元素,元素命名要符合标识符命名规则,同时采用大写字母+下划线方式命名SUN=10,MON,TUE,WED,THU,FRI,SAT};//直接访问枚举printf("%d,%d,%d\n",SUN,WED,SAT);// 定义枚举类型的变量(先定义变量,后赋值)enum Week week;week = TUE;printf("%d\n",week);//一定是这个枚举类型中定义的元素// 定义枚举类型变量的同时赋值(定义变量和赋值同时进行)enum Week week1 = THU;printf("%d\n",week);enum H{A,B,C//多个元素使用逗号分隔}x,y;x=B;y=C;printf("x=%d,y=%d\n",x,y);//1,2return 0;
}
typedef
说明:
给类型重命名,不会影响到类型本身
作用:给已有的类型起别名
格式:
typedef 已有类型名 新别名;
使用:
//方式一
//定义一个结构体类型
struct student
{int id;char *name;char sex;int age;
};
// 类型重命名
typedef struct Student Stu;
//定义结构体变量
struct Stu stu={1,"张”,'w',21};
//方式2
typedef struct PersonInfo
{int a;double b;
}Per;//结构体类型的别名,本质上还是数据类型
//定义变量
struct Per per = {2,5};
-
应用场景:
-
数据类型复杂(结构体、共用体、枚举、结构体指针、无符号的长整型)时使用
-
为了跨平台兼容性,例如:
1.size_t;类型重命名后的数据类型:typedef unsigned long size_t;
2.unit 16:类型重命名后数据类型
-
-
案例
#include<stdio.h> struct student {int age;char* name;double score; } int arr[3]; typedef struct student Stu_t; typedef Stu_t* pstu_t; void test1() {Stu_ts1={23,"zhangsan",23.33,{11,22,33}};printf("%d,%s,%f,%d\n",s1.age,s1.name, s1.score, s1.arr[0]);//Stu t *p = &s1;Stu t* p;p = &s1;pStu_t p2;p2 = P;printf("%d,%s,%f,%d\n",p2->age,p2->name,p2->score, p2->arr[0]); }
文件操作
概述
-
什么是文件?
文件是保存在外存储器(一般代指磁盘,U盘,移动硬盘等)的数据的集合。
-
文件操作体现在哪几个方面
1.文件内容的读取
2.文件内容的写入
数据的读取和写入可被视为针对文件进行输入(input)和输出(output)操作,此时数据像水流一样从外存储器流向内存,或者从内存流向外存储器,所以系统形象的成文件操作为文件流。
C语言程序对文件的操作采用“文件缓冲机制"。就是说在程序对文件的数据读写并不是直接操作文件中的数据,而是系统会为文件在内存中创建“文件缓冲区",程序对文件的操作,其实是在缓冲区进行的。
-
文件的分类
根据数据的存储方式划分:
文本文件(ASCII文件)
二进制文件
-
文件的标识
①文件系统中:路径+文件名,举例
d:/aaa/bbb.txt
②C语言程序中:文件指针(文件类型指针),语法:
FILE*指针变量名;
-
文件操作的步骤:
打开文件
文件处理(读写文件)
关闭文件
-
文件的操作
文件的打开与关闭
打开文件
打开文件,让系统为文件创建文件缓冲区
- 函数名:
fopen()
- 头文件:
#include <stdio.h>
- 函数原型:
FILE* fopen(const char *path,const char *mode
)` - 函数功能:打开文件,并为文件创建缓冲区
- 函数参数:
- "path:目标文件的路径
- mode:文件打开的方式(读-,写-w,读写-r+,二进制-读rb,二进制写-rw,附加-a)
- 返回值:
- 成功:返回文件指针FILE*(缓冲区首地址)
- 失败:返回NULL;
关闭文件
文件关闭,文件使用完毕,一定要释放内存
-
函数名:fclose
-
头文件:
#include<stdio.h>
-
函数原型:
int fclose(FILE *fP)
-
函数功能:
- fp:已经打开的文件指针
-
返回值:
- 成功:返回0
- 失败:返回EOE(-1)
#include <stdio.h> int main() {//在命令行执行./a.out的时候,传递一个需要打开的目录文件的地址if(argc<2){printf("输入有误,请按照<%s 文件路径>格式输入\n",argv[0]);return -1;}// 根据提供的文件路径,打开文件FILE* fp = fopen(argv[l],"1");//校验文件是否读取成功if(!fp){perror("文件打开失败\n");return -1;}puts("文件打开成功!\n");//关闭文件int ret = fclose(fp);if(ret==-1){perror("文件关闭失败");return -1;}puts("关闭成功"); }
文件的顺序读写
单字符读取
函数名:fgetc
头文件:#include <stdio.h>
函数原型::`int fgetc(FILE *fp);
函数功能:从fp代表的文件中获取一个字符
- 函数参数:
- fp我们需要操作的文件的指针
- 返回值:
- 成功:返回读取到的字符
- 失败:或者文件末尾,返回EOF(-1)
#include <stdio.h>
int main()
{//在命令行执行./a.out的时候,传递一个需要打开的目录文件的地址if(argc<2){printf("输入有误,请按照<%s 文件路径>格式输入\n",argv[0]);return -1;}// 根据提供的文件路径,打开文件FILE* fp = fopen(argv[l],"1");//校验文件是否读取成功if(!fp){perror("文件打开失败\n");return -1;}puts("文件打开成功!\n");int re =0;//char ch;while((re=fgetc(fp))!=-1)//while(ch=fgetc(fp)!=EOF)printf("%c\n",re);// printf("%c\n",re);//关闭文件int ret = fclose(fp);if(ret==-1){perror("文件关闭失败");return -1;}puts("关闭成功");
}
多字符读取
-
函数名:fgets0
-
头文件:
#include <stdio.h>
-
函数原型:
char*fgets(char *buf,int size,FILE* fp)
; -
函数功能:从如代表的文件中获取size个字符(size大小以字节为单位),放置在buf代表的内存中
-
函数参数:
- buf:内存空间首地址用于存放读取的字节
- size:待读取的字符,实际读取size
- fp:已经打开文件的指针
-
返回值:
- 成功:返回buf
- 失败:或者文件末尾,返回NULL
-
案例
#include <stdio.h> #include <string.h> int main() {//在命令行执行./a.out的时候,传递一个需要打开的目录文件的地址if(argc<2){printf("输入有误,请按照<%s 文件路径>格式输入\n",argv[0]);return -1;}// 根据提供的文件路径,打开文件FILE* fp = fopen(argv[l],"1");//校验文件是否读取成功if(!fp){perror("文件打开失败\n");return -1;}puts("文件打开成功!\n");char buf[64]={0};while((re=fgets(buf,64,fp))!=NULL){printf("%s\n",buf);memset(buf,0,sizeof(buf));}//关闭文件int ret = fclose(fp);if(ret==-1){perror("文件关闭失败");return -1;}puts("关闭成功"); }
单字符写入
- 函数名:fput
- 头文件:
#include<stdio.h>
- 函数原型:
int fputc(int c,FILE*fp)
; - 函数功能:向fp代表的文件中写入一个字符c
- 函数参数:
c:待写入的字符
fp:已打开的文件指针 - 返回值:
- 成功:返回字符c
- 失败:返回EOF(-1)
#include <stdio.h> #include <string.h> int main() {//在命令行执行./a.out的时候,传递一个需要打开的目录文件的地址if(argc<2){printf("输入有误,请按照<%s 文件路径 文本数据>格式输入\n",argv[0]);return -1;}// 根据提供的文件路径,打开文件FILE* fp = fopen(argv[l],"w");//校验文件是否读取成功if(!fp){perror("文件打开失败\n");return -1;}puts("文件打开成功!\n");//借助循环,一个字符一个字符写入while(*argv[2]!='\0'){fputc(*argv[2],fp);argv[2]++;}//关闭文件int ret = fclose(fp);if(ret==-1){perror("文件关闭失败");return -1;}puts("关闭成功"); }
多字符写入
-
函数名:fputs
-
头文件:
#include<stdio.h>
-
函数原型:
int fputs(int c,FILE*fp)
; -
函数功能:向fp代表的文件中写入一个字符数组buf[]
-
函数参数:
buf:待写入的字符数组
fp:已打开的文件指针 -
返回值:
- 成功:返回非负整数(>0)
- 失败:返回EOF(-1)
-
案例:
#include <stdio.h> #include <string.h> int main() {//在命令行执行./a.out的时候,传递一个需要打开的目录文件的地址if(argc<2){printf("输入有误,请按照<%s 文件路径 文本数据>格式输入\n",argv[0]);return -1;}// 根据提供的文件路径,打开文件FILE* fp = fopen(argv[l],"w");//校验文件是否读取成功if(!fp){perror("文件打开失败\n");return -1;}puts("文件打开成功!\n");//借助循环,一个字符一个字符写入fputs(fargv[2],fp);//关闭文件int ret = fclose(fp);if(ret==-1){perror("文件关闭失败");return -1;}puts("关闭成功"); }
综合案例
实现从a文件读取内容,写入到b文件
#include <stdio.h>
#include <string.h>
int main()
{//在命令行执行./a.out的时候,传递一个需要打开的目录文件的地址if(argc<3){printf("输入有误,请按照<%s 读文件路径 写文件路径>格式输入\n",argv[0]);return -1;}// 根据提供的文件路径,打开文件FILE* fp1 = fopen(argv[l],"1");FILE* fp2 = fopen(argv[2],"2");//校验文件是否读取成功if(!fp1||!fp2){perror("文件打开失败\n");return -1;}puts("文件打开成功!\n");char buf[64]={0};while((re=fgets(buf,64,fp1))!=NULL){//printf("%s\n",buf);fputs(buf,fp2);memset(buf,0,sizeof(buf));}//关闭文件int ret1 = fclose(fp1);int ret2 = fclose(fp2);if(ret1==-1||ret2==-1){perror("文件关闭失败");return -1;}puts("关闭成功");
}
判别文件结束
- 函数名:feof(fp)
- 头文件:
#include<stdio.h>
- 函数原型: int feof(fp);
- 函数功能:在读如指向的文件时判断是否遇到文件结束。
- 函数参数:
- fp:已打开文件的指针
- 返回值:
- 文件未读取完毕:返回0
- 文件已读取完毕:返回非0
数据块的读写
数据块的读取
- 函数名:fread
- 函数原型:
size_t fread(void* ptr,size_t size,size_t count,FILE* fp);
int arr[4] - 函数功能:从fp代表的文件中以字节为单位(一个数据块)读取count个数据块存放在内存中。
- 函数参数:
- ptr:内存空间首地址,用于存放读到的数据(任意类型缓冲数据)
- size:数据块大小,以字节为单位
- count:带读取的数据块的个数
- fp:已打开的文件指针
- 返回值:
- 成功:返回实际读取的字节数大小
- 失败:返回<0
数据块的写入
-
函数名: fwrite
-
函数原型:
size_t fwirte(const void* ptr,size_t size, FILE*fp)
-
函数功能:向fp代表的文件中以size为一个数据块写入count个数据块存放在内存中。
-
函数参数:
- ptr:内存空间首地址,用于存放写入的数据(任意类型缓冲数据)
- size:数据块大小,以字节为单位
- count:待写入的数据块的个数
- fp:已打开的文件指针
-
返回值:
-
成功:返回实际写入的字节数大小
-
失败:返回<0
- 写入文件
#include <stdio.h> #define SIZE 4//学生数量 //创建学生结构体 struct Student {char name[20];int num;int age;char addr[50] }stus[SIZE]; void save() {FILE *fp;int i;//打开文件if((fp=fopen("stu-list","wb"))==NULL)//wb二进制写入{perror("文件打开失败");return -1;}//写入数据for(i=0;i<SIZE;i++){fwrite(&stud[i],sizeof(struct Student),1,fp);}//关闭文件fclose(fp);return 0; } int main(int argc,char *argv[]) {int i;printf("请输入学生的信息:姓名,学号,年龄,住宅\n");for(i=0;i<SIZE;i++){scanf("%s%d%d%s",stus[i].name,&stus[i].num,&stus[i].age,stus[i].addr);save();} }
-
数据块的读
#include <stdio.h> #define SIZE 4//学生数量 //创建学生结构体 struct Student {char name[20];int num;int age;char addr[50] }stus[SIZE]; int main(int argc,char *argv[]) {int i;FILE*fp;if((fp = fopen("stu-list"."rb"))== NULL)//rb 以二进制读取{perror("文件打开失败!");return -1;}printf("请输入学生的信息:姓名,学号,年龄,住宅\n");for(i=0;i<SIZE;i++){fread(&stuslil,sizeof(struct student),1,fp);// 将读取的数据输出到控制台printf("%-10s%4d%4d%-20s\n",stus[i].name,stus[i].num,stus[i].age,stus[i].addr);fclose(fp);} }
-
文件的随机读写
-
说明:C语言允程序员在读写文件内容的时候,可以在指定位置上读写数据
-
文件随机读写的核心操作:文件位置指针的定位
-
文件位置指针移动方法:
-
rewind
-
头文件:
#include <stdio.h>
-
函数原型:
void rewind(FILE* fp)
; -
函数功能:将文件位置指针定位到文件开头
-
函数参数:
- fp:已经打开文件的指针
- 返回值:空类型
-
fseek
- 头文件:
#include <stdio.h>
- 函数原型:
int fseek(FILE* fp,long offset,int whence);
- 函数功能:将文件位置指针定位到指定位置
- 函数参数:
- fp:已经打开的文件的指针
- ofset:相对于参考位置的偏移量
- whence:参考位置
- SEEK_SET 或0:表示文件头
- SEEK_CUR 获1:表示当前读写的位置
- SEEK_END 或2:表示文件尾
- 返回值
- 成功:0
- 失败:-1
- 头文件:
-
ftell
- 头文件:
#include<stdio.h>
- 函数原型:
long ftell(FILE* fp)
; - 函数功能: 获取文件位置指针当前位置
- 头文件:
-
函数参数:
- fp:已经打开的文件的指针
-
返回值
-
成功:0
-
失败:-1
-
-
案例:
#include <stdio.h> /* *一个磁盘文件,第一次将它的内容通过控制台输出,第二次把它复制到另一个文件上。 */ int main() {if(argc<2){perror("请使用<%s 被读取文件 被写入文件>的方式!\n"}return -1;}//创建两个指针,用来接收打开的文件FILE *fp1,*fp2;fp1=fopen(argv[1],"r");fp2=fopen(argv[2],"w");// 第一次,读取文件内容通过控制台打印 while(!feof(fp1))putchar(getc(fp1));//输出到控制台//将指针指问文件的头,否则下次读取文件,会读取不到内容 rewind(fp1);// 第二次,读取文件内容将其拷贝至fp2对应的文件中while(!feof(fp1))putc(getc(fp1),fp2);//输出到文件//关闭文件fclose(fp1);fclose(fp2); }
案例二:
#include <stdio.h> #include <stdlib.h> //需求:在磁盘文件上存储10个学生的数据,要求第1,3,5,7,9个学生数据输入计算机,并在屏幕上显示出来。 typedef struct Student {char name[20];int num;int age;char sex; }Stu; //创建一个学生数组 Stu stu[10]={0}; int main() {int i;FILE *fp;//打开文件if((fp = fopen("stu-dat","rb"))==NULL){perror("文件打开失败!\n");return -1;}//循环录入for(i=0;i<10;i+=2){// 跳过对应位置,改变文件指针的指向7fseek(fp,i*sizeof(Stu),0);fread(&stu[i],sizeof(Stu),1,fp);//输出到控制台printf("%s,%d,%d,%c\n",stu[i].name,stu[i].num,stu [i].age,stu[i].sex);} }
案例:
#include <stdio.h> //下列c程序的功能是,用“追加"的形式打开文件gg.txt,查看文件读写指针的位置, //然后向文件写入“data",再查看文件读写指针的位置。 int main() {long p;FILE*fp;if((fp = fopen(argv[1],"a"))==NULL)//此时的mode:a代表追加(a是append){perror("文件打开失败!");return -1;}p=ftell(fp);printf("%ld",p);// 向文件添加数据fputs("data",fp);p = ftell(fp);printf("p=%ld\n",p);fclose(fp);return 0; }
-
/循环录入
for(i=0;i<10;i+=2)
{
// 跳过对应位置,改变文件指针的指向7
fseek(fp,i*sizeof(Stu),0);
fread(&stu[i],sizeof(Stu),1,fp);
//输出到控制台
printf(“%s,%d,%d,%c\n”,stu[i].name,stu[i].num,stu
[i].age,stu[i].sex);
}
}
案例:```c
#include <stdio.h>
//下列c程序的功能是,用“追加"的形式打开文件gg.txt,查看文件读写指针的位置,
//然后向文件写入“data",再查看文件读写指针的位置。
int main()
{long p;FILE*fp;if((fp = fopen(argv[1],"a"))==NULL)//此时的mode:a代表追加(a是append){perror("文件打开失败!");return -1;}p=ftell(fp);printf("%ld",p);// 向文件添加数据fputs("data",fp);p = ftell(fp);printf("p=%ld\n",p);fclose(fp);return 0;
}