前言
你是否在C代码里面看到一些方法签名 method( A ** pointer )
method( A * pointer )
脑袋就会充血,总是感觉会绕一下。什么是 指针 ?什么是 指针的指针 ?
看谭浩强的时候,总感觉是什么都懂,但是一看到真实的代码,就感觉理解上还不够深入。
最近在看 Linux 的原理,顺便捡起 C语言 编码。结合 linux 的内存结构,反而对指针有了进一步的了解,希望这篇文章对你有帮助。
PS: 🦉 linux 的C语言的开发环境配置,后续补充一篇文章
程序例子说明
所有代码都是运行在 64位 Centos7.4中
int a = 123;
printf("a address: %lx\t value:%d \n", &a, a);
//a address: 7fffffffdf5b value:123
printf("\n");
int * b = (int *)malloc(sizeof(int) * 1); *b = 11;
printf("b address: %lx\t value:%lx pointed-value:%d \n", &b, b, *b);
//b address: 7fffffffdf58 value:602010 pointed-value:11
printf("\n");
int * c = &a;
printf("c address: %lx\t value:%lx pointed-value:%d \n", &c, c, *c);
//c address: 7fffffffdf50 value:7fffffffdf5b pointed-value:123
代码下面就是输出的信息,我们一个个看。
int a = 123;
int a = 123;
printf("a address: %lx\t value:%d \n", &a, a);
//a address: 7fffffffdf5b value:123
简单理解
- 就是在
stack
中有创建一个 变量a,数据类型是 int,赋值是 123
深入理解
- 在
stack
地址7fffffffdf5b
上,分配了 4Bytes 内存,创建变量 a,是 int 类型,value 是 123。 - 变量 a 包含:1. 内存地址,stack
7fffffffdf5b
; 2. 值, 123,占用内存 4 Bytes
后续的内存图,都是根据打印出来的变量值,来绘画出真实内存值的情况。
根据值和图得知,变量a 代表一个地址,地址指向 stack 一段内存,内存值是 123。
int * b = (int *)malloc(sizeof(int) * 1); *b = 11;
int * b = (int *)malloc(sizeof(int) * 1); *b = 11;
printf("b address: %lx\t value:%lx pointed-value:%d \n", &b, b, *b);
//b address: 7fffffffdf58 value:602010 pointed-value:11
简单理解
- 创建变量 b,是
int pointer
,指向heap
内存地址;在heap
对应的地址申请内存,数据类型是 int,赋值是 11
深入理解
- 在
heap
地址60 20 10
上,分配了 4Bytes 内存,是 int 类型 - 在
stack
地址7f ff ff ff df 58
上,创建变量 b,分配了 8Bytes 内存,是 int piointer 类型,value 是60 20 10
- 在
heap
地址60 20 10
上赋值,value 是11
- 变量 b 包含:1. 内存地址,stack
7f ff ff ff df 58
; 2. 值,60 20 10
,占用内存 8 Bytes
int * b = (int *)malloc(sizeof(int) * 1);
根据值和图得知,变量b 代表一个地址,地址指向 stack 一段内存,内存值是 60 20 10
。
:::info
变量是 stack地址 和 对应的内存
:::
int * c = &a
int * c = &a;
printf("c address: %lx\t value:%lx pointed-value:%d \n", &c, c, *c);
// c address: 7fffffffdf50 value:7fffffffdf5b pointed-value:123
正常理解
- 创建变量c,是
int pointer
,指向变量 a 地址
深入理解
- 在
stack
地址7f ff ff ff df 50
上,创建变量 c,分配了 8Bytes 内存,是 int piointer 类型,value 是7f ff ff ff df 5b
(就是 变量a 的地址) - 变量 c 包含:1. 内存地址,stack
7f ff ff ff df 50
; 2. 值,7f ff ff ff df 5b
,占用内存 8 Bytes
:::info
指针变量,对应内存的值,可以是 heap
地址,同样可以是 stack
地址
:::
总结
- 变量,就是 一个Stack地址 和 地址指向的内存 而已;不论是 普通变量,指针变量,和 指针的指针变量
- 创建变量
- 变量的地址,一定是 Stack地址
- 分配内存,可以分配在
stack
中,也可以分配在heap
中,看情况而定
再进一步思考
指针仅仅是一种数据类型
pointer
就是和 int
char
等基础的类型一样,变量都是定义在内存中,并且占用了一定容量内存保存数据。
int a = 123;
int * b = (int *)malloc(sizeof(int) * 1);
printf("size of pointer: %d\n", sizeof(a)); //4
printf("size of pointer: %d\n", sizeof(b)); //8 (64bits机器)
总结
指针就是数据类型,不要给他吓到;定义变量的时候, int *
= int-pointer
,可能会理解更加容易。
变量,就是定义某种数据类型;所以 变量 的通用规则,也同样应用到指针上。
创建变量
printf("a address: %lx\t value:%d \n", &a, a);
//a address: 7fffffffdf5b value:123
printf("b address: %lx\t value:%lx pointed-value:%d \n", &b, b, *b);
//b address: 7fffffffdf58 value:602010 pointed-value:11
&a
&b
都是指向了 stack
中的地址,地址中的内存 保存着 value
。
int a = 123
,定义在7f ff ff ff df 5b
地址上,分配了4Bytes内存,保存的是 int类型,value 是 123。int * b = (int *)malloc(sizeof(int) * 1);
,定义在7f ff ff ff df 58
地址上,分配了8Bytes内存,保存的是 int pointer类型,value 是 602010。
602010
是指向heap
中的地址,同时地址后续的4Bytes
内存,保存的是 11。
总结
- 创建变量 = stack内存区 指定一段地址 + 分配指向内存
- 基础变量,直接在内存中赋值
- 指针,里面保存的是内存地址
- 创建变量,转换成机器语言,就是
address
,memory space
和set value into memory space
,机器是 **不管 **你什么a,b,c
的
使用变量在入参中
void output(int a , int * b ) {
printf("value:%d \n", a); //value:123
printf("value:%lx \n", b); //value:602010
}
上图中,在 output栈帧中,开辟内存,复制 **a**
和 **b**
的内存值。方法体内的 a
b
地址,就是 output栈帧中的地址。
总结
- 变量入参,在子栈帧内存中新开地址,使用 原变量内存value来赋值到新开地址对应的内存中
- value 在 父栈帧 和 子栈帧 都有一份的,值是一样的;且你改 子栈帧,是不会影响到 父栈帧的值
- 如果去修改
*value
,那么有机会改动到 同值value指向内存
指针类型
_printf("b address: %lx\t value:%d pointed-value:%d \n", &b, b, *b);_
&b
就是变量b 的地址,就是 stack 地址,我们非常少使用到这个值,因为stack
会弹出frame
的,所以保存都是临时保存b
就是 变量b地址 指向的内存值,variable value
,这个在 入参 中也有体现*b
就是变量b's value
作为地址 指向的内存值
总结:
- 指针类型,与普通变量一样,内存里面的值是一段内存地址
总结
- 指针类型变量,不需要畏惧,就是一种数据类型变量,同样是分配地址和内存
- 在理解栈帧、堆、栈 上去理解指针会更加通彻
- C语言,就是操纵内存的语言