C语言航空订票系统课程设计


目录

1.设计目的:

2总体设计和功能:

3.菜单设计

4.各功能代码详解(闲话少扯):

4.1.C语言文件的操作:

4.2.读取航班信息:

C语言知识回顾 

4.3.打印航班信息

5.根据要求查找航班(航班号、起点站、终点站)

扫描二维码关注公众号,回复: 8838895 查看本文章

6.订票功能(链表操作)


前言:最经做了一个课程设计,设计的内容就是航空订票系统,又认真复习了一遍c语言的知识,感觉这个设计对于初学者来说,C的能力和逻辑能力会有一个提升,为了更好的总结自己学习的成果,故写下此篇博客记录一下该课程设计的重点知识,以便以后回顾。


1.设计目的:

1.  数据结构课程设计是综合运用数据结构课程中学到的几种典型数据结构,以及程序设计语言(C语言),自行实现一个较为完整的应用系统的设计与开发

2.  通过课程设计,自己通过系统分析、系统设计、编程调试,写实验报告等环节,进一步掌握应用系统设计的方法和步骤,灵活运用并深刻理解典型数据结构在软件开发中的应用 。

3.  学会将知识应用于实际的方法,提高分析和解决问题的能力,增加综合能力。

  航空订票系统:

(1)熟练掌握链表存储结构及其建立过程和常用操作;

(2)熟练掌握队列的建立过程和常用操作;

(3)学会自己调试程序的方法并掌握一定的技巧。

2总体设计和功能:

通过此系统可以实现如下功能:

  1. 读取磁盘的航班信息和客户订票信息(通过C语言的FILE功能)。
  2. 显示航线信息:可以显示在磁盘读入的航班信息。
  3. 显示客户信息:可以查询的客户信息包括,在磁盘文件读入的客户信息和通过 系统订票的客户信息。
  4. 查询各航线信息:可以通过三种方式去查询一个航线的信息,第一:通过航班 号,第二:通过起点查询;第三:通过终点站查询航班信息。
  5. 订票功能:用户可以在系统进行订票,订票需要输入客户的、航班号、身份证 号码、客户姓名、仓位等级进行预定。
  6. 退票功能:退票功能,需要客户提供需要退票的航班号进行查询,然后输入客 户姓名,系统查询到此客户信息退票成功,否则失败。

3.菜单设计

3.1主菜单代码如下:

int main()
{
	int sel;
	readinfo(&L);
	readinfo_book(&B);
	InitOrder();
	while (1)
	{
		printf("\n\n\n\n");
		printf("\t欢迎进入航班订票系统\n");
		printf("*****************************\n");
		printf("*       航空订票客运系统    *\n");
		printf("*      1.显示各航线信息     *\n");
		printf("*      2.查询各航线信息     *\n");
		printf("*      3.订          票     *\n");
		printf("*      4.退          票     *\n");
		printf("*      0.退  出  系  统     *\n");
		printf("*****************************\n");
		printf("请 选 择(0-4):\n");
		scanf("%d", &sel);
		switch (sel)
		{
		case 1:meau1(); break;//选择菜单1
		case 2:meau2(); break;//选择菜单2
		case 3:orderTicket(); break;//订票
		case 4:refund_ticket(); break;//退票
		case 0:return;//退出程序
		default:printf("输入错误\n"); break;
		}
	}

 界面如下:

主程序是整个系统的入口,首先初始化L和B的结构体变量,打印提示信息,然后让用户输入一个数值,从.0-4,输入数值1进入菜单1(meau1()):

meau1()程序如下:

void meau1(void)
{
	int subsel;
	while (1)
	{
		printf("============================\n");
		printf("=  显示各航线信息的子菜单  =\n");
		printf("============================\n");
		printf("*      1.显示所有航线     *\n");
		printf("*      2.显示订单客户     *\n");
		printf("*      3.返回主菜单       *\n");
		printf("============================\n");
		printf("请 选 择(1-3):\n");
		scanf("%d", &subsel);
		switch (subsel)
		{
		case 1:printAllofAirMsg(); break;
		case 2:printOrderCustomByAirNum1(); break;
		case 3:return;
		default:printf("输入错误\n"); break;
		}
	}
}

界面如下:

meau2() 程序如下:

void meau2(void)
{
	int subsel;
	while (1)
	{
		printf("============================\n");
		printf("=     航线信息查询子菜单   =\n");
		printf("============================\n");
		printf("*      1.按航班号查询       *\n");
		printf("*      2.按起点站查询       *\n");
		printf("*      3.按终点站查询       *\n");
		printf("*      4.返回主菜单         *\n");
		printf("============================\n");
		printf("请 选 择(1-4):\n");
		scanf("%d", &subsel);
		switch (subsel)
		{
		case 1:searchbyAirno(); break;
		case 2:searchbystartPlace(); break;
		case 3:searchbyEndPlace(); break;
		case 4: return;
		default:printf("输入错误\n"); break;
		}
	}
}

界面如下: 

还有一些菜单都是都是比较简单的知识,直接看源代码即可。 


4.各功能代码详解(闲话少扯):

4.1.C语言文件的操作:

在这个系统中,需要读取两个文件,一个是航班信息文件,一个是订票客户信息文件,后缀都是(.txt),内容如下:

航班信息.txt

航班号	起点	终点	飞行日	起飞时间	到达时间	机型	价格	乘员定额	余票量
CA1544	合肥	北京	1.3.5	10:55	12:40	A733	960	      100	 90 
MU5341	上海	广州	每日	14:20	16:15	M90	    1280	  150	150 
CZ3869	重庆	深圳	2.4.6	08:55	10:35	733	    1010	  100	100 
MU3682	桂林	南京	2.3.4	20:50	22:15	M90	    1380	  150	120 
HU1836	上海	北京	每日	09:40	11:20	738	    1250	  120	120 
CZ3528	成都	厦门	1.3.5	15:10	16:50	CRJ	    1060	  130	130 
MU4594	昆明	西安	2.4.6	10:15	11:40	328	    1160	  140	140 
SC7425	青岛	海口	1.3.6	19:20	21:20	DH4	    1630	  190	190 
CA1234	洛阳	上海	1.3.5	08:00	10:00	DH4	    1050	  300	300 
CA4321	shai	洛阳	2.4.6	16:00	18:00	DH4	    1100	  300	300 

订票信息.txt

航班号	姓名	身份证	订票数量
CA1544	丁方	410221    4
CA1544	邢风	410222    4
CA1544	刘向	410223    2
MU5341	wan 	415225    2
MU5341	严寒	412003    12
MU3682	吴伟	412009    2
MU3682	刘敏	400281    1

在系统运行时,首先会从电脑本地磁盘读取上面两个文件的信息到两个不同的结构体里面,然后就可以通过读取结构体的内容获取到这个航班信息和订票客户的信息了(注意结构体的成员变量应该是和我们所需要读取文件的内容是一致的,就是说要读取多少的内容,就需要为这个结构体变量开辟多少的静态内存):

航班信息结构体如下:

//航班信息结构体定义,每个航班号都会有不同的乘客名单,所以每个航班都应该有一个链表
typedef struct airinfo
{
	char Airno[8];//航班号
	char start[6];//出发地
	char end[6];//目的地
	char sche[6];//飞行日
	char time1[8];//出发时间
	char time2[8];//到达时间
	char mode[5];//机型
	int  price;//票价
	int  fixed;//  乘客定额
	int  remained;//余票
	PBookList order;/*指向乘员名单链表的头指针,通过这个指针就可以找到所有乘客的名单了*/
}AirInfo,*PAirInfo;

客户订单结构体:

//航订票客户列表体结构体定义
typedef struct Book
{
	char Airnum[8];//航班号
	char name[20];//客户姓名 
	char didentify[6];//身份证号 
	int  order_amount;//订票数量
	int grade;
	struct Book *Pnext;//指向下一个用户的首地址
}*PBookList, BookList;

接下来再定义两个结构体,去定义航班信息和客户的总体信息,以及统计航班数和客户订单数量:

//航班信息总体结构体定义
typedef struct
{
	AirInfo s[MAX]; //航班信息数组
	int acount;  //记录当前航班信息数
}SSList;
//订单客户总体信息
typedef struct
{
	BookList book[BOOKMAX];
	int book_acount;
}SbookList;


#define MAX  20
#define BOOKMAX  100

4.2.读取航班信息:

下贴上程序,然后再进行分析:

//读取文本信息,并赋值给结构体变量,传入的参数是SSList结构体变量的指针
void readinfo(SSList *L)
{
	FILE *fp;//定义文件指针
	if ((fp = fopen("航班信息.txt", "r")) == NULL)
	{
		printf("航班文件不存在 \n");
		exit(1);
	}
	else
	{
		int i = 0; char tep[500];
		L->acount = 0;     //航班次数初始化
		while (!feof(fp))
		{
			fgets(tep, 500, fp);//读取第一行说明:航班号  起点  终点 略..;
			//读取正确的信息;
			if (10 != fscanf(fp, "%s %s %s %s %s %s %s %d %d %d", L->s[i].Airno, L->s[i].start, L->s[i].end, L->s[i].sche, L->s[i].time1, L->s[i].time2,
				L->s[i].mode, &L->s[i].price, &L->s[i].fixed, &L->s[i].remained))
			{
				printf("读取文件出错\n");
				//关闭文件流指针,退出;
				fclose(fp);
				exit(1);
			}
			i++;
			L->acount++;
		}
	}
	fclose(fp);
}

程序分析:

提示:文件读取的详细解释:带我查看

注意:这里打开的文件使用的相对路径。 

如果fopen返回了打开文件的首地址,打开成功,进行航班信息的读取工作。


  • fcanf函数的讲解

格式化输入函数fscanf

 调用:fscanf(fpt,格式控制,地址列表);

 功能:以ASCII码值的方式从fpt关联的文件中读取数据,按格式控制字符串中指定的数据格式转换后送到由输入地址列表中相应项指定的内存单元。函数返回值为正确处理的数据项个数。

例子:

如果文件的内容为 ”6,6.6“,则可以使用如下语句读取:

//m和a是已经定义的int类型和double类型的变量

fcanf(fp,"%d,%lf",&m,&a);   //注意此处是地址列表
 

fscanf(fp, "%s %s %s %s %s %s %s %d %d %d",
                L->s[i].Airno, L->s[i].start, L->s[i].end, L->s[i].sche,
                L->s[i].time1,L->s[i].time2,L->s[i].mode, &L->s[i].price, 
                &L->s[i].fixed, &L->s[i].remained))

解释:fscanf函数的第一个参数是打开文件的指针变量,第二个参数格式控制,第三个参数就是读取的地址列表。

我们需要读入的数据以空格隔开,共有十个数据,所以上面橙色字体的格式控制有10个,我们需要读入的是结构体里面,定义了一个结构体变量L来存放它。

为什么是这种形式赋值:L->s[i].Airno

回忆一下:我们传入这个函数的形参是SSList *类型的

这里为了去统计航班信息数,使用了一个结构体的嵌套:如下:

如果在函数void readinfo(SSList *L),中需要去改变第i个航班的Airno的成员变量的值,如何做?


C语言知识回顾 

此处就涉及到了C语言指针一些语法的问题了,先复习一下指针的知识吧,例如我定义了一下的两个变量

int a=5;   //定义了一个整形变量a
int * b; //定义了一个变量b,这个变量是整形的指针变量,用于存放整形数据的地址
b = &a;  //把a的地址 赋予给b这个指针变量

上面的语句相当于做了什么事呢?用一个简图表示如下:

那么在C语言中有规定,此时:*b  和  的值是相等的。

注意:*b的含义是:以b内容(1000h)为地址的变量的值(那就是变量a的值咯)。


继续深入,结合结构体:

现在定义一个如下的结构体:

typedef struct student
{
    int age;  //结构体成员变量
    int num;
}stu;

stu stu1;  //定义了一个结构体变量stu1,此时已经在内存开辟了一块静态空间给结构体变量stu1,因为没有
           //进行赋值,所以里面的是垃圾值

如果此时我们想在主函数调用一个函数去改变这个stu1结构体变量的信息,如何做?

提示:如果我们想通过函数调用的方法去改变一个函数的值,那必须传递指针才能做到,因为当你在主函数中调用一个函数,那么此时就会分一块新的空间给这个函数,即使我们改变了调用函数的值,但是函数执行结束,就会自动释放内存,也无法把我们想要的结果传递回来。所以在主函数通过调用函数的方式改变一个变量或者结构体变量,必须传递指针(当然还有返回值,但是返回值只能返回一个数据)。

因此定义一个函数为:void change_stu_msg(stu * student)

那么在这个函数中应该怎样写,可以考虑一下,这个函数的形参是stu * 类型的,表示的是接受stu结构体变量的地址,那么想要改变stu1这个结构体变量的内容,传递进来的应该是 : stu1的地址(&stu1)。

通过上面知道,此时 student = &stu1,也就是student这个结构体指针变量存放了stu1的地址。

那么,*student 就等价于 stu1 ,此时想要改变stu1结构体变量的值,函数就可以如下这样写:

void change_stu_msg(stu * student)
{
    (*student).age=10;
    (*student).num=20;
    
}

那么当我们在main主函数中调用这个函数:change_stu_msg(&stu1);

执行结果:这个结构体变量的成员,age=10,num=20;不再是一个垃圾值了。

那么箭头  -> 和这个有什么关系? 这点其实就是语法的规定而已

在C语言中规定:

还是拿上面的函数举例,为了方便书写,可以把 :(*student).    等价成为    ->    

那么 void change_stu_msg(stu * student) 也可以这样子写:

void change_stu_msg(stu * student)
{
    student->age=10;
    student->num=20;
    
}

这下应该对上面的赋值语句有所了解了吧。


复习完C语言的知识,回到刚刚那么问题:

如果在函数void readinfo(SSList *L),中需要去改变第i个航班的Airno的成员变量的值,如何做?

这个函数的形参不就是接受一个 SSList 结构体变量的指针嘛,那先定义一个结构体变量咯:SSList L;

提示:其实这个L变量就是用来存放我们的数据的,只是现在是一些垃圾值,void readinfo(SSList *L) 这个函数就是对这个变量 L 进行初始化滴。

那在主函数中调用的话,必须把L的指针传递进去,即为:readinfo(&L);

此时就会有这样的一个关系: L = &L;     //注意此时这两个L不是一样的,一个是实参,一个是形参。形参的L可以随便改

这样看起来怪怪的,把形参的L修改成 List 把,这样容易看一点 ,即为:void readinfo(SSList *List) 

此时有这样一个关系: List = &L;    那么 *List = L 。

而L结构体有两个成员变量,如下:

改变第一个成员变量的值使用:(*List).s[MAX] 

可以看到s[MAX] 是一个数组,他是一个怎样的数组呢?AirInfo类型的数组,而Airinfo是一个结构体,那s[MAX] 就是一个结构体数组(定义MAX为20),AirInfo结构体有什么内容?

从内存角度来说其实就是开辟了类似如下的一大块静态内存:

那么想改变第2个航班的信息,就必须定位到 s[1]这个结构体咯,即为:(*List).s[1]

想改变这个结构体变量  s[1]的成员变量  Airno[8],如何做?  即为:(*List).s[1].Airno ="Hello"  

在C语言复习那部分,知道  (*List).  可以等价于  List->

这样子就可以回答上面提出的问题了:

如果在函数void readinfo(SSList *List),中需要去改变第i个航班的Airno的成员变量的值,如何做?

在函数中可以这样写:List->s[ i ].Airno ="Hello"


从本地磁盘读取用户信息,因为其逻辑和读取航班信息是一样的,只贴出程序:

//读取订单客户的文件,传入的参数是BookList结构体变量的指针。
//读取到订单客户的信息应给是存储在一个数组里面。例如:book[BOOKMAX];
void readinfo_book(SbookList * book)
{
	FILE *fp;//定义文件指针
	if ((fp = fopen("订票信息.txt", "r")) == NULL)  //以只读的方式打开
	{
		printf("订票信息.txt文件不存在 \n");
		exit(1);
	}
	else
	{
		int i = 0; char title[500];  //读
		B.book_acount = 0;
		while (!feof(fp))  //C提供了一个测试文件状态的函数feof(pf),当文件未结束时feof函数的值为0,
			               //否则为非0值。使用函数feof来判断文件是否结束既可用于文本文件,还可用于二进制文件
		{
			fgets(title, 500, fp);//读取第一行说明:航班号  起点    终点 略去;
			//读取正确的信息,格式化读取信息,把fp所指向的文件读取到结构体里面去
			if (4 != fscanf(fp, "%s %s %s %d", B.book[i].Airnum, B.book[i].name, B.book[i].didentify, &B.book[i].order_amount))
			{
				printf("读取文件出错\n");
				//关闭文件流指针,退出;
				fclose(fp);
				exit(1);
			}
			i++;
			B.book_acount++;
		}
	}
	fclose(fp);
}

有了这两个结构体和结构体成员变量,还有文件读取函数,就可以把这些航班信息和客户信息读取到我们所定义的结构体里面,我们结构体就是存储。也就是存储到如下的结构体里面

4.3.打印航班信息

通过在主函数调用读取航班信息和读取订票用户信息,然后把文本数据读取到L和B的结构体变量:

通过上面的函数在结构体变量已经进行了赋值,也就是说我们的航班信息和客户订票信息已经储存于内存了。


接下来就可以通过调用相应的结构体去读取信息啦:

  • 打印航班信息:

代码如下,此处把结构体成员变量L的内容打印出来:

void printAllofAirMsg(void)
{
	int i = 0;
	for (i = 0; i < L.acount; i++)  //L.account是统计航班个数的,打印所有航班
	{
		printf("航班号 起点 终点 飞行日 起飞时间 到达时间 机型 价格 乘员定额 余票量\n");
		printf("%s %s %s %s %s %s %s %d %d %d\r\n", L.s[i].Airno, L.s[i].start, L.s[i].end, L.s[i].sche, L.s[i].time1, L.s[i].time2, L.s[i].mode, L.s[i].price, L.s[i].fixed, L.s[i].remained);


	}
}

已上的程序完成了一些简单的文件操作,需要掌握的知识是:

1.文件的操作

2.结构体的定义

3.结构体变量的赋值

4.打印结构体变量的内容 


5.根据要求查找航班(航班号、起点站、终点站)

此处只讲解一下按航班号查询航班信息,其他两个查询方式几乎和第一个一样。

先贴出代码如下:

/*根据客户提出的航班号输出航线信息*/
void searchbyAirno()
{
	PAirInfo info, a;
	char Airnum01[10];
	int i = 0, sel;
	info = L.s;
	a = L.s;
	printf("===============================\n");
	printf("== 为您列出航班号供您选择:   =\n");
	for (int j = 0; j < L.acount; j++)
	{
		printf("%d           %s\n", j, a[j].Airno);

	}
	printf("===============================\n");
	printf("请输入要选择航班的序号:");
	scanf("%d", &sel);
	//根据用户的选择,给Airnumber变量赋值不同的航班号
	if (sel >= L.acount) {
		printf("输入错误\n");
		return;
	}
	else  //输入的序列号有效
	{
		strcpy(Airnum01, info[sel].Airno);
	}

	while (i < MAXSIZE)
	{
		if (!strcmp(Airnum01, a[i].Airno)) break;
		i++;
	}
	if (i >= MAXSIZE)
	{
		printf("\n\n");
		printf("对不起,该航线未找到!\n");
		printf("\n\n");
	}

	else
	{
		printf("================================================================================\n");
		//printf("航班号 起点 终点 飞行日 起飞时间 到达时间 机型 价格 乘员定额 余票量\n");
		printOneofAirMsg(i);
	}
}

在界面上显示效果如下:

接下来读取航班序号,来判断你选择的航班信息:

打印航班信息:

void printOneofAirMsg(int i)
{
	
		printf("航班号 起点 终点 飞行日 起飞时间 到达时间 机型 价格 乘员定额 余票量\n");
		printf("%s %s %s %s %s %s %s %d %d %d\r\n", L.s[i].Airno, L.s[i].start, L.s[i].end, L.s[i].sche, L.s[i].time1, L.s[i].time2, L.s[i].mode, L.s[i].price, L.s[i].fixed, L.s[i].remained);

}

效果如下:


6.订票功能(链表操作)

其实这一部分最终要的就是链表的操作,无非就是链表的创建,链表的增加,链表的删除等问题。

所以首先需要熟悉的是链表


最近比较忙,先贴上代码吧。

代码链接:https://download.csdn.net/download/qq_36243942/10785641

发布了91 篇原创文章 · 获赞 247 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/qq_36243942/article/details/83501636