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


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

    #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

  • 相关阅读:
    分组与子报表Active Report6 使用(二)
    网站开发人员应该知道的62件事[转]
    如何恢复SVN中已删除文件或文件夹
    java中的List排序[转]
    [原]ActiveReport6 for net使用(一)
    Windows XP 不用输入密码自动登录
    IE不加载ActiveX控件的解决办法
    winRAR 打包小技巧
    iis负载均衡与文件同步[网摘]
    ASP.net的PDF打印(水晶报表)[摘]
  • 原文地址:https://www.cnblogs.com/mingyunrangwozoudaoxianzai/p/15534055.html
Copyright © 2020-2023  润新知