下面以一個例子來引出這種錯誤:
#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