关于用二级指针创建内存那些事

关于在子函数中需用二级指针创建内存那件事

这是我们平时使用指针传递修改变量值的例子:
例一:

void fun(int* p) {
    cout << "p3=" << p << endl;
    cout<<"p4= " << &p << endl;
    *p = 5;  
    cout << "(fun)**p=" << *p << endl;
}

int main()
{
    int* p = NULL;
    p = (int*)malloc(sizeof(int));
    *p = 12;
    cout << "p1=" << p << endl;
    cout << "p2=" << &p << endl;
    fun(p);
    cout << "int =" << *p;
    free(p);

    return 0;
}

在这里插入图片描述
结果如上图所示,我们成功在子函数内修改*p的值。

而后我们想在主函数中定义一个指针变量,然后再子函数中申请内存,并将该内存地址保存在主函数申请的指针变量中,执行代码如下:
例二:

void fun(int* p) {
    cout << "p3=" << p << endl;
    cout<<"p4= " << &p << endl;
    p = (int*)malloc(sizeof(int));
    cout << "p5=" << p << endl;
    cout << "p6= " << &p << endl;
    *p = 5;  
    cout << "(fun)**p=" << *p << endl;
}

int main()
{
    int* p = NULL;
    cout << "p1=" << p << endl;
    cout << "p2=" << &p << endl;
    fun(p);
    cout << "int =" << *p;
    free(p);

    return 0;
}

结果如下:
在这里插入图片描述
我们可以看到虽然在子函数中虽然空间的值已经是5,但主函数中并没有成功修改。

在例一中我们在执行完 **int *p = NULL;**这条语句后会得到一块内存空间,

在这里插入图片描述
其中*p是空间中的值,这里指向NULL,所以值是0x00(略写),而该空间的地址&p我们设为0xF8。
而后执行malloc申请内存空间,并将内存首地址赋给p,这里把首地址设为0xC0,
在这里插入图片描述
而后执行fun§,在执行fun§函数的时候会系统会申请一块临时变量,并把参数p赋给形参,于是就有了
在这里插入图片描述

这就是例一中各内存空间的地址的由来
在这里插入图片描述
此时我们想在子函数中通过p来修改子函数的值,于是执行p=5;
在此时子函数的形参p的值仍是0xC0,是一个地址,而通过*p就能读写该地址所对应的值,所以在子函数中 (0xC0) 就能修改主函数中的p的值。

而在例二中
我们同样先执行int *p = NULL;定于了指针变量,但并没有申请内存空间,所以p指向0x00,而该指针变量地址我们设为0x78
在这里插入图片描述
而后执行fun§函数,同样系统会申请一块临时变量,并把实参p的值传给形参,这里实参p的值是0x00,设形参地址为0x50.
在这里插入图片描述
而后开始malloc申请内存空间,并将首地址赋给形参p,(注意,这里实参传给形参的值是0x00,所以形参的值是0x00)
我们把malloc空间首地址设为0x80,所以形参p的首地址也相应的变为了0x80

在这里插入图片描述
这就是例二里各内存空间地址的由来

在这里插入图片描述

此时我们想通过p来修改空间的值,这样主函数中也能通过p对空间进行读写,
于是执行p=5;此时执行的p是子函数形参中的*p,也就是0x80所对应的地址空间,于是就有
在这里插入图片描述
此时子函数中申请内存的空间的值已经成功变成5,但主函数里的p对应的值仍是0x00,所以主函数中的值仍无法改变。

  • 这里我们需要缕清两个点
    • 在子函数中传的指针传递也会生成一个临时变量,只是该临时变量是地址
    • 在例一中是有明确的空间地址,主函数传给子函数的内存地址没有改变,所以可以在子函数中直接通过*(内存)的方式修改主函数的值。但在例二中由于申请内存空间并给形参重新赋值,导致主函数与子函数的值不同,所以子函数中*p无法修改主函数中的值。

我们想要在子函数中申请内存空间并能在主函数中也能对该空间进行读取可以有如下方法:
1、在子函数中返回malloc内存的值,在主函数中接收,这样主函数就能对该内存空间进行读取

在这里插入图片描述

2、通过二级指针对地址进行保存修改

例三

void fun(int**  p) {
    cout << "p3=" << p << endl;
    cout<<"p4= " << &p << endl;
    cout <<"p5= " << *p << endl;
    cout << "p6= " << &(*p) << endl;
    cout << "p7= " << &(**p) << endl;
    *p = (int*)malloc(sizeof(int));
    cout << "p8=" << p << endl;
    cout << "p9= " << &p << endl;
    cout << "p10= " << *p << endl;
    cout << "p11= " << &( * p) << endl;
    cout << "p12= " << &(**p) << endl;
    **p = 5;  
    cout << "(fun)**p=" << *p << endl;
}

int main()
{
    int* p = NULL;
    cout << "p1=" << p << endl;
    cout << "p2=" << &p << endl;
    fun(&p);
    cout << "int =" << *p;
    free(p);

    return 0;
}

结果如图

在这里插入图片描述

同样在执行int *p = NULL;后系统会申请一块内存空间,这里我们设空间地址为0x88,并将p指向0x00
在这里插入图片描述

而后执行fun(int **p),因为这里是二级指针,也就是指向指针地址的指针,所以我们可以把指针地址传过去,这样就避免多定义一个二级指针变量,
void fun(int *p)就是把p传过去,所以void fun(int **p)就是把p的地址传过去,也就是fun(&p)

同样在执行fun(&p)后系统会申请临时一块内存空间,并把实参值传给形参,实参也就是p的地址,也就是0x08,形参地址我们设为0x60
在这里插入图片描述

因为形参p的值此时是0x88,所以执行*p时,此时得到的就是0x88空间所对应的值,也就是NULL(0x00)

而后malloc申请内存空间,注意此时形参p是二级指针,也就是int**,而malloc的返回值强制转回的一级指针int*,所以应用p接收(注意此时p值是0x88,p是0x00),
我们设malloc首地址是0x6100,所以执行
p=(int
)malloc(sizeof(int))后,*p的值变为了0x6100

在这里插入图片描述

此时让我们缕一缕,在子函数中,p=0x88,p的地址&p是0x60,也就是控制台截图的p3,p4。p5=*p 即 *(0x88) 也就是0x88地址所存储的值,所以是NULL,0x00。p6=&(*p),也就是存储0x00的地址,也就是0x88。p7=&(**p)就是0x00的地址的地址,即NULL的地址,没有意义。
在这里插入图片描述

而后用p存储malloc首地址,所以此时p=0x6100,所以p10=p就更新为0x6100,而p前面为NULL,也就是此时主函数中存储的p值由NULL变为0x6100,但其他值仍然不变,所以p8=p还是0x88,p9=&p还是0x60,p11=&(p)也就是前面存储NULL的空间,现在存储0x6100的空间的地址,也就是0x88。p=0x6100,**p=5,所以&(**p)=0x6100,所以p12=0x6100。
此时在子函数中的
p和主函数中的p对应的是同一块内存空间的值,这块内存空间存储的是malloc空间的地址,通过
(0x6100)就可以修改malloc的值。
在这里插入图片描述

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值