0


(新版)SJTU-OJ-1038.小可怜的指针题

题目描述

助教是个小可怜,因为她不知道要出什么机考题了。 然后她发现大家已经学完了指针,欣喜若狂。但是她要跑实验,不是很想出题。于是她偷了一道憨憨助教出的指针题,改一改准备拿来出题。

写出以下代码中的两个函数

    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;}
标签:

本文转载自: https://blog.csdn.net/weixin_51394621/article/details/119208919
版权归原作者 小小代码团 所有, 如有侵权,请联系我们删除。

“(新版)SJTU-OJ-1038.小可怜的指针题”的评论:

还没有评论