C++Primer_课后习题第六章

本文答案,部分参考于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;
}

思维导图

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Huangpengyu123/article/details/107326689