主播不行了,主播一天半把铠甲系统又改回影院票务了,把主播差点肝没了
这是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层