指针
指针作为C语言的精华,也是入门的难点。是很多初学者很惧怕的东西,我也是敲了2年代码才比原来理解得更好一些,不敢说运用得出神入化,但也还算凑合。下面谈谈自己的理解。
指针是什么?
不同的书,不同的人都有不同的理解形式,有的人把他作为一种很特别的类型,有的人把他作为一种概念上抽象的东西。我当然也有自己的理解:
指针 = 一种用于存放地址的变量类型
它本身也要占据内存,一般在32位机型上占4个字节,也就是一个int的大小。要注意一点,无论是什么样类型的指针,占的大小都是一样的。(本文假设环境就是32位,后面不再赘述)
比如:
int *p;
void **p;
struct Node *p;
double*****************p;(夸张一点,我没见过这么惨绝人寰的使用)
当你敲下上面的任意一句,运行的到这里的时候,就会分配一个4字节的内存,里面存了一个地址—一个数值。
如下的代码,在运行时内存是什么样子的?
是这样的:
(这里的内存地址我随便写的)
此处注意,p本身也是占据内存的,p的内存里放了a的地址,以便可以通过p来操作a。
那有人会问了,我为什么不直接操作a?非要弄一个指针来指向它之后再操作它呢?对此我的理解是: 编译器是不会关心你指针与否来操作一块内存,它只知道把你的代码翻译成机器代码(error,warning什么的还是人为的东西,是用来辅助程序员的,编译器也是人写的也是程序啊亲)。其实你敲的这些代码,只是对自己的一种助记符,永远记住:代码是写给人看的不是写给机器看的,一个好的程序员,应该认真对待自己的代码,不要仅仅“能实现”就觉得完事了。C因高效著称很大原因也是因为指针的小巧。
讲到这里,不得不说下左值和右值。
这个简单理解起来就是:左值代表内存单元,右值代表内存单元里的值。
p本身占据一块内存,刚才我们写的里面值存放的是: 0x101010 ,如果你接下来给它赋值:
我们分别画出图来:
(p = NULL)
(p = 0x12345)
(int b = 99; p = &b )
上面的图,注意箭头我没有指到里面,内存中实际上也不可能有箭头这样的东西,这样画是为了方便理解。这里p作为左值,它里面原先的内容由“0x101010”一直变到了”0x025564”,里面的内容只要是个整型值随便什么都可以的(但是要有意义)。
这里明白了p本身占内存,里面存的不过是个整型值之后,我们来看看它的右值,这里就举一个例子,很清楚明白:
这里p作为右值,把它的内容”0x101010”写到了刚分配的指针变量 p2的内存里面,如图:
左值右值明白了之后,我们来看看解引用,也就是”*p” 这种表达式。
“*p”可以理解为,跳转到p所存地址的内存,也就是拿到这块内存的控制权。这里很显然”*p”代表了a这个变量,如果我写:
那内存里就变成了这个样子:
作为右值赋值给其他变量,写如下代码:
那内存就成了这个样子:
小结:
这次介绍了指针的基本概念,以及指针作为左值右值的时的含义及用法。我们通过以上可以发现:无论你声明的是普通变量(inta ,struct Node….),还是指针变量(int*a, Node *p….),本身都是存在于内存里的,本质上还是通过地址来进行操作(即便你写的是 int a ,在编译器眼里不过也是一个地址,然后这个地址按照一个整形来解释),而指针(无论几级指针)作为存放地址的变量,有着灵活的特点(指针可以很方便地表达很多数据结构如:链表,树,图….),每当你写下一句代码时,你脑袋里面要有它们在内存里大概分配情况的样子,作为一个C\C++程序员,对内存还是要敏感。
有点晚了明天还上班,其他零散的知识,以及指针和数组、指针作为函数参数就放到后面讲吧。