1.内存和地址
计算机的内存由数以亿计的位(bit)组成,每个位可以容纳值0或1。每个字节(byte)包含8个位,为了存储更大的值,把两个或更多个字节合在一起作为一个更大的内存单位。许多机器以字为单位存储整数,每个字一般由2个或4个字节组成。注意,尽管一个字包含了4个字节,它仍然只有一个地址,至少它的地址是它最左边那个字节的位置还是最右边那个字节的位置,不同的机器有不同的规定。另一个需要注意的硬件事项是边界对齐。对于C程序员,只需对:1)内存中的每个位置由一个独一无二的地址标识;2)内存中的每个位置都包含一个值。变量与内存位置之间的关联并不是硬件所提供的,它是由编译器为我们实现的,所有的这些变量给了我们一种更方便的方法记住地址——硬件仍然通过地址访问内存位置。
2.值和类型
不能简单地通过检查一个值的为来判断它的类型。显然值的类型并非值的本身所固有的一种特性,而是取决于它的使用方式。
3.指针变量的内容
指针的初始化是用&操作符完成的,它用于产生操作数的内存地址。一个 变量的值就是分配给这个变量的内存位置所存储的数值。
4.间接访问操作符
通过一个指针访问它所指向的地址的过程称为间接访问或解引用指针。
5.未初始化和非法的指针
int *a;
...
*a=12;
我们声明了这个变量,但未对它进行初始化,所以我们没办法预测12这个值将存储于什么地方。
6.NULL指针
标准定义了NULL指针,它作为一个特殊的指针变量,表示不指向任何东西。NULL指针的概念是非常有用的,因为它给了你一种方法,表示某个特点的指针目前并未指向任何东西。对指针进行解引用操作可以获得它所指向的值。
7.指针、间接访问和左值
指针变量可以作为左值,镔不是因为它们是指针,而是因为它们是变量。对指针变量进行间接访问表示我们应该访问指针所指向的位置。间接访问指定了一个特点的内存位置,这样我们可以把间接访问表达式的结果作为左值使用。
8.指针、间接访问和变量
*&a=25;
首先,&操作符产生变量a的地址,它是一个指针变量;接着,*操作符访问其操作数所表示的地址,在这个表达式中,操作数是a的地址,所有值25就存储于a中。
9.指针常量
指针常量:假定变量a存储于位置100,*(int *)100=25;这种强制类型转换技巧的机会是绝无仅有的,唯一的用处是你偶尔需要通过地址访问内存中某个特点的位置,它并不是用于访问某个变量而是访问硬件本身。
10.指针的指针
int a=12;
int *b=&a;
int **c=&b;
11.指针表达式
char ch='a';
char *cp=&ch;
*cp+1;//访问紧随ch之后的内存位置,但标定式左值是非法的
*(cp+1);//访问ch后面的那个内存位置
++cp;//先增加操作数的值再返回这个结果,这份拷贝的存储位置并未清晰定义,所以他不是一个合法左值
cp++;//先拷贝在增加,左值依旧不合法
*++cp;//间接访问操作符作用于增值后的指针的拷贝上,所以它的右值是ch后面那个内存地址的值
*cp++;//它的右值和左值分别是变量ch的值和ch的内存位置
++*cp;//先执行的是间接访问操作,然后cp所指向的位置的值增加1,表达式结果是增值后的值一份拷贝,左值非法
(*cp)++;//先执行间接访问,左值非法
++*++cp;//左值非法
++*cp++;//左值非法
12.指针运算
1)算法运算:指针±整数;
2)关系运算:<,<=,>,>=;
13.总结
计算机的内存中的每个位置都由一个地址标识。指针就是它的值表示内存地址的变量。无论是程序员还是计算机都无法通过值的位模式来判断它的类型,类型是通过值的使用方法隐式地确认的。指针变量的值并非它所指向的内存位置所存储的值,必须使用间接访问了获得它所指向位置存储的值。
声明一个指针变量并不会自动分配任何内存,在对指针执行间接访问前,指针必须进行初始化:或者使它指向现有的内存,或者给它分配动态内存。NULL指针就是不指向任何东西的指针。指针运算只有作用于数组中其结果才是可以预测的。对任何并非指向数组元素的指针执行算术运算是非法的。如果两个指针都指向同一个数组中的元素,那么它们之间可以相减。任何指针之间都可以进行比较,测试它们相等或不相等。
14.警告的总结
1)错误地对一个未初始化的指针变量进行解引用。
2)错误地对一个NULL指针进行解引用;
3)向函数错误地传递NULL指针;
4)未检测到指针表达式的错误,从而导致不可预料的结果;
5)对一个指针进行减法运算,使它非法地指向了数组第1个元素的前面的内存位置;
15.编程提示的总结
1)一个值应该只具有一种意思;
2)如果指针并不指向任何有意义的东西,就把它设置为NULL;