指针小记

发布时间 2023-11-22 21:01:47作者: 小菜碟子

针对为什么传一级空指针进函数不会改变指针的指向而引发的思考

首先先看下面的错误代码

 1 #include <iostream>
 2 using namespace std;
 3 #include <stdlib.h>
 4 #include <string.h>
 5 void func(int *p)
 6 {
 7     p = (int *)malloc(sizeof(int) * 10);
 8     memset(p, 0, sizeof(p));
 9     p[0] = 1;
10 }
11 int main()
12 {
13     int *p = NULL;
14     func(p);
15     cout << p[0] << endl;
16     return 0;
17 }

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

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

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

重点放在

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

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

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

为什么二级指针就可以了呢?

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 void getMemery(int **p)
 4 {
 5     /*申请1024个int大小*/
 6     *p = malloc(sizeof(int)*1024);
 7     if(NULL == *p)
 8     {
 9         printf("malloc failed
10 ");
11         *p = NULL;
12     }
13 }
14 int main(void)
15 {
16     int *p = NULL;
17     getMemery(&p);
18     printf("address of p is %p
19 ",p);
20     free(p);
21     p = NULL;
22     return 0;
23 }

从运行结果可以看到,p的值被改变了,而不再是初始的NULL。