《C++ Primer》第6章 6.3节习题答案

《C++ Primer》第6章 函数

6.3节 返回类型和return语句

练习6.30:编译第200页的str_subrange函数,看看你的编译器是如何处理函数中的错误的。
【出题思路】
函数对于返回结果的要求是:每一条return语句的结果类型必须与函数的返回值类型相同,并且在函数执行逻辑中每一个可能的结束点都应该有一条return语句。
【解答】
该函数在作者所用的编译环境中无法编译通过,编译器发现了一个严重错误,即for循环中的return语句是非法的。函数的返回值类型是布尔值,而该条return语句没有返回任何值。事实上程序还存在另一个严重错误,按照程序的逻辑,for循环有可能不会中途退出而是一直执行完毕,此时显然缺少一条return语句处理这种情况。遗憾的是,编译器无法发现这一错误。

练习6.31:什么情况下返回的引用有效?什么情况下返回常量的引用有效?
【出题思路】
函数返回其结果的过程与它接受参数的过程类似。如果返回的是值,则创建一个未命名的临时对象,并把要返回的值拷贝给这个临时对象;如果返回的是引用,则该引用是它所引对象的别名,不会真正拷贝对象。
【解答】
如果引用所引的是函数开始之前就已经存在的对象,则返回该引用是有效的;如果引用所引的是函数的局部变量,则随着函数结束局部变量也失效了,此时返回的引用无效。当不希望返回的对象被修改时,返回对常量的引用。

练习6.32:下面的函数合法吗?如果合法,说明其功能;如果不合法,修改其中的错误并解释原因。
int &get(int *arry, int index) { return array[index]; }
int main() {
    int ia[10];
    for(int i = 0; i != 10; ++i)
        get(ia, i) = i;
}
【出题思路】
考查当函数的参数和返回值是复合类型时,如何向函数传入数据及如何接受返回结果。读者尤其需要理解函数是怎样返回引用类型的。
【解答】
该函数是合法的。get函数接受一个整型指针,该指针实际指向一个整型数组的首元素,另外还接受一个整数表示数组中某个元素的索引值。它的返回值类型是整型引用,引用的对象是arry数组的某个元素。当get函数执行完毕后,调用者得到实参数组arry中索引为index的元素的引用。
在main函数中,首先创建一个包含10个整数的数组,名字是ia。请注意,由于ia定义在main函数的内部,所以ia不会执行默认初始化操作,如果此时我们直接输出ia每个元素的值,则这些值都是未定义的。接下来进入循环,每次循环使用get函数得到数组ia中第i个元素的引用,为该引用赋值i,也就是说,为第i个元素赋值i。循环结束时,ia的元素依次被赋值为0~9。

#include <iostream>

using namespace std;

int &get(int *array, int index)
{
    cout << "index[" << index << "] = " << array[index] << "  ";
    if(0 == index % 3)
        cout << endl;
    return array[index];
}

int main()
{
    int ia[10];
    for(int i = 0; i != 10; ++i)
    {
        //get(ia, i)  返回是一个数组的引用ia[i]    相当于 ia[i] = i;
        get(ia, i) = i;
    }
    cout << endl;
    
    for(int j = 0; j != 10; ++j)
    {
        cout << "ia[" << j << "] = " << ia[j] << "  ";
        if(0 == j % 3)
            cout << endl;
    }
    
    return 0;
}

运行结果:

 练习6.33:编写一个递归函数,输出vector对象的内容。
【出题思路】
函数的递归分为直接递归和间接递归。编写递归函数的关键是确定递归规律和递归终止条件。
【解答】
满足题意的程序如下所示:

#include <iostream>
#include <vector>
#include <time.h>

using namespace std;

//递归函数输出vector<int>的内容
void print(vector<int> vInt, unsigned index)
{
    unsigned long sz = vInt.size();
    if(!vInt.empty() && index < sz)
    {
        cout << "vInt[" << index << "] = " << vInt[index] << endl;
        print(vInt, index + 1);
    }
}

void print(vector<int> vInt)
{
    for(auto val: vInt)
    {
        cout << "val = " << val << endl;
    }
}

int main()
{
    vector<int> v = {1, 3, 5, 7, 9, 11, 13, 15};
    print(v, 0);
    print(v);
    return 0;
}

运行结果:

练习6.34:如果factorial函数的停止条件如下所示,将发生什么情况?
if(val != 0)
【出题思路】
理解递归函数的执行逻辑。
【解答】
因为原文中递归函数的参数类型是int,所以理论上用户传入factorial函数的参数可以是负数。按照原程序的逻辑,参数为负数时函数的返回值是1。如果修改递归函数的停止条件,则当参数的值为负时,会依次递归下去,执行连续乘法操作直至溢出。因此,不能把if语句的条件改成上述形式。

练习6.35:在调用factorial函数时,为什么我们传入的值是val-1而非val--?
【出题思路】
回顾后置递减运算符参与表达式运算时的求值规律。
【解答】
如果把val-1改成val--,则出现一种我们不期望看到的情况,即变量的递减操作与读取变量值的操作共存于同一条表达式中,这时有可能产生未定义的值。

练习6.36:编写一个函数的声明,使其返回数组的引用并且该数组包含10个string对象。不要使用尾置返回类型、decltype或者类型别名。
【出题思路】
因为数组不能被拷贝,所以函数不能直接返回数组,但是可以返回数组的指针或引用。
【解答】
要想使函数返回数组的引用并且该数组包含10个string对象,可以按照如下所示的形式声明函数:
string (&func())[10];
上述声明的含义是:func()表示调用func函数无须任何实参,(&func( ))表示函数的返回结果是一个引用,(&func( ))[10]表示引用的对象是一个维度为10的数组,string (&func( ))[10]表示数组的元素是string对象。

练习6.37:为上一题的函数再写三个声明,一个使用类型别名,另一个使用尾置返回类型,最后一个使用decltype关键字。你觉得哪种形式最好?为什么?
【出题思路】
直接编写返回数组引用的函数比较烦琐且不易理解,使用类型别名、尾置返回类型和decltype关键字都可以简化这一过程。
【解答】
使用类型别名:
typedef string arr[10];
arr& func();
使用尾置返回类型:
auto func()->string(&)[10];
使用decltype关键字:
string str[10];
decltype(str) &func();

练习6.38:修改arrPtr函数,使其返回数组的引用。
【出题思路】
数组也是一个对象,所以可以定义数组的引用。要想为数组的引用赋值,只需要把数组名赋给该引用即可。
【解答】
满足题意的arrPtr函数是:

#include <iostream>
#include <string.h>

using namespace std;

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;
}


int main()
{
    for(auto od: odd)
        cout << "odd=====" << od << endl;
    int *a = arrPtr(1);
    
    for(int i = 0; i < 5; ++i)
        a[i] = i * 3;
    
    for(int j = 0; j < 5; ++j)
        cout << "a[" << j << "] = " << a[j] << endl;
    
    return 0;
}

运行结果:

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值