这段时间一直在看C语言方面的内容,为的是巩固一下基础知识,把握一些细节上的东西。
指针一直是C语言中的难点,也是重点。每年的面试题,在这上面来下功夫为难我们的也不算少数。所以自己把这部分又复习了一遍,现在把一些重点的东西写下来。
指针的概念
指针是一个特殊的变量,它里面存储的数值被解释成内存里的一个地址,要搞清楚一个指针需要搞清指针的四方面的内容:(1)、指针的类型。(2)、指针所指向的类型。(3)、指针的值或者叫指针所指向的内存区。(4)指针本身所占据的内存区。
现在我们用例子分别说明。
(1) int *ptr;
(2) char *ptr;
(3) int **ptr;
(4) int (*ptr)[3];
(5) int *(*ptr)[4];
1、指针的类型
从语法的角度看,只要我们把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。这事指针本身所具有的类型。例如:
(1) int *ptr;//指针的类型是 int*
(2) char *ptr; //指针的类型是 char *
(3) int **ptr; //指针的类型是 int **
(4) int (*ptr)[3]; //指针的类型是 int (*)[3]
(5) int *(*ptr)[4]; //指针的类型是 int *(*)[4]
2、指针所指向的类型
当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译器将把那片内存区里的内容当作什么来看待。
从语法上来看,我们只须把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。例如:
(1) int *ptr;//指针所指向的类型是 int
(2) char *ptr; //指针所指向的类型是 char
(3) int **ptr; //指针所指向的类型是 int *
(4) int (*ptr)[3]; //指针所指向的类型是 int ()[3]
(5) int *(*ptr)[4]; //指针所指向的类型是 int *()[4]
在指针的算术运算中,指针所指向的类型有很大的作用。
3、指针的值——或者叫指针所指向的内存区或地址
指针的值是指针本身存储的数值,这个值将被编译器当作是一个地址,而不是一个一般的数值。在32位程序里,所有类型的指针的值都是一个32位整数,因为32位程序里内存地址全都是32位长。指针所指向的内存区就是从指针的值所代表的那个内存地址开始,长度为sizeof(指针所指向的类型)的一片内存区。以后,我们说一个指针的值是XX,就相当于说该指针指向了以XX为首地址的一片内存区域;我们说一个指针指向了某块内存区域,就相当于说该指针的值是这块内存区域的首地址。
指针所指向的内存区和指针所指向的类型是两个完全不同的概念。在上面所举的例子中,指针所指向的类型已经有了,但由于指针还未初始化,所以它所指向的内存区是不存在的,或者说是无意义的。
4、指针本身所占据的内存区
指针本身占了多大的内存,只要用函数sizeof(指针的类型)测一下就知道了。在32位平台里,指针本身占据了4个字节的长度。
指针本身占据的内存这个概念在判断一个指针表达式是否是左值时很有用。
指针的算术运算
指针可以加上或减去一个整数。指针的这种运算的意义和通常的数值加减运算意义是不一样的,以单元为单位。
一个指针ptrold加(减)一个整数后n后,结果是一个新的指针ptrnew,ptrold的类型和ptrnew的类型相同,ptrnew所指向的类型和ptrold所指向的类型也相同。ptrnew的值将比ptrold的值增加(减少)了n乘sizeof(ptrold所指向的类型)个字节。就是说,ptrnew所指向内存区将比ptrold所指向的内存区高(低)地址方向移动了n乘sizeof(ptrold所指向的类型)个字节。
两个指针不能进行加法运算,这事非法操作,因为进行加法后,得到的结果指向一个不知所向的地方,而且毫无意义。两个指针可以进行减法操作,但必须类型相同,一般用在数组方面。
有效的指针运算包括:(1)、相同类型指针之间的赋值运算。(2)、指针同整数之间的加法或减法运算。(3)、指向相同数组中元素的两个指针间的减法或比较运算。(4)将指针赋值为0或指针与0之间的比较运算。
指针和数组
数组名和指针之间有一个不同之处。指针是一个变量,因此,在C语言中,语句pa = a和pa++都是合法的。但数组名不是变量,因此,类似于a = pa和a++形式的语句都是非法的。
声明了一个数组的数组TYPE array[n],则数组名称array就有两重含义:第一,它代表整个数组,它的类型是TYPE[n];第二,它是一个常量指针,该指针的类型是TYPE*,该指针指向的类型是TYPE,也就是数组的单元的类型,该指针指向的内存区就是数组第0号单元,该指针自己占有单独的内存区,注意它和数组第0号单元占据的内存区是不同的。该指针的值是不能修改的,即类似array++的表达式是错误的。
在不同的表达式中数组名array可以扮演不同的的角色。(1)、在表达式sizeof(array)中,数组名array代表数组本身,故这时sizeof函数测出的是整个数组的大小。(2)、在表达式*array中,array扮演的是指针,因此这个表达式的结果就是数组第0号单元的值。sizeof(*araay)测出的是数组单元的大小。(3)、表达式array+n中,array扮演的是指针,故array+n的结果是一个指针,它的类型是TYPE*,它指向的类型是TYPE,它指向数组第n号单元。sizeof(array+n)测出的是指针类型的大小。在32位程序中结果是4.