C语言经典考题:火车站售票程序的数据建模与实现

发布时间:2026/10/28 21:15:33

C语言经典考题:火车站售票程序的数据建模与实现 简介这份资源是东软集团IA事业部2007年编码考试C语言试题C卷面向准备技术面试、刷题巩固C语言基础的开发者与在校学生核心考察数组或链表等数据结构设计、售票规则的条件判断以及文件读写操作。压缩包内共1个doc文档约54KB完整收录了火车站售票编程题的题干、座位布局示意、售票优先级规则说明以及可直接复用的GetRequest与OutputResult函数参考实现。题目要求模拟一节80座车厢的售票流程涵盖单张随机出票、两张优先相邻、三四张优先同间隔等场景并需从request.txt读取请求、向result.txt追加结果。已有232人学习该试题读者可借此练习数据结构建模、循环与条件分支组织、文件句柄静态管理等技能并对照编码规范要求打磨代码风格是检验C语言基本功与工程习惯的实用练习材料。1. 一份十七年前的 C 语言编码考题为什么今天还值得拆前阵子整理旧资料翻出一份 2007 年某公司 IA 事业部的编码考试题 C 卷题目是「火车站售票程序」。乍看像课后作业细读才发现它把 C 语言面试里最容易翻车的几块——数组状态建模、文件读写、静态变量生命周期、优先级规则落地——全塞进了一道 40 分的题里。它不考算法花活考的是你能不能把一段带业务规则的流程写成结构清楚、能跑、结果对的代码。这份资源适合两类人一是准备 C 语言笔试、想找一道「有真实业务约束」的练手题的人二是带新人、想找一个能讲清数据结构与文件操作配合的案例的工程师。下面按「题目到底要什么 → 怎么建模 → 怎么实现 → 坑在哪」拆开讲代码可以直接抄去跑。2. 把售票规则翻译成数据结构80 个座位怎么存这道题的第一个分水岭不在写循环而在建模。题目给的座位布局是 1 到 80按间隔分组1、2、5、6 在一个间隔3、4、7、8 在另一个间隔往后每 8 个座位重复这个模式。很多人上来就开一个int seat[80]存 0/1 表示是否售出然后写一堆if判断相邻和同间隔写到后面自己都绕晕。问题出在座位号是「一维」的但业务规则是「二维」的——相邻关系和间隔归属都不是靠座位号加减能直接算出来的。2.1 座位编号与间隔的映射关系先把布局规律抽出来。观察题目图第 1 排是 1、2、过道、3、4第 2 排是 5、6、过道、7、8以此类推。也就是说每 8 个座位构成一个「大块」块内偏移 0、1 是左侧相邻对偏移 2、3 是右侧相邻对偏移 4、5 是下一排左侧相邻对偏移 6、7 是下一排右侧相邻对。而「一个间隔」指的是同一排左右两侧那 4 个座位即偏移 {0,1,2,3} 或 {4,5,6,7}。用座位号n从 1 开始反推块索引block (n - 1) / 8块内偏移off (n - 1) % 8相邻对off为偶数时n与n1相邻因为 0-1、2-3、4-5、6-7 成对间隔编号section block * 2 (off 4 ? 1 : 0)这套映射是整道题的地基。我一般会先写一个小的验证程序把 1 到 80 全部打印出(座位号, 相邻伙伴, 间隔号)肉眼核对几组再往下写。别嫌麻烦这一步省下来后面调试相邻判断时你会花三倍时间还找不着北。2.2 状态数组与辅助索引的设计数据结构我推荐两个数组配合#define SEAT_COUNT 80 #define SECTION_COUNT 40 /* seatState[i] 0 未售1 已售下标 0 对应座位 1 */ int seatState[SEAT_COUNT]; /* sectionSeat[s][k] 存第 s 个间隔内第 k 个座位的座位号k 取 0..3 */ int sectionSeat[SECTION_COUNT][4];seatState负责 O(1) 查某座位卖没卖sectionSeat是预计算好的「间隔 → 座位号」反查表初始化时一次性填好后面判断「某间隔还剩几张、剩的是哪几张」就不用每次现算。这是典型的空间换清晰度多花 160 个 int换来售票逻辑里少写两层嵌套取模。初始化代码void InitLayout(void) { for (int n 1; n SEAT_COUNT; n) { int block (n - 1) / 8; int off (n - 1) % 8; int section block * 2 (off 4 ? 1 : 0); int posInSection off % 4; /* 间隔内位置 0..3 */ sectionSeat[section][posInSection] n; seatState[n - 1] 0; } }参数说明block是 8 座大块编号off是块内偏移section落在 0..39posInSection把偏移 0..3 和 4..7 都压回 0..3正好对应间隔内四个位置。跑完这段sectionSeat[0]应该是{1,2,3,4}sectionSeat[1]是{5,6,7,8}可以拿这个当自检点。2.3 相邻关系的判定别用座位号硬减相邻只有一种情况同一间隔内位置 0 和 1 相邻位置 2 和 3 相邻。注意题目明确说 1 和 5 不算相邻、2 和 3 不算相邻——2 和 3 虽然座位号连着但分属左右两侧中间隔着过道。所以判定相邻绝不能写abs(a-b)1必须回到间隔内位置int IsAdjacent(int a, int b) { int sa SectionOf(a), sb SectionOf(b); if (sa ! sb) return 0; int pa PosInSection(a), pb PosInSection(b); return (pa / 2) (pb / 2); /* 0-1 一组2-3 一组 */ }SectionOf和PosInSection就是 2.1 里那两个公式的封装。这样写的好处是规则和代码一一对应将来布局变了只改映射函数判定逻辑不动。血泪经验考场上有人图快直接a1b结果 2 和 3 被判成相邻售 2 张票时优先规则全乱输出和标准答案对不上还查不出原因。3. 售票主流程四种票数、三级优先级的落地建模清楚后主流程其实是「按票数分派到不同策略函数」。题目规则可以归纳成一张优先级表先把它写死在心里再落代码。请求票数第一优先兜底策略不足时1 张任意未售座位无无总有空位或全满2 张同一间隔内相邻对任意两张未售不足 2 张则提示不足3 张同一间隔内 3 张任意 3 张未售不足 3 张则提示不足4 张同一间隔整 4 张任意 4 张未售不足 4 张则提示不足注意题目对 3、4 张的表述「优先售一个间隔内的票如果剩余票数不足就提示不足不售票。如果不能满足优先原则则售任何位置的票。」这里有个容易读错的点——「剩余票数不足」指的是全车厢剩余票数不足请求数不是「某间隔内不足」。间隔内凑不齐 3 张属于「不能满足优先原则」应该走兜底随便卖而不是拒绝。这个区分直接决定边界用例过不过。3.1 售 1 张与售 2 张先找相邻对售 1 张最简单从头扫第一个未售即可题目说「随便售出一张」不要求随机顺序扫完全可接受还便于结果复现。售 2 张的核心是找相邻对。遍历 40 个间隔每个间隔检查 (位置0,1) 和 (位置2,3) 两组只要两张都未售就成对卖出int SellTwo(int *out) { for (int s 0; s SECTION_COUNT; s) { for (int g 0; g 2; g) { int a sectionSeat[s][g * 2]; int b sectionSeat[s][g * 2 1]; if (!seatState[a - 1] !seatState[b - 1]) { seatState[a - 1] seatState[b - 1] 1; out[0] a; out[1] b; return 2; } } } return SellAny(2, out); /* 兜底任意两张未售 */ }g取 0 时检查位置 0-1取 1 时检查位置 2-3正好覆盖间隔内两组相邻对。找不到就落到SellAny。这里有个隐含约定优先规则只要求「存在相邻就卖相邻」没要求卖哪一对所以顺序遍历第一个命中的即可结果确定、好对答案。3.2 售 3 张与售 4 张整间隔优先3 张和 4 张共用「整间隔」思路区别只在需要几张。先统计全车厢剩余总数不够就直接返回不足够的话再找间隔int SellInSection(int need, int *out) { int remain CountRemain(); if (remain need) return -1; /* 全车不足提示不售 */ for (int s 0; s SECTION_COUNT; s) { int freeCnt 0, tmp[4], t 0; for (int k 0; k 4; k) { int n sectionSeat[s][k]; if (!seatState[n - 1]) { tmp[t] n; freeCnt; } } if (freeCnt need) { /* 该间隔能凑齐 */ for (int i 0; i need; i) { seatState[tmp[i] - 1] 1; out[i] tmp[i]; } return need; } } return SellAny(need, out); /* 优先原则不满足兜底 */ }参数need传 3 或 4。freeCnt need是关键售 3 张时一个间隔剩 3 张或 4 张都算满足优先售 4 张时必须剩满 4 张。tmp暂存该间隔的空位号命中后按序卖出。找不到合适间隔就SellAny兜底注意此时全车剩余已确认够need兜底一定能成。3.3 主循环与文件接口的对接题目给了GetRequest和OutputResult两个函数直接复用即可主循环就是把它们串起来int main(void) { InitLayout(); int req, seats[4]; while (GetRequest(req)) { int sold 0; switch (req) { case 1: sold SellOne(seats); break; case 2: sold SellTwo(seats); break; case 3: case 4: sold SellInSection(req, seats); break; default: continue; } if (sold 0) { /* 不足按题目要求提示不写座位 */ printf(余票不足本次请求 %d 张未售出\n, req); continue; } OutputResult(seats, sold); } return 0; }GetRequest内部用静态变量缓存了整个request.txt的内容第一次调用时一次性读完再关闭文件后续从内存数组取。这个设计有个前提输入文件里最多 80 个请求且用 0 作为结束标记。你调试时如果发现读到一半就停了先检查文件里是不是混进了 0或者请求数超过 80 被截断——这是这份框架自带的边界不是你的逻辑错。4. 文件读写与静态变量框架里藏着的几个雷题目把GetRequest和OutputResult的实现直接给了说「可以直接使用」但「能用」和「用对」是两回事。这段框架代码里有几处细节不提前说清楚调试时会怀疑人生。4.1 GetRequest 的静态缓存机制bool GetRequest(int *p) { static FILE* fp fopen(d:\\request.txt, r); static int nIndex 0; static int inputData[80] {0}; static bool isfirst true; int i; if (isfirst) { for (i 0; i 80; i) { if (fscanf(fp, %d,, inputData[i]) EOF) break; } isfirst false; fclose(fp); } if (inputData[nIndex] 0 || nIndex 80) return false; *p inputData[nIndex]; return true; }三个static各司其职fp只打开一次inputData缓存全部请求isfirst保证只读一遍文件。fscanf的格式串是%d,注意那个逗号——它要求数字后面跟逗号。题目说输入可以用空格、制表符、换行分隔但这段代码只认逗号格式串里的逗号会「吃掉」一个非数字字符空格换行也能凑合过但如果文件里是1 2 3这种纯空格分隔fscanf读第一个1后期待逗号遇到空格会匹配失败后续读取就错位了。稳妥做法是把格式串改成%d让fscanf自动跳过所有空白符。这是我在类似题目上翻过的车框架给的代码不一定适配你的测试文件读进来全是 0 或乱序先怀疑格式串。4.2 OutputResult 的追加模式与格式void OutputResult(int * SeatNum, int Count) { FILE* fp fopen(d:\\result.txt, a); int i; fprintf(fp, \n); for (i 0; i Count; i) { fprintf(fp, %d,, SeatNum[i]); } fprintf(fp, \n); fclose(fp); }a是追加模式每次售票结果接在文件末尾不会覆盖历史记录这符合「多次售票、逐次记录」的要求。但要注意追加模式不会自动清空旧文件你反复跑程序result.txt会越积越长对答案时容易看串行。我的习惯是每次测试前手动删掉result.txt或者在main开头用w模式打开一次再关掉把文件清空。另外fopen返回值没判空如果d:\盘不存在或没写权限fp是 NULLfprintf直接崩。加一行if (!fp) { perror(result.txt); return; }能省不少排查时间。4.3 路径写死带来的移植问题框架里路径是d:\\request.txt和d:\\result.txt写死在函数内部。换台机器没有 D 盘程序静默失败——GetRequest里fopen返回 NULLfscanf(NULL, ...)是未定义行为可能直接段错误也可能读到垃圾。题目说「根据实际情况可以修改给出的程序」那就大方改把路径提成宏或全局变量或者改成相对路径request.txt把文件放可执行文件同目录。改的时候注意GetRequest里fp是静态初始化路径必须在编译期确定用宏最省事#define REQ_PATH request.txt #define RES_PATH result.txt然后把两处fopen的参数换掉。这一步改动小但能让程序在你自己的机器上跑起来不然连第一步都迈不出去。5. 避坑与排查五个真实会卡住你的点5.1 现象售 2 张时把 2 和 3 当成相邻卖了原因相邻判定用了abs(a-b)1或a1b没考虑过道分隔。2 和 3 座位号连续但分属左右两侧题目明确不算相邻。解决回到间隔内位置判定用 2.3 的IsAdjacent位置 0-1、2-3 才成对。写完拿 1 到 8 号座位两两跑一遍确认只有 (1,2)(3,4)(5,6)(7,8) 返回真。5.2 现象售 3 张时某间隔只剩 2 张程序直接提示不足不卖了原因把「间隔内凑不齐」误判成「全车不足」。题目说的是全车剩余不足才拒售间隔内不够属于「不能满足优先原则」应走兜底随便卖。解决先CountRemain()判全车总数够就继续找间隔找不到合适间隔调SellAny(need, out)不要提前 return 不足。5.3 现象result.txt 里结果越跑越多对不上标准输出原因OutputResult用追加模式旧结果没清。反复调试时历史记录堆叠。解决每次运行前清空结果文件或在main开头以w打开一次result.txt再关闭。测试脚本里加一句rm -f result.txt也行。5.4 现象GetRequest 读到第二个请求就返回 false原因输入文件里混入了 0而框架用inputData[nIndex] 0当结束标记或者请求数超过 80nIndex 80触发停止。解决检查request.txt内容确保只有 1 到 4 的数字、没有 0请求数控制在 80 以内。如果业务上真需要 0得改框架的结束判定逻辑但考试场景按题目约定来即可。5.5 现象程序在别人机器上直接崩溃自己机器正常原因路径写死d:\对方没有 D 盘fopen返回 NULL 未判空后续文件操作是未定义行为。解决路径改成相对路径或宏配置两处fopen后都加判空失败时打印perror并退出。这是移植性最基本的后悔药早加早省心。6. 用状态快照验证结果一个能省半天调试的习惯这道题最容易出的错不是编译不过而是「跑起来了、结果看着像对的、其实某条规则错了」。光靠肉眼扫result.txt很难发现尤其售 3 张兜底和间隔优先混在一起时。我一般会加一个调试开关每次售票后打印全车厢状态快照用固定输入跑一遍人工核对前几轮确认规则无误再关掉。快照函数这样写void DumpState(void) { for (int s 0; s SECTION_COUNT; s) { printf(间隔%2d: , s); for (int k 0; k 4; k) { int n sectionSeat[s][k]; printf(%2d[%c] , n, seatState[n - 1] ? X : O); } printf(\n); } printf(剩余: %d\n\n, CountRemain()); }X表示已售O表示未售每行一个间隔正好对应题目图的布局。拿一份手写的小输入比如2 2 3 4 1预期是第一次卖 (1,2)第二次卖 (3,4)同间隔相邻对优先第三次请求 3 张时第一个间隔已满、第二个间隔 {5,6,7,8} 全空应卖 (5,6,7)第四次请求 4 张时第二个间隔只剩 8 号一张凑不齐 4 张走兜底从后面间隔随便卖 4 张。对着快照一步步看哪条规则没生效一目了然。验证时重点盯三个边界全车只剩 1 张时请求 2 张应提示不足、某间隔剩 3 张时请求 4 张应兜底而非拒售、请求 4 张但全车只剩 3 张应提示不足。这三个用例过了规则实现基本就稳了。从那以后我每次写这类带优先级的模拟题都强制先写快照再写主逻辑调试时间至少砍一半。希望这个习惯也能帮到你这份考题的完整框架和输入样例拿去照着跑一遍比看十篇讲解都管用。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/28 21:15:33

AG3335M Datasheet解读:GNSS芯片选型与设计避坑指南

简介:AG3335M Datasheet 面向从事高精度卫星定位开发的硬件工程师与嵌入式软件人员,提供 AG3335M 及 AG3335MN 两款 GNSS 接收芯片的完整技术规格。文档重点说明两者在 L5 频段上的差异——AG3335MN 仅支持 IRNSS,并系统梳理 L1/L5 双频多星座…

2026/10/28 21:15:33

impeccable与perfect、flawless辨析:从词源到搭配的完全指南

我最初注意到"impeccable"这个词,是在一篇外媒对某位主厨的采访里,对方形容一道菜品时用了"impeccable balance of flavors"。当时的直觉是,这个词比perfect更高级、比excellent更精准,但真要我用它造句&…

2026/10/28 21:15:33

AI能力落地的核心技术:Function Calling、MCP与Agent Skills

1. 项目概述:AI能力落地的三大核心技术支柱在AI技术快速发展的今天,大模型的能力边界不断拓展,但如何让这些能力真正落地到实际应用中,却是一个值得深入探讨的问题。经过多年实践,我发现Function Calling、MCP&#xf…

2026/10/28 22:37:06

2026年脑机接口测试IDE的核心技术与应用实践

1. 脑机接口测试IDE的现状与需求2026年的脑机接口开发环境正在经历一场革命性变革。传统的脑机接口开发工具往往需要开发者同时掌握神经科学、信号处理和编程等多领域知识,这种高门槛严重限制了脑机接口技术的普及应用。目前主流的脑机开发环境如OpenBCI的Cyton Boa…

2026/10/28 22:37:06

React性能调试哲学:caveman原始人方法论

1. 项目概述:一个被误读的“原始人”,实则是 React 性能优化的隐喻代号“caveman”这个词在搜索引擎里一搜,满屏都是 token 报错、npx 安装失败、React 面试高频题和各种登录失败日志。但如果你真去 npm registry 上查caveman这个包名&#x…

2026/10/28 22:37:06

家庭储能与主动配电网的协同优化技术解析

1. 产消者模式与家庭储能的能源革命当屋顶光伏板成为越来越多家庭的标配,一个全新的能源时代正在我们眼前展开。去年夏天,我在为自家安装5kW光伏系统时,供电公司的工作人员随口提到:"现在像您这样既用电又发电的用户&#xf…

2026/10/28 22:37:06

VPX62电源标准中文四层解读与选型设计要点

简介:VITA 62.0 电源标准中文版面向 VPX 电源模块设计、验证与系统集成工程师,解决模块化电源在机箱供电中的规范依据问题,适合硬件选型、接口核对和测试验收等场景。压缩包内为 1 个 docx 文件,约 567KB,内容围绕 ANS…

2026/10/28 22:37:06

基于OCSSA-VMD-CNN-BILSTM的轴承故障诊断模型

1. 项目背景与核心价值轴承作为旋转机械的核心部件,其健康状态直接影响设备运行安全。传统振动信号分析方法在复杂工况下存在特征提取不充分、诊断精度不足等问题。本项目提出的OCSSA-VMD-CNN-BILSTM混合模型,通过智能优化算法与深度学习的有机结合&…

2026/10/28 22:32:04

信号发生器白屏维修:电源、背光、接口与BGA返修全流程

信号发生器白屏这件事,说大不大,说小也不小。它不像射频指标漂移那样需要一堆仪器比对,也不像电源炸机那样一眼能看出烧痕,白屏往往就卡在“屏幕是亮的但什么都没显示”这个尴尬状态上:背光有、画面无,或者…

2026/10/28 14:42:12

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/28 15:28:56

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/28 3:32:29

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/28 0:02:13

Python股票自动交易系统源码解析:从行情获取到风控的完整链路

简介:这份资源是面向高校计算机、金融相关专业毕业设计场景的完整项目源码包,主题为基于Python的股票自动交易系统,适合需要完成毕设选题、课程设计或自学金融量化交易开发的学生与开发者参考。压缩包共收录687个文件,整体约14.93…

2026/10/28 0:02:13

视酷酷信IM源码部署指南:Java 17+MySQL 8.0.33实战配置

简介:这是一套2024年亲测可部署的视酷酷信IM即时通讯系统源码,面向具备Java、OC、C#及Vue开发能力的技术人员,解决私有化即时通讯平台快速搭建与二次定制需求,尤其适用于需集成商城、保障数据主权的中小型企业或独立开发者。资源共…

2026/10/28 0:02:13

Python爬取百度迁徙数据:接口解析、批量采集与避坑指南

简介:这份资源是一个用Python爬取百度迁徙数据的脚本压缩包,面向具备Python基础、希望入门网络爬虫与数据解析的开发者,解决按日期获取全国热门城市人口迁徙数据的问题。包内共1个文件,为单个py脚本,压缩包约1KB&#…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑