前几日在论坛上看到一个C语言指针的问题,引发的思考和深入
先看下面例子:
int *p; *p = 7; //段错误
如上例子,若定义指针,只是定义指针的本身,却没有定义指针所指的地址(或者定义指针 = NULL,NULL是宏定义来的,其值为无类型的0,即#define NULL (void*)0),所以赋值其指向地址的值,必定会因为没有指向地址发生内存错误导致程序崩溃。
其正确操作应该为:
int k; int *p; printf("%p\n",p); p = &k; printf("%p\n",p); *p = 7; printf("*p = %d\n",*p);
进入正题,直接上代码(一级指针传参):
void fun1(int *p){ printf("--%p\n",p); *p = 20; } void fun2(int *p){ printf("--%p\n",&p); *p = 20; } void fun3(int a) { printf("&a = %p\n",&a); a = 10; } int main() { #if 1 //实参传递 int a; printf("&a:%p\n",&a); fun3(a); printf("a = %d\n",a); #endif printf("\n"); #if 1 int p1; printf("%p\n",&p1); fun1(&p1); // 指针&p1和p所指的地址都一样 形参传递 printf("p1 = %d\n",p1); fun2(&p1); // 整数p1和指针p本身的地址不一样 类似实参传递 #endif printf("\n"); #if 1 int *p2; printf("%p\n",p2); // p2 指向地址默认为0x0(cygwin64编译环境) 但是有的编译器把不初始化的指针作为野指针 printf("%p\n",&p2); fun1(p2); //(注意)看似正确,其实不然,段错误 1.由p2和p的指针本身地址可以看出,p2和p是不同的指针,也就是相当于 // p2是按实参方式传递 // 2.因为p2指针未初始化,所以没有指向的内存,所以(*p)是不存在的 // 所以不存在*p = 20 的操作 printf("p2 = %d\n",p2); #endif return 0; }
运行结果:
&a:0xffffcbfc
&a = 0xffffcbd0
a = 0
0xffffcbf8
--0xffffcbf8
p1 = 20
--0xffffcbd0
0x0
0xffffcbf0
--0x0
Segmentation fault (核心已转储)
二级指针问题
void fun(int ** p) { printf("p = %p\n",p); printf("&p = %p\n",&p); int a = 20; *p = &a; } int main() { #if 1 int *p1; printf("p1:%p\n",p1); printf("&p1:%p\n",&p1); fun(&p1); printf("%d\n",*p1); printf("\n"); int **p2; printf("p2:%p\n",p2); printf("&p2:%p\n",&p2); //fun(p2); //段错误 //printf("%d\n",*p2); //段错误 #endif printf("\n"); #if 1 int a; int *b = &a; int **p3 = &b; printf("&a = %p\n",&a); printf("b = %p\n",b); printf("&b = %p\n",&b); printf("*p3 = %p\n",*p3); printf("p3:%p\n",p3); printf("&p3:%p\n",&p3); fun(p3); printf("%d\n",**p3); #endif return 0; }
运行结果:
p1:0x0
&p1:0xffffcbf8
p = 0xffffcbf8
&p = 0xffffcbb0
20
p2:0x0
&p2:0xffffcbf0
&a = 0xffffcbec
b = 0xffffcbec
&b = 0xffffcbe0
*p3 = 0xffffcbec
p3:0xffffcbe0
&p3:0xffffcbd8
p = 0xffffcbe0
&p = 0xffffcbb0
20
分析如下图: