指針作爲參數傳入函數的陷阱

下面以一個例子來引出這種錯誤:

#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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章