什么是指针?先看看什么是内存地址
首先,我们要搞清楚数据结构在计算机里面到底怎么存取?怎么描述它们 。
任何数据结构(struct)以及组成数据结构的基本数据类型,一旦分配了内存空间,那么就会有两个部分来描述这块内存:内存的地址(红色部分,不占用实际空间,相当于门牌号,用于寻址)与内存的值(绿色部分,是实际的信息存储部分,占用内存空间,以byte为单位) 。就像下面这张图:
文章插图
数据在内存中的结构
所以一块内存,或者一个符号(编程语言的符号其实就代表了一块内存,所以它们代表同一个意思)有两个重要的属性:
- 内存或者符号的地址
- 内存或者符号的值
这两个属性如同一个事物的两面,不可分割,形影不离 。
有时候,如果对事情的本质进行深挖的话,你可能对一些基本概念有更深刻的理解 。比如,到这里,如果你理解了内存或者编程语言的符号有两个基本的属性:地址与值,那么你就可以理解C/C++中的&与=操作符的含义 。
- &作用在一个符号上的底层含义就是——获取这个符号的两个重要属性之一——符号的地址
- =作用在一个符号上的底层含义就是——获取这个符号的两个重要属性之一——符号的内存值 。int a=1;含义就是获取符号a的内存值,并将内存值赋值成1 。
可以推断出,从CPU的角度,或者编程语言底层来看,没有数据类型的概念,任何数据都是一块块连续的、长短不一的内存存储单元而已,就像上图所画 。那么问题就变成了,怎么描述这块内存呢?
答案是:内存的起始地址+长度 。比如下面这个结构:
struct Test {int a;short b;
对于test这个结构,怎么描述它?
答案是:struct test是——符号a的内存地址+6个字节长度的数据块,如果要读取或者写入test某个部分(a或者b),编译器至少要编译两条指令:1、获取test也就是a符号的地址,2、根据类型定位偏移量就行了 。这就是数据结构的本质了 。
那么对数据结构成员变量的访问就很容易理解了:
- test.a就可以被编译成符号a的地址+向高地址取4个字节的内存块 。
- test.b就可以看成符号a的地址向高地址偏移4个字节+向高地址取2个字节的内存块 。
是不是有点类似数学中的极坐标系的概念 。而实际上系统确实是这么做的 。
站在编译器的角度看看符号与变量
指针在C与C++中很难理解,但是又是重要的构成部分,没有了指针其实就发挥不出语言的光芒了 。因为指针是很自然的事物,它是承接CPU取址与程序可读性的关键概念,理解了它就既能看穿机器的运行,又能写出合理的优雅的代码去描述业务 。
要真正理解指针或者更普遍的意义来说,理解符号,就得将自己想象成编译器去读代码,这样一切都会变得理所当然的容易起来 。
我们看到的程序都是由变量符号组成的,本质上符号代表一块内存,比如上面的结构体就有三个变量符号或者简称符号:test,a,b 。每个符号其实都对应一块型如下图的内存块:
文章插图
内存块的两个维度
再来看看这个代码片段
typedef struct test {int a;short b;} Test;Test t;t.a =1;t.b =2;Test* t_ptr = &t;t_ptr->a = 3;
- Test t:如果“我”是编译器,看到这行代码,我获得的信息是:t是一个符号,它有两个维度的信息:1、地址是&t;2、长度是sizeof(Test) = 6(不考虑对齐) 。而且我会自动补全表达式为Test t = 0初始化t代表的这块内存 。生成的底层代码应该做这些:1、给符号t分配一个内存地址,地址一共6个byte长度;2、将这6个byte的地址的值都填充为0 。
- t.a = 1:语义是给符号a的值,赋值1 。符号a的地址就是t的地址,符号a的长度4个字节,=的含义就是获取a的内存值,最后将int 1填充到这4个字节的内存中,完成赋值 。
- 潮汕美食:探索舌尖上的美味与文化
- 生姜薏米水功效与作用
- 生姜紫苏水功效与作用
- 白酒泡樱桃功效与作用
- 于和伟|于和伟乱睡门后露面,与风波女主眼神躲闪刻意避嫌王丽坤再受累
- |解读电视剧《爱情而已》探寻当代人情感、职场与家庭之路
- 面膜泥的功效与作用,面膜泥的正确使用方法 面膜泥多久后洗掉?
- 附桂骨痛颗粒的功效与作用
- 百合莲子绿豆汤的功效与作用
- 红糖与赤砂糖有什么区别