题目描述
助教是个小可怜,因为她不知道要出什么机考题了。 然后她发现大家已经学完了指针,欣喜若狂。但是她要跑实验,不是很想出题。于是她偷了一道憨憨助教出的指针题,改一改准备拿来出题。
写出以下代码中的两个函数
f
u
n
A
funA
funA 和
f
u
n
B
funB
funB 的声明与定义,使得
f
u
n
A
(
p
)
=
a
funA(p)=a
funA(p)=a 能实现通过指针
p
p
p访问用户输入的数组
a
a
a,
f
u
n
B
funB
funB 能将
p
,
q
p,q
p,q 指向的两个数组的对应位相乘,并存储到数组
c
c
c 的对应位中。
#include <iostream>
#include <cstring>
using namespace std;
int n;
// 写出两个函数的声明
int main() {
int a[100], b[100], c[100];
cin >> n;
for (int i = 0;i < n; ++i)
cin >> a[i];
for (int i = 0;i < n; ++i)
cin >> b[i];
int **p,**q;
funA(p) = a;
funA(q) = b;
funB(c,p,q);
for (int i = 0; i < n; ++i)
cout << c[i] << " ";
return 0;
}
// 写出两个函数的定义
要求如下:
除了实现
f
u
n
A
funA
funA和
f
u
n
B
funB
funB外,不能修改包括
m
a
i
n
main
main 函数在内的其他代码,不能**在全局**定义新的变量、指针、数组和函数等,不能调用其他的库。
f
u
n
A
funA
funA 和
f
u
n
B
funB
funB 内不能调用任何输入输出函数(包含但不限于cin,cout,scanf,prinf,getchar,putchar等等)。
不允许存在内存泄漏。
用户输入的单个数组长度不会超过98,而且
−
1000
≤
a
i
,
b
i
≤
1000
-1000 \leq a_i, b_i \leq 1000
−1000≤ai,bi≤1000.
输入格式
(无)
输出格式
(无)
样例输入
8547491101-92-60-81-7
样例输出
5-3614-240-810
数据范围
(无)
题目吐槽
首先看到这个题目,是不是有一种冲动,把
c[i]
改成
a[i] * b[i]
,然后直接完事了。事实证明确实可以通过AC,但是显然题目不想让我们这样去做,我们要通过函数,返回一个引用类型。
什么?不会?给我回去看课本!171面!球球你们好好看看课本,这个真的课本上有。什么?老师没讲?那没事了,自学去23333(doge)如果不想看书就好好看这篇文章也可以。(本段内容全部划掉)
看了一下机考情况,这道题目考试的时候只有一个人AC了,另外还有四只小盆友尝试了一次,然后就没有然后了。看来这个题目对于初学者确实很烦。函数在等号的左边确实很少见,而且这个知识点也很偏僻,初学基本不怎么用到。加上这个题还融合了二级指针一起考,难度更大了。
这是什么助教?到底是谁可怜 2333。卖菜什么的最讨厌了(不是)。在正式开始之前我们先复习一下指针所有的知识,毕竟指针也是很重要的一个知识点,也是难点。
- 指针的定义、访问、赋值(一级指针)[这个还不会真的不用做这个题目了2333 快回去看书]
- 常量指针、指针常量、指向常量的指针常量 [课本 P155面]
- 动态变量、动态变量的创建与回收、动态数组、动态数组的创建与回收
- 引用类型
指针
不妨我们用几个简单的问题复习指针。
- 问题一:下列关于定义指针说法正确的有哪些?
int * p1, p2
定义的是两个指针,因为int *
属于一个类型名。int a; int *p1 = &a;
是正确的指针赋值语句。int a; int *p1; p1 = &a;
是正确的指针赋值语句。int a; int *p1; *p1 = &a;
是正确的指针赋值语句。- 解答:选项二、选项三正确。
int * p1, p2
定义的是一个指针,int *
也不属于一个类型名,星号属于变量名。选项二、选项三语句是等价的,*p1经过解引用,等式变成了a = &a;
显然不对。 - 问题二:常量指针,指针常量,指向常量的指针常量的定义方法与区别?
- 解答:课本P155
题目解答
在正式解答这个题目之前,我们首先看看课本的案例,代码清单的7-9给出了一个返回引用值的案例。下面这个案例来自课本。之前没好好看的可以现场看看。
//文件名:7-9.cpp//返回引用值的函数示例#include<iostream>usingnamespace std;int a[]={1,3,5,7,9};int&index(int);//声明返回引用的函数voidmain(){index(2)=25;//将a[2]重新赋值为25
cout <<index(2);}int&index(int j){return a[j];}
那么问题来了,既然是等号左边是函数,上面这个案例函数
index(2)
返回的是什么?是
a[2]
,有人就要问了,
a[2] = 5
呀,为啥返回的不是5呢,这就是
int &index(int j)
函数与
int index(int j)
的差别了,前者返回的是一个变量名,可以在等式的坐标,后者只能返回一个数字。明白了这一部分,你应该明白
&
的精妙了。
继续回到我们的试题,
funA(p) = a;
,我们还是看看这个等式:等式的左边是什么?是一个函数,等式的右边是什么?是一个
a
我们知道,数组名实际上就是一个指针,
a
也就是一个一级指针,也就是说,这个函数
funA(p)
的返回值是一个一级指针,函数是传入值是一个二级指针。[这是谁出的这个题目出来挨打!不是] 也就是说我们要实现一个函数,传入的二级指针,返回的是一个一级指针!而且返回的这个一级指针还可以通过后面的
funB(c,p,q);
,获取一级指针
a
b
的内容。
完了绕晕了怎么办。简单点说,我们首先要明白这个函数目的是啥,传入的是啥类型,传出的是什么,仅此而已够了!
那么,好啦,我们可以把函数大概写出来。
int*&funA(int**a){// 写内容}
上面的代码哪里错了?hhh如果你学的比较扎实的话一眼就可以看出来,传入的设置有问题,这个函数中
int **a
是一个形参!形参在函数运行完了就没有然后了!变量销毁,失效了,很明显我们这个题目要的就是要操作二级指针
**p
,你需要对传入的这个指针
**p
操作,结果上面那个函数你弄一个形参操作来操纵去有什么意义呢?
如果没有懂还是请看课本,171面,有这样的一段话:注意,在定义返回引用的函数时,不能返回该函数的局部变量,因为局部变量的生存期仅限于函数内部,当函数返回时,局部变量就消失了。此时引用该变量就会引起一个无效的引用,导致程序运行时出错。返回引用的函数中,返回的值也不能是一个表达式,因为表达式不是左值而是一个临时值。 什么?不会左值?回去看课本 P172!doge
请认真阅读上面的这一段话。你不能返回局部变量,所以你更不可以操作一个形参!那不是开玩笑?既然我们要操作的不可以是新参,在这个函数里面我们要操作的是真实的二级指针
p
,怎么办?如果不会那我们再看一个例子。
案例: 下面哪一个交换
main
函数中的
int
变量
x
与
y
的函数是正确的?
voidswap(int a,int b){int temp = a;
a = b;
b = temp;}
// 主函数中这样调用 swap(&x,&y);voidswap(int* a,int* b){int temp =*a;*a =*b;*b = temp;}
当然是第二个。那么我们在看下面的代码:
// 主函数中这样调用 swap(x,y);voidswap(int&a,int&b){int temp = a;
a = b;
b = temp;}
这就是引用,函数调用的时候,
int &a = x;
int &b = y;
,说白了就是给变量 x,y起啦一个新的名字 a,b;然后你可以操作a,b,这与你操作 x y是等价的。这就是引用!请看课本P169。我们再次回到这题目来,所以函数应该像下面这么写:(补充 int 与 *写在一起,不要问为什么,就是这样,C++习惯,这并不意味着
int *
是一个类型!只是为了方便,一眼看出这个一个一级指针,指向
int
数据类型的一级指针)
int*&funA(int**&a){// 写内容}
然后,请你默写出二级指针的赋值方法。什么?又不会?请看课本的P175面。好啦明白了,二级指针的赋值距离如下:
int x =10;int*p;int**q;
p =&x;// 一级指针等于指向的变量取址
q =&p;// 二级指针等于一级指针取址
于是就有人会问,那我能不能这样写
f
u
n
A
funA
funA:
int*&funA(int**&a){int*m;// 定义一个一级指针
a =&m;// 赋值二级指针return*a // 返回这个一级指针}
回答是:**错误,完全错误!** 为什么?理由是你定义了一个一级指针,其值是随机的,可能指向某一个地址,或者说是一个野指针(野指针就是说指针指向的地址是未经过申请的,通过野指针访问的地址的非法的,我们会拒绝这种非法的访问。)所以,你定义的这个一级指针没人知道指向什么地方,也不是通过合法的途径申请的地址,所以这个地址就是非法的,非法的就不能访问,访问就会报错!
所以我们还是要做合法公民,按照合法的途径申请一个地址。合法的方法当然是
new
,当然,你
new
了就一定要
delete
int*&funA(int**&a){
a =newint*// 赋值二级指针return*a // 返回这个一级指针}
补充说明:*和乘号还是要区分一下,通过括号解决问题。
voidfunB(int*c,int**p,int**q){for(int i =0; i< n ; i++){
c[i]=(*p)[i]*(*q)[i];}delete p;delete q;}
完整 AC 代码!规范不泄露内存的哦!
#include<iostream>#include<cstring>usingnamespace std;int n;// 写出两个函数的声明int*&funA(int**&p);voidfunB(int*c,int**x,int**y);intmain(){int a[100], b[100], c[100];
cin >> n;for(int i =0;i < n;++i)
cin >> a[i];for(int i =0;i < n;++i)
cin >> b[i];int**p,**q;funA(p)= a;funA(q)= b;funB(c,p,q);for(int i =0; i < n;++i)
cout << c[i]<<" ";system("pause");return0;}// 写出两个函数的定义int*&funA(int**&z){
z =newint*;return*z;}voidfunB(int*c,int**p,int**q){for(int i =0; i< n ; i++){
c[i]=(*p)[i]*(*q)[i];}delete p;delete q;}
版权归原作者 小小代码团 所有, 如有侵权,请联系我们删除。