C语言项目篇:二、课程管理系统

         为加强对于C语言的巩固和复习,以实战项目为导向,串起所有C语言的语法,达到活学活用的目的,本篇博客,详细总结利用C语言编码简单编码实现生活中的课程管理系统后台开发的整个过程,学习多文件编程和调试,提高实际的编码开发能力。

目录

一、课程信息结构体设计

二、操作课程的功能函数设计

三、文件操作的函数功能设计

四、函数的具体实现

4.1  文件操作的函数具体实现

4.2  课程管理函数具体实现

五、主函数逻辑代码

六、项目完整代码


整个课程管理系统完成的主要功能如下图所示:

项目描述:

        实现一个简单的课程管理系统,课程的信息主要包括:课程编号、课程名称、授课教师、上课时间、上课地点,为贴近实际,课程信息数据会保存在如上的一个.txt文件中,这样断电后,数据不会丢失,对文件中的数据操作就要用到文件操作的相关知识,每次都是从文件中读取数据,对文件进行操作后,再向文件写入数据,实现永久性的对课程的增删改查。

一、课程信息结构体设计

      由上面的分析可知,描述课程信息主要包括5个结构体成员:课程编号、课程名称、授课教师、上课时间、上课地点,因此,设计如下:


#define MAXSIZE 50

typedef struct CourseInfo
{
	char Id[5];            //课程编号
	char CourseName[20];   //课程名称
	char TecherName[15];   //授课教师
	char CourseTime[40];   //上课时间
	char Address[5];       //上课地点
}CourseInfo;

//定义全局的课程信息数组和记录有效课程信息记录的变量

CourseInfo course[MAXSIZE];            //定义课程类型的结构体数组,初始大小为50
int cursize = 0;                      //表示当前的记录个数,数组中有效元素个数

二、操作课程的功能函数设计

根据需求分析,我们主要实现以下几个功能:

  1. 展示课程基本信息
  2. 增加课程
  3. 根据课程名称删除课程
  4. 根据课程名称修改课程
  5. 根据课程名称查找课程
//函数的声明,主要实现课程的增删改查
void listCourse();        //展示课程
void addCourse();        //增加课程
void deleteCourse();    //根据课程名称删除课程
void updateCourse();   //根据课程名称修改课程
int  findCourse();    //根据课程名称查找课程

三、文件操作的函数功能设计

     为实现数据的持久性保存,我们将课程的信息保存到文件中,因此,这便涉及到文件的操作,便需要我们实现以下两个功能:

  1. 从文件中读取数据到内存
  2. 内存向文件写入课程信息数据
//函数的声明
void loadDate(CourseInfo* c, int* cursize);        //将文件数据加载到内存
void saveDate(CourseInfo* c, int* cursize);        //将内存数据保存到文件

四、函数的具体实现

4.1  文件操作的函数具体实现

从文件中读取数据到内存的基本思路:

  1. 打开需要读取的文件
  2. 循环以逗号分隔的形式读取文件的记录数据存放到课程信息的结构体数组中
  3. 关闭文件
//1.将文件数据加载到内存
void loadDate(CourseInfo* c, int* cursize)  //传入结构体指针和记录有效数组元素个数变量的地址
{
	//1.打开文件
	FILE* fp = fopen("C:\\Users\\王恒\\Desktop\\courses.txt", "r");
	if (!fp)
	{
		printf("文件打开失败!\n");
		exit(-1);
	}

	//2.读取文件数据存放到内存(结构体数组)
	int i = 0;
	while (feof(fp) == 0)   //判断是否读取到文件的末尾
	{
		fscanf(fp, "%[^,],%[^,],%[^,],%[^,],%[^\n]\n", c[i].Id, c[i].CourseName, c[i].TecherName, c[i].CourseTime, c[i].Address); //fscanf 从文件中逐行读取数据并存储到结构体数组中
		i++;
	}
	*cursize = i;

	//3.关闭文件
	fclose(fp);
}

内存向文件写入课程信息数据(输出数据到文件)的基本思路:

  1. 打开需要写入数据的文件
  2. 将数据输出到文件
  3. 关闭文件
//2.将内存的数据保存到文件
void saveDate(CourseInfo* c, int* cursize)
{
	//1.打开文件
	FILE* fp = fopen("C:\\Users\\王恒\\Desktop\\courses.txt", "w");
	if (!fp)
	{
		printf("文件打开失败!\n");
		exit(-1);
	}

	int size = *cursize;

	//2.将数据写入文件
	for (int i = 0; i < size; i++)
	{
		fprintf(fp, "%s,%s,%s,%s,%s\n", c[i].Id, c[i].CourseName, c[i].TecherName, c[i].CourseTime, c[i].Address);
		fflush(fp);           //刷新缓冲区
	}

	//3.关闭文件
	fclose(fp);
}

4.2  课程管理函数具体实现

展示课程基本信息基本思路:

  1. 加载数据到内存(结构体数组)
  2. 对结构体数组的元素进行遍历打印
//初始化数据
bool status = false;   //标志位,只需要初始化一次
static void InitData() 
{
	if (!status)
	{
		loadDate(course,&cursize);
		status = true;
	}
}


//函数的具体实现
void listCourse()
{
	InitData();
	//从文件读数据到数组
	loadDate(course, &cursize);
	for (int i = 0; i < cursize; i++)
	{
		printf("%s    %-15s %-10s   %-10s     %-10s\n", course[i].Id, course[i].CourseName, course[i].TecherName, course[i].CourseTime, course[i].Address);
	}
	printf("\n");

}

增加课程的基本思路:

  1. 加载数据到内存(结构体数组)
  2. 输入增加的课程信息数据
  3. 将增加后的课程信息保存到文件中
void addCourse()
{
	InitData();   //初始化数据
	printf("请输入课程编号:\n");
	scanf("%s", course[cursize].Id);
	printf("请输入课程名称:\n");
	scanf("%s", course[cursize].CourseName);
	printf("请输入教师名称:\n");
	scanf("%s", course[cursize].TecherName);
	printf("请输入上课时间:\n");
	scanf("%s", course[cursize].CourseTime);
	printf("请输入上课地点:\n");
	scanf("%s", course[cursize].Address);
	cursize++;

	//将增加后的课程信息保存到文件中
	saveDate(course, &cursize);
	printf("\n");
	
}

根据课程名称删除课程基本思路:

  1. 加载数据到内存(结构体数组)
  2. 遍历结构体数组找该课程,进行数据元素的移动(删除)
  3. 将删除后的课程信息保存到文件中

 

void deleteCourse()
{
	InitData();            //初始化数据
	assert(cursize > 0);  //判空操作
	char s[20] = { 0 };
	printf("请输入需要删除的课程名称:\n");
	scanf("%s", s);

	//1.循环遍历找到该课程
	int i = 0;
	for (; i < cursize; i++)
	{
		if (strcmp(course[i].CourseName, s) == 0)
		{
			//2.进行数组元素覆盖
			for (int j = i + 1; j < cursize; j++)
			{
				course[j - 1] = course[j];         //结构体数组元素整体赋值
			}

			//利用内存拷贝函数进行元素删除
			/*memmove(course + i, course + i + 1, sizeof(CourseInfo) * cursize - 1 - i);
			memset(&course[cursize-1],0, sizeof(CourseInfo));  将最后一个数组元素清0*/  
			cursize--;
			printf("删除成功!\n");
			break;
		}
	}
	if (i == cursize)
	{
		printf("未找到该课程,删除失败!\n");
		printf("\n");
	}

	//将删除后的课程信息保存到文件中
	saveDate(course, &cursize);

}

根据课程名称修改课程基本思路:

  1. 加载数据到内存(结构体数组)
  2. 遍历结构体数组找该课程,输入需要修改的课程信息
  3. 将修改后的课程信息保存到文件中
void updateCourse()
{
	InitData();    //初始化数据
	assert(cursize > 0);  //判空操作
	//思路:先根据课程名称找到该课程,然后进行修改其中的成员变量
	int res=findCourse();
	if (res == -1)
	{
		printf("该课程不存在,无法修改!\n");
	}
	else
	{
		//找到了该课程,且下标为i,对该课程的信息进行修改(成员变量进行修改)
		printf("请输入需要修改的信息(1-4):1:修改课程编号,2:修改授课教师,3:修改上课时间,4:修改上课地点\n");
		int choice;
		char id[10] = {0};
		char teacher[10] = {0};
		char time[30] = {0};
		char address[10] = {0};
		scanf("%d", &choice);
		switch (choice)
		{
		case 1:
			printf("请输入新的课程编号:\n");
			scanf("%s", id);
			strcpy(course[res].Id, id);
			break;
		case 2:
			printf("请输入新的授课教师:\n");
			scanf("%s", teacher);
			strcpy(course[res].TecherName, teacher);
			break;
		case 3:   
			printf("请输入新的上课时间:\n");
			scanf("%s", time);
			strcpy(course[res].CourseTime, time);
			break;
		case 4:
			printf("请输入新的上课地点:\n");
			scanf("%s", address);
			strcpy(course[res].Address, address);
			break;
		default:
			printf("输入有误,请输入1-4");
		}
	}

	//将修改后的课程信息保存到文件中
	saveDate(course, &cursize);
}

根据课程名称查找课程基本思路:

  1. 加载数据到内存(结构体数组)
  2. 遍历结构体数组找该课程,输出课程信息
int  findCourse()
{
	InitData();    //初始化数据
	assert(cursize > 0);  //判空操作
	char coursename[10] = { 0 };
	printf("请输入需要查找的课程名称:\n");
	scanf("%s", coursename);
	//1.遍历结构体数组
	int i = 0;
	for (; i < cursize; i++)
	{
		if (strcmp(course[i].CourseName, coursename) == 0)
		{
			break;
		}
	}

    //2.条件判断
	if (i == cursize)
	{
		printf("不存在该课程!\n");
		return -1;
	}
	else
	{
		printf("该课程存在!\n");//找到该课程,打印该课程对应的信息
		printf("该课程编号为:%s,该课程授课教师为:%s,该课程上课时间为:%s,该课程上课地点为:%s",course[i].Id,course[i].TecherName,course[i].CourseTime,course[i].Address);
		printf("\n");
		return i;
	}
	
}

五、主函数逻辑代码

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h> 
#include"course.h"


//代码的主要逻辑

void printmenu()//菜单函数
{
	printf("   课程管理系统\n");
	printf("*****************\n");
	printf("   1.添加课程\n");
	printf("   2.删除课程\n");
	printf("   3.查看所有课程\n");
	printf("   4.根据课程名称搜索\n");
	printf("   5.修改课程信息\n");
	printf("   6.退出系统\n");
	printf("*****************\n");
	printf("\n");
}


int main()
{
	printmenu();
	while (1)
	{
		int choice;
		printf("请输入你的选择1-6:\n");
		scanf("%d", &choice);
		switch (choice)
		{
		case 1:
			addCourse();
			printmenu();
			break;
		case 2:
			deleteCourse();
			printmenu();
			break;
		case 3:
			listCourse();
			printmenu();
			break;
		case 4:
			findCourse();	 //根据课程名称查找课程
			printmenu();
			break;
		case 5:
			updateCourse();   //根据课程名称修改课程信息
			printmenu();
			break;
		case 6:
			printf("退出系统\n");
			break;
		default:
			printf("输入有误!请输入1-6\n");
		}
	}
	return 0;
}

六、项目完整代码

course.h

#pragma once
#ifndef COURSE_H
#define COURSE_H


#define MAXSIZE 50


typedef struct CourseInfo
{
	char Id[5];
	char CourseName[20];
	char TecherName[15];
	char CourseTime[40];
	char Address[5];
}CourseInfo;


//函数的声明,主要实现课程的增删改查

void listCourse();        //展示课程
void addCourse();        //增加课程
void deleteCourse();    //根据课程名称删除课程
void updateCourse();   //根据课程名称修改课程
int findCourse();    //根据课程名称查找课程

#endif

course.c

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <stdbool.h>   //C语言引入bool类型的头文件
#include "course.h"
#include "fileop.h"
#include <assert.h>
#include <stdlib.h>


//定义全局结构体数组和记录有效数组元素个数的变量
CourseInfo course[MAXSIZE];           //定义课程类型的结构体数组,初始大小为50
int cursize = 0;                      //表示当前的记录个数,数组中有效元素个数

//初始化数据
bool status = false;  //全局变量
static void InitData()  //加static修饰函数,其他文件无法进行调用
{
	if (!status)
	{
		loadDate(course,&cursize);
		status = true;
	}
}

//函数的具体实现
void listCourse()
{
	InitData();
	//从文件读数据到数组
	loadDate(course, &cursize);
	for (int i = 0; i < cursize; i++)
	{
		printf("%s    %-15s %-10s   %-10s     %-10s\n", course[i].Id, course[i].CourseName, course[i].TecherName, course[i].CourseTime, course[i].Address);
	}
	printf("\n");

}


void addCourse()
{
	InitData();   //初始化数据
	printf("请输入课程编号:\n");
	scanf("%s", course[cursize].Id);
	printf("请输入课程名称:\n");
	scanf("%s", course[cursize].CourseName);
	printf("请输入教师名称:\n");
	scanf("%s", course[cursize].TecherName);
	printf("请输入上课时间:\n");
	scanf("%s", course[cursize].CourseTime);
	printf("请输入上课地点:\n");
	scanf("%s", course[cursize].Address);
	cursize++;

	//将增加后的课程信息保存到文件中
	saveDate(course, &cursize);
	printf("\n");
	
}


void deleteCourse()
{
	InitData();            //初始化数据
	assert(cursize > 0);  //判空操作
	char s[20] = { 0 };
	printf("请输入需要删除的课程名称:\n");
	scanf("%s", s);

	//1.循环遍历找到该课程
	int i = 0;
	for (; i < cursize; i++)
	{
		if (strcmp(course[i].CourseName, s) == 0)
		{
			//2.进行数组元素覆盖
			for (int j = i + 1; j < cursize; j++)
			{
				course[j - 1] = course[j];         //结构体数组元素整体赋值
			}

			//利用内存拷贝函数进行元素删除
			/*memmove(course + i, course + i + 1, sizeof(CourseInfo) * cursize - 1 - i);
			memset(&course[cursize-1],0, sizeof(CourseInfo));  将最后一个数组元素清0*/  
			cursize--;
			printf("删除成功!\n");
			break;
		}
	}
	if (i == cursize)
	{
		printf("未找到该课程,删除失败!\n");
		printf("\n");
	}

	//将删除后的课程信息保存到文件中
	saveDate(course, &cursize);

}


void updateCourse()
{
	InitData();    //初始化数据
	assert(cursize > 0);  //判空操作
	//思路:先根据课程名称找到该课程,然后进行修改其中的成员变量
	int res=findCourse();
	if (res == -1)
	{
		printf("该课程不存在,无法修改!\n");
	}
	else
	{
		//找到了该课程,且下标为i,对该课程的信息进行修改(成员变量进行修改)
		printf("请输入需要修改的信息(1-4):1:修改课程编号,2:修改授课教师,3:修改上课时间,4:修改上课地点\n");
		int choice;
		char id[10] = {0};
		char teacher[10] = {0};
		char time[30] = {0};
		char address[10] = {0};
		scanf("%d", &choice);
		switch (choice)
		{
		case 1:
			printf("请输入新的课程编号:\n");
			scanf("%s", id);
			strcpy(course[res].Id, id);
			break;
		case 2:
			printf("请输入新的授课教师:\n");
			scanf("%s", teacher);
			strcpy(course[res].TecherName, teacher);
			break;
		case 3:   
			printf("请输入新的上课时间:\n");
			scanf("%s", time);
			strcpy(course[res].CourseTime, time);
			break;
		case 4:
			printf("请输入新的上课地点:\n");
			scanf("%s", address);
			strcpy(course[res].Address, address);
			break;
		default:
			printf("输入有误,请输入1-4");
		}
	}

	//将修改后的课程信息保存到文件中
	saveDate(course, &cursize);
}


int  findCourse()
{
	InitData();    //初始化数据
	assert(cursize > 0);  //判空操作
	char coursename[10] = { 0 };
	printf("请输入需要查找的课程名称:\n");
	scanf("%s", coursename);
	//1.遍历结构体数组
	int i = 0;
	for (; i < cursize; i++)
	{
		if (strcmp(course[i].CourseName, coursename) == 0)
		{
			break;
		}
	}

    //2.条件判断
	if (i == cursize)
	{
		printf("不存在该课程!\n");
		return -1;
	}
	else
	{
		printf("该课程存在!\n");//找到该课程,打印该课程对应的信息
		printf("该课程编号为:%s,该课程授课教师为:%s,该课程上课时间为:%s,该课程上课地点为:%s",course[i].Id,course[i].TecherName,course[i].CourseTime,course[i].Address);
		printf("\n");
		return i;
	}
	
}

fileop.h

#pragma once
#ifndef FILE_OP_H
#define FILE_OP_H


#include"course.h"

//函数的声明
void loadDate(CourseInfo* c, int* cursize);        //将文件数据加载到内存
void saveDate(CourseInfo* c, int* cursize);        //将内存数据保存到文件
#endif 

fileop.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"fileop.h"

#include<stdlib.h>
#include<stdio.h>   //写在.c文件中


//函数的具体实现

//1.将文件数据加载到内存
void loadDate(CourseInfo* c, int* cursize)  //传入结构体指针和记录有效数组元素个数变量的地址
{
	//1.打开文件
	FILE* fp = fopen("C:\\Users\\王恒\\Desktop\\courses.txt", "r");
	if (!fp)
	{
		printf("文件打开失败!\n");
		exit(-1);
	}

	//2.读取文件数据存放到内存(结构体数组)
	int i = 0;
	while (feof(fp) == 0)   //判断是否读取到文件的末尾
	{
		fscanf(fp, "%[^,],%[^,],%[^,],%[^,],%[^\n]\n", c[i].Id, c[i].CourseName, c[i].TecherName, c[i].CourseTime, c[i].Address); //fscanf 从文件中逐行读取数据并存储到结构体数组中
		i++;
	}
	*cursize = i;

	//3.关闭文件
	fclose(fp);
}


//2.将内存的数据保存到文件
void saveDate(CourseInfo* c, int* cursize)
{
	//1.打开文件
	FILE* fp = fopen("C:\\Users\\王恒\\Desktop\\courses.txt", "w");
	if (!fp)
	{
		printf("文件打开失败!\n");
		exit(-1);
	}

	int size = *cursize;

	//2.将数据写入文件
	for (int i = 0; i < size; i++)
	{
		fprintf(fp, "%s,%s,%s,%s,%s\n", c[i].Id, c[i].CourseName, c[i].TecherName, c[i].CourseTime, c[i].Address);
		fflush(fp);
	}

	//3.关闭文件
	fclose(fp);
}

     至此,整个项目就结束了,可以看出项目的整体逻辑比较简单,可以用来训练我们的编码逻辑思维,逐步训练就可以达到实际开发的高度!如果喜欢,点赞加关注!

  • 23
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未来可期,静待花开~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值