C++ primer(第五版)第6章习题答案

第六章 函数

 

6.1

形参:在函数参数列表中声明的局部变量,它们由每个函数调用中提供的参数初始化。

实参:函数调用中提供的值,用于初始化函数的参数。

 

6.2

(a) 返回值类型应该是string

(b) 返回值类型为void

(c) 函数体缺少左花括号

(d) 函数体没有花括号

 

6.3

#include <iostream>

int fact(int val)
{
    if (val == 0 || val == 1) return 1;
    else return val * fact(val-1);
}

int main()
{
    int j = fact(5);  // j equals 120, i.e., the result of fact(5)
    std::cout << "5! is " << j << std::endl;
    return 0;
}

 

6.4

#include <iostream>
#include <string>

using std::cin;
using std::cout;
using std::endl;

int fact(int val)
{
    int ret = 1;
    while (val > 1) ret *= val--;
    return ret;
}

void factorial_with_interacts()
{
    for (int val = 0; cout << "Enter a number within [0, 13): ", cin >> val;) {
        if (val < 0 || val > 12) continue;
        cout << val << "! =" << fact(val) << endl;
    }
}

int main()
{
    factorial_with_interacts();
}

 

6.5

template <typename T>

T abs(T i)

    return i >= 0 ? i : -i;

}

 

6.6

局部变量:在块中定义的变量;

形参:在函数参数列表中声明的局部变量

局部静态变量:在程序的执行路径第一次经过对象定义语句时初始化,并且直到程序终止才被销毁,在此期间即使对象所在函数结束执行也不会对它有影响。

// example
size_t count_add(int n)       // n is a parameter.
{
    static size_t ctr = 0;    // ctr is a static variable.
    ctr += n;
    return ctr;
}

int main()
{
    for (size_t i = 0; i != 10; ++i)  // i is a local variable.
      cout << count_add(i) << endl;

    return 0;
}

 

6.7

size_t generate()

{

   static size_t ctr = 0;

    return ctr++;

}

 

6.8

Chapter6.h


int fact(int val);
int func();

template <typename T> T abs(T i)
{
    return i >= 0 ? i : -i;
}

 

6.9

fact.cc

#include "Chapter6.h"
#include <iostream>

int fact(int val)
{
    if (val == 0 || val == 1)
        return 1;
    else
        return val * fact(val - 1);
}

int func()
{
    int n, ret = 1;
    std::cout << "input a number: ";
    std::cin >> n;
    while (n > 1) ret *= n--;
    return ret;
}

factMain.cc

#include "Chapter6.h"
#include <iostream>

int main()
{
    std::cout << "5! is " << fact(5) << std::endl;
    std::cout << func() << std::endl;
    std::cout << abs(-9.78) << std::endl;
}

 

6.10

#include <iostream>
#include <stdexcept>
#include <string>

using std::cin;
using std::cout;
using std::endl;

void swap(int* const lhs, int* const rhs)
{
    auto tmp = *lhs;
    *lhs = *rhs;
    *rhs = tmp;
}

int main()
{
    for (int lht, rht; cout << "Please Enter:\n", cin >> lht >> rht;) {
        swap(&lht, &rht);
        cout << lht << " " << rht << endl;
    }
}

 

6.11

#include <iostream>

void reset(int& i)
{
    i = 0;
}

int main()
{
    int i = 42;
    reset(i);
    std::cout << i << std::endl;
}

 

6.12


#include <iostream>
#include <string>

using std::cin;
using std::cout;
using std::endl;

void swap(int& lhs, int& rhs)
{
    auto tmp = lhs;
    lhs = rhs;
    rhs = tmp;
}

int main()
{
    for (int left, right; cout << "Please Enter:\n", cin >> left >> right;) {
        swap(left, right);
        cout << left << " " << right << endl;
    }
}

 

6.13

void f(T)被传值调用,函数对形参做的所有操作都不会影响实参:void f(&T)被传引用调用,引用形参绑定传入的实参,可以改变其值。

 

6.14

一个形参应该是引用类型:

void reset(int &i)
{
        i = 0;
}

一个形参不能是引用类型:

void print(std::vector<int>::iterator begin, std::vector<int>::iterator end)
{
        for (std::vector<int>::iterator iter = begin; iter != end; ++iter)
                std::cout << *iter << std::endl;
}

 

6.15

(a) s在函数中不会被修改,但occur的结果必须通过函数去计算

(b) 避免直接拷贝string对象,直接拷贝char会更加高效。

(c) s可能会被修改,occurs不会被改变。

 

6.16 

因为这个函数不会改变传入的参数,形参应该被定义成const string& s,否则会给调用者误导,即可以修改它的值,同时也限制了函数所能接受的实参类型,不能把const string,字面值,需要类型转化的对象传给形参,而且不能在调用该常量引用的函数中使用。

 

6.17

#include <iostream>
#include <string>

using std::string;

bool hasUppercase(const string& str)
{
    for (auto c : str)
        if (isupper(c)) return true;
    return false;
}

const string& makeLowercase(string& str)
{
    for (auto& c : str)
        if (isupper(c)) c = tolower(c);
    return str;
}

int main()
{
    string str("Hello World!");
    std::cout << std::boolalpha << hasUppercase(str) << std::endl;
    std::cout << makeLowercase(str) << std::endl;
}

                             

6.18

(a) bool compare (const matrix& m1, const matreix& m2);

(b) vector<int>::iterator change_val (int, vector<int>::iterator);

 

6.19

(a)只用一个参数

(b,c,d)合法

 

6.20

能用就用,当引用的值需要改变设为普通引用。如果我们让一个参数成为一个普通的引用,而它应该是一个常量的引用,那么这个引用值可能会改变。

 

6.21

#include <iostream>

int LargerOne(int i, const int* const ip)
{
    return (i > *ip) ? i : *ip;
}

int main()
{
    int c = 6;
    std::cout << LargerOne(7, &c) << std::endl;
}

 

6.22

#include <iostream>

void swap(const int*& lhs, const int*& rhs)
{
    auto temp = lhs;
    lhs = rhs;
    rhs = temp;
}

int main()
{
    const int i = 42, j = 99;
    auto lhs = &i;
    auto rhs = &j;
    swap(lhs, rhs);
    std::cout << *lhs << " " << *rhs << std::endl;
}

 

6.23

#include <iostream>

using std::begin;
using std::cout;
using std::end;
using std::endl;

void print(int* const pi)
{
    if (pi) cout << *pi << endl;
}

void print(const char* p)
{
    if (p)
        while (*p) cout << *p++;
    cout << endl;
}

void print(const int* beg, const int* end)
{
    while (beg != end) cout << *beg++ << " ";
    cout << endl;
}

void print(const int ia[], size_t size)
{
    for (size_t i = 0; i != size; ++i) cout << ia[i] << " ";
    cout << endl;
}

void print(const int (&arr)[2])
{
    for (auto i : arr) cout << i << " ";
    cout << endl;
}

int main()
{
    int i = 0, j[2] = {0, 1};
    char ch[5] = "pezy";

    print(ch);
    print(begin(j), end(j));
    print(&i);
    print(j, end(j) - begin(j));
    print(const_cast<const int(&)[2]>(j));
}

 

6.24

因为不能拷贝数组,所有我们无法以值传递的方式使用数组参数。因为数组会被转换为指针,所以我们为函数传递一个数组时,实际上传递的是指向数组首元素的指针。

在这个问题中,const int ia[10] 实际上与const int*一样,数组的大小是不相关的,这里可以传const int ia[3]也可以是const int ia[255].如果想要传递一个大小为10的数组,我们应该使用引用像这样:void print10(const int (&ia)[10]) {/*...*/}

 

6.25 & 6.26

#include <iostream>
#include <string>

int main(int argc, char** argv)
{
    std::string str;
    for (int i = 1; i != argc; ++i) {
        str += argv[i];
        str += " ";
    }

    std::cout << str << std::endl;
}

 

6.27

#include <initializer_list>
#include <iostream>

int sum(const std::initializer_list<int>& il)
{
    int sum = 0;
    for (auto i : il) sum += i;
    return sum;
}

int main(void)
{
    std::cout << sum({1, 2, 3, 4, 5}) << std::endl;
}

 

6.28

const string& 常量字符串引用

 

6.29

取决于initializer_list元素的类型。当类型为PODType时,不需要引用。因为POD的复制成本很低(比如int)。否则,使用引用(const)是更好的选择。

 

6.30

错误#1:没有返回一个值

错误#2:控制流可能尚未返回任何值就结束了函数的执行,编译器可能检查不出这一错误。

 

6.31

(1) 当返回局部对象的引用时无效

(2) 当我们希望返回的对象被修改时,被返回的常量引用无效。

when you can find the preexisted object that the reference refered.(这个答案感觉不符合)

 

6.32

合法,给数组赋值了0~9。

 

6.33


#include <iostream>
#include <vector>

using std::cout;
using std::vector;
using Iter = vector<int>::iterator;

void print(Iter beg, Iter end)
{
    if (beg != end) {
        cout << *beg << " ";
        print(std::next(beg), end);
    }
}

int main()
{
    vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9};
    print(vec.begin(), vec.end());
}

 

6.34

如果参数为正数,递归停止到零;如果参数为负数,递归不会停止。

 

6.35

递归函数将始终使用val作为参数,会发生递归循环。

 

6.36

string (&func(int i)) [10]

string (&func(string (&arrStr) [10])) [10]

 

6.37

using ArrT = string [10];

ArrT& func1(ArrT& arr);

 

auto func2(ArrT& arr) -> string(&)[10];

 

string arrS[10];

decltype(arrS)& func3(ArrT& arr);

我喜欢第一种方式,因为理解以后使用简洁方便

 

6.38

decltype(odd)& arrPtr(int i)

{

     return (i % 2) ? odd : even;

}

 

6.39

(a) 重复声明。

(b) 错误声明,不允许两个函数除了返回类型外其他所有的要素都相同。

(c) 合法。

 

6.40

(a) 正确

(b) 错误,函数的后续声明只能为之前那些没有默认值的形参添加默认实参,而且该形参右侧的所有形参必须有默认值。

 

6.41

(a) 非法,不匹配ht

(b) 合法。

(c) 合法,不符初衷,wd会被赋值为机器上该符号对应的数值。

 

6.42

#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::string;

string make_plural(size_t ctr, const string& word, const string& ending = "s")
{
    return (ctr > 1) ? word + ending : word;
}

int main()
{
    cout << "singual: " << make_plural(1, "success", "es") << " "
         << make_plural(1, "failure") << endl;
    cout << "plural : " << make_plural(2, "success", "es") << " "
         << make_plural(2, "failure") << endl;
}

 

6.43

都放,(a)是内联函数,(b)是函数声明

 

6.44

#include <iostream>
#include <string>

using std::string;

inline bool isShorter(const string& s1, const string& s2)
{
    return s1.size() < s2.size();
}

int main()
{
    std::cout << isShorter("pezy", "mooophy") << std::endl;
}

 

6.45

内联机制用于优化规模小,流程直接,频繁调用的函数。

 

6.46

constexpr函数的返回类型及所有形参的类型都得是字面值类型,而且函数体中必须有且只有一条return语句。string 类型不是字面值类型。

 

6.47

#include <iostream>
#include <vector>
using std::cout;
using std::endl;
using std::vector;

//#define NDEBUG

void printVec(vector<int>& vec)
{
#ifndef NDEBUG
    cout << "vector size: " << vec.size() << endl;
#endif
    if (!vec.empty()) {
        auto tmp = vec.back();
        vec.pop_back();
        printVec(vec);
        cout << tmp << " ";
    }
}

int main()
{
    vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9};
    printVec(vec);
    cout << endl;
}

 

6.48

这个循环允许用户一直输入一个单词直到找到该单词为止。

这不是assert的一个好用法,assert宏常用于检查“不能发生”的条件。但是assert总是在用户输入eof时发生,这种行为很自然,检查毫无必要。使用 assert (!cin || s == sought)会更好。

 

6.49

函数匹配中第一步中,选定调用对应的重载函数集,集合中的函数为候选函数.

2个特征:1.与被调用的函数同名,2,其声明在调用点可见。

第二部考察本次调用提供的实参,从候选函数中选出能被这组实参调用的函数,称为可行函数.

2个特征:1.其形参数量与本次调用提供的实参数量相等,2.每个实参的类型与对应的形参类型相同,或者可以转换成形参的格式。

 

6.50

(a) 不合法,调用具有二义性。

(b)匹配于 void f(int)

(c)匹配于 void f(int, int)

(d)匹配于 void f(double, double = 3.14)

 

6.51

#include <iostream>
using std::cout;
using std::endl;

void f()
{
    cout << "f()" << endl;
}

void f(int)
{
    cout << "f(int)" << endl;
}

void f(int, int)
{
    cout << "f(int, int)" << endl;
}

void f(double, double)
{
    cout << "f(double, double)" << endl;
}

int main()
{
    // f(2.56, 42); // error: 'f' is ambiguous.
    f(42);
    f(42, 0);
    f(2.56, 3.14);
}

 

6.52

(a) 通过类型提升实现的匹配3

(b) 通过算数类型转换4

 

6.53

(a) 第一句只能调用非常量对象,第二句都可以.

(b) 第一句的实参是指向非常量的指针,第二句都可以。

(c) 不合法。都是调用指向字符类型的指针

 

6.54

int func(int a, int b);

using PF = int (*)(int a, int b);

vector<PF> vec;

int func(int a, int b);

using pFunc1 = decltype(func) *;
typedef decltype(func) *pFunc2;
using pFunc3 = int (*)(int a, int b);
using pFunc4 = int(int a, int b);
typedef int(*pFunc5)(int a, int b);
using pFunc6 = decltype(func);

std::vector<pFunc1> vec1;
std::vector<pFunc2> vec2;
std::vector<pFunc3> vec3;
std::vector<pFunc4*> vec4;
std::vector<pFunc5> vec5;
std::vector<pFunc6*> vec6;

 

6.55

int add(int a, int b) {return a + b;}

int subtract(int a, int b) {return a - b;}

int multiply(int a, int b) { return a * b;}

int divide(int a, int b) { return b != 0 ? a/b : 0;}

 

6.57

vector<decltype(func)*> vec{add, subtract, multiply, divide};

for (auto f: vec)

   cout << f(2, 2) << endl;

#include <iostream>
#include <string>
#include <vector>
using std::cout;
using std::vector;

//!
//! @brief Exercise 6.54
//! @note  define the function type fp
//!
inline int f(const int, const int);
typedef decltype(f) fp; // fp is just a function type not a function pointer

//!
//! @brief Exercise 6.55
//! @note  Store pointers to these functions in the vector
//!
inline int NumAdd(const int n1, const int n2)
{
    return n1 + n2;
}
inline int NumSub(const int n1, const int n2)
{
    return n1 - n2;
}
inline int NumMul(const int n1, const int n2)
{
    return n1 * n2;
}
inline int NumDiv(const int n1, const int n2)
{
    return n1 / n2;
}

vector<fp*> v{NumAdd, NumSub, NumMul, NumDiv};

int main()
{
    //!
    //! @brief Exercise 6.56
    //! @note  Call each element in the vector and print their result.
    //!
    for (auto it = v.cbegin(); it != v.cend(); ++it)
        cout << (*it)(2, 2) << std::endl;

    return 0;
}

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值