【影院管理系统】

主播不行了,主播一天半把铠甲系统又改回影院票务了,把主播差点肝没了

这是bll.c文件

cs 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <time.h>
#include "entity.h"
#include "dal.h"
#include "ui.h"
#include "bll.h"

// 添加电影
void addMovie() {
	clearScreen();

	movie* newmovie = (movie*)malloc(sizeof(movie));
	if (!newmovie) {
		printf("分配内存失败\n");
		getchar(); getchar();
		clearScreen();
		return;
	}

	int maxid = 0;
	movie* p = movieList;
	while (p) {
		if (p->id > maxid) maxid = p->id;
		p = p->next;
	}
	newmovie->id = maxid + 1;

	printf("请输入电影名称:");
	scanf("%s", newmovie->title);

	p = movieList;
	while (p) {
		if (strcmp(p->title, newmovie->title) == 0) {
			printf("错误:电影名「%s」已存在!\n", newmovie->title);
			free(newmovie);
			getchar(); getchar();
			clearScreen();
			return;
		}
		p = p->next;
	}

	printf("请输入票价:");
	scanf("%f", &newmovie->price);

	printf("请输入电影类型(动作/喜剧/科幻/动画/剧情等):");
	scanf("%s", newmovie->type);

	printf("请输入电影时长(分钟):");
	scanf("%d", &newmovie->duration);

	printf("请输入导演:");
	scanf("%s", &newmovie->director);

	printf("请输入主演:");
	scanf("%s", &newmovie->actor);

	printf("请选择该电影固定放映厅(1-7):");
	int hall;
	scanf("%d", &hall);
	newmovie->fixedHall = (HallScene)(hall - 1);

	getchar();
	newmovie->startTime = inputTimeSafe("请输入上映开始时间");
	newmovie->endTime = inputTimeSafe("请输入上映结束时间");

	if (newmovie->startTime >= newmovie->endTime) {
		printf("错误:结束时间必须大于开始时间!\n");
		free(newmovie);
		getchar(); getchar();
		clearScreen();
		return;
	}

	newmovie->status = MOVIE_AVAILABLE;

	newmovie->next = movieList;
	movieList = newmovie;

	char startBuf[50], endBuf[50];
	formatTimestamp(newmovie->startTime, startBuf, sizeof(startBuf));
	formatTimestamp(newmovie->endTime, endBuf, sizeof(endBuf));

	printf("\n电影「%s」添加成功!ID:%d\n票价:%.2f\n类型:%s\n时长:%d分钟\n导演:%s\n主演:%s\n固定影厅:%d\n上映时间:%s ~ %s\n",
		newmovie->title, newmovie->id, newmovie->price, newmovie->type,
		newmovie->duration, newmovie->director, newmovie->actor,
		newmovie->fixedHall + 1,
		startBuf, endBuf);

	save_to_file();
	printf("按任意键继续...\n");
	getchar(); getchar();
	clearScreen();
}

// 查看我的订单
void myOrders() {
	clearScreen();

	if (currentUser == NULL) {
		printf("请先登录系统后再查看购票记录!\n");
		getchar(); getchar();
		clearScreen();
		return;
	}

	char orderTime[64];

	order* userOrder = orderList;
	int userOrderCount = 0;

	printf("\n======= 我的观影记录 =======\n");

	while (userOrder != NULL) {
		if (userOrder->userId == currentUser->id) {
			userOrderCount++;

			formatTimestamp(userOrder->timestamp, orderTime, sizeof(orderTime));
			printf("订单ID: %d | 电影: %s | 影厅: %d | 场次: %d | 座位: %c%d | 总价: %.2f | 取票码: %s\n",
				userOrder->id,
				userOrder->movieName,
				userOrder->hallId + 1,
				userOrder->timeIdx + 1,
				'A' + userOrder->row, userOrder->col + 1,
				userOrder->totalPrice,
				userOrder->ticketCode
			);
		}
		userOrder = userOrder->next;
	}

	if (userOrderCount == 0) {
		printf("你暂无任何购票记录!\n");
	}

	printf("\n按任意键返回菜单...\n");
	getchar(); getchar();
	clearScreen();
}

// ================= 购票 =================
// =================== 购票函数 ===================
void buyTicket() {
	clearScreen();
	if (!currentUser) {
		printf("请先登录!\n");
		getchar(); getchar();
		return;
	}

	browseMovies();

	int mid;
	printf("请输入电影ID:");
	scanf("%d", &mid);

	movie* m = findMovieById(mid);
	if (!m) {
		printf("未找到该电影!\n");
		getchar(); getchar();
		return;
	}

	int t;
	printf("\n请选择场次(1-%d):", TIMES);
	scanf("%d", &t);

	if (t < 1 || t > TIMES) {
		printf("场次输入错误!\n");
		getchar(); getchar();
		return;
	}

	int timeIdx = t - 1;        // 转换为链表索引
	int hallId = m->fixedHall;  // 固定影厅

	// 查找当前影厅场次节点
	SeatNode* node = findSeatNode(hallId, timeIdx);
	if (!node) {
		// 节点不存在,初始化影厅×场次
		initSeatList();
		node = findSeatNode(hallId, timeIdx);
		if (!node) {
			printf("场次初始化失败!\n");
			getchar(); getchar();
			return;
		}
	}

	// 显示座位矩阵
	showSeatMatrix(hallId, timeIdx);

	// 选择座位
	char rc;
	int col;
	printf("请选择座位(如 A 1):");
	scanf(" %c %d", &rc, &col);

	int row = (rc >= 'A' && rc <= 'E') ? rc - 'A' : rc - 'a';
	col--; // 转换为索引

	if (row < 0 || row >= ROWS || col < 0 || col >= COLS) {
		printf("无效座位!\n");
		getchar(); getchar();
		return;
	}

	if (node->seats[row][col] == 1) {
		printf("该座位已被占用!\n");
		getchar(); getchar();
		return;
	}

	// 占用座位
	node->seats[row][col] = 1;

	// 创建订单
	order* no = (order*)malloc(sizeof(order));
	no->id = 1;
	for (order* o = orderList; o; o = o->next) {
		if (o->id >= no->id)
			no->id = o->id + 1;
	}

	no->userId = currentUser->id;
	no->movieId = m->id;
	strcpy(no->movieName, m->title);
	no->quantity = 1;
	no->totalPrice = m->price;
	no->hallId = hallId;
	no->timeIdx = timeIdx;
	no->row = row;
	no->col = col;
	no->timestamp = time(NULL);
	sprintf(no->ticketCode, "%08d", rand() % 100000000);
	no->next = orderList;
	orderList = no;

	save_to_file();
	printf("\n✅ 购票成功!\n");
	getchar(); getchar();
}

// 删除电影
void deleteMovie() {
	clearScreen();

	printf("===== 当前所有电影列表 =====\n");
	movie* p = movieList;
	if (!p) {
		printf("暂无电影可删除!\n");
		printf("按任意键返回...\n");
		getchar(); getchar();
		clearScreen();
		return;
	}

	printf("ID\t名称\t\t时长\t影厅\t状态\n");
	printf("-----------------------------------------\n");
	while (p) {
		const char* statusStr;
		switch (p->status) {
		case MOVIE_AVAILABLE: statusStr = "可售"; break;
		case MOVIE_PLAYING:   statusStr = "热映中"; break;
		case MOVIE_PREVIEW:   statusStr = "预告"; break;
		case MOVIE_OFF:       statusStr = "已下架"; break;
		default: statusStr = "未知"; break;
		}

		printf("%d\t%-15s%d\t%d\t%s\n",
			p->id,
			p->title,
			p->duration,
			p->fixedHall + 1,
			statusStr);
		p = p->next;
	}

	int id;
	printf("\n请输入要删除的电影ID: ");
	scanf("%d", &id);

	movie* cur = movieList;
	movie* pre = NULL;

	while (cur != NULL) {
		if (cur->id == id) {
			if (pre == NULL) {
				movieList = cur->next;
			}
			else {
				pre->next = cur->next;
			}
			free(cur);
			save_to_file();
			printf("\n电影删除成功!\n");
			printf("按任意键继续...\n");
			getchar(); getchar();
			clearScreen();
			return;
		}
		pre = cur;
		cur = cur->next;
	}

	printf("\n未找到ID为 %d 的电影\n", id);
	printf("按任意键继续...\n");
	getchar(); getchar();
	clearScreen();
}

// 修改电影信息
void updateMovie() {
	clearScreen();
	printf("===== 可修改电影列表 =====\n");
	movie* p = movieList;
	if (!p) {
		printf("暂无电影可修改\n按任意键返回...\n");
		while (getchar() != '\n');
		clearScreen();
		return;
	}

	printf("电影ID\t名称\t\t上映时间\t\t状态\n");
	while (p) {
		char startBuf[50], endBuf[50];
		formatTimestamp(p->startTime, startBuf, sizeof(startBuf));
		formatTimestamp(p->endTime, endBuf, sizeof(endBuf));

		const char* statusStr;
		switch (p->status) {
		case MOVIE_AVAILABLE: statusStr = "可售"; break;
		case MOVIE_PLAYING:   statusStr = "正在上映"; break;
		case MOVIE_PREVIEW:   statusStr = "预告/筹备"; break;
		case MOVIE_OFF:       statusStr = "已下架"; break;
		default: statusStr = "未知状态"; break;
		}

		printf("%d\t%-15s%s ~ %s\t%s\n", p->id, p->title, startBuf, endBuf, statusStr);
		p = p->next;
	}

	int id;
	printf("\n请输入要修改的电影ID: ");
	scanf("%d", &id);

	p = movieList;
	while (p) {
		if (p->id == id) break;
		p = p->next;
	}

	if (!p) {
		printf("未找到ID为 %d 的电影\n按任意键返回...\n", id);
		while (getchar() != '\n');
		clearScreen();
		return;
	}

	clearScreen();
	printf("===== 修改电影:%s =====\n", p->title);

	printf("当前上映开始时间:");
	char oldStart[50];
	formatTimestamp(p->startTime, oldStart, sizeof(oldStart));
	printf("%s\n", oldStart);
	getchar();
	p->startTime = inputTimeSafe("请输入新的上映开始时间");

	printf("当前上映结束时间:");
	char oldEnd[50];
	formatTimestamp(p->endTime, oldEnd, sizeof(oldEnd));
	printf("%s\n", oldEnd);
	p->endTime = inputTimeSafe("请输入新的上映结束时间");

	if (p->startTime >= p->endTime) {
		printf("错误:结束时间必须晚于开始时间!\n");
		while (getchar() != '\n');
		clearScreen();
		return;
	}

	printf("\n当前状态:");
	switch (p->status) {
	case MOVIE_AVAILABLE: printf("可售"); break;
	case MOVIE_PLAYING: printf("正在上映"); break;
	case MOVIE_PREVIEW: printf("预告/筹备"); break;
	case MOVIE_OFF: printf("已下架"); break;
	}
	printf("\n");
	printf("请输入新状态(1=可售 2=正在上映 3=预告/筹备 4=下架):");
	int newStatus;
	scanf("%d", &newStatus);

	if (newStatus == 1) p->status = MOVIE_AVAILABLE;
	else if (newStatus == 2) p->status = MOVIE_PLAYING;
	else if (newStatus == 3) p->status = MOVIE_PREVIEW;
	else if (newStatus == 4) p->status = MOVIE_OFF;

	save_to_file();
	printf("\n电影信息修改成功!\n");
	printf("按任意键返回...\n");

	while (getchar() != '\n');
	getchar();
	clearScreen();
}

// 管理员修改座位
void updateSeatStatus()
{
	clearScreen();
	printf("\n===== 管理员修改座位 =====\n");

	int h, t;
	printf("影厅(1-7):");
	scanf("%d", &h);
	printf("场次(1-4):");
	scanf("%d", &t);

	SeatNode* node = findSeatNode(h - 1, t - 1);
	if (!node)
	{
		printf("场次未初始化!\n");
		getchar(); getchar();
		return;
	}

	showSeatMatrix(h - 1, t - 1);

	char rc;
	int col;
	printf("请输入要修改的座位(如 A 1):");
	scanf(" %c %d", &rc, &col);

	int row = (rc >= 'A' && rc <= 'E') ? rc - 'A' : rc - 'a';
	col--;

	if (row >= 0 && row < ROWS && col >= 0 && col < COLS)
	{
		node->seats[row][col] = !node->seats[row][col];
		save_to_file();
		printf(" 修改成功!\n");
	}

	getchar(); getchar();
}

// ================= 退票 =================
void refundTicket()
{
	clearScreen();
	if (!currentUser)
	{
		printf("请先登录!\n");
		getchar(); getchar();
		return;
	}

	printf("\n======= 你的订单 =======\n");
	order* p = orderList;
	int count = 0;
	while (p)
	{
		if (p->userId == currentUser->id)
		{
			count++;
			printf("订单ID: %d | 影厅:%d 场次:%d | 座位:%c%d\n",
				p->id,
				p->hallId + 1,
				p->timeIdx + 1,
				'A' + p->row, p->col + 1);
		}
		p = p->next;
	}

	if (count == 0)
	{
		printf("暂无订单!\n");
		getchar(); getchar();
		return;
	}

	int oid;
	printf("\n请输入要退票的订单ID:");
	scanf("%d", &oid);

	order* prev = NULL;
	p = orderList;
	while (p)
	{
		if (p->id == oid && p->userId == currentUser->id)
		{
			// 释放座位
			SeatNode* node = findSeatNode(p->hallId, p->timeIdx);
			if (node)
			{
				node->seats[p->row][p->col] = 0;
			}

			// 删除订单
			if (prev == NULL)
				orderList = p->next;
			else
				prev->next = p->next;

			free(p);
			save_to_file();
			printf("✅ 退票成功!\n");
			getchar(); getchar();
			return;
		}
		prev = p;
		p = p->next;
	}

	printf("未找到该订单!\n");
	getchar(); getchar();
}

// ================= 显示座位 =================
void showSeatMatrix(int hallId, int timeIdx) {
	SeatNode* node = findSeatNode(hallId, timeIdx);
	if (!node) {
		printf("场次未初始化!\n");
		return;
	}

	printf("\n=======================================\n");
	printf("          影厅 %d | 场次 %d\n", hallId + 1, timeIdx + 1);
	printf("=======================================\n");

	printf("   ");
	for (int j = 0; j < COLS; j++)
		printf("%2d ", j + 1);
	printf("\n");

	for (int i = 0; i < ROWS; i++) {
		printf("%c  ", 'A' + i);
		for (int j = 0; j < COLS; j++)
			printf("%c  ", node->seats[i][j] ? 'X' : 'O');
		printf("\n");
	}
	printf("=======================================\n");
	printf("          O = 可售    X = 已售\n");
	printf("=======================================\n\n");
}

// 时间输入工具
time_t inputTimeSafe(const char* tip) {
	char buf[64];
	struct tm t;
	time_t result;
	int year, month, day, hour, min, sec;

	int c;
	while ((c = getchar()) != '\n' && c != EOF);

	while (1) {
		printf("%s(格式:2026-3-18 10:00:00):\n", tip);
		if (!fgets(buf, sizeof(buf), stdin)) continue;
		buf[strcspn(buf, "\n")] = 0;

		if (sscanf(buf, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &min, &sec) == 6) {
			if (hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || sec > 59) continue;
			if (month < 1 || month > 12 || day < 1 || day > 31) continue;

			memset(&t, 0, sizeof(t));
			t.tm_year = year - 1900;
			t.tm_mon = month - 1;
			t.tm_mday = day;
			t.tm_hour = hour;
			t.tm_min = min;
			t.tm_sec = sec;
			t.tm_isdst = -1;

			result = mktime(&t);
			if (result != -1) return result;
		}
		printf("格式错误!\n");
	}
}
// 修改密码
void changePassword() {
	clearScreen();

	// 未登录判断
	if (!currentUser) {
		printf("请先登录!\n");
		getchar(); getchar();
		clearScreen();
		return;
	}

	char oldPwd[50];
	char newPwd[50];
	char confirmPwd[50];

	printf("===== 修改密码 =====\n");
	printf("请输入旧密码:");
	inputPassword(oldPwd, 50);
	printf("\n");

	// 验证旧密码
	if (strcmp(currentUser->password, oldPwd) != 0) {
		printf("旧密码错误!\n");
		getchar(); getchar();
		clearScreen();
		return;
	}

	// 输入新密码
	printf("请输入新密码:");
	inputPassword(newPwd, 50);
	printf("\n");

	printf("请确认新密码:");
	inputPassword(confirmPwd, 50);
	printf("\n");

	// 两次密码不一致
	if (strcmp(newPwd, confirmPwd) != 0) {
		printf("两次输入的密码不一致!\n");
		getchar(); getchar();
		clearScreen();
		return;
	}

	// 修改密码
	strcpy(currentUser->password, newPwd);
	save_to_file();

	printf("密码修改成功!\n");
	getchar(); getchar();
	clearScreen();
}

影院票务管理系统功能总结与实现解析

本项目是一个完整的影院票务管理系统,支持从电影管理到用户购票、退票及座位管理的完整流程,实现了管理员和普通用户的多角色操作。


项目功能概述;系统角色与模块

系统包含两个主要角色:

  • 管理员:管理电影、影厅座位、查看所有订单

  • 普通用户:注册登录、浏览电影、购票、退票、查看个人订单、修改密码

核心模块包括:

  • 电影管理:添加、删除、修改电影信息,包括上映时间、票价、影厅和状态

  • 购票系统:用户可以选择电影、场次、座位进行购票,生成唯一取票码

  • 订单管理:记录用户订单信息,支持用户查看个人订单、退票

  • 座位管理:显示座位矩阵,可由管理员修改座位状态

  • 用户管理:用户注册、登录、修改密码

  • 文件存储 :系统所有数据通过 save_to_file 持久化到文件,保证数据在程序退出后保存


电影管理;增删改查功能

  • 添加电影:输入名称、票价、类型、时长、导演、主演、固定放映厅及上映时间

    • 自动生成电影ID

    • 防止同名电影重复添加

    • 校验开始和结束时间合法性

  • 删除电影:根据电影ID删除电影,更新链表及文件

  • 修改电影信息:管理员可修改上映时间和电影状态,保证时间逻辑正确

  • 电影状态管理:电影状态包括"可售、正在上映、预告/筹备、已下架",便于票务和管理


购票系统;选座购票流程

  • 用户可浏览所有电影及对应信息

  • 输入电影ID和场次选择对应影厅

  • 显示座位矩阵(O=可售,X=已售)

  • 用户选择座位,系统检查座位是否可用

  • 成功占用座位后生成订单,订单包括:电影信息、影厅、座位、总价、取票码

  • 所有订单记录持久化存储


订单管理;查看与退票

  • 查看个人订单:登录用户可查看自己的观影记录,包括电影名称、座位、总价和取票码

  • 退票功能:用户可选择订单ID退票,系统释放对应座位并删除订单

  • 系统确保用户只能操作自己的订单


座位管理;座位显示与管理员修改

  • 每个影厅的每场次座位矩阵采用二维数组表示

  • 显示座位矩阵:行列标识,O=可售,X=已售

  • 管理员修改座位状态:可手动修改座位状态(占用或释放)

  • 支持初始化影厅×场次座位,保证场次信息正确


用户管理;安全性与体验

  • 登录验证:购票、退票、查看订单功能需登录

  • 密码修改:用户可修改密码,系统验证旧密码和确认新密码

  • 密码输入保护:输入密码不可直接显示,增强安全性


时间输入与校验;保证逻辑正确

  • 输入时间格式固定为 YYYY-MM-DD HH:MM:SS

  • 系统校验时间合法性:年、月、日、小时、分钟、秒

  • 上映时间逻辑检查:结束时间必须晚于开始时间


数据存储;文件持久化

  • 所有用户、电影、订单、座位数据通过文件保存

  • 系统启动时加载数据,关闭时自动保存

  • 保证重启后数据不丢失


项目亮点;技术实现特点

  • 使用链表管理电影和订单信息,动态添加和删除节点

  • 使用二维数组和链表结合管理座位信息,方便显示和修改

  • 使用时间戳 time_t 管理电影上映时间及订单时间

  • 管理员和普通用户功能分离,安全性和逻辑清晰

  • 支持多影厅、多场次座位管理,覆盖实际影院需求


总结;系统价值与可拓展性

本项目实现了一个完整的影院票务管理系统,功能覆盖从电影管理到用户购票、退票及座位管理,具备以下优势:

  • 功能完整、操作流程合理

  • 数据持久化,保证信息安全

  • 管理员和用户角色分离,操作清晰

  • 可扩展性强,可增加多影厅、多场次、多票价策略

该系统不仅适合作为学习链表、结构体、时间处理、文件存储等C语言基础知识的练手项目,也可作为小型影院票务管理系统的原型。

bll.h

cs 复制代码
#ifndef BLL_H
#define BLL_H
#include "entity.h"

// 用户相关
void login();
void reg();
void findPassword();
void changePassword();
void view_all_users();

// 电影相关
void browseMovies();
void searchMovie();
void addMovie();
void deleteMovie();
void updateMovie();

// 购票 & 订单
void buyTicket();
void myOrders();
void refundTicket();

// 座位
void updateSeatStatus();
void showSeatMatrix(int hallId, int timeIdx);

// 工具函数
time_t inputTimeSafe(const char* tip); // 补上这个声明

#endif

dal.c

cs 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <time.h>
#include "entity.h"
#include "dal.h"
#include "ui.h"
#include"bll.h"
user* head = NULL;
user* currentUser = NULL;
movie* movieList = NULL;
order* orderList = NULL;
SeatNode* seatList = NULL;

// 查找场次节点
SeatNode* findSeatNode(int hallId, int timeIdx) {
    SeatNode* p = seatList;
    while (p) {
        if (p->hallId == hallId && p->timeIdx == timeIdx) return p;
        p = p->next;
    }
    return NULL;
}

// 创建/初始化节点
void initSeatList() {
    for (int h = 0; h < HALLS; h++) {
        for (int t = 0; t < TIMES; t++) {
            if (findSeatNode(h, t)) continue;
            SeatNode* s = (SeatNode*)malloc(sizeof(SeatNode));
            s->hallId = h;
            s->timeIdx = t;
            memset(s->seats, 0, sizeof(s->seats));
            s->next = seatList;
            seatList = s;
        }
    }
}

// 保存
void save_to_file() {
    FILE* fp = fopen("data.txt", "w");
    if (!fp) return;

    user* u = head;
    while (u) {
        fprintf(fp, "USER %d %s %s \"%s\" \"%s\" %d\n",
            u->id, u->name, u->password,
            u->securityQuestion, u->securityAnswer, u->isAdmin);
        u = u->next;
    }

    movie* m = movieList;
    while (m) {
        fprintf(fp, "MOVIE %d \"%s\" %.2f \"%s\" %d %lld %lld %d \"%s\" \"%s\" %d\n",
            m->id, m->title, m->price, m->type, m->status,
            (long long)m->startTime, (long long)m->endTime,
            m->duration, m->director, m->actor, m->fixedHall);
        m = m->next;
    }

    order* o = orderList;
    while (o) {
        fprintf(fp, "ORDER %d %d %d \"%s\" %d %.2f %d %d %d %d %lld \"%s\"\n",
            o->id, o->userId, o->movieId, o->movieName,
            o->quantity, o->totalPrice,
            o->hallId, o->timeIdx, o->row, o->col,
            (long long)o->timestamp, o->ticketCode);
        o = o->next;
    }

    SeatNode* s = seatList;
    while (s) {
        fprintf(fp, "SEATNODE %d %d ", s->hallId, s->timeIdx);
        for (int i = 0; i < ROWS; i++)
            for (int j = 0; j < COLS; j++)
                fprintf(fp, "%d ", s->seats[i][j]);
        fprintf(fp, "\n");
        s = s->next;
    }

    fclose(fp);
}

// 加载(已完整修复所有枚举强制类型转换)
void load_from_file() {
    FILE* fp = fopen("data.txt", "r");
    if (!fp) { initSeatList(); return; }

    char type[20], line[1024];
    while (fscanf(fp, "%19s", type) != EOF) {
        fgets(line, sizeof(line), fp);

        if (!strcmp(type, "USER")) {
            user* u = (user*)malloc(sizeof(user));
            if (sscanf(line, "%d %49s %49s \"%99[^\"]\" \"%99[^\"]\" %d",
                &u->id, u->name, u->password,
                u->securityQuestion, u->securityAnswer, &u->isAdmin) == 6) {
                u->next = head; head = u;
            }
            else free(u);
        }
        else if (!strcmp(type, "MOVIE")) {
            movie* m = (movie*)malloc(sizeof(movie));
            int id, st, dur, hall; long long sst, set; float pri;
            if (sscanf(line, "%d \"%[^\"]\" %f \"%[^\"]\" %d %lld %lld %d \"%[^\"]\" \"%[^\"]\" %d",
                &id, m->title, &pri, m->type, &st, &sst, &set, &dur,
                m->director, m->actor, &hall) == 11) {
                m->id = id;
                m->price = pri;
                m->status = (MovieStatus)st;        // ✅ 强制转换
                m->startTime = (time_t)sst;
                m->endTime = (time_t)set;
                m->duration = dur;
                m->fixedHall = (HallScene)hall;     // ✅ 强制转换
                m->next = movieList;
                movieList = m;
            }
            else free(m);
        }
        else if (!strcmp(type, "ORDER")) {
            order* o = (order*)malloc(sizeof(order));
            int id, uid, mid, qty, h, ti, r, c; long long ts; float tp;
            if (sscanf(line, "%d %d %d \"%[^\"]\" %d %f %d %d %d %d %lld \"%[^\"]\"",
                &id, &uid, &mid, o->movieName, &qty, &tp,
                &h, &ti, &r, &c, &ts, o->ticketCode) == 12) {
                o->id = id;
                o->userId = uid;
                o->movieId = mid;
                o->quantity = qty;
                o->totalPrice = tp;
                o->hallId = h;
                o->timeIdx = ti;
                o->row = r;
                o->col = c;
                o->timestamp = (time_t)ts;
                o->next = orderList;
                orderList = o;
            }
            else free(o);
        }
        else if (!strcmp(type, "SEATNODE")) {
            SeatNode* s = (SeatNode*)malloc(sizeof(SeatNode));
            sscanf(line, "%d %d", &s->hallId, &s->timeIdx);
            char* p = line;
            while (*p != ' ') p++; p++;
            while (*p != ' ') p++; p++;
            for (int i = 0; i < ROWS; i++)
                for (int j = 0; j < COLS; j++) {
                    sscanf(p, "%d", &s->seats[i][j]);
                    while (*p == ' ') p++;
                    while (*p >= '0' && *p <= '9') p++;
                }
            s->next = seatList; seatList = s;
        }
    }
    fclose(fp);
}

user* findUserById(int id) {
    user* p = head; while (p) { if (p->id == id) return p; p = p->next; } return NULL;
}
user* findUserByName(const char* name) {
    user* p = head; while (p) { if (!strcmp(p->name, name)) return p; p = p->next; } return NULL;
}
movie* findMovieById(int id) {
    movie* p = movieList; while (p) { if (p->id == id) return p; p = p->next; } return NULL;
}
order* findOrderById(int id) {
    order* p = orderList; while (p) { if (p->id == id) return p; p = p->next; } return NULL;
}

影院票务管理系统功能总结与数据层解析

本项目是一个完整的影院票务管理系统,覆盖从电影管理、用户管理到购票、退票和座位管理的完整流程。本文将总结项目功能、各模块实现方式及数据管理策略。


项目功能概述;系统角色与模块

系统主要角色:

  • 管理员:管理电影信息、影厅座位、查看所有订单

  • 普通用户:注册登录、浏览电影、购票、退票、查看个人订单、修改密码

核心模块:

  • 电影管理:增删改查电影信息,包括票价、类型、上映时间和固定影厅

  • 购票系统:用户选择电影、场次、座位进行购票,生成唯一取票码

  • 订单管理:记录用户订单信息,可查看、退票

  • 座位管理:影厅座位矩阵显示与修改,支持管理员管理

  • 用户管理:注册、登录、修改密码、安全问题验证

  • 文件存储:通过文件保存数据,保证系统重启后信息不丢失


数据结构与存储;链表与座位矩阵

系统采用 链表管理用户、电影、订单和座位节点

  • user* head:用户链表头指针

  • movie* movieList:电影链表头指针

  • order* orderList:订单链表头指针

  • SeatNode* seatList:座位节点链表,管理影厅×场次座位信息

座位矩阵使用二维数组 seats[ROWS][COLS] 表示每个影厅每场次的座位状态,0表示可售,1表示已售。


数据访问层实现;查找与初始化

  • 查找节点:通过ID或链表遍历找到用户、电影或订单

  • 初始化座位节点initSeatList 遍历所有影厅和场次,创建座位节点,确保影厅×场次信息完整

  • 场次查找findSeatNode(hallId, timeIdx) 查找特定影厅和场次的座位节点

这种链表+数组结合的方式灵活、易扩展,适合管理多影厅、多场次的座位信息。


数据持久化;文件保存与加载

  • 保存数据save_to_file 将用户、电影、订单和座位信息写入 data.txt

    • 用户信息包含ID、用户名、密码、密保问题、管理员状态

    • 电影信息包含ID、名称、票价、类型、状态、上映时间、时长、导演、主演、固定影厅

    • 订单信息包含ID、用户ID、电影ID、座位信息、总价、取票码、时间戳

    • 座位信息按影厅和场次保存矩阵

  • 加载数据load_from_file 从文件读取数据

    • 对枚举类型(电影状态、影厅编号)进行强制类型转换

    • 支持文件不存在时初始化座位

    • 确保链表和座位矩阵完整恢复

通过文件持久化,系统可以在重启后继续操作,数据安全可靠。


用户与电影查找;便捷操作

系统提供多种查找函数,便于业务逻辑调用:

  • findUserById / findUserByName:根据ID或用户名查找用户

  • findMovieById:查找指定电影

  • findOrderById:查找指定订单

  • findSeatNode:查找影厅×场次座位节点

这些函数保证业务层(BLL)能够方便获取数据,简化操作流程。


项目亮点;技术实现特点

  • 链表管理数据:动态增删改查灵活,适合多用户、多电影、多订单场景

  • 二维数组表示座位:座位状态直观、操作简便

  • 文件持久化:保证数据重启后依然可用

  • 多角色权限:管理员和普通用户功能分离,安全性高

  • 时间管理 :使用 time_t 管理电影上映时间和订单时间,保证逻辑正确

  • 扩展性强:可支持多影厅、多场次、多票价策略


总结;系统价值与可拓展性

本项目实现了一个功能完整的影院票务管理系统,覆盖电影管理、座位管理、用户管理及购票流程,具备以下优势:

  • 功能完善、流程合理

  • 数据持久化、信息安全

  • 链表+数组组合结构,便于扩展和维护

  • 支持管理员和普通用户多角色操作

该系统不仅适合学习链表、结构体、时间处理和文件存储等C语言基础知识,也可以作为小型影院票务管理系统原型使用,后续可扩展在线支付、座位推荐、影院统计等功能。

dal.h

cs 复制代码
#ifndef DAL_H
#define DAL_H
#include "entity.h"

extern user* head;
extern user* currentUser;
extern movie* movieList;
extern order* orderList;
extern SeatNode* seatList;

void save_to_file();
void load_from_file();
void initSeatList();
SeatNode* findSeatNode(int hallId, int timeIdx);

user* findUserById(int id);
user* findUserByName(const char* name);
movie* findMovieById(int id);
order* findOrderById(int id);

#endif

下一篇写ui层

相关推荐
gulinigar1 小时前
C++中的观察者模式实战
开发语言·c++·算法
星空露珠1 小时前
迷你世界UGC3.0脚本Wiki对象模块管理接口 GameObject
开发语言·数据库·算法·游戏·lua
码界奇点2 小时前
基于Java GUI和Access数据库的图书馆管理系统设计与实现
java·开发语言·数据库·毕业设计·源代码管理
Moshow郑锴2 小时前
JAVA JDK26新特性分析 - 一个注重性能优化、生产就绪和前瞻性安全的版本
java·开发语言·jvm
Jackey_Song_Odd2 小时前
Part 1:Python语言核心 - 缩进与代码块
开发语言·python
@PHARAOH2 小时前
HOW - Go 开发入门(二)
开发语言·后端·golang
BUG?不,是彩蛋!2 小时前
从零到一掌握 K 线与技术指标:Java 实战教程 | MA, RSI, MACD 全解析
java·开发语言·spring boot·量化投资
冰暮流星2 小时前
javascript之变量作用域
开发语言·前端·javascript
biter down2 小时前
C++ 设计不可被继承的类
java·开发语言·c++