关于 C++ 函数传入指针的问题(小白求教) - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Tony042
V2EX    C

关于 C++ 函数传入指针的问题(小白求教)

  •  
  •   Tony042 2019-07-04 11:22:11 +08:00 4024 次点击
    这是一个创建于 2343 天前的主题,其中的信息可能已经有所发展或是发生改变。
    struct PolyNode { int coef; int expon; PolyNode *Link; }; typedef PolyNode *Polynomial; struct PolyQueue { Polynominal Front; Polynominal Rear; }; typedef PolyQueue *PolyQueuePtrl; void AddPolyNode(PolyQueuePtrl Ptrl, const int coef, cons int expon) { Polynominal Temp = new PolyNode; Temp->coef = coef; Temp->expon = expon; Temp->Link = nullptr; if (Ptrl->FrOnt== nullptr) Ptrl->FrOnt= Temp; if (Ptrl->Rear != nullptr) Ptrl->Rear->Link = Temp; Ptrl->Rear = Temp; } void Attach(Polynomial &rear, const int coef, const int expon) { rear->Link = new PolyNode; rear = rear->Link; rear->coef = coef; rear->expon = expon; rear->Link = nullptr; } 

    最近在学习数据结构,在用 C++实现一个队列的时候,有了一个疑问希望能获得各位大佬的解答。我写了两个函数来实现在队列末尾新增一个元素的操作。一个传入的是队列的指针,另外一个传入的是队列里面的 Rear 指针,定义和具体实现在上方代码中,在传入队列指针的时候直接传入即可实现插入的操作,但是在传入 Rear 指针的时候一定要传入 Rear 指针的引用才可以,同样是指针为什么一个传值就可以了,另一个要传引用呢?

    34 条回复    2019-07-04 21:50:29 +08:00
    zjsxwc
        1
    zjsxwc  
       2019-07-04 11:55:14 +08:00
    传指针与传引用并没有问题,

    如图:
    https://i.loli.net/2019/07/04/5d1d78494694f93937.png

    你的代码:
    https://paste.ubuntu.com/p/tD66H7V74M/
    srt180
        2
    srt180  
       2019-07-04 11:57:37 +08:00 via iPhone
    需要改变入参就引用
    jmc891205
        3
    jmc891205  
       2019-07-04 12:03:25 +08:00
    我猜你是插入之后看 ptrl->rear 来检查有没有插入成功
    你的 Attach 只传指针进去的时候 插入其实是成功了的 但是 ptrl->rear 没有更新 所以你以为是插入没有成功
    Tony042
        4
    Tony042  
    OP
       2019-07-04 12:27:04 +08:00 via iPhone
    @zjsxwc 是的,谢谢你,代码是正确的代码,我的意思是,为什么把 Attach 函数第一个参数由&rear 改成 rear 就不对了呢
    zjsxwc
        5
    zjsxwc  
       2019-07-04 12:31:19 +08:00
    @Tony042

    没有不对啊,我发的代码里 函数 AttachTest 的结果是对的啊
    Tony042
        6
    Tony042  
    OP
       2019-07-04 12:31:19 +08:00 via iPhone
    @srt180 但是两个都是指针呀,我目前的理解是传入指针指向的结构体里的指针与传值一样,如需修改得声明饮用,但是传指针的话是不用声明引用就可以直接修改的。
    Tony042
        7
    Tony042  
    OP
       2019-07-04 12:33:40 +08:00
    @zjsxwc 我贴的代码是正确的代码,但是如果把 void Attach(Polynomial &rear, const int coef, const int expon)这个声明改成 void Attach(Polynomial rear, const int coef, const int expon) 这个函数就不生效了,所以我是想问 rear 和&rear 的区别
    Tony042
        8
    Tony042  
    OP
       2019-07-04 12:36:10 +08:00
    @jmc891205 对的是这样的,可为什么没更新呢,我通过 attch 函数传入的那个参数值就是 Ptrl->Rear, 比如 Attach ( Ptrl->Rear,3,5)
    zjsxwc
        9
    zjsxwc  
       2019-07-04 12:40:15 +08:00
    @Tony042
    我发的代码里 &rear 改成 rear 后, 仍旧生效。

    rear 和&rear 的区别,
    简单来说 只是 “副作用”的区别,
    &引用方式是有副作用的,在子函数里对变量的修改,会影响到外面调用函数里的变量值,
    一般&引用方式传值是为了能够返回变量,
    比较 C++不能和 golang 那样一次性 return 多个值。
    zjsxwc
        10
    zjsxwc  
       2019-07-04 12:41:11 +08:00
    “比较 ” ---》 “毕竟”
    Tony042
        11
    Tony042  
    OP
       2019-07-04 12:44:13 +08:00
    @zjsxwc xi 谢谢您的回复,我运行了您的,如果输出 pqp->rear->coef 的值的话,AttachTest 是不生效的,我在您的代码后面加了一个 cout 输出,请您瞅一下 https://paste.ubuntu.com/p/pzTNnPC74x/
    srt180
        12
    srt180  
       2019-07-04 12:46:54 +08:00 via iPhone
    @Tony042 指针就是地址,加不加引用代码逻辑都完成了。不同的是加引用的话 attach 函数 rear 的实参变成了入参的 link,不加引用的话 rear 的实参还是入参,相当于对参数而言加了引用就是读写权限,不加就是只读。
    AddPolynode 函数不需要引用是因为入参只读了。
    zjsxwc
        13
    zjsxwc  
       2019-07-04 12:49:20 +08:00
    @Tony042

    理解了你所谓 “ AttachTest 是不生效”,
    很简单,
    因为 AttachTest 没有副作用,所以外面的 pqp->Rear 没有更新
    Tony042
        14
    Tony042  
    OP
       2019-07-04 12:49:53 +08:00
    @srt180 谢谢讲解,感觉有点转过来了,AddPolynode 和 Attach 的区别还是在于指针更改了没有,由于 Attach 更改了指针所以要用引用,刚学 C++没多久,遇到指针还是很迷,还好有你们的帮助
    Tony042
        15
    Tony042  
    OP
       2019-07-04 12:51:34 +08:00
    @zjsxwc 对的,没错,实际上值已经加上了,现在理解了
    Tony042
        16
    Tony042  
    OP
       2019-07-04 12:52:24 +08:00
    @jmc891205 对的,我现在理解了,值已经加在链表上面了,但是 rear 没有更新,谢谢您
    Tony042
        17
    Tony042  
    OP
       2019-07-04 12:53:54 +08:00
    @zjsxwc 对了,能麻烦告诉下你用的 IDE 是什么么,看着很不错哇
    zjsxwc
        18
    zjsxwc  
       2019-07-04 12:56:59 +08:00   1
    @Tony042

    clion
    lvdong
        19
    lvdong  
       2019-07-04 13:00:58 +08:00   1
    指针本身也是变量,如果要改变指针自身的值,就需要引用,仅改变指针指向变量的值,指针按照值传递就可以了
    stackexplode
        20
    stackexplode  
       2019-07-04 14:26:36 +08:00
    越搞不懂 C++,在学习过程中就越不要用那么多 typedef,什么 Polynomial &,真的非常容易混淆
    你参数展开成 PolyNode *& rear,一下就懂了,传进来的是指针的引用,你一旦修改 rear,传进来的指针值就会被修改
    如果是 PolyNode * rear,传进来只是一个指针,也就是一个值,修改 rear 就不会对传入方有影响
    b00tyhunt3r
        21
    b00tyhunt3r  
       2019-07-04 16:32:51 +08:00
    nullptr 是什么?宏吗?
    b00tyhunt3r
        22
    b00tyhunt3r  
       2019-07-04 16:37:52 +08:00
    @b00tyhunt3r 饿 查了一下原来是 11 的新类型,请问这里为什么不直接用 NULL ?
    jmc891205
        23
    jmc891205  
       2019-07-04 16:47:17 +08:00
    @b00tyhunt3r
    假设你有一个函数 void test_null(int ptr)

    test_null(nullptr)会在编译的时候就报错
    test_null(NULL)不会
    b00tyhunt3r
        24
    b00tyhunt3r  
       2019-07-04 17:00:21 +08:00
    @jmc891205 这个理解,NULL 相当于还是有个 0 值
    但楼主这里用 nullptr 的意义是?
    jmc891205
        25
    jmc891205  
       2019-07-04 17:08:50 +08:00
    @b00tyhunt3r
    意义是养成在所有地方都用 nullptr 抛弃 NULL 的好习惯
    b00tyhunt3r
        26
    b00tyhunt3r  
       2019-07-04 18:17:07 +08:00
    LZ,你的代码我原样复制在 mac+gcc4.2.1 上跑了一遍,
    结果很奇怪,直接报了错 segmentation fault:11,

    排查了一下发现是这句的问题:
    Ptrl->Rear->Link = Temp;

    具体来说把 “->Link ”注释掉就好了,应该是直接调用了 link 这个空指针。
    你运行没问题吗?
    也请大佬帮忙看一下谢谢
    @jmc891205
    @stackexplode
    @zjsxwc
    @srt180
    jmc891205
        27
    jmc891205  
       2019-07-04 19:07:09 +08:00 via iPhone
    @b00tyhunt3r 把你调用 lz 函数的代码贴出来
    b00tyhunt3r
        28
    b00tyhunt3r  
       2019-07-04 19:30:59 +08:00
    #include <iostream>
    using namespace std;

    struct poly
    {
    int coef;
    int expon;
    poly* link;
    };
    typedef poly* node;

    struct polyqueue
    {
    node front;
    node rear;
    };
    typedef polyqueue* polyq;

    void addpoly(polyq q, const int coef, const int expon)
    {
    node tmp = new poly;
    tmp->coef = coef;
    tmp->expon = expon;
    tmp->link = nullptr;
    if(q->frOnt== nullptr)
    {q->frOnt= tmp;}
    if(q->rear != nullptr)
    {q->rear->link = tmp;}
    q->rear = tmp;
    }

    int main()
    {
    polyq x=new polyqueue;
    addpoly(x,1,1);

    return 0;
    }


    @jmc891205 是一样的啊
    jmc891205
        29
    jmc891205  
       2019-07-04 20:22:28 +08:00
    @b00tyhunt3r
    类成员是指针的话 编译器自动生成的默认构造函数 不保证能正确地初始化他们为 nullptr
    Tony042
        30
    Tony042  
    OP
       2019-07-04 20:47:22 +08:00
    @jmc891205 那为什么这个代码 https://paste.ubuntu.com/p/tD66H7V74M/运行没问题,但 @b00tyhunt3r 的就有问题呢,我在 windows 下用 clang 跑了一遍,遇到的也是相同的情况
    Tony042
        31
    Tony042  
    OP
       2019-07-04 20:50:06 +08:00
    @b00tyhunt3r 楼里面的大佬说的应该是对的,我在初始化 PolyQueue 类型指针的时候,是调用了另一个函数显示初始化它们为 nullptr,但是我现在也不太明白为什么 https://paste.ubuntu.com/p/tD66H7V74M/这个代码运行起来没问题,而运行你的代码就会 stackfault
    b00tyhunt3r
        32
    b00tyhunt3r  
       2019-07-04 21:40:45 +08:00
    @Tony042 你的代码我看了, 和我的除了变量名不一样 其实是一模一样啊。
    @jmc891205 的意思是说有一定几率不会成功将两个 link ( front 和 rear 的)初始化为 null 吗?

    也就是说这么写是不安全的?那应该怎样改呢
    谢谢回复!
    jmc891205
        33
    jmc891205  
       2019-07-04 21:46:53 +08:00
    @Tony042
    没有初始化的指针可能是任何值,这个跟编译器的实现、运行程序的环境等等都有关系

    @b00tyhunt3r
    应该在 struct/class 的构造函数中显示地初始化每一个成员变量
    jmc891205
        34
    jmc891205  
       2019-07-04 21:50:29 +08:00
    @b00tyhunt3r
    上面我的回复写了个错别字
    应该在 struct/class 的构造函数中「显式」地初始化每一个成员变量
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1138 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 23:32 PVG 07:32 LAX 15:32 JFK 18:32
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86