C++实验100道习题答案:从刷题到调试的实战指南
发布时间:2026/10/23 22:33:47 锦皓数字建站

简介这份资源是西北工业大学C实验课程的100道习题答案合集面向正在学习C程序设计的高校学生与自学者帮助解决实验课中语法不熟、思路卡壳、调试困难等问题。压缩包共98个文件全部为cpp源代码整体约32KB每份代码对应一道习题的完整实现涵盖基础语法、函数与递归、类与对象、数组与动态内存、字符串处理、输入输出流、结构体与联合体、指针、模板及异常处理等核心知识点。目前已有901人学习下载。每道题的解答均包含清晰的逻辑分析、步骤分解与可运行代码读者可对照题目理解变量声明、流程控制、封装继承多态、new与delete内存管理等具体用法并借助源码调试过程掌握排错思路从而举一反三系统提升C编程能力为后续课程与项目开发打下基础。1. 从一份 C 习题答案说起它到底能帮你省下多少时间如果你正在啃 C 基础大概率经历过这种场景对着实验指导书上的题目语法能看懂思路也大概有但真到动手写的时候指针怎么传、引用什么时候用、类里的构造函数为什么报错全卡住了。这时候你需要的不是再翻一遍教材而是一份能跑通、能对照、能帮你定位问题的参考实现。这份“C 实验 100 道习题答案”就是干这个的——它覆盖了从基本语法、函数、数组、指针到类与对象、继承多态、运算符重载、模板和文件操作这些 C 实验课的核心考点每道题都有对应的源码和必要注释。适合正在上 C 实验课、准备期末机考、或者想靠刷题把语法肌肉记忆练出来的同学。它不是那种只给最终输出的“答案册”而是能让你逐行对照、理解每一步为什么这么写的参考代码集。下面我从怎么用、怎么避坑、怎么进阶三个层面把这份资源拆开讲清楚。2. 先搞清楚这 100 道题的技术分布别拿到就从头刷2.1 题目类型与知识点映射这份习题答案按实验课的常见进度组织大致可以分成几个模块。我拿到手第一件事不是从第一题开始抄而是先扫一遍目录看看哪些是我已经熟的、哪些是我一写就翻车的。常见的分布是这样的模块题量占比核心考点典型翻车点基础语法与流程控制约 15%循环、分支、输入输出格式cin与getline混用导致跳过输入函数与参数传递约 15%值传递、引用传递、默认参数引用传参时误传临时变量数组与指针约 20%一维/二维数组、指针运算、动态内存数组越界、delete与delete[]混用类与对象约 20%构造/析构、拷贝构造、友元浅拷贝导致双重释放继承与多态约 15%虚函数、纯虚函数、虚析构基类指针delete不触发派生类析构运算符重载与模板约 10%operator、函数模板、类模板重载时返回类型写错文件操作与综合约 5%fstream、字符串流文件打开模式组合错误这个表不是让你背的是让你在刷题前先定位自己的薄弱区。比如你指针本来就虚那就别急着往后翻类与对象先把数组与指针那 20 道集中做掉。常见做法是每天集中攻一个模块做完对照答案把编译报错和逻辑错误分开记录。2.2 怎么判断一道题值不值得深挖不是每道题都值得你花 30 分钟死磕。我的判断标准很简单如果这道题涉及内存管理、对象生命周期、或者多态行为那就值得深挖如果只是换个循环边界或者改个输出格式扫一眼答案知道套路就行。举个例子下面这种题就属于必须亲手写一遍的// 题目实现一个 String 类要求支持拷贝构造和赋值运算符 class String { private: char* data; int len; public: String(const char* str ) { len strlen(str); data new char[len 1]; strcpy(data, str); } // 拷贝构造深拷贝 String(const String other) { len other.len; data new char[len 1]; strcpy(data, other.data); } // 赋值运算符先释放旧内存再深拷贝 String operator(const String other) { if (this other) return *this; // 自赋值检查 delete[] data; len other.len; data new char[len 1]; strcpy(data, other.data); return *this; } ~String() { delete[] data; } };这段代码的关键不在语法而在三个地方拷贝构造里new的时机、赋值运算符里的自赋值检查、析构里delete[]和new[]的配对。参数说明other是常量引用避免拷贝且防止修改原对象this other是自赋值保护少了这行在s s时会先释放再访问已释放内存。逻辑说明先分配新内存再拷贝顺序反了就会丢数据。这种题你抄一遍没用必须自己写一遍然后故意把自赋值检查删掉看它怎么崩才能记住。2.3 答案的使用姿势对照而不是复制我见过太多人把答案下载下来编译跑通输出对上了就觉得自己会了。结果考试换个数字就写不出来。正确的用法是先自己写写完编译编译不过看报错报错解决不了再翻答案。翻答案的时候重点看三样东西——变量命名习惯、边界条件处理、资源释放位置。比如指针题里答案在delete之后有没有把指针置空类题里拷贝构造有没有处理自赋值这些细节才是这份资源真正值钱的地方。你如果只是复制粘贴那这 100 道题对你来说就是 100 个孤立的代码片段串不起来。3. 把答案跑起来环境配置与逐题验证流程3.1 编译环境的选择与常见报错这份答案里的代码大部分是标准 C用 g 或者 clang 都能编。但实验课常用的 IDE 可能是 Visual Studio、Dev-C 或者 Code::Blocks不同环境对标准的支持程度不一样。我一般会先用命令行 g 过一遍确认代码本身没问题再放到 IDE 里跑。常见做法是# 编译单个 cpp 文件开启所有警告 g -stdc11 -Wall -Wextra -o test test.cpp # 如果用到数学库加 -lm g -stdc11 -Wall -o test test.cpp -lm # 运行 ./test参数说明-stdc11指定标准版本有些题用了auto或者范围 for不指定会报错-Wall -Wextra打开额外警告能帮你发现未初始化变量、符号比较这些隐性问题。逻辑说明先编译再运行不要一上来就在 IDE 里点运行IDE 的报错信息有时候被截断命令行的完整输出更容易定位问题。如果你在 Windows 上用 Visual Studio注意两点一是strcpy、scanf这类函数会报安全警告可以在文件开头加#define _CRT_SECURE_NO_WARNINGS二是有些题用了变长数组VS 不支持需要改成动态分配或者用vector。3.2 逐题验证的标准化步骤不要一次编译 100 个文件那样报错混在一起根本看不过来。我一般按模块来每个模块建一个文件夹里面放题目源码和测试输入。步骤是这样的从答案里挑出当前模块的题目复制到自己的工程目录重命名成有意义的文件名比如ex03_pointer_swap.cpp。先不编译快速扫一遍代码看有没有明显的语法问题比如漏分号、括号不匹配。编译把警告当错误看。警告往往指向潜在的运行时问题。构造测试用例。不要只用题目给的样例自己造边界数据空输入、最大值、最小值、重复值。运行对比输出。如果输出不对用cout在关键位置打印中间变量或者用调试器单步。下面是一个典型的测试用例构造示例以“判断素数”这道题为例// 测试用例边界值 特殊值 void testIsPrime() { // 正常情况 assert(isPrime(7) true); assert(isPrime(10) false); // 边界情况 assert(isPrime(2) true); // 最小素数 assert(isPrime(1) false); // 1 不是素数 assert(isPrime(0) false); // 0 不是素数 assert(isPrime(-5) false); // 负数不是素数 // 大数测试 assert(isPrime(9973) true); // 接近 int 范围的素数 }逻辑说明assert在调试时有用发布时可以用#define NDEBUG关掉。参数说明每个断言覆盖一种边界这样你改代码的时候能立刻知道有没有破坏原有逻辑。常见坑是只测了正常情况结果负数输入导致死循环或者错误输出。3.3 用版本管理记录你的修改这份答案是参考不是圣旨。你一定会遇到答案写法和你思路不一样、或者答案本身有 bug 的情况。这时候别直接改原文件用 git 建个仓库每改一道题提交一次。这样你既能保留原始答案又能看到自己的修改轨迹。命令很简单git init git add ex03_pointer_swap.cpp git commit -m 完成指针交换题修正了答案中未置空指针的问题这样做的好处是过一周你回头看能清楚知道自己当时卡在哪、怎么解决的。血泪经验没有版本管理改乱了想回退都回不去只能重新下载。4. 避坑与排查这 100 道题里最容易翻车的五个地方4.1 指针与动态内存删了又用用了又删现象程序在delete之后还能访问那块内存输出看起来正常但偶尔崩溃或者输出乱码。原因delete只是把内存还给系统指针本身还指向原来的地址继续访问就是悬空指针。解决delete之后立刻把指针置为nullptr后续使用前先判空。常见做法是封装一个safeDelete函数但更根本的是养成习惯——谁分配谁释放释放完就置空。4.2 拷贝构造与赋值浅拷贝导致双重释放现象程序在析构时崩溃报double free or corruption。原因类里用了指针成员但没有自定义拷贝构造和赋值运算符编译器生成的默认版本只复制指针地址两个对象指向同一块内存析构时释放两次。解决只要类里有指针成员就老老实实写拷贝构造、赋值运算符和析构也就是常说的“三法则”。如果用了 C11还可以考虑移动构造和移动赋值变成“五法则”。4.3 虚析构缺失基类指针删派生类对象现象通过基类指针delete派生类对象时派生类的析构函数没被调用导致资源泄漏。原因基类析构函数不是虚函数delete时只调用了基类析构。解决只要类可能被继承并通过基类指针删除基类析构必须声明为virtual。这条在继承与多态模块的题目里反复出现别嫌烦。4.4 输入流状态cin失败后后续输入全乱现象输入一个字母程序进入死循环或者后续所有输入都被跳过。原因cin进入失败状态缓冲区里的错误字符没被清除后续读取直接失败。解决输入失败后调用cin.clear()清除状态再用cin.ignore()清空缓冲区。常见写法if (!(cin num)) { cin.clear(); // 清除错误状态 cin.ignore(10000, \n); // 丢弃缓冲区内容 cout 输入无效请重新输入 endl; }参数说明10000是丢弃的最大字符数\n是分隔符表示一直丢到换行。逻辑说明先清状态再清缓冲区顺序反了没用。4.5 文件操作打开模式组合错误现象文件明明存在但读取为空或者写入后文件内容被清空。原因fstream的打开模式没组合对比如用ios::in打开输出文件或者用ios::out打开已有文件导致截断。解决读文件用ifstream写文件用ofstream追加用ios::app。如果既要读又要写用fstream并明确指定ios::in | ios::out需要追加时再加ios::app。注意ios::out单独使用会截断文件这是最常见的翻车点。5. 从答案到能力用这 100 道题练出调试直觉5.1 把每道题当成一次小型代码审查答案跑通只是起点。我后来养成一个习惯每道题对照答案之后问自己三个问题——如果输入规模扩大十倍这段代码还成立吗如果去掉某个边界检查会在什么情况下出错有没有更简洁的写法比如数组排序题答案用了冒泡你能不能改成std::sort指针遍历能不能改成迭代器这种追问能把一道题的价值放大三倍。5.2 用调试器替代打印大法新手喜欢用cout打印中间变量这没错但效率低。这 100 道题里至少有 20 道涉及指针和内存用调试器看地址和值的变化直观得多。以 gdb 为例g -g -o test test.cpp # -g 生成调试信息 gdb ./test (gdb) break main # 在 main 函数打断点 (gdb) run # 运行 (gdb) next # 单步执行 (gdb) print ptr # 打印指针地址 (gdb) print *ptr # 打印指针指向的值 (gdb) continue # 继续运行参数说明-g是关键没有它 gdb 看不到源码和变量名。逻辑说明先断点再运行用next逐行用print检查状态。一旦你习惯用调试器定位段错误的速度会快很多。5.3 建立自己的错题本这 100 道题里你一定会反复踩同一类坑。我的做法是建一个 Markdown 文件每踩一个坑就记一条现象、原因、解决、涉及题目编号。比如“悬空指针”这条我会记下是在哪几道题里出现的下次再遇到类似代码先搜错题本。这个习惯坚持下来期末复习的时候你只需要翻错题本不用重新刷 100 道题。5.4 进阶技巧用静态分析工具提前发现问题编译器警告只是第一道防线。像cppcheck这类静态分析工具能在不运行代码的情况下发现内存泄漏、未初始化变量、数组越界等问题。安装后直接跑cppcheck --enableall --inconclusive test.cpp参数说明--enableall打开所有检查--inconclusive显示不确定的警告。逻辑说明它不能替代编译器但能发现一些编译器忽略的隐患。我一般会在提交实验报告前跑一遍把明显的问题先修掉。从那以后我每次拿到一份习题答案都强制自己先跑通、再改错、最后用调试器走一遍关键题而不是直接复制。希望这份拆解能帮你把这 100 道题真正变成自己的东西。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。