指针作为参数传入函数的陷阱

下面以一个例子来引出这种错误:

#include <iostream>
using namespace std;
#include <stdlib.h>
#include <string.h>
void func(int *p)
{
    p = (int *)malloc(sizeof(int) * 10);
    memset(p, 0, sizeof(p));
    p[0] = 1;
}
int main()
{
    int *p = NULL;
    func(p);
    cout << p[0] << endl;
    return 0;
}

一个很简单的函数,就是给*p在函数中分配空间并将p[0]置成1,最后打印输出p[0]。但是运行的结果却是segmengt fault

我们通过查看这段程序的汇编代码来分析一下出现段错误的原因。

 

Dump of assembler code for function func(int*):
   0x00000000004008cd <+0>:     push   %rbp
   0x00000000004008ce <+1>:     mov    %rsp,%rbp
   0x00000000004008d1 <+4>:     sub    $0x20,%rsp
   0x00000000004008d5 <+8>:     mov    %rdi,-0x18(%rbp)
   0x00000000004008d9 <+12>:    mov    $0x28,%eax
   0x00000000004008de <+17>:    mov    %rax,%rdi
   0x00000000004008e1 <+20>:    callq  0x400780 <malloc@plt>
   0x00000000004008e6 <+25>:    mov    %rax,-0x8(%rbp)
   0x00000000004008ea <+29>:    mov    -0x8(%rbp),%rax
   0x00000000004008ee <+33>:    mov    $0x8,%edx
   0x00000000004008f3 <+38>:    mov    $0x0,%esi
   0x00000000004008f8 <+43>:    mov    %rax,%rdi
   0x00000000004008fb <+46>:    callq  0x400750 <memset@plt>
   0x0000000000400900 <+51>:    mov    -0x8(%rbp),%rax
   0x0000000000400904 <+55>:    movl   $0x1,(%rax)
   0x000000000040090a <+61>:    leaveq
   0x000000000040090b <+62>:    retq   
End of assembler dump.

重点放在

    sub $0x20,%rbp
    mov %rdi,-0x18(%rbp)

这两句汇编代码上。

sub $0x20,%rbp的意思是给栈分配0x20大小的空间。

而mov %rdi,-0x18(%rbp)的意思是把函数的第一个参数的值压入栈中存储。
这说明了什么?说明了函数中的*p其实是一个临时变量,和主函数并不是同一个*p了。给临时变量申请内存并赋值当前不能反映到主函数的*p上,所以主函数的*p还是个空指针,而打印空指针当然就段错误了。

下面介绍两种解决方法:
1.函数返回临时指针的地址:

#include <iostream>
using namespace std;
#include <stdlib.h>
#include <string.h>
int* func(int *p)
{
    //此时的p是个临时指针
    p = (int *)malloc(sizeof(int) * 10);
    memset(p, 0, sizeof(p));
    p[0] = 1;
    return p;  //返回地址
}
int main()
{
    int *p = NULL;
    p = func(p);
    cout << p[0] << endl;
    return 0;
}

2.传入指向指针的指针

#include <iostream>
using namespace std;
#include <stdlib.h>
#include <string.h>
//*p存储的是main函数*ptr的地址
void func(int **p)
{
    *p = (int *)malloc(sizeof(int) * 10);
    memset(*p, 0, sizeof(*p));
    *p[0] = 1;
}
int main()
{
    int *ptr = NULL;
    func(&ptr);
    cout << ptr[0] << endl;
    return 0;
}

 

如果传的是已分配了内存空间的变量,则不需要指针的指针处理。如下:

void func(int *p)
{
    p[0] = 99;
}
int main()
{
    int *p = NULL;
    p = (int *)malloc(sizeof(int) * 10);
    func(p);
    cout << p[0] << endl;
    return 0;
}

 

 

转 https://blog.csdn.net/Move_now/article/details/71944689

posted @ 2021-11-10 16:27  半夏生  阅读(158)  评论(0编辑  收藏  举报