C和指针——指针

内存和地址:计算机的内存由数以万计的位(bit)组成,每个可以容纳值0或1。由于一个位所能表示的值的范围太有限,所以单独的位用处不大,通常许多位合成一组作为一个单位,这样就可以存储范围较大的值。如下所示:

one

这些位置的每一个都被称为字节(byte),每个字节都包含了存储一个字符所需要的位数。在许多现代的机器上,每个字节包含8位,可以存储无符号值0到255,或有符号值-128到127。每个字节通过地址来标识,如上图方框上面的数字所示。

为了存储更大的值,可以把两个或多个字节组合在一起作为一个更大的内存单位字。如下图表示的内存位置与上图相同,但它是以4个字节的字来表示。

two

由于包含了更多的位,每个字可以容纳的无符号整数的范围是0到4294967295(img),可以容纳的有符号整数的范围是从-2147483648(img)至2147483648(img)。注意,尽管一个字包含了4个字节,它仍然只有一个地址。至于它的地址是它最左边的那个字节的位置还是最右边那个字节的位置,不同的机器有不同的规定。另一个要注意的硬件事项是边界对齐。在要求边界对齐的机器上,整型值存储的起始位置只能是某些特定的字节,通常是2或4的倍数。

内存中的每个位置由一个独一无二的地址标识。

内存中的每个位置都包含一个值。

名字和内存位置之间的关联不是硬件所提供的,它是由编译器实现的。变量给了一种更为方便的方法来记住地址——硬件仍然通过地址访问内存位置。

不能简单地通过检查一个值的位来判断它的类型。为了判断值的类型(以及它的值),必须观察程序中这个值的使用方式。显然,值的类型并非值本身所固有的一种特性,而实取决于它的使用方式。

指针变量的内容:指针的初始化是用&操作符完成的,它用于产生操作数的内存地址。

间接访问操作符:通过一个指针访问它所指向的地址的过程称为间接访问或解引用指针。这个用于执行间接访问的操作符是单目操作符。

NULL指针:标识定义了NULL指针,它作为一个特殊的指针变量,表示不指向任何东西。要使一个指针变量为NULL,可以给它赋一个零值。NULL指针的概念是非常有用的,因为它提供一种方法,表示某个特定的指针目前并未指向任何东西。同时因为NULL指针未指向任何东西,因此对一个NULL指针进行解引用操作是非法的。在对指针进行解引用操作之前,必须确定该指针并非NULL指针。

指针运算:指针加上一个整数的结果是另一个指针。当一个指针和一个整数指向算术运算时,整数在执行加法运算前始终会根据合适的大小进行调整。这个“合适的大小”就是指针所指向类型的大小,“调整”就是把整数值和“合适的大小”相乘。

C的指针算术运算只限于把两种形式:加减。标准定义这种形式只能用于指向数组中某个元素的指针。

指针 - 指针:只有当两个指针都指向同一个数组中的元素时,才允许一个指针减去另一个指针。两个指针相减的结果类型是pridiff_t,它是一个有符号整数类型。减法运算的值是两个指针在内存中的距离(以数组元素的长度为单位,而不是以字节为单位),因为减法运算的结果将除以数组元素类型的长度。

关系运算:对指针指向关系运算也是有限制的。用以下关系操作符对两个指针进行比较是可能的:< <= > >= 。前提是它们都指向同一个数组中的元素。

注:标准允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针进行比较,但不允许与指向数组第1个元素之前的那个内存位置的指针进行比较。同时,如果一个指针减去一个整数后,运算结果产生的指针所指向的位置在数组第一个元素之前,那么它是非法的。加法运算稍有不同,如果结果指针指向数组最后一个元素后面的那个内存位置仍是合法的(但不能对这个指针指向间接访问操作),不过再往后就不合法了。