[C]文件读写 与 外部函数的综合入门案例

*声明:文中给出的代码 往往 并非最佳解决方案,源于个人学习,仅供学习交流、抛砖引玉之用,请读者宽容看待,多多思考、多多突破。

*注:如遇安全性错误C4996可添加此行代码于文件头:#pragma warning(disable :4996)。

一、函数、类型 介绍 参考(相关权益归原作者所有):

C 文件读写 | 菜鸟教程 (runoob.com)

C typedef | 菜鸟教程 (runoob.com)

C 结构体 | 菜鸟教程 (runoob.com)

外部函数:同在项目源文件夹中的代码文件,其中的函数如有需要是可以互相调用的。

无前缀的函数如:int MAX(){......}默认等同于extern int MAX(){......},是可以被此目录下其他代码文件调用的,但请注意,为规范编写、便于维护和团队合作,请不要直接引用其他源文件中的函数!每个源文件应有一个对应的  同名.h头文件来  注明其函数接口,需要调用时应直接引入相应头文件再调用,这样可以让编译器辅助检查函数的一致性。如需要设定为内部函数则应写为:static int MAX(){......},此时便不可被调用。此外static还有很多其他用途,更多可参考:

extern 与头文件(*.h)的区别和联系 | 菜鸟教程 (runoob.com)

C 语言中 static 的作用 | 菜鸟教程 (runoob.com)

二、案例解决方案代码分享:

1、随机点名(分为两文件部分)

文件:AddData.c

#include <stdio.h>

void AddData(FILE* fp)
{
	int i;
	char InPut[52];
	printf("每条记录输入完后请回车以录入(最多999条数据!!)\n在“学号:”后输入“#”后回车结束录入\n");
	for (i = 0;; i++) {
		rewind(stdin);
		printf("\n学号(不超过50位):\n");
		fgets(InPut, 52, stdin); //fgets读入一行数据,会读入\n
		if (InPut[0] == '#')
			break;
		fputs(InPut, fp); //写入一整行数据,如果数组内有\n,会写入\n,没有则不添加
		printf("名字(不超过50位):\n");
		fgets(InPut, 52, stdin);
		fputs(InPut, fp);
	} //重复读取判断并对文件进行写入。
	fseek(fp, 0, 0); //写入完毕,指针回到开头。
	printf("已新增%d条数据。\n", i);
}

文件:main.c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

extern void AddData(FILE* fp); //声明从项目中另一个AddData.c文件引入的函数
typedef struct { //struct后一般要加类型名,此处对其整体进行了命名,所以并不必要,链表等结构体调用时需要使用此处类型名
	char num[51];//学号
	char name[51];//姓名
}Student; //自定义结构体并命名(命名用于方便书写类型名)

int NUM; //数据总条数
Student stud[500]; //用来存储数据
int RandomNUM(int list[])
{//数组的传递是传递第一个元素的地址,也可看作指向数组第一个元素的指针,不是值传递,所以最后数组会被改变,不用传回
	int random;
	srand((unsigned)time(NULL));
	do {
		random = rand() % NUM; //保证随机的学号在给定人数区间内1~(NUM-1)
	} while (list[random] != 0); //避免重复点名
	return (random);
}
void Tongj(int list[])
{
	for (int i = -1; i++ < NUM;) {
		if (list[i] != 2)
			continue; //是0或者1就跳过重新i++并判断,由于人数较多,只输出缺勤人员
		printf("%s%s", stud[i].num, stud[i].name); //输出人员信息
		printf("缺\n\n");
	}//如有需要 可以用循环判断+putchar避免输出字符串末尾的\n。而相反puts会自动多追加一个\n
}
int main()
{//a+表示直接在之前记录上追加、更新内容,无文件则创建;t表示以文本而非二进制格式读写,此命令会在文件目录下生成名为file.txt的文档来储存数据
	FILE* fp = fopen("file.txt", "a+t"); //如有更复杂的需求,可用fseek库函数指回开头或调整位置
	int list[500] = { 0 }, named = 0, random; //list相当于为所有数据重新对应了一个编号并储存统计信息
	while (1) {
		printf("开始点名?(添加记录请输入'g',输入其他直接开始)");
		if (getchar() == 'g')
			AddData(fp); //调用从项目中另一个AddData.c文件引入的函数
		else
			break;
	}
	for (NUM = 0; fgets(stud[NUM].num, 51, fp) && fgets(stud[NUM].name, 51, fp); NUM++);
	//读入所有数据并用n记录总数据条数fgets读取错误等会返回空指针即NULL(0)用于判断。
	do {
		random = RandomNUM(list);
		printf("学号:%s姓名:%s请报道!(1-到,2-没到,3-停止点名,输入其他重新随机)\n", stud[random].num, stud[random].name);
		rewind(stdin);
		switch (getchar()) {
		case '1':list[random] = 1; break;
		case '2':list[random] = 2; break;
		case '3':continue; //continue可以跳过下面的if统计,直接到while的判断,由于到/缺必然被赋值,所以不赋值看作直接结束用于while判断
		default:random = NUM; continue; //由于定义的RandomNUM函数取random时不会为NUM,此处借用来当while的判断符
		}
		if (++named == NUM) { //统计已点数据条数
			printf("已全部点完\n");
			Tongj(list); //输出统计结果
			return 0;
		}
	} while (list[random] != 0 || random == NUM);
	Tongj(list); //输出统计结果
	return 0;
}

*注:两文件同时创建并放在项目源目录下即可。也可将AddData中的函数直接放到main.c中运行。


总结:

文件读写对于一个程序来说是完成更复杂任务的重要功能,使程序操作逻辑更贴近使用场景,有着重要意义,应给予重视并熟练掌握。而外部函数的引用对模块化开发有着重要帮助,虽并不必须,但可以提升程序可读性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值