一个比较规范的C语言多文件编程的例子
学习完C语言的基本课程,很多老师都会布置一个大作业,让同学们编写出学生信息管理系统。学生信息管理系统可以用来管理班级学生,对学生信息(包括姓名、性别、年龄、成绩等)进行增加、删除、更改、查询等操作。
该系统主要有两种实现方案:
- 第一种将学生信息直接保存在二进制文件中,当需要查询或者更新时,要能够使用文件操作函数精确定位学生信息;
- 第二种使用数据结构中的链表,将学生信息暂时缓存在链表,如果有变化,才更新到文件。
本节我们以第一种方案为例,搭建起学生信息管理系统的框架,将前面几节的知识综合运用起来。
创建一个文件夹,命名为 StuInfo,并添加以下几个文件:
可以看到,
- 我们将所有的头文件放在了 include 目录,
- 将所有的源文件放在了 module 目录,
- 而 main.c 作为主模块,直接放在了 StuInfo 目录。
下面是对各个文件的说明:
1) main.c
程序主模块,执行入口,会调用其他模块中的函数。
2) stu.c 和 stu.h
该模块包含了程序的大部分代码,实现了对学生信息的增删改查操作。
3) tools.c 和 tools.h
包含了一些通用的函数,比如文件复制、获取文件大小、数据插入、数据删除等与文件操作有关的函数(在《C语言文件操作》一章已经对它们进行了实现),这些函数不仅可以用于当前项目,也可以不加修改地移植到其他项目,通用性很强,不妨将它们称为工具型函数。
4) vars.c 和 vars.h
定义了一些全局变量。比如文件指针 fp、学生总数、文件长度等。
5) config.h
配置文件,几乎都是宏定义,比如规定了学号的最大值、姓名的最大长度、成绩的最大值、文件路径等。
下面给出了每个文件包含的简略代码。由于本节仅仅是演示,所以下面的代码不完整,我们将在《C语言项目实践》中讲解学生信息管理系统的具体编码。
main.c 源码:
#include <stdio.h> #include <stdlib.h> #include "./include/config.h" #include "./include/stu.h" #include "./include/vars.h" int main(){ init(); //addStuInfo(); //deleteStuInfo(); //findStuByID(); //findStuByName(); fclose(fp); return 0; }
stu.c 源码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "../include/config.h" #include "../include/stu.h" #include "../include/tools.h" #include "../include/vars.h" //初始化 void init(){ //打开文件 if( (fp=fopen(FILENAME, "rb+")) == NULL && (fp=fopen(FILENAME, "wb+")) == NULL ){ pause("Error on open %s file!", FILENAME); exit(EXIT_FAILURE); } //获取文件长度 fileSize = getFileSize(fp); } //添加学生信息 void addStuInfo(){ //finsert(fp, nPreEleCount*stuSize, &stu, stuSize); pause("提示:添加成功!按任意键返回..."); } //删除学生信息 void deleteStuInfo(){ //fdelete(fp, index*stuSize, stuSize); pause("提示:删除成功,按任意键返回..."); } //修改学生信息 void alterStuInfo(){ //fwrite(&stu, stuSize, 1, fp); pause("提示:修改成功,按任意键返回..."); } //根据学号查询学生信息 void findStuByID(){ pause("错误:该学生信息不存在,查询失败!按任意键返回..."); } //根据姓名查询学生信息 void findStuByName(){ pause("错误:没有查询到相关记录!按任意键返回..."); } //根据成绩查询学生信息 void findStuByScores(){ pause("错误:没有查询到相关记录!按任意键返回..."); } //显示所有学生信息 void showAllStu(){ pause("\n共有%d条学生信息,按任意键返回...", n); }
stu.h 源码:
#ifndef _STU_H #define _STU_H //学生信息结构体 typedef struct _STU{ int id; //学号 char name[20]; //姓名 char sex[4]; //性别 int age; //年龄 float math; //数学成绩 float cn; //语文成绩 float en; //英语成绩 }STU; //初始化 extern void init(); //学生信息增删改查 extern void addStuInfo(); extern void deleteStuInfo(); extern void alterStuInfo(); extern void findStuByID(); extern void findStuByName(); extern void findStuByScores(); extern void showAllStu(); #endif
tools.c 源码:
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <conio.h> #include <stdarg.h> //获取文件大小(以字节计) long getFileSize(FILE *fp){ long fsize; //TODO: return fsize; } //文件复制函数 long fcopy(FILE *fSource, long offsetSource, long len, FILE *fTarget, long offsetTarget){ long nBytes = 0; //总共复制了多少个字节 //TODO: return nBytes; } //向文件中插入内容 int finsert(FILE *fp, long offset, void *buffer, int len){ //TODO: return 0; } //从文件中删除内容 int fdelete(FILE *fp, long offset, int len){ //TODO: return 0; } //暂停程序 void pause(const char *str, ...){ va_list vl; char buf[500] = {0}; va_start(vl, str); vsnprintf(buf, 500, str, vl); va_end(vl); printf(buf); getch(); printf("\n"); }
tools.h 源码:
#ifndef _TOOLS_H #define _TOOLS_H extern long getFileSize(FILE *fp); //获取文件大小 extern long fcopy(FILE *fSource, long offsetSource, long len, FILE *fTarget, long offsetTarget); //文件内容复制 extern int finsert(FILE *fp, long offset, void *buffer, int len); //向文件中插入数据 extern int fdelete(FILE *fp, long offset, int len); //删除文件内容 extern void pause(const char *str, ...); //暂停程序 #endif
vars.c 源码:
FILE *fp = NULL; //文件指针 int stuCount = 0; //总共有多少条学生信息 long fileSize = 0; //文件长度(占用的字节数)
vars.h 源码:
#ifndef _VARS_H #define _VARS_H extern FILE *fp; extern int stuCount; extern long fileSize; #endif
config.h 源码:
#ifndef _CONFIG_H #define _CONFIG_H #define FILENAME "stu.data" //保存学生信息的文件名称(含路径) #define MAX_STU_ID 99 //学号的最大值 #define MAX_STU_NAME 10 //姓名的最大长度 #define MAX_STU_AGE 100 //年龄的最大值 #define MAX_STU_MATH 150 //数学成绩的最大值 #define MAX_STU_EN 150 //英语成绩的最大值 #define MAX_STU_CN 150 //语文成绩的最大值 #endif