2008年(126)
分类: C/C++
2008-05-02 09:35:36
/*提示:本文内容未全部经过程序测试和经典书籍论证,作者不保证所有内容均完全正确,请正确参考,Copyright @ Shine*/
第6章 指针
终于进入这本书的精华部分了….
指针是c中一种数据类型,它的内容是一个地址,或者是可以看成是一个书的目录,通过它就可以索引到你感兴趣的区域。
对于32位的机器来说,它的寻址范围就是0x00000000~0xffffffff,指针占用的内存空间为4个字节。如果将来晋升为64位的时候,指针恐怕也要增加为8个字节了,下面问题又来了,知道指针指向的内存首地址了(对于big endian和small endian应该会有区别),如何知道变量占用的空间延续的长度,这个就要靠指针的类型来实现了。
比如:char * pStr;
通过它只能访问一个字节偏移(offset)的内存空间。
int * pValue;//它就可以访问4个字节偏移内的数据。所以对指针进行强制类型转换的时候就可以看作是扩大或缩小指针能够获取数据的偏移量。
0x
0x21 0xf3 0x78 0xa3 0x89 0x03
更形象的例子:如果对于上面的pStr和pValue都赋值为0x000021f5,利用pStr可以访问0x000021f5地址,而利用pValue可以访问0x000021f5~0x000021f8这段内存中的数据。
由 于指针的内容为内存地址,也是一个数值,如果要使用指针访问变量必须保证这个地址的有效性。指针变量内部存放的是一个数值,它当然也可以进行各种运算(参 见书)。对应的很多概念也就很容易理解了。在具有操作系统的计算机上,内存的分配和释放是要靠操作系统来管理的。对于一个未初始化的指针,它的数值也许是 个垃圾值,如果不保证有效性就直接去操作,这和你随便写了一个地址然后过去抢劫没有任何的区别!
定义了一个NULL,通常情况下 #define NULL 0
这样NULL就被作为一个特殊标记(因为0x00000000地址是特殊用途的,它具有可以被作为特殊标记的合理性)。如果一个指针变量被赋值为NULL,就认为它是空的,没有指向任何地址。这样我们也就可以利用NULL的返回值来表示分配内存失败、获取指针失败等异常;检查指针有效性等。
一个良好的编程风格就是,定义了一个指针就赋值为NULL,在释放指针指向的内存空间后,把指针也赋值为NULL,以防止“野指针出现”。例如:
int *p = NULL;
p = (int *) malloc(sizeof(int));//假定分配的是0x
*p = 34;
free(p);//注意free只会释放内存,而p仍然指向0x
*p = 39;//绝对禁止!!!这就是野指针
随着p指向内存的释放,p也应该被重新初始化为NULL。
p = NULL;
举个通俗的例子来讲,指针就好像钥匙,你去住店,(操作系统)分配给你了一个房间,第二天退房了,没有交还钥匙,隔天你拿着钥匙又去住这个房间或者是往里面放东西,这也是一种入室抢劫行为。野指针,所谓野就会指针的值不合法,不是有效的。
由于指针内存放的是内存地址,所以在使用的时候就要保证你指向的内存地址是有效的,至少在操作的阶段,被你当作容器,仓库的阶段是属于你的。这就是指针使用中最容易出现的问题。
暂时一个小节,来看一个程序例子,虽然这种使用方法非常的不规范,就好像人们说的“合法却不合理”,它的使用违背了c语言的道德规范。
#include
#include
using namespace std;
int main(int argc, char *argv[])//编译器的问题,必须进行强制类型变换
{
unsigned int adr;//我们用一个整型变量来存放内存地址,来模拟指针
char str = 'a';
float pi = 3.14;
adr = (unsigned int)&str;//首先用这个整型存放str字符的地址
printf("The value of %d address is %c.\n",adr,*((char *)adr)); //利用这个地址可以得到str的值。
adr = (unsigned int)π
printf("The value of %d address is %f.\n",adr,*((float *)adr));//同样可以获得pi浮点数值
system("PAUSE");
return EXIT_SUCCESS;
}
再来看一下关于野指针的问题:
#include
#include
using namespace std;
int main(int argc, char *argv[])
{
int *adr;
adr = (int *) malloc(sizeof(int));
*adr = 23;
printf("The value of %d address is %d.\n",adr,*adr);
free(adr);
printf("After release memory,the address value is retained.\n");
printf("if you do not believe that,see the value of adr = %d.\n",adr);
// *adr = (34 +65);//invalude usage!!!野指针,空间被释放而指针指向的地址没有被清零
adr = NULL;
system("PAUSE");
return EXIT_SUCCESS;
}