【C++习题】 《C++语言程序设计第四版》第1~6章 编程习题记录
【2_27】编写一段程序,运行时向用户提问“你考了多少分?(0~100)”,接受输入后判断其等级并显示出来。
判断依据如下:等级={优秀 (90~100分);良好 (80~89分);一般 (60~79分);不及格 (0~59分);}
要求:必须用switch语句实现。
代码:
int Code2_27()
{
int scores = 0;
cout << "你考了多少分?" << endl;
cin >> scores;
int caseScores = scores / 10; //用“整除”将分数的逻辑范围转化为case常量
switch (caseScores)
{
case(10):case(9): cout << "你的等级为:优秀"; //多个case对应一个表达式写法
break;
case(8): cout << "你的等级为:良好";
break;
case(7):case(6): cout << "你的等级为:一般";
break;
case(5):case(4):case(3):case(2):case(1):case(0):cout << "你的等级为:不合格";
break;
default:cout << "请检查分数是否在此范围内!" << endl;
break;
}
return scores;
}
需要注意的点:
1.switch语句里的case只能跟常量,而判断分数明显是逻辑判断,因此需要将逻辑值转化为常量
2.switch里多个case对应相同表达式的时写法
【2_28】实现一个简单的菜单程序,运行时显示"Menu: A(dd) D(elete) S(ort) Q(uit),Select one:"提示用户输入,A 表示增加,D 表示删除,S 表示排序,Q 表示退出,输入为 A、D、S 时分别提示"数据已经增加、删除、排序。"直到输入为 Q 时程序结束。
要求:必须使用 Switch 语句。
代码:
int Code2_28()
{
char userInput;
cout << "Menu: A(add) D(delete) S(sort) Q(quit),Select one:" << endl;
cin >> userInput;
while (userInput !='Q')
{
switch (userInput)
{
case 'A':cout << "数据已经增加...." << endl; break;
case 'D':cout << "数据已经删除..." << endl; break;
case 'S':cout << "数据已经排序..." << endl; break;
default:cout << "未找到此功能,请重新输入...." << endl; break;
}
cin >> userInput;
continue;
}
cout << "程序即将退出...." << endl;
return 0;
}
需要注意的点:
1.switch对应的常量不仅只有整型常量,还有实型常量和字符型常量等,因此可直接匹配字符'A'。
【2_29】用穷举法找出1~100的质数并显示出来,并分别用while、do-while、for循环语句实现.。
代码:
int Code_2_29()
{
//质数定义:不能被它本身和1以外的数整除
/*
* description:用while循环求1~100之间的质数
* parm: null
* return: null
*/
int number_1 = 1;
while (number_1 >=1&& number_1 <=100)
{
int i = 1;
int counts = 0;
while (i<= number_1)
{
if (number_1%i == 0) //整除的意思也就是求余数为0
{
counts++; //counts是余数为0的记次数
}
i++; //i从1递增到number本身
}
if (counts==2) //如果是两次整除就是1和本身,说明是质数
{
cout << number_1 << "是质数" << endl;
}
number_1++;
}
cout << "**************分割线***************" << endl;
/*
* description:用do...while循环求1~100之间的质数
* parm: null
* return: null
*/
int number_2 = 1;
do
{
int i = 1;
int counts = 0;
do
{
if (number_2%i==0)
{
counts++;
}
i++;
} while (i<= number_2);
if (counts==2)
{
cout << number_2 << "是质数" << endl;
}
number_2++;
} while (number_2 >=1&& number_2 <=100);
cout << "**************分割线***************" << endl;
/*
* description:用for循环求1~100之间的质数
* parm: null
* return: null
*/
for (int number_3 = 1; number_3 <= 100; number_3++)
{
int counts = 0;
for (int i = 1; i <= number_3; i++)
{
if (number_3%i==0)
{
counts++;
}
}
if (counts==2)
{
cout << number_3 << "是质数"<<endl;
}
}
return 0;
}
需要注意的点:
1.整除的意思也就是求余数为0
2.本质是双层循环嵌套:第一层循环穷举1~100,第二层循环穷举从1~自身
【2_32】在程序中定义一个整型变量,赋以 1~100 的值,要求用户猜这个数,比较两个数的大小,把结果提示给用户,直到猜对为止。
代码:
#include<cmath>
#include<time.h>
int Code_2_32()
{
srand((unsigned)time(NULL)); //置随机数种子
int number = rand()%100+1; //在1-100内随机取一个数
int guessNum = -1;
cout << "请猜一猜这个数字是多少?(1~100)" << endl;
cin >> guessNum;
while (guessNum != number)
{
if (guessNum>number)
{
cout << "输入的值偏大,请重新输入.." << endl;
}
else
{
cout << "输入的值偏小,请重新输入..." << endl;
}
cin >> guessNum;
}
cout << "恭喜你,猜对了!" << endl;
return 0;
}
需要注意的点:
1.置随机数种子是必要的,否则每次随机都是固定的,是假随机
2.注意从1~100取一个随机数的写法,用到了求余+1操作(不加1是在0~99取随机数)
【2_34】口袋中有红、黄、蓝、自、黑种颜色的球若干个。每次从口袋中取出个不同颜色的球,问有多少种取法?
代码:
#include<iomanip>
int Code_2_34()
{
//本质上是三层循环嵌套问题,每个循环体循环5次,判断i,j,k是否相同,不同就是三种不同的颜色
enum Color
{
Red=1,Yellow,Blue,White,Black //枚举值设为从1开始
};
//Color nowColor; //测试枚举用
int totals = 0; //totals代表一共有多少次取法
//第一层循环i
for (int i = 1; i <= 5; i++)
{
//第二层循环j
for (int j = 1; j <= 5; j++)
{
//第三层循环k
for (int k = 1; k <= 5; k++)
{
//判断i,j,k是否相同,如果不同,则说明是取到了三种不同颜色
if (i!=k && k!=j && j!=i)
{
//totals计数+1
totals++;
cout << setw(3) << totals;
//接下来判断和输出i,j,k三种不同颜色各是什么
//只需要用switch分别匹配当前i,j,k对应的枚举值即可
//首先判断i是什么颜色
switch (i)
{
case Red:cout <<setw(8)<< "Red"; break;
case Yellow:cout << setw(8) << "Yellow"; break;
case Blue:cout << setw(8) << "Blue"; break;
case White:cout << setw(8) << "White"; break;
case Black:cout << setw(8) << "Black"; break;
}
//其次判断j是什么颜色
switch (j)
{
case Red:cout << setw(8) << "Red"; break;
case Yellow:cout << setw(8) << "Yellow"; break;
case Blue:cout << setw(8) << "Blue"; break;
case White:cout << setw(8) << "White"; break;
case Black:cout << setw(8) << "Black"; break;
}
//最后判断k是什么颜色
switch (k)
{
case Red:cout << setw(8) << "Red"; break;
case Yellow:cout << setw(8) << "Yellow"; break;
case Blue:cout << setw(8) << "Blue"; break;
case White:cout << setw(8) << "White"; break;
case Black:cout << setw(8) << "Black"; break;
}
cout << endl; //换行
}
}
}
}
cout << "答:共有" << totals << "种取法." << endl;
return 0;
}
需要注意的点:
1.问题可抽象为从5个球中取三次,三次都是不同的颜色。因此,取三次进一步抽象为3层循环,每层循环执行5次,遍历所有可能的结果,从中找出三层循环都取到不一样的颜色这种情况,再分别匹配三层循环中i,j,k分别是什么颜色即可。
2.匹配可用switch分别匹配i,j,k的序号,再输出枚举类型中对应的颜色(变量类型名)即可。
【例3_4】寻找并输出11~999之间的数m,它满足m、m2和m3均为回文数。
注:回文数是指其各位数字左右对称的整数。例如:121,676,94249等。满足上述条件的数如m=11 ,m2 = 121 ,m3 = 1331。
代码:
/*
* description: 输入一个数字,返回其反序数
* parm: 传入int型整数—number
* return: 返回int型反序数—reverseOrder
*/
int reverse_Num(int number)
{
//求余%10:获得当前的最低位也就是个位
//整除/10:舍弃当前的最低位也就是个位
int modResult = 0; //存放求余后的数
int dividRrsult = number; //存放整除后的数
int reverseOrder = 0; //存放反序后的数
while (dividRrsult>0) //只要整除后的数仍然大于0,说明至少是两位数,继续整除
{
modResult = dividRrsult % 10; //每次反复求余10,求出当前最低位个位
reverseOrder = reverseOrder * 10 + modResult; //因为每次都舍弃了一个10位,所以每循环一次就乘10一次补上,再加上最新求得最低位构成反序数
dividRrsult = dividRrsult / 10; //舍弃最低位个位
}
return reverseOrder;
}
int Exam_3_4()
{
for (int number = 11; number <= 999; number++)
{
//对number反序
int reverseNum1 = reverse_Num(number);
//对number平方反序
int reverseNum2 = reverse_Num(number*number);
//对number的三次方反序
int reverseNum3 = reverse_Num(number*number*number);
//判断number其本身、平方、三次方是否都和反序相同
if (number==reverseNum1 && number*number==reverseNum2 && number*number*number==reverseNum3)
{
cout << number << "是回文数" << endl;
}
}
return 0;
}
需要注意的点:
1.要求回文数,核心是求其每个数的反序数。因此,此题解决关键就在于求反序。
2.反序数求解是用到了两个符号:【%求余】和【/整除】,%求余10可以求出当前的最低位(个位),/整除10可以舍弃当前的最低位(个位)。这里需要注意的是,求反序数时,每整除一次10,就缩小了10倍,因此在反序时每次都是*10返回去再加上此时%10的个位即可(上述代码17行处)
【例3_6】投骰子的随机游戏。
游戏规则是:每个骰子有六面,点数分别为1、2、3、4、5、6。每轮投两次骰子,第一轮如果和数为7或11则为胜,游戏结束;和数为2、3或12则为负,游戏结束;和数为其它值则将此值作为自己的点数,继续第二轮、第三轮…直到某轮的和数等于点数则取胜,若在此前出现和数为7则为负。
代码:
#include <cmath>
#include<ctime>
int Exam_3_6()
{
bool winFlag;
srand(time(0));
//第一轮
int point1 = rand() % 6 + 1;
int point2 = rand() % 6 + 1;
int sum = point1 + point2;
if (sum == 7 || sum == 11)
{
cout << "第一轮sum为" << sum <<endl;
cout << "You are Win" << endl;
}
else if (sum == 2 || sum == 3 || sum == 12)
{
cout << "第一轮sum为" << sum << endl;
cout << "You are lose" << endl;
}
else
{
//开始第N轮,直到出现和数等于点数或和数为7时停止.
int roundNum;
bool endFlag=false;
for (roundNum = 2; sum!=roundNum ; roundNum++)
{
int point1 = rand() % 6 + 1;
int point2 = rand() % 6 + 1;
int sum = point1 + point2;
if (sum==7)
{
cout << "第" << roundNum << "轮和数为7"<<endl;
cout << "You are lose" << endl;
endFlag = true;
break;
}
}
if (!endFlag)
{
cout << "第"<<roundNum<<"轮时,和数为"<<sum << endl;
cout << "You are Win" << endl;
}
}
return 0;
}
需要注意的点:
1.随机函数rand()%number是产生的[0~number-1]范围的随机数,若想产生[1~number]范围只需要在后面加1。
2.rand()操作是假随机操作,应该用srand(seed)置随机数种子,否则在每次程序运行开始时种子都会默认为1;
【3_13】用递归的方法编写函数求Fibonacci级数,公式为:
Fn=Fn-1+Fn-2(n>2),F1=F2=1
代码:
int fib(int n)
{
int answer = 0;
if (n==1||n==2)
{
answer = 1;
return answer;
}
else
{
answer = fib(n - 1) + fib(n - 2); //递归调用:调用自身
return answer;
}
}
int Code_3_13()
{
int n;
cout << "请输入n的值..." << endl;
cin >> n;
cout<<fib(n);
return 0;
}
需要注意的点:
1.递归调用自身,需要缕清思路。
【3_15】编写递归函数getPower计算x的y次方,在同一个程序中正对整型和实型实现两个重载的函数:
int getPower(int x,inty); //整形形式,当y<0时,返回0
double getPower(double x,int y); //实型形式
代码:
#include<cmath>
//重载函数-int型函数
int getPower(int x, int y)
{
int answer;
if (y < 0)
{
return 0;
}
if (y==1)
{
answer = x;
return answer;
}
else
{
//x的y次方=x*(x的y-1次方)
answer = x * getPower(x, y - 1); //递归调用:不断降低y的次数,直至为1后返回
cout << "int型被调用了" << endl;
return answer;
}
}
//重载函数-double型函数
double getPower(double x, int y)
{
double answer;
if (y < 0)
{
return 0;
}
if (y==1)
{
answer = x;
return answer;
}
else
{
//x的y次方=x*(x的y-1次方)
answer = x * getPower(x, y - 1); //递归调用:不断降低y的次数,直至为1后返回
cout << "double型被调用了" << endl;
return answer;
}
}
int Code_3_15()
{
int x1,y1;
double x2;int y2;
cout << "请输入整形x1,y1的值:"<<endl;
cin >> x1;
cin >> y1;
cout<<x1<<"的"<<y1<<"次方为:"<<getPower(x1, y1)<<endl;
cout << "重载函数测试:double型" << endl;
cout << "请输入double型x2,int型y2的值:" << endl;
cin >> x2;
cin >> y2;
cout << x2 << "的" << y2 << "次方为:" << getPower(x2, y2) << endl;
return 0;
}
需要注意的点:
1.函数的递归调用,x的y次幂分解为x* (y-1)次幂,形成递归。
2.重载函数即相同函数名称函数但是变量类型不同,编译器会根据传入的参数自动确定。
【4_10】设计一个用于人事管理的“人员”类,由于考虑到通用性,这里只抽象出所有类型人员都有的属性:编号、性别、出生日期、身份证号等。其中“出生日期”声明为一个“日期”类内嵌子对象,用成员函数实现对人员信息的录入和显示,要求包括构造函数和析构函数、复制构造函数、内联成员函数、带默认形参的成员函数、类的组合。
代码:
//Date类的定义
class Date
{
public:
Date(int yy=1970,int mm=1, int dd=1); //Date类成员函数之构造函数的声明(#默认形参的成员函数)
Date(Date &d); //Date类成员函数之复制构造函数的声明
void setDate(); //Date类成员函数之设置出生日期函数的声明
void showDate(); //Date类成员函数之显示出生日期函数的声明
~Date(){} //Date类成员函数之析构函数的声明
//Date类私有数据成员
private:
int Year, Month, Day;
};
//Date类成员函数之构造函数的实现
//注意:使用inline关键字变为内联构造函数,当然也可不用inline关键字直接在类内定义实现
inline Date::Date(int yy, int mm, int dd)
{
Year = yy;
Month = mm;
Day = dd;
}
//Date类成员函数之复制构造函数的实现
Date::Date(Date &d)
{
Year = d.Year;
Month = d.Month;
Day = d.Day;
}
//Date类成员函数之设置出生日期函数的实现
void Date::setDate()
{
cout << "请分别输入出生年、月、日:" << endl;
cin >> Year >> Month >> Day;
}
//Date类成员函数之显示出生日期函数的实现
void Date::showDate()
{
cout << Year << "年" << Month << "月" << Day << "日";
}
//Person类的定义
class Person
{
public:
Person(int firstNum, char firstSex, Date firstDate, string firstID); //Person组合类成员函数之构造函数的声明(内嵌子类对象Date)
Person(Person&p); //Person组合类成员函数之复制构造函数的声明
void inputPerson(); //Person组合类成员函数之录入人员函数的声明
void showPerson(); //Person组合类成员函数之显示人员函数的声明
~Person(){} //Person组合类成员函数之析构函数的声明
//Person组合类数据成员,注意:其数据成员包含Date类对象birthDate
private:
int number; char sex; Date birthDate; string id;
};
//Person组合类成员函数之构造函数的实现(内嵌子类对象Date)
//注意:因为是组合类,这里的构造函数使用了初始化列表(:冒号及之后的)来初始化
Person::Person(int firstNum, char firstSex, Date firstDate, string firstID) :number(firstNum), sex(firstSex), birthDate(firstDate), id(firstID)
{
cout << "调用构造函数初始化完毕!" << endl;
}
//Person组合类成员函数之复制构造函数的实现
//注意:因为是组合类,这里的复制构造函数使用了初始化列表(:冒号及之后的)来实现对象的复制
Person::Person(Person &p) :number(p.number), sex(p.sex), birthDate(p.birthDate), id(p.id)
{
cout << "调用复制构造函数!" << endl;
}
//Person组合类成员函数之录入人员函数的实现
void Person::inputPerson()
{
cout << "**************分隔符strat**************" << endl;
cout << "开始录入人员:" << endl;
cout << "请输入该人员的编号:" << endl;
cin >> number;
cout << "请输入该人员的性别(m 或 f):" << endl;
cin >> sex;
birthDate.setDate(); //调用Date类对象birthdate成员函数setDate
cout << "请输入该人员的身份证号:" << endl;
cin >> id;
cout << "信息录入完毕!" << endl;
cout << "**************分隔符end**************" << endl;
}
//Person组合类成员函数之显示人员函数的实现
void Person::showPerson()
{
cout << "**************分隔符strat**************" << endl;
cout << "#编号:" << number << endl;
cout << "#性别:" << sex << endl;
cout << "#出生日期:", birthDate.showDate(), cout << endl; //调用Date类对象birthdate的成员函数showDate
cout << "#身份证号:" << id << endl;
cout << "信息显示完毕!" << endl;
cout << "**************分隔符end**************" << endl;
}
int Code_4_10()
{
//Date类对象的实例化和初始化
Date firstDate(1970, 1, 1);
/*Person类对象的实例化和初始化
注意:这里Person类内嵌了Date类,因此实例化了一个对象firstDate使得Person类对象myPerson1能够初始化
在这里Date类相当于一个自定义类型,首先你得有一个Date类对象才能赋值初始化*/
Person myPerson1(0, 'm', firstDate, "370000197001010000");
myPerson1.showPerson(); //显示初始化后的myPerson1人员信息
myPerson1.inputPerson(); //录入myPerson1人员信息
myPerson1.showPerson(); //录入人员信息后再次显示myPerson1刚录入的信息
Person myPerson2 = myPerson1; //调用复制构造函数将对象myPerson1复制到对象myPerson2
myPerson2.showPerson(); //显示myPerson2的人员信息
return 0;
}

需要注意的点:
1.组合类的构造函数和复制构造函数和普通类没什么区别,只不过在其实现形式上用了初始化列表(:冒号),其本质还是没有变化,都是进行了初始化赋值操作,只是效率有所提高。
2.内联成员函数可以直接写在类定义内,也可以写在类外,但要加关键字inline
3.组合类调用构造函数初始化,若有参数,且参数之一是内嵌类对象,则内嵌类对象必须先实例化和初始化,如上所示myPerson1的实例化和初始化中内嵌对象Date类的对象firstDate,其Date firstDate(1970, 1, 1)先进行了实例化,再传入对象myPerson1,充当其初始化的参数。
【5_11】在一个文件中定义一个全局变量n,主函数main(),在另一个文件中定义函数fn1(),在main()中对n赋值,再调用fn1(),在fn1()中也对n赋值,显示n最后的值。
代码:
//Antoher.h
#pragma once
#ifndef _ANOTHER_H
#define _ANOTHER_H
int fn1();
#endif // !_ANOTHER_H
//Another.cpp
#include"pch.h"
#include<iostream>
using namespace std;
int fn1()
{
extern int n;
n=99;
cout<<n<<endl;
return 0;
}
//main.cpp
#include"pch.h"
#include<iostream>
using namespace std;
int n;
extern int fn1();
int main()
{
n=0;
cout<<n<<endl;
fn1();
return 0;
}
需要注意的点:
1.一般而言,我们要把一些声明放在.h文件中
2.需要调用其他文件的函数时,有很多方法,可以直接添加cpp文件声明extern也可以用#include头文件的形式
【5_13】 定义类X、Y、Z,函数h(X*),满足:类X有私有成员i,Y的成员函数g(X*)是X的友元函数,实现对X的成员i加1,类Z是类X的友元类,其成员函数f(X*)实现对X的成员i加5,函数h(X*)是X的友元函数,实现对X的成员i加10。
代码:
class X; //X类的前向声明
//Y类的定义
class Y
{
public:
void g(X* xClass); //声明Y类的成员函数g(X*)
Y() {} //Y类的内联构造函数
~Y() {} //Y类的内联复制构造函数
};
//X类的定义
class X
{
public:
//friend class Y; //声明类Z为类X的友元类
friend void Y::g(X* xClass); //声明Y的成员函数g(X*)为X类的友元函数
friend class Z; //声明类Z为类X的友元类
friend void h(X*); //声明普通函数h(X*)是类X的友元函数
X(int ii); //X类的构造函数声明
X(X &x); //X类的复制构造函数声明
~X(){} //X类的析构函数声明
private:
int i;
};
//X类的构造函数实现
X::X(int ii)
{
i = ii;
cout << "i的值:" << i << endl;
}
//X类的复制构造函数实现
X::X(X &x)
{
i = x.i;
}
//Y类的成员函数g(X*)实现
void Y::g(X* xClass)
{
xClass->i= xClass->i+1; //修改X::i的值+1
cout << "i的值:" << xClass->i<<endl;
}
//定义Z类
class Z
{
public:
Z() {} //Z类的内联构造函数
void f(X*); //声明Z类的成员函数f(X*)
~Z() {} //Z类的析构函数
};
//Z类的成员函数f(X*)的实现
void Z::f(X* xClass)
{
xClass->i = xClass->i + 5; //修改X::i的值+5
cout << "i的值:" << xClass->i << endl;
}
//普通函数h(X*)的定义
void h(X*xClass)
{
xClass->i = xClass->i + 10; //修改X::i的值+10
cout << "i的值:" << xClass->i << endl;
}
int Code_5_13()
{
X xTest(0); //X类的实例化且通过构造函数初始化
Y yTest; //Y类的实例化对象yTest
Z zTest; //Z类的实例化对象zTest
yTest.g(&xTest); //对象yTest调用xTest函数
zTest.f(&xTest); //对象zTest调用zTest函数
h(&xTest); //函数h(X*)调用
return 0;
}
需要注意的点:
1.注意友元函数和友元类对本类私有成员的访问方式:可以参数传递直接实例化X类xclass,也可指针访问(X*xclass)
2.类的声明和定义不同,声明了你就写用不牵涉类内部细节的语句,只有定义了才可以用牵涉类细节的语句。如此题中前向声明了X类,Y类中可以用X*xclass,但不能说是用X::X的成员函数,因为那只是一个声明