构造类型-枚举
建议:如果定义不相干的常量,使用宏定义:如果需要定义一组相关的常量,使用枚举。以后正式开发switch的case后访问的就是枚举。
-
定义
我们一般情况下,定义常量使用宏定义(#define 红名称值),宏定义非常适合没有关联关系的常量;但是有时候我们可能需要对一组拥有关联关系的量进行定义,比如 ==周一~周日、1月~12月、方向(上下左右中)等,那么使用宏定义,就不是很清晰,这时就需要用到枚举。
枚举的存在就是将多个拥有关系的常量组合到一起,提高代码的可读性。
说明:
- 枚举类型定义了一组常量,我们在开发中直接使用这些常量。(常用)
- 当然枚举类型也可以类似于结构体一样定义变量等操作。(不常用)
- 枚举常量有默认值,从0开始依次+1;我们可以在定义时指定它的默认值,如果个别没有赋值,可以根据赋值依次+1推导。
特点:
定义了一组常量,类似于定义了多个自定义常量(宏定义)。
提供了代码的可读性。
定义语法:
定义枚举类型名以后就可以定义该枚举类型的变量
c
enum 枚举类型名 变星列表;
在定义枚举类型的同时定义该枚举类型的变量。
c
enum 枚举类型名{枚举元素列表}变星列表;
直接定义枚举变量
c
enum{枚举元素列表}变星列表;
案例
c
#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,2
return 0;
}
typedef
说明:
给类型重命名,不会影响到类型本身
作用:给已有的类型起别名
格式:
c
typedef 已有类型名 新别名;
使用:
c
//方式一
//定义一个结构体类型
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:类型重命名后数据类型
-
-
案例
c#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)
c#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)
c
#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
-
案例
c#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)
c#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)
-
案例:
c#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文件
c
#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
- 写入文件
c#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(); } }
-
数据块的读
c#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
-
-
案例:
C#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); }
案例二:
c#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) { // 跳过对应位置,改变文件指针的指向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; }
-
/循环录入
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;
}