读K&R之指针、数组名和数组指针
直到不久前,我都不曾认真地了解过C。大学课堂上学习过C++,在那段不长的时间里,学到的东西一直支撑着我对C的认知。等工作五年后,我重新学习C时,发现自己好生浅薄。就在自己还在读《The C Programming Language》的第二章时,网络上传来了Dennis M. Ritchie过世的消息。大师已逝,他所留下的知识将会继续惠泽着后人。我把阅读《The C Programming Language》所作的笔记整理出来,希望更多的人能够学习到Dennis M. Ritchie所建立的知识,这也算是对大师的一种纪念。
关于指针
指针是一种保存变量地址的变量,是能够存放一个地址的一组存储单元。
地址运算符&只能应用于内存中的对象,即变量与数组元素,不能作用于表达式、常量或register类型的变量。一元运算符*是间接寻址或间接引用运算符,当它作用于指针时,将访问指针所指向的对象。
指针只能指向某种特定类型的对象,也就是说,每个指针都必须指向某种特定的数据类型。一个例外情况是指向void类型的指针,可以存放指向任何类型的指针,但它不能间接引用其自身。ANSI C使用类型void*代替char *作为通用指针的类型。
在计算p+n时,n将根据p指向的对象的长度按比例缩放,而p指向的对象的长度则取决与p的声明。
有效的指针运算包括相同类型指针之间的赋值运算;指针同整数之间的加法或减法运算;指向相同数组中元素的两个指针间的减法或比较运算;将指针赋值为0或指针与0之间的比较运算。
通常,对指针有意义的初始化值只能是0或者是表示地址的表达式。C语言保证,0永远不是有效的数据地址。
关于数组名
数组名所代表的就是该数组最开始的一个元素的地址。其和指针是不同的,区别在于指针是一个变量,但数组名不是变量。
当把数组名传递给一个函数时,实际上传递的是该数组第一个元素的地址。在被调用函数中,该参数是一个局部变量,因此,数组名参数必须是一个指针,也就是一个存储地址值的变量。
如果p是一个指向数组中某个元素的指针,那么p+=i将对p进行加i的增量运算,使其指向指针p当前所指向的元素之后的第i个元素。对数组元素a[i]的引用也可以写成*(a+i)这种形式。
关于数组指针
K&R在第五章中并没有提到数组指针,这里说的数组指针是指向数组的指针的意思,其和指针数组在定义形式上有细微的区别:
int *pa[13]; /* pa: array[13] of pointer to int */ int (*p)[13]; /* p: pointer to array[13] of int */ |
这里,前者是一个数组,后者是一个指针。看下面一道朋友发来的一道练习题,原始出处见The Ksplice Pointer Challenge。
#include <stdio.h> int main() { int x[5]; printf("%pn", x); printf("%pn", x+1); printf("%pn", &x); printf("%pn", &x+1); return 0; } |
这是题目假定x的内存地址是0x7fffdfbf7f00(64位平台),不上机运行代码,看能做对几个。
第一个问题显然是考察数组名即数组第一个元素的地址这么个知识点,第二个问题则是考察数组地址运算,其中的1代表了一个数组元素长度,即sizeof(int)。
第三个问题我就迷糊了,如果x是一个指针,那么&x取得的值和x的值相同,即&x==x成立,那么x所指向值又是什么?此时,我的糊涂就在于把数组名和指针等同了起来。&是地址运算符,&x就是取得x的地址,明白这一点,那么答案就清楚了。
第四个问题我更加迷糊,&x+1代表什么意思呢?现在,x是数组,&x则是一个指向长度为5的整数数组的指针。那么&x+1,也就是再加上长度为5的整数数组的长度。
精彩。