指针的引用*&应用场景

引子

最近在写一个有关链表的操作例子,需要计算两个链表的数值之和,并完成链表后移操作,但是在调试过程中发现,自己编写的函数无法实现链表元素后移,每次都是计算的 Head List(即,总是指向ListHead头部)。对应的代码如下:

//define a List struct.
struct ListNode {
    ListNode(int x) : val(x), next(NULL) {}
    int val;
    ListNode * next;
};

//Implement the sum of NodeLists value and pointer to next ListNode.
int sumTwoListVal(ListNode* left, ListNode* right, int& carry)
 {
        int sum = left->val + right->val + carry;
        if (sum >= 10)  carry= 1;
        else            carry= 0;

        left = left->next;
        right = right->next;

        return sum % 10;
 }

后面修改为指针的引用(*&)就可以完成需要的功能,还是基本功不够扎实,并未深刻理解指针和引用,首次书写的时候居然没有意识到这点。特此记录下来,并重新梳理下指针的引用场景。

指针的引用

我们先用例子熟悉一下指针的引用定义:

int val = 10;
int *ptr = &val;     //define a pointer
int ref = &val;      //define a reference
int *& ptrRef = ptr  //define a pointer reference

//function declaration
void fooPtr(int *ptr_val);
void fooPtrRef(int *&ptrRef_val);

//call function
fooPtr(ptr);         
fooPtrRef(ptr);

当我们把一个指针作为参数传递给一个函数或者方法时,其实是把指针的副本(copy)传递给了函数,即把指针的值本身传递到ptr_val。其实质还是属于值传递
因此,当我们在函数或者方法内部修改指针(注意,不是修改指针所指向的值)时,其实修改的是函数内部指针的副本(copy),而非外部的指针本身。还是接用知乎大神们的图示看一下(尽管不是很清晰,但懒的重新画了,有时间再更新)。

下图是普通指针变量方式(即调用 fooPtr(ptr) ),此时外部传入的实参 ptr 的地址可以认为是1000,形参 ptr_val 的地址是 1004,他们指向的内存单元数值都是10。当修改函数内部形参 ptr_val 地址的时候,实参 ptr 的地址是不会改变的。

图示存粹是为了理解方便,与文中描述有差异,请注意对比
指针变量
我们再看看指针的引用调用方式(即调用 fooPtrRef(ptr) ),此时外部传入的实参 ptr 的地址还认为是1004,形参 ptr_val 的地址也是 1004,他们指向的内存单元数值都是10。根据引用的定义,此时 ptrRef_val 就是实参 ptr 的别命。因此当修改函数内部形参 ptrRef_val 地址的时候,实参 ptr 的地址也会随之改变。

图示存粹是为了理解方便,与文中描述有差异,请注意对比
指针的引用

引用场景

当函数调用时需要修改指针的指向,或者函数调用结束后指针所指的这块内存会发生改变的时候,就需要使用指针的引用,或者指针的指针。

举例1(修改指针的指向):

  • 如上面因子中提出的,当使用链表做参数,如果只是类似遍历查找链表元素的时,此时链表并未做任何修改,可以使用普通指针遍历方式;
  • 若是增加、删除、修改链表操作,意味着传入的节点指针(一般多为HeadNode* )可能发生改变,此时就需要要使用 指针的引用。

开头的例子正确定义方式如下:

int sumTwoListVal(ListNode*& left, ListNode*& right, int& carry)

举例2(子函数内存改变):
常见的就是调用 malloc 分配一块内存空间,常见的面试题中都会碰到,这里不在赘述,只把例子放在这里。

面试中长碰到的试题:

# include <stdio.h>
# include <stdlib.h>
# include <string.h>

void foo(char *p)
{
   p = (char *)malloc(sizeof(char) * 100);
}

int main()
{
    char *str = NULL;
    foo(str);  
    
    strcpy(str, "hello world");   //it will be segment fault here.
    printf("%s\n", str);
}

提供的解题思路一般是要使用二级指针,代码如下,:

# include <stdio.h>
# include <stdlib.h>
# include <string.h>

void foo(char **p)
{
   *p = (char *)malloc(sizeof(char) * 100);
}

int main()
{
    char *str = NULL;
    foo(&str);     // Notice here is str address.
    
    strcpy(str, "hello world");   //it will be OK 
    printf("%s\n", str);
}

当然,看完本篇,推荐你使用指针的引用这种方式,毕竟看起来更为清晰。

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

void foo(char *&p)
{
   p = (char *)malloc(sizeof(char) * 100);
}

int main()
{
    char *str = NULL;
    foo(str);           //It still using str here not it's address.
    
    strcpy(str, "hello world");
    printf("%s\n", str);
}

参考

https://blog.csdn.net/matrix_google/article/details/77543192
https://zhuanlan.zhihu.com/p/139543762

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值