C语言的灵魂就是指针;没有理解指针,就没有学好C语言
一、内存和地址
提到c语言,从第一版标准语法出世至今,该语言成为计算机学界多年屹立不倒不倒的旗帜,秘诀就在指针。
而提到指针就不得不讲内存和地址。
基本概念
1.内存(Memory),其作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。只要计算机在运行中,CPU就会把需要运算的数据调到内存中进行运算,当运算完成后CPU再将结果传送出来,内存的运行也决定了计算机的稳定运行。
2.内存地址,在电脑运算中,地址是一种用于软件及硬件等不同层级中的数据概念,用来访问电脑主存中的数据。
地址与内存的关系
形象一点,我们可以把计算机中的内存看作银行里用于存储业主金条的保险箱。每个保险箱有一定的容量,可以存储你能想象到的各种奇珍异宝,为了不使拿钥匙的管理员混淆甲老板存宝石的箱子和乙老板存大金条的箱子,每一个箱子都有一个固定的编码。计算机的内存由数以万计的位(bit)组成,每个位可以容纳0或1。由于一个位所能表示值的范围太有限,所以我们通常规定8个位为一个字节(byte),一个字节的容量就是我们虚拟银行保险箱的**单位大小。为了装下一整幅字画,我们把两个或者更多个单位和在一起作为一个更大的保险箱,机器以字为单位存储整数,每个字一般由两个或四个字节组成。
1.内存中的每个位置都有一个独一无二的地址标识。
2.内存中的每个位置都包含一个值。
注意事项:
- 一个字包含4个(或2)字节,但它仍然只有一个地址,至于左对齐还是右对齐和编译器的规定有关,不唯一。
- 边界对齐(boundary alignment),此为硬件事项,很少能影响c语言程序员,所以重点在?1和2两条。
二、值和类型
考虑下面这个以二进制形式表示的32位数:
01100111011011000110111101100010
下面这是位可以被解释的许多结果中的几种。这些值都是基于Motorola 68000的处理器上得到的,若系统不一样,得到的解释又不一样。(下表为markdown语法写的表,为什么知乎不提供markdown编辑qaq,生气一分钟)
类型 | 值
----|----
1个32位整数|1735159650
2个16位整数|26476和28514
4个字符|glob
浮点数|1.116533*10^24^
所以我们不能简单地通过检查一个值的位来判断它的类型。
指针变量的内容
让我们来看下面这段c语言代码:(编辑器代码块好评?)
int a=112, b=1;
float c=3.14;
int *d=&a;
float *e=&c;
假设d的地址为112和它的内容为100(区分指针变量的地址和内容是非常重要的),现在我们可以给出下表。
表达式|右值|类型
------|-----|-----
a|112|int
b|-1|int
c|3.14|float
d|100|int*
e|108|float*
*d|112|int
*e|3.14|float
由上表我们能得出分别命名为a、b、c、d、e的房间之间的次序关系,而d中存储的是a房间的另一把钥匙,所以*d即d+?,就可以得到a中的宝物了,即引用*d等同于直接引用a,此操作即为指针的间接访问(indirdction)操作
三、未初始化和非法的指针
int *num;
...
*num=12;
这个声明创建了一个叫num的指针变量,后面那条赋值语句将12存储在了num所指向的内存位置。但num指向哪里呢?我们声明了这个变量,但未对它进行初始化,所以没有办法预料12究竟存在了哪里,是不是改变了我们原先声明的变量值。
如果num的初始值是个非法地址,语句将会出错,程序也将终止[^2]。但若包含合法地址,接下来就是一个非常难以捕捉的bug。所以在对指针间接访问之前,一定要确保其已被初始化。
- 双重间访
顾名思义就是指针的指针。
以上~看到这里,道友一定手痒了吧,不妨来几道指针常用实例练练手。明天见~
[^1]:也被称为内存储器和主存储器.是由内存芯片、电路板、金手指等部分组成
[^2]:段违例(segmentation violation),或者内存错误(memory fault),也一般是保护性异常(general protection exception)的根源之一。