本文答案,部分参考于C++ Primer 习题集
前面章节的习题答案
文章目录
6.1
区别:
形参:形参出现再函数定义的地方,形参列表可以包含0个,1个,或多个形参,多个形参之间用逗号分隔,形参规定了一个函数所接受的类型和数量.
实参:实参出现函数调用的地方,实参的数量和形参一样多,实参的主要作用是初始化形参,并且这种初始化过程是一 一对应的,即第一个实参初始化第一个形参,第二个初始化第二个,实参的类型必须和形参的类型想匹配.
6.2
(a)
返回值类型和函数类型不匹配.
函数类型是int,返回值类型是string.
(b)
函数没有定义类型
©
少了一个 ‘{’ 括号,而且没有返回值
(d)
少了一队花括号
6.3
#include <iostream>
using namespace std;
int fact(int n){
int sum=1;
for(int i=1;i<=n;++i){
sum*=i;
}
return sum;
}
int main() {
int result=fact(5);
cout<<result;
return 0;
}
6.4
#include <iostream>
using namespace std;
int fact(int n);
int main() {
cout<<"请输入你要算的阶乘"<<endl;
int n=0;
cin>>n;
int result=fact(n);
cout<<result;
return 0;
}
int fact(int n){
int sum=1;
for(int i=1;i<=n;++i){
sum*=i;
}
return sum;
}
6.5
#include <iostream>
using namespace std;
int Absult(int n);
int main() {
cout<<"请输入一个整数"<<endl;
int n=0;
cin>>n;
int result=Absult(n);
cout<<result;
return 0;
}
int Absult(int n){
if(n<0)
return -n;
else
return n;
}
6.6
形参和局部静态变量都是局部变量的一种
形参:形参是一种自动对象,函数开始时为形参申请内存空间,我们用调用函数时提供的实参初始化形参对应的自动对象.
普通变量对应的自动对象也容易理解,我们在定义该变量的语句处创建自动对象,如果定义语句提供了初始值,则用该值初始化,否则,执行默认初始化.当该变量所在的块结束后,变量失效.
局部静态变量比较特殊,它的声明周期贯穿函数调用及之后的时间.局部静态变量所对应的对象成为局部静态对象,它的生命周期从定义语句处开始,直到程序结束处才终止.
下面是例子程序:
#include <iostream>
using namespace std;
double myADD(double val1,double val2){
double result=val1+val2;
static unsigned iCnt=0;
++iCnt;
cout<<"该函数已经累计执行了"<<iCnt<<"次"<<endl;
return result;
}
int main(void){
double num1,num2;
cout<<"请输入两个数:";
while(cin>>num1>>num2){
cout<<num1<<"与"<<num2<<"的求和结果是:"<<myADD(num1,num2)<<endl;
}
return 0;
}
6.7
#include <iostream>
using namespace std;
int myADD(void){
static int iCnt=-1;
iCnt++;
return iCnt;
}
int main(void){
for(int i=0;i<10;++i){
cout<<"运行次数是:"<<myADD()<<endl;
}
return 0;
}
6.8
#pragma once
#ifndef CHAPTER6_H_INCLUDED
#define CHAPTER6_H_INCLUDED
int fact(int);
double myABS(double);
double myABS2(double);
#endif
6.9
fact.cc文件的内容是
#include"Chapter6.h"
using namespace std;
int fact(int val) {
if (val < 0)
return -1;
int ret = 1;
for (int i = 1; i != val + 1; ++i)
ret *= i;
return ret;
}
factMain.cc里面的内容
#include"Chapter6.h"
#include<iostream>
using namespace std;
int main() {
int num;
cout << "请输入一个整数";
cin >> num;
cout << num << "的阶乘是:" << fact(num) << endl;
return 0;
}
6.10
#include <iostream>
using namespace std;
void Swap(int *,int *);
int main(void){
int a=1,b=2;
cout<<a<<b<<endl;
Swap(&a,&b);
cout<<a<<b<<endl;
}
void Swap(int *a,int *b){
int t=*a;
*a=*b;
*b=t;
}
6.11
#include <iostream>
using namespace std;
void reset(int &);
int main(void){
int i=1;
cout<<i<<endl;
reset(i);
cout<<i<<endl;
}
void reset(int & i){
i=0;
}
6.12
#include <iostream>
using namespace std;
void Swap(int &,int &);
int main(void){
int a=1,b=2;
cout<<a<<b<<endl;
Swap(a,b);
cout<<a<<b<<endl;
}
void Swap(int &a,int &b){
int t=a;
a=b;
b=t;
}
我觉得是引用,引用更加的清晰,和明了.
而且不需要额外的声明指针变量,也避免了拷贝指针的值
6.13
① void f(T) T就是一个普通的形参,在函数里面改变T的值,并不会影响到实参. 采用的是传值参数
② void f(&T) T这个就相当于实参的一个别名,在函数里面改变T的值,会影响到对应的实参. 采用的是传引用参数.
6.14
① 当函数需要改变实参的值的时候,我们需要使用引用类型 比如交换两个数,当对象是string对象时,我们为了避免过长的拷贝字符,最好采用引用类型.
② 当函数不能改变实参的值,或不需要改变实参的值的时候,我们不要用引用类型 比如求某个数的阶乘.
6.15
因为需要.string类型是我们输入的字符串. char 就是我们要配对的字符.size_type 是我们的计数器.
s是常量引用是因为,程序在计数的过程中,不需要改变s的值,而且也不能改变
occurs不是常量引用是因为,程序在计数的过程中,计数器的值是一定要改变的.这里不能使用常量引用.
char 不需要改变实参
s是普通引用也没有关系,只要程序写对就OK.
occurs是常量引用的话,就一定会报错.
6.16
bool is_empty(const string &s){return s.empty();}
6.17
#include <iostream>
#include <cctype>
using namespace std;
void To_lower(string &);
bool is_Tup(const string &);
int main(void){
string a,b;
cin>>a>>b;
cout<<a<<" "<<b<<endl;
To_lower(a);
cout<<a<<endl;
if(is_Tup(b)){
cout<<"True";
}
else{
cout<<"False";
}
}
void To_lower(string &s){
for(auto &a:s){
a=tolower(a);
}
}
bool is_Tup(const string &s){
for(auto a:s){
if(isupper(a))
return true;
}
return false;
}
不相同,因需要改写的那个不能加常量. 也就是不能使用常量引用.
只是判断的那个可以加常量.
6.18
bool compare(const matrix&,const matrix &);
vector<int> change_val(vector<int> &,int&);
6.19
(a)
非法,因为有参数不匹配了.
(b)©(d)
都是合法的.
6.20
① 在不能改变这个形参的时候,因该是常量引用.
② 如果没有改变这个形参,那就没有关系,如果改变了形参,程序不会报错,但是程序的意义就发生了改变.
6.21
int Point_int(int a,const int * b){
if(a<*b)
return *b;
return a;
}
因为指针的值不会被修改,所以应该是const int *
6.22
这题是我考虑的太肤浅了.
这题有两种理解:
① 交换指针本身的值,即指针所指向对象的值.
② 交换指针所指的内容.
下面是三个函数
① Swap_value就是值传递.所有的改变只在这个函数里面发生,函数结束了,就还原.
② Swap_value2也是值传递,但是这个改变的是指针指向对象的值.因为我们使用的是解引用的方式.
③ Swap_value3也是用了指针引用的形式,因为前面讲过,指针本身也是一个对象,是对象,就可以使用引用这种方式,改变了引用,指针也就改变了,值和地址也就都改变了.
代码如下:
#include <iostream>
#include <cctype>
using namespace std;
void Swap_value(int *,int *);
void Swap_value2(int *,int *);
void Swap_value3(int *&,int *&);
int main(void){
int a=1,b=2;
int *pa=&a,*pb=&b;
cout<<"交换之前pa和pb的值:"<<*pa<<" :"<<*pb<<" :"<<pa<<" :"<<pb<<endl;
Swap_value(pa,pb);
cout<<"交换之后pa和pb的值:"<<*pa<<" :"<<*pb<<" :"<<pa<<" :"<<pb<<endl;
cout<<"\n\n";
cout<<"交换之前pa和pb的值:"<<*pa<<" :"<<*pb<<" :"<<pa<<" :"<<pb<<endl;
Swap_value2(pa,pb);
cout<<"交换之后pa和pb的值:"<<*pa<<" :"<<*pb<<" :"<<pa<<" :"<<pb<<endl;
cout<<"\n\n";
cout<<"交换之前pa和pb的值:"<<*pa<<" :"<<*pb<<" :"<<pa<<" :"<<pb<<endl;
Swap_value3(pa,pb);
cout<<"交换之后pa和pb的值:"<<*pa<<" :"<<*pb<<" :"<<pa<<" :"<<pb<<endl;
cout<<"\n\n";
}
void Swap_value(int *a,int *b){
int *t=a;
a=b;
b=t;
}
void Swap_value2(int *a,int *b){
int t=*a;
*a=*b;
*b=t;
}
void Swap_value3(int *&a,int *&b){
int *t=a;
a=b;
b=t;
}
6.23
#include <iostream>
#include <cctype>
using namespace std;
void print(int end,const int *a);
void print2(const int *a);
void print3(const int*b,const int*e);
int main(void){
int i=0,j[2]={0,1};
print(sizeof(j)/sizeof(*j),j);
print2(&i);
auto b=begin(j);
auto e=end(j);
print3(b,e);
}
void print(int end,const int *a){
for(int i=0;i<end;++i){
cout<<*(a+i)<<endl;
}
}
void print2(const int *a){
cout<<*a<<endl;
}
void print3(const int*b,const int*e){
while(b<e){
cout<<*b<<endl;
b++;
}
}
6.24
有一个潜在的问题,当传入的数组长度小于10的时候,会出现问题.
6.25
#include <iostream>
#include <cctype>
using namespace std;
int main(int argc,char **argv){
string str;
for(int i=0;i!=argc;++i)
str+=argv[i];
cout<<str<<endl;
return 0;
}
运行方式如下:
6.26
#include <iostream>
#include <cctype>
using namespace std;
int main(int argc,char **argv){
for(int i=0;i!=argc;++i){
cout<<"argc["<<i<<"]:"<<argv[i]<<endl;
}
return 0;
}
6.27
#include <iostream>
#include <initializer_list>
using namespace std;
int sum(initializer_list<int> a);
int main(){
initializer_list <int> b{1,2,3,4,5,6,7,8};
cout<<sum(b)<<endl;
return 0;
}
int sum(initializer_list<int> a){
int sum=0;
for(auto t:a){
sum+=t;
}
return sum;
}
6.28
elem 是const string &类型
6.29
不能,因为 initializer_list 里面的内容都是常量,
普通引用可能会改变里面的内容,要改为 常量引用.
6.30
代码如下:
#include <iostream>
#include <initializer_list>
using namespace std;
bool str_subrange(const string &str1,const string &str2);
int main(){
}
bool str_subrange(const string &str1,const string &str2){
if(str1.size()==str2.size())
return str1==str2;
auto size=(str1.size()<str2.size())?str1.size():str2.size();
for(decltype(size) i =0;i!=size;++i){
if(str1[i]!=str2[i])
return;
}
}
报错栏的消息:
F:\File\Sublime Text\C++ Source\C++Primer.cpp: In function 'bool str_subrange(const string&, const string&)':
F:\File\Sublime Text\C++ Source\C++Primer.cpp:14:13: error: return-statement with no value, in function returning 'bool' [-fpermissive]
14 | return;
| ^~~~~~
[Finished in 2.2s with exit code 1]
[shell_cmd: g++ -Wall -std=c++0x "F:\File\Sublime Text\C++ Source\C++Primer.cpp" -o "C++Primer" && start cmd /c ""F:\File\Sublime Text\C++ Source/C++Primer" & pause "]
[dir: F:\File\Sublime Text\C++ Source]
[path: C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;"F:\SoftWare\JDK\bin;F:\SoftWare\JDK\jre\bin";F:\SoftWare\MySQL\bin;C:\Program Files\Common Files\Autodesk Shared\;F:\SoftWare\Git\Git\cmd;F:\SoftWare\Node_js\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\dotnet\;C:\Program Files (x86)\Common Files\Thunder Network\KanKan\Codecs;C:\Program Files\Git\cmd;C:\Program Files\Git LFS;F:\File\Tim\Maven\Maven\apache-maven-3.5.2\bin;F:\SoftWare\MinGW\bin;"F:\SoftWare\Apache-tomcat-8.5.46\bin;F:\SoftWare\Apache-tomcat-8.5.46\lib";C:\Users\HPY\AppData\Local\Microsoft\WindowsApps;F:\SoftWare\IDEA\IntelliJ IDEA 2019.1.3\bin;F:\SoftWare\Node_js;C:\Users\HPY\AppData\Roaming\npm;C:\Users\HPY\AppData\Local\BypassRuntm;C:\Users\HPY\AppData\Local\Microsoft\WindowsApps;]
6.31
无效:局部变量的引用
局部常量.
6.32
正确,含义就是给ia数组从0-9依次赋值.
6.33
#include <iostream>
#include <vector>
using namespace std;
void factVec(vector<int> a,int index);
int main(){
vector<int> a{1,2,3,4,5,6,7,8,9};
factVec(a,8);
}
void factVec(vector<int> a,int index){
if(index!=-1){
cout<<a[index]<<endl;
factVec(a,index-1);
}
}
6.34
不能,因为,传入的参数,可能是负数,如果是负数,就会一直无线的循环下去.
#include <iostream>
#include <vector>
using namespace std;
int factorial(int );
int main(){
int val=3.6;
cout<<factorial(val)<<endl;
}
int factorial(int val){
if(val!=0)
return factorial(val-1)*val;
return 1;
}
6.35
变量的递减操作和读取变量值的操作在同一条语句上,有可能产生未定义的值.
6.36
string (&func())[10];
6.37
#include <iostream>
#include <vector>
using namespace std;
int main(){
//使用类型别名 ①
typedef string arr[10];
arr& func();
//使用类型别名 ②
using arrT[10];
arrT* func();
//使用尾置返回类型
auto func()->string(&)[10];
//使用decltype关键字
string str[10];
decltype(str) &func();
}
6.38
代码如下:
#include <iostream>
#include <vector>
using namespace std;
int main(){
int odd[]={1,3,5,7,9};
int even[]={0,2,4,6,8};
}
//返回一个引用,改引用对象是一个含有5个整数的数组
decltype(odd) &arrPtr(int i){
return (i%2) ?odd:even;//返回数组的引用
}
6.39
(a)
非法的,因为顶层const不影响传入的对象,它们的形参是无法区分的.
(b)
非法的
只有返回值不一样的函数不可以出现.
©
合法的
6.40
(a)
正确
(b)
错误.
默认实参声明
如果一个形参有了默认值,那么它右边的所有形参有必须有默认值.
6.41
(a)
非法的,ht没有实参
(b)
合法的
©
语义上是合法的,但是不是程序想要的.
wd 会被初始化为42
6.42
#include <iostream>
#include <string>
using namespace std;
string make_plural(int , const string&, const string& ending ="s");
int main() {
cout << make_plural(2, "success") << endl;
cout << make_plural(2, "failure") << endl;
}
string make_plural(int ctr, const string& word, const string& ending ) {
return (ctr > 1) ? word + ending : word;
}
注意的地方
① 在我的编译器里,默认值一定要写在声明里面.
② 在声明里面写了默认值,在下面的定义里面,就不能再写.
6.43
(a)
应该定义在头文件里,
因为a是内联函数
(b)
定义在源文件里
6.44
inline bool isShorter(const string &s1,const string &s2){
return s1.size()<s2.size()
}
6.45
前面的基本都行,因为小,而且简单.
在函数类型前面加一个inline就行了
6.46
不能,因为返回的时候,用到了标准库string里面的 size()函数
6.47
#include<iostream>
#include<vector>
using namespace std;
//递归输出vector<int>的内容
void print(vector<int> vInt, unsigned index) {
unsigned sz = vInt.size();
//设置在此处输出调试信息
#ifndef NDEBUG
cout << "vector对象的大小是:" << sz << endl;
#endif // !NDEBUG
if (!vInt.empty() && index < sz) {
cout << vInt[index] << endl;
print(vInt, index + 1);
}
}
int main() {
vector<int> v = { 1,3,5,7,9,11,13,15 };
print(v, 0);
return 0;
}
打开编译器的时候
输出
vector对象的大小是:8
关闭调试器的时候,只输出vector对象的内容,不输出大小
6.48
这题答案抄于答案书.
该程序对吧assert的使用有不合理之处,在调试期打开的情况下,当用户输入字符串s并且s的内容与sought不相等时,执行循环体,否则继续执行assert(cin)语句,换句话说,程序执行到assert的原因可能有两个,一是用户终止了输入,②是用户输入的内容正好与sought的内容一样.如果用户尝试终止输入,assert为假,这和程序的原意是不相符的.
当调试器关闭时,assert什么也不做.
6.49
当程序中存在多个同名的重载函数时,编译器需要判断调用的是其中的那个函数.
候选函数,就是那些同名的重载函数.
特征:
① 与被调用的函数同名,
② 其声明在调用点可见
然后我们就要选择了,那些选出来可以被调用的函数就是可行函数
特征:
① 一是其形参数量与本次调用提供的实参数量相等.
② 每个实参的类型与对应的形参类型相同或者能转换成形参的类型.
6.50
(a)
二义性
(b)
void f(int)
©
void f(int int )
(d)
void f (double double)
6.51
#include <iostream>
#include <string>
using namespace std;
void f(){
cout<<"空";
}
void f(int a){
cout<<"int";
}
void f(int a,int b){
cout<<"int int ";
}
void f(double a,double b){
cout<<"double double ";
}
int main() {
//f(2.56,42);
cout<<"\n";
f(42);
cout<<"\n";
f(42,0);
cout<<"\n";
f(2.56,3.14);
cout<<"\n";
}
结果
int
int int
double double
6.52
(a)
类型提升,字符串提升到int
(b)
算术类型转换
double转换成int
6.53
(a)(b)
都是合法的,就是一个是普通的引用,一个是常量引用(a)
(b) 一个是形参指向了常量,一个没有指向.
(a)和(b)的const都是底层的const
©
这里的const是顶层的const,不会对形参产生影响.
不合法,
6.54
int func(int,int);
vector<decltype(func)*> vF;
6.55
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int add(int, int);
int subtract(int, int);
int ride(int, int);
int divide(int, int);
int main() {
decltype(add)* p1 = add, * p2 = subtract, * p3 = ride, * p4 = divide;
vector<decltype(add)*> vF = { p1,p2,p3,p4 };
return 0;
}
int add(int a, int b) {
return a + b;
}
int subtract(int a, int b) {
return a - b;
}
int ride(int a, int b) {
return a * b;
}
int divide(int a, int b) {
return a/b;
}
6.56
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int add(int, int);
int subtract(int, int);
int ride(int, int);
int divide(int, int);
void Compute(int a, int b, int (*p)(int, int));
int main() {
int i = 5, j = 10;
decltype(add)* p1 = add, * p2 = subtract, * p3 = ride, * p4 = divide;
vector<decltype(add)*> vF = { p1,p2,p3,p4 };
for (auto p : vF) {
Compute(i,j, p);
}
return 0;
}
int add(int a, int b) {
return a + b;
}
int subtract(int a, int b) {
return a - b;
}
int ride(int a, int b) {
return a * b;
}
int divide(int a, int b) {
return a/b;
}
void Compute(int a, int b, int (*p)(int, int)) {
cout << p(a, b) << endl;
}