北京大学C++程序设计编程作业答案+解析·从C走进C++

本章一共包含四个编程习题:

  1. 简单的swap
  2. 难一点的swap
  3. 好怪异的返回值
  4. 神秘的数组初始化

以下习题答案全部通过OJ,使用编译器为:G++(9.3(with c++17))

1. 简单的swap

考点:变量值的引用

解析:swap函数需要交换两个参数的值,但是调用函数的时候没有传入指针,所以我们很容易想到需要传入变量的引用,这样在函数内部变更参数的值,才能影响函数外部的变量的值,否则只会影响函数参数的值,而外部则不受影响。

答案:完整源码地址

// 这里只给到需要补完的代码,完整代码请移步到github
void swap(
    // 在此处补充你的代码
    A &a, A &b
) {
    int tmp = a.x;
    a.x = b.x;
    b.x = tmp;
}

2. 难一点的swap

考点:指针的引用

解析:本题和上一题,简单的swap,比较相似,但是这里传入的参数不再是变量的值,而是其指针。而且注意,swap函数内部是直接变换传入的指针,而不是变换指针指向的值,如下面例子所示:

// int *a, int *b
// Example 1
// 这里变换的是指针变量a指向的指针,但是指针指向的值不变
int *tmp = a;
a = b;

// Exmaple 2
// 这里变换的是指针变量a指向指针的值,但其指向的指针不变
int tmp = *a;
*a = *b;

所以,这里的swap函数的参数需要:1)必须是指针类型,和外部传入的参数一致;2)参数还必须是指针的引用,这样swap函数内部交换变量指向的指针,才能改变外部指针变量所指向的指针发生改变。

答案:完整源码地址

// 这里只给到需要补完的代码,完整代码请移步到github
void swap(
	// 在此处补充你的代码
    int *&a, int *&b
) {
    int *tmp = a;
    a = b;
    b = tmp;
}

3. 好怪异的返回值

考点:返回值的引用

解析:这里考点还是引用,只是现在我们需要对函数返回值进行修改,并且该返回值还是存储在数组中的值,我们需要对返回值进行修改,达到同时修补数组中值的目的。注意函数返回值是数组a在下标i的值,不是指针,如果我们只返回该值,而不是引用,在外部修改函数的返回值也只是修改该返回值自身,与数组a存储的值没有关联,因为没有返回引用,程序会对返回值进行复制,而不是返回值本身。

答案:完整源码地址

// 这里只给到需要补完的代码,完整代码请移步到github
// 在此处补充你的代码
int &getElement( int *a, int i ) {
    return a[ i ];
}

4. 神秘的数组初始化

考点:数值指针

解析:首先我们注意数组的a的类型,它表示一个指向int类型的二维数组的指针。请注意下面数组类型之间的关系:

a = b; // 不会编译错误
auto c = b; // int *c

// d 等价 e
int **d; // 表示一个二维数组的第一个值的地址
int *e[ 1 ]; // 表示一个长度为1二维数组的指针
int f[ 2 ][ 1 ]; // 表示一个长度为2*1的二维数组
auto g = e; // int **g
auto h = f; // int (*h)[ 1 ]
d = e; // 不会编译错误

int (*i)[ 1 ]; // 表示一个指向多维数组的指针
// d = i; // 编译错误: Incompatible pointer types assigning to 'int **' from 'int (*)[1]'
i = h; // 不会编译错误
i = &b; // 不会编译错误

// Example of data_type (*var_name)[size_of_array];
int arr[ 3 ][ 4 ] = { { 10, 11, 12, 13 },
                  { 20, 21, 22, 23 },
                  { 30, 31, 32, 33 } };
int (*ptr)[ 4 ];
ptr = arr;
// 几种方法用于访问位于arr的第二行,第三个的元素:
std::cout << ( arr[ 1 ][ 2 ] ) << std::endl; // 22
std::cout << ( *( ptr + 1 ) )[ 2 ] << std::endl; // 22
std::cout << *( *( ptr + 1 ) + 2 ) << std::endl; // 22
std::cout << *( ( ptr + 1 )[ 2 ] )<< std::endl; // Undefined value

std::cout << ptr << std::endl; // Base address, 0x7fff6dbf2d70
std::cout << ( ptr + 1 ) << std::endl; // 0x7fff6dbf2d80, offset by 16 bytes compared to the base addr, which is the size of one row, which is 4 integers.
std::cout << &( ptr[ 1 ] ) << std::endl; // 0x7fff6dbf2d80, same as the previous one.
std::cout << ( *( ptr + 1 ) + 2 ) << std::endl; // 0x7fff6dbf2d88, offset by 24 bytes compared to the base, which is the the size of 6 integers before 22

// 更多内容,有兴趣的童鞋可以参考下面文章:
// https://www.geeksforgeeks.org/pointer-array-array-pointer/
// https://stackoverflow.com/questions/8108416/excess-elements-of-scalar-initializer-for-pointer-to-array-of-ints

再者,注意题目中的给的条件:

*a[ 2 ] = 123; // 表示a[2][0] = 123
a[ 3 ][ 5 ] = 456;
if ( !a[ 0 ] ) { // 表示a[0]为null,即第一行的数组为null
    std::cout << *a[ 2 ] << "," << a[ 3 ][ 5 ]; // 123,456
}

所以,a至少需要初始化为一个包含4个指针的数组,但第一个数组指针为null,第三个数组长度至少为1,第四个数组长度至少为6,第二个数组可为null。

答案:完整源码地址

// 这里只给到需要补完的代码,完整代码请移步到github
int *a[] = {
    // 在此处补充你的代码
    nullptr,
    new int[ 6 ] { 1, 2, 3, 4, 5, 6 },
    new int[ 6 ] { 1, 2, 3, 4, 5, 6 },
    new int[ 6 ] { 1, 2, 3, 4, 5, 6 }
}; // 这里a表示一个指向二维数组的指针

下一章:

5. 参考资料

  1. C++程序设计
  2. pixiv illustration: fiction

6. 免责声明

※ 本文之中如有错误和不准确的地方,欢迎大家指正哒~

※ 此项目仅用于学习交流,请不要用于任何形式的商用用途,谢谢呢;


www.pixiv.net/en/artworks/119974313

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值