若定义不相关的常量使用宏定义;若定义一组相关的常量使用枚举。switch中case后访问的就是枚举。
定义:
我们一般情况下定义常量使用宏定义(#define),宏定义适合没有关联关系的常量;但有时需要对一组有关联关系的量进行定义,例如:星期、月份、方向(上下左右中)等,若使用宏定义,可读性差,这时使用枚举。
说明
特点:
定义一组常量,类似于定义了多个自定义常量(宏定义)
提供了代码的可读性
语法
//定义枚举类型名以后可以定义该枚举类型的变量
enum 枚举类型名 变量列表;
//定义枚举类型的同时定义该枚举类型的变量
enum 枚举类型名{枚举元素列表} 变量列表;
//直接定义枚举变量
enum {枚举元素列表} 变量列表;
enum Week
{
//定义枚举元素
SUN = 10,MON,TUE,WED,THU,FRI,SAT
};
//访问枚举元素
printf("%d,%d,%d\n",SUN,WED,SAT);
//定义枚举类型变量(先定义,后赋值)
enum Week week;
//初始化
week = TUE;
//定义枚举变量同时赋值
enum Week week1 =THU;
说明:给类型重命名,不会影响类型本身
作用:给已有的类型起别名
格式:
//先定义结构体类型,再重命名
typedef 已有类型名 新别名;
struct Student
{
int id;
char name[20];
char sex;
};
//类型重命名
typedef struct Student Stu;
//定义结构体变量
struct Stu stu = {1,"张三",'M'};
//定义结构体的同时重命名
typedef struct PersonInfo
{
int a;
double b;
} Per;//结构体的别名,本质上还是数据类型
struct Per per = {1,5};
应用场景:
typedef unsigned long size_t
什么是文件
文件是保存在外存储器(U盘,移动硬盘)的数据的集合。
文件操作体现在哪几个方面
数据的读取和写入可被视为针对文件进行输入(Input)和输出(Output)操作,此时数据像水流一样从外存储器流向内存。或者从内存流向外存储器,所以系统形象的称文件操作为文件流。
C语言程序对文件的操作采用"文件缓存机制"。就是说在程序对文件的数据读写并不是直接操作文件中的数据,而是系统会为文件在内存中创建"文件缓冲区",程序对文件的操作,其实是在缓冲区进行。
文件的分类
文件的标识
E:\YQ\code\Homework\20241217
文件操作的步骤:
打开文件,让系统为文件创建文件缓冲区
函数名:fopen()
头文件:#inculde
函数原型:FILE* fopen(const char *path,const char *mode);
函数功能:打开文件,并为文件创建缓冲区
形参
path:目标文件的路径
mode:文件打开的方式(r-读、w-写、re-读写)
type | 读写性 | 文本/进制文件 | 新建/打开 |
---|---|---|---|
r | 读 | 文本 | 打开文件 |
w | 写 | 文本 | 新建文件 |
a | 添加 | 文本 | 有就打开无则建新 |
r+ | 读写 | 无限制 | 打开 |
w+ | 读写 | 无限制 | 建新文件 |
a+ | 读写添加 | 无限制 | 有就打开无则建新 |
返回值
文件关闭,文件使用完毕,一定要释放内存
#inculde
int fclose(FILE* fp);
#include
int main(int argc, char *argv[])
{
// 在命令行执行./a.out的时候,传递一个需要打开的目录文件的地址
if (argc < 2)
{
printf("输入有误,请按照<%s文件路径>格式输入\n", argv[0]);
return -1;
}
// 根据文件路径打开文件
FILE *fp = fopen(argv[1], "r");
// 校验文件是否读取成功
if (!fp)
{
perror("文件打开失败!");
return -1;
}
puts("文件打开成功!\n");
int ret = fclose(fp);
if (ret == -1)
perror("文件关闭失败");
puts("文件关闭成功");
return 0;
}
#inculde
int fgetc(FILE* fp);
方式一(ASCII码)
#include
int main(int argc, char *argv[])
{
// 在命令行执行./a.out的时候,传递一个需要打开的目录文件的地址
if (argc < 2)
{
printf("输入有误,请按照<%s文件路径>格式输入\n", argv[0]);
return -1;
}
// 根据文件路径打开文件
FILE *fp = fopen(argv[1], "r");
// 校验文件是否读取成功
if (!fp)
{
perror("文件打开失败!");
return -1;
}
char re = 0;
// 循环读取文件中所有字符
while ((re = fgetc(fp)) != -1)
{
printf("%c", re);
}
puts("文件打开成功!\n");
int ret = fclose(fp);
if (ret == -1)
perror("文件关闭失败");
puts("文件关闭成功");
return 0;
}
方式二(ASCII值)
#include
int main(int argc, char *argv[])
{
// 在命令行执行./a.out的时候,传递一个需要打开的目录文件的地址
if (argc < 2)
{
printf("输入有误,请按照<%s文件路径>格式输入\n", argv[0]);
return -1;
}
// 根据文件路径打开文件
FILE *fp = fopen(argv[1], "r");
// 校验文件是否读取成功
if (!fp)
{
perror("文件打开失败!");
return -1;
}
int re = 0;
// 循环读取文件中所有字符
while ((re = fgetc(fp)) != EOF)
{
printf("%c", re);
}
puts("文件打开成功!\n");
int ret = fclose(fp);
if (ret == -1)
perror("文件关闭失败");
puts("文件关闭成功");
return 0;
}
#inculde
char *fgets(char *buf,int size,FILE *fp)
案例:
#include
#include
int main(int argc, char *argv[])
{
// 在命令行执行./a.out的时候,传递一个需要打开的目录文件的地址
if (argc < 2)
{
printf("输入有误,请按照<%s文件路径>格式输入\n", argv[0]);
return -1;
}
// 根据文件路径打开文件
FILE *fp = fopen(argv[1], "r");
// 校验文件是否读取成功
if (!fp)
{
perror("文件打开失败!");
return -1;
}
char ch[64] = {0};
// 循环读取文件中所有字符
while (fgets(ch, 64, fp) != NULL)
{
printf("%s", ch);
memset(ch, 0, sizeof(ch));
}
puts("文件打开成功!\n");
int ret = fclose(fp);
if (ret == -1)
perror("文件关闭失败");
puts("文件关闭成功");
return 0;
}
#inculde
int fputc(int c,FILE* fp);
#include
#include
int main(int argc, char *argv[])
{
// 在命令行执行./a.out的时候,传递一个需要打开的目录文件的地址
if (argc < 3)
{
printf("输入有误,请按照<%s 文件路径 文本数据>格式输入\n", argv[0]); // ./a.out./ demo01.c hello return -1;
}
// 根据提供的文件路径,打开文件(mode:r,w,rw)
FILE *fp = fopen(argv[1], "w");
// 校验文件是否读取成功
if (!fp)
{
perror("文件打开失败!\n");
return -1;
}
puts("文件打开成功!");
// 单字符写入
// 借助循环,一个字符一个字符写入
while (*argv[2] != '\0')
{
fputc(*argv[2], fp); //
argv[2]++; // 指针偏移
}
// 关闭打开的文件
int ret = fclose(fp);
if (ret == -1)
{
perror("文件关闭失败!");
return -1;
}
puts("文件关闭成功!");
return 0;
}
#inculde
int fputs(const char* buf,FILE* fp);
/**
* 多字符写入
*/
#include
int main(int argc, char **argv)
{
if (argc < 3)
{
printf("输入有误,请按照<%s 文件路径 文本数据>格式输入\n", argv[0]);
return -1;
}
FILE *fp = fopen(argv[1], "w");
if (!fp)
{
perror("文件打开失败!");
return -1;
}
// 单字符写入
// ./a.out file1.txt I_Love_Your
fputs(argv[2], fp);
fclose(fp);
return 0;
}
#include
#include
int main(int argc, char *argv[])
{
// 在命令行执行./a.out的时候,传递一个需要打开的目录文件的地址
if (argc < 2)
{
printf("输入有误,请按照<%s 被读文件路径 被写文件路径>格式输入\n", argv[0]); // ./a.out./ demo01.c return -1;
}
// 根据提供的文件路径,打开文件(mode:r,w,rw)
FILE *fp_r = fopen(argv[1], "r");
FILE *fp_w = fopen(argv[2], "w");
// 校验文件是否读取成功
if (!fp_r || !fp_w)
{
perror("文件打开失败!\n");
return -1;
}
puts("文件打开成功!");
// 创建一个缓冲区(也就是每次读取字节的大小)
char buf[64] = {0};
// 循环读取文件中所有字符
while (fgets(buf, 64, fp_r) != NULL)
{
// 写入文件
fputs(buf, fp_w);
// 每读取一次,都需要清空缓冲区
memset(buf, 0, sizeof(buf));
}
// 关闭打开的文件
int ret1 = fclose(fp_r);
int ret2 = fclose(fp_w);
if (ret1 == -1 || ret2 == -1)
{
perror("文件关闭失败!");
return -1;
}
puts("文件关闭成功!");
return 0;
}
#inculde
int feof(FILE* fp);
函数名:fread
函数原型:size_t fread(void *ptr,size_t size,size_t count,FILE *fp);
函数功能:从fp指向的文件中以字节为单位(一个数据块)读取count个数据块存放在内存中
形参
返回值
#include
#define SIZE 2
struct Student
{
char name[20];
int num;
int age;
char address[50];
} stus[SIZE];
/*
保存学生信息到文件
*/
int save()
{
FILE *fp;
int i;
if ((fp = fopen("stu", "wb")) == NULL) // stu保存文件的名称
{
perror("文件打开失败!");
return -1;
}
// 写入数据
for (i = 0; i < SIZE; i++)
{
fwrite(&stus[i], sizeof(struct Student), 1, fp);
}
// 关闭文件
fclose(fp);
return 0;
}
int main()
{
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].address);
// 保存文件
}
save();
return 0;
}
size_t fwrite(const void *ptr,size_t size,size_t count,FILE *fp);
#include
#define SIZE 2 // 存放学生的个数
// 创建学生结构体
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", "rb")) == NULL) // rb 以二进制读取
{
perror("文件打开失败!");
return -1;
}
// 循环读取二进制读取
for (i = 0; i < SIZE; i++)
{
fread(&stus[i], 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);
return 0;
}
说明:C语言允许在读写文件内容时,可在指定位置上读写数据
文件随机读写的核心操作:文件位置指针的定位
文件位置指针移动方法:
rewind
#include
void rewind(FILE *fp);
#include
/*
有一个磁盘文件第一次将他内容通过控制台输出
第二次将其复制到另一个文件
*/
int main()
{
// 创建两个指针,用来接收打开的文件
FILE *fp1, *fp2;
// 校验
if (!fp1 && !fp2)
{
perror("文件打开失败!");
return -1;
}
puts("文件打开成功!\n");
// 打开文件
fp1 = fopen("1.txt", "r");
fp2 = fopen("2.txt", "w");
// 第一次,读取文件内容通过控制台打印
while (!feof(fp1)) // feof函数检测文件是否读完
{
putchar(getc(fp1));
}
rewind(fp1);
// 第二次,读取文件内容将其拷贝至2.txt
while (!feof(fp1))
{
putc(getc(fp1), fp2);
}
fclose(fp1);
fclose(fp2);
return 0;
}
fseek
头文件:#include
函数原型: int fseek(File *fp,long offset,int whence);
函数功能:将文件位置指针定位到指定位置
形参
fp:已打开的文件的指针
offset:相对参考位置的偏移量
whence:参考位置
SEEK_SET或0:表示文件头
SEEK_CUR或1:表示当前读写位置
SEEK_END或2:表示文件尾
返回值:
成功:0
失败:-1
#include
#include
/*
在磁盘文件上存储10个学生的数据
要求1,3,5,7,9这五个学生信息输入计算机,并显示
*/
// 定义学生结构体
struct Student
{
char name[20];
int id;
char sex;
};
typedef struct Student Stu;
Stu stus[3] = {0};
int main()
{
FILE *fp = NULL;
int len = sizeof(stus) / sizeof(stus[0]);
printf("%d", len);
// 写入数据
if ((fp = fopen("stu", "wb")) == NULL) // stu保存文件的名称
{
perror("文件打开失败!");
return -1;
}
printf("请输入学生的信息:姓名、学号、性别\n");
for (int i = 0; i < len; i++)
{
scanf("%s%d %c", stus[i].name, &stus[i].id, &stus[i].sex);
}
fwrite(stus, sizeof(Stu), len, fp);
fclose(fp); // 关闭文件
// 打开文件
if ((fp = fopen("stu", "rb")) == NULL)
{
perror("文件打开失败!");
return -1;
}
for (int i = 0; i < len; i += 2)
{
// 跳过文件位置,改变文件指针的指向
fseek(fp, i * sizeof(Stu), 0);
fread(&stus[i], sizeof(Stu), 1, fp);
printf("%s %d %c\n", stus[i].name, stus[i].id, stus[i].sex);
}
fclose(fp);
return 0;
}
ftell
#include
long ftell(FILE* fp);
#include
int main(int argc, char *argv[])
{
long p;
FILE *fp;
if ((fp = fopen(argv[1], "a")) == NULL) // 此时的mode:a代表追加(a是append)
{
perror("文件打开失败!");
return -1;
}
// 获取当前位置
p = ftell(fp);
printf("p=%ld\n", p);
// 向文件添加数据
fputs("data", fp);
p = ftell(fp);
printf("p=%ld\n", p);
fclose(fp);
return 0;
}