- 版权声明:本书的官方、完整习题答案通常由出版社或作者持有,并未完全公开,以下内容是基于该书知识点和常见习题整理的思路解析、代码示例和参考答案,旨在帮助您学习和理解,不能替代您自己的思考和练习。
- 版本差异:不同版本的教材,章节顺序和习题可能略有不同,请根据您手中的具体版本进行参考。
- 学习目的:学习编程的关键在于理解原理、动手实践,直接复制粘贴答案对编程能力的提升帮助有限,建议您先自己尝试编写,遇到困难时再参考这里的思路。
关键知识点总结
在开始解答习题前,我们先快速回顾一下钱能老师《C++程序设计教程》中的核心知识点,这些是解决大多数习题的基础。

C++基础语法
- 数据类型:
int,float,double,char,bool,以及它们的修饰符(如long,short,unsigned)。 - 变量与常量:变量的定义、初始化、作用域,常量使用
const关键字或#define宏定义。 - 运算符:
- 算术运算符:, , , ,
- 关系运算符:
>,<,>=,<=, , - 逻辑运算符:
&&, , - 位运算符:
&, ,^, ,<<,>> - 赋值运算符:, , 等
- 其他:
sizeof, (三元运算符)
- 输入输出:
std::cin和std::cout,配合>>和<<运算符。
流程控制
- 顺序结构:代码从上到下顺序执行。
- 选择结构:
if-else语句switch-case语句
- 循环结构:
for循环while循环do-while循环break和continue的使用
函数
- 函数定义:返回类型 函数名(参数列表) { 函数体 }
- 函数声明:返回类型 函数名(参数列表);
- 参数传递:
- 值传递:默认方式,函数内部修改不影响外部变量。
- 引用传递:使用
&符号,函数内部修改会直接影响外部变量。 - 指针传递:传递变量的地址,功能上类似引用传递。
- 函数重载:在同一作用域内,可以定义多个同名函数,只要它们的参数列表(参数个数或类型)不同。
数组与字符串
- 一维数组:定义、初始化、访问(通过下标)。
- 多维数组:特别是二维数组,常用于表示矩阵。
- 字符串:
- C风格字符串:字符数组,以
'\0'使用strcpy,strlen,strcmp等函数(需包含<cstring>)。 - C++标准库字符串:
std::string类,更安全、易用,推荐使用。
- C风格字符串:字符数组,以
指针
- 指针的定义: 符号,用于声明指针变量,存放内存地址。
- 取地址符:
&符号,用于获取变量的地址。 - 指针运算: (解引用/间接寻址),, 等。
- 指针与数组:数组名在大多数情况下会“退化”为其首元素的地址,因此可以通过指针遍历数组。
- 指针与函数:通过指针或引用,可以让函数操作外部变量或动态分配的内存。
结构体与联合体
- 结构体 (
struct):将不同类型的数据组合成一个整体,通过 访问成员,通过指针访问成员用->。 - 联合体 (
union):所有成员共享同一块内存空间,同一时间只能存储一个成员的值。
类与对象 (面向对象编程的核心)
- 类 (
class):自定义的数据类型,包含数据成员(属性)和成员函数(方法)。 - 对象 (
object):类的实例。 - 访问修饰符:
public:任何地方都可以访问。private:只能在类内部访问(默认)。protected:在类内部和派生类中可以访问。
- 构造函数:在创建对象时自动调用,用于初始化对象,没有返回值。
- 析构函数:在对象生命周期结束时自动调用,用于清理资源(如释放内存),函数名为
~类名()。 this指针:指向当前对象的指针。
动态内存分配
new:在堆上分配内存,返回指向该内存的指针。delete:释放由new分配的内存。new[]和delete[]:用于分配和释放数组。
习题答案与解析(示例)
这里选取一些教材中典型的、有代表性的章节和习题进行解析。
示例1:第3章 - 函数与程序结构
编写一个函数,判断一个整数是否为素数(质数),并在 main 函数中调用它测试从 1 到 100 的所有素数。
思路解析:
- 素数定义:一个大于1的自然数,除了1和它自身以外不再有其他因数。
- 函数设计:
- 函数名:
isPrime - 参数:一个整数
int num。 - 返回值:如果是素数,返回
true(或1);否则返回false(或0),使用bool类型更符合 C++ 风格。 - 逻辑:
- 处理特殊情况:小于等于1的数不是素数。
- 从 2 开始,到
num-1(或更优化的sqrt(num))进行遍历,检查是否有能整除num的数。 - 如果找到任何一个因数,立即返回
false。 - 如果遍历结束都没有找到因数,则返回
true。
- 函数名:
main函数:- 使用一个
for循环遍历 1 到 100。 - 在循环内,对每个数字调用
isPrime函数。 - 根据返回值,如果是
true,则输出该数字。
- 使用一个
参考代码:
#include <iostream>
#include <cmath> // 为了使用 sqrt 函数进行优化
// 函数声明
bool isPrime(int num);
int main() {
std::cout << "1到100之间的素数有:" << std::endl;
for (int i = 1; i <= 100; ++i) {
if (isPrime(i)) {
std::cout << i << " ";
}
}
std::cout << std::endl;
return 0;
}
// 函数定义:判断一个数是否为素数
bool isPrime(int num) {
// 小于等于1的数不是素数
if (num <= 1) {
return false;
}
// 2是唯一的偶素数
if (num == 2) {
return true;
}
// 排除所有偶数
if (num % 2 == 0) {
return false;
}
// 从3开始,到sqrt(num),步长为2,检查是否有因数
for (int i = 3; i <= sqrt(num); i += 2) {
if (num % i == 0) {
return false; // 如果有因数,则不是素数
}
}
// 如果没有找到因数,则是素数
return true;
}
示例2:第5章 - 数组与字符串
有一个已按升序排序的整型数组,现输入一个整数,将其插入到数组中,并保持数组仍为升序。
思路解析:
- 输入数据:首先需要一个已经排序的数组,
int arr[10] = {1, 3, 5, 7, 9};,还需要知道当前数组中已有多少个有效元素(count = 5),以及要插入的数字insertNum。 - 查找插入位置:遍历数组,找到第一个大于
insertNum的元素的位置,这个位置就是insertNum应该插入的位置,如果所有元素都小于insertNum,则插入到数组末尾。 - 元素后移:从找到的插入位置开始,将后面的所有元素都向后移动一位,为新元素腾出空间,注意:必须从数组末尾开始向后移动,否则会覆盖掉未移动的元素。
- 插入元素:将
insertNum放入腾出的空位。 - 更新计数:数组中的有效元素数量
count需要加 1。
参考代码:
#include <iostream>
int main() {
int arr[10] = {1, 3, 5, 7, 9};
int count = 5; // 当前数组中的元素个数
int insertNum;
std::cout << "原始数组: ";
for (int i = 0; i < count; ++i) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
std::cout << "请输入要插入的整数: ";
std::cin >> insertNum;
// 1. 查找插入位置
int insertPos = 0;
while (insertPos < count && arr[insertPos] < insertNum) {
insertPos++;
}
// 循环结束后,insertPos 就是要插入的位置
// 2. 元素后移
// 从最后一个元素开始,向后移动一位
for (int i = count; i > insertPos; --i) {
arr[i] = arr[i - 1];
}
// 3. 插入元素
arr[insertPos] = insertNum;
// 4. 更新计数
count++;
std::cout << "插入后的数组: ";
for (int i = 0; i < count; ++i) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
return 0;
}
示例3:第7章 - 类与对象
设计一个 Student 类,包含姓名(name)、学号(id)和成绩(score)三个私有数据成员,要求提供构造函数、设置和获取这些成员信息的公有函数,以及一个用于显示学生信息的 display 函数。
思路解析:
- 定义类
Student:- 私有数据成员:
std::string name,std::string id,double score。 - 公有成员函数:
- 构造函数:
Student(std::string n, std::string i, double s),用于初始化对象。 - 设置函数 (Setter):
setName,setId,setScore。 - 获取函数 (Getter):
getName,getId,getScore。 - 显示函数:
display,使用std::cout打印所有信息。
- 构造函数:
- 私有数据成员:
- 实现成员函数:在类定义外部实现这些函数,需要使用 作用域解析符。
main函数测试:- 创建一个
Student对象,使用构造函数初始化。 - 调用
display函数显示信息。 - 调用
setScore修改成绩。 - 再次调用
display函数,验证修改是否成功。
- 创建一个
参考代码:
#include <iostream>
#include <string>
// Student类的定义
class Student {
private: // 私有成员,外部无法直接访问
std::string name;
std::string id;
double score;
public: // 公有成员,外部可以访问
// 构造函数
Student(std::string n, std::string i, double s) {
name = n;
id = i;
score = s;
std::cout << "学生 " << name << " 的信息已创建。" << std::endl;
}
// 设置函数
void setName(std::string n) { name = n; }
void setId(std::string i) { id = i; }
void setScore(double s) { score = s; }
// 获取函数
std::string getName() { return name; }
std::string getId() { return id; }
double getScore() { return score; }
// 显示信息函数
void display() {
std::cout << "--- 学生信息 ---" << std::endl;
std::cout << "姓名: " << name << std::endl;
std::cout << "学号: " << id << std::endl;
std::cout << "成绩: " << score << std::endl;
std::cout << "----------------" << std::endl;
}
};
int main() {
// 创建一个Student对象,调用构造函数
Student stu1("张三", "2025001", 95.5);
// 调用display函数显示初始信息
stu1.display();
// 修改学生成绩
std::cout << "将张三的成绩修改为 98.0..." << std::endl;
stu1.setScore(98.0);
// 再次调用display函数,查看修改后的信息
stu1.display();
return 0;
}
学习建议
- 动手敲代码:不要只看不练,将书上的例子和这里的解析代码都自己亲手敲一遍,观察运行结果。
- 理解优于记忆:理解每个语法点背后的设计思想(比如为什么要有引用?为什么要有类?),比死记硬背语法重要得多。
- 调试是关键技能:学会使用编译器的错误提示信息,并学会使用调试器(GDB, VS Debugger 等)单步跟踪程序,观察变量变化,这是排查问题的最快方法。
- 多思考“为什么”:
- 这个函数为什么用引用传递而不是值传递?
- 这个循环为什么用
for而不是while? - 这个成员变量为什么是
private的?
- 善用工具:一个好的 IDE(如 Visual Studio, VS Code, CLion)能极大地提高你的开发效率。
希望这份详细的总结和示例能对您的学习有所帮助!祝您学习顺利!
