下面摘自百度百科:
大家都认为,c语言之所以强大,以及其自由性,很大部分体现在其灵活的指针运用上。因此,说指针是c语言的灵魂,一点都不为过。同时,这种说法也让很多人产生误解,似乎只有C语言的指针才能算指针。basic不支持指针,在此不论。其实,pascal语言本身也是支持指针的。从最初的pascal发展至今的objectpascal,可以说在指针运用上,丝毫不会逊色于c语言的指针。
首先我们来看看NULL的定义:
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
NULL在C++中的定义就是0,在C中的定义是(void *)0,本质上还是0;指针的值说白了就是一个数字,这个数字存在一个变量中,这个变量就称为指针。
那么说随便一个数字都行吗?肯定不是。这个数字是用来表示内存单元的,因此它必须是合法的内存地址,不管在什么系统上它的值在ULONG(unsigned long)范围内,ULONG在32位系统上是0-0xFFFFFFFF,在64位系统上就是0-0xFFFFFFFFFFFFFFFF;也就是说ULONG根据运行环境改变。
以32位操作系统为例,在操作系统加载的时候要接管内存,那么它怎么管理呢?就是给每个内存单元编号,这个编号是一个ULONG类型的整数,所以它只能从0编号到0xFFFFFFFF,在普通PC上最小寻址单元是Byte(字节),也就是最多可以编号0x100000000个字节=4GB,这也就是为什么大于4G内存的电脑都需要安装64位操作系统的原因,32位操作系统最高支持4G内存,超出部分无法编号,操作系统也就不能管理,因此不能被使用。
注:以下以为32位系统
C语言中指针就是一个编号,不管什么类型的指针都是以个ULONG类型的整数。那么你不禁要问,为什么我们在定义指针的时候还要指定类型?
举个例子:
void IncreaseInt(int *pi)
{
(*pi) += 256;
}
void IncreaseChar(char *pc)
{
(*pc)++;
}
int main()
{
int a = 0;
char b = 'A';
IncreaseInt(&a);
printf("%d\n", a);
IncreaseChar(&b);
printf("%c\n", b);
getchar();
return 0;
}
在函数IncreasInt中我们使用了“*”运算符,*运算符就是我们从内存的位置取出值。假设变量a的地址是0x1000,传到函数IncreasInt中pi的值就是0x1000,我们使用“*”就可以从内存的0x1000处取往后4个字节,加上256后放进0x1000-0x1003里; 在函数IncreasChar中我们也使用了“*”运算符,假设b的地址是0xffc,传到函数IncreasChar中pc的值就是0xffc,我们使用“*”就可以从内存的0xffc处取1个字节,自增之后放进0xffc里。
那么编译器怎么知道“*”要取几个字节,这就是指针类型的作用了,指针类型就是告诉编译器这个指针指向的目标占用的内存是多大,使用*和[]的时候才知道要取几个字节。
————————————————————————————割了————————————————————————————
最近项目太忙,把这个给忘了,七夕闲着没事,给补上。
不管数据在硬盘还是内存中,数据的都是以二进制的方式存在的,比如有一块存储空间的数据是:00010100000100000000000000000000,在工具中为了方便一般使用16进制:41 01 00 00;X86的计算机都是按照小端存储的(什么是小端存储自行百度),这个数据如果使用int类型就是0x141即321,如果使用char是0x41,只取出来第一个字节,不管什么类型来表示数据都是不变的,其实本质上他们是同一块数据。指针表示的就是某块内存的地址。也就是说如果上述存储空间是内存,地址是0x1000,那么如果是int* p = 0x1000,那么*p的值就是0x141,如果是char* p = 0x1000, *p的值就是0x41。
从上面的讲述中大家应该可以明白,内存中存储数据跟类型无关,它不考虑你是什么类型,只有程序才去考虑类型;因为同样一块数据使用不同类型取出的值一样,比如0xffffffff,使用unsigned int 取值是4294967295,使用int取值是-1,使用unsigned char 取值是255(0xff),下面有个例子:
int main()
{
int a = 0;
int b[2];
b[2] = 10;
printf("%d\n", a);
return 0;
}
应该有相当一部分人认为会输出0, 认为是10并且知道原因的请绕道,本文不适合你。不知道结果的继续往下看,我先不说答案:
简单划一下函数的栈内存示意图:
假设main函数基址为bp
参数空间(本例无参)
main函数基址 ----------------------------------------------- bp
a的地址即&a为bp-4
b[1]的地址bp-8
b[0]的地址bp-12
假设int* p = b;那么&b[0] = p, &b[1] = p + 1,以此类推b[2] = p + 2 ,那么字节偏移就是:p = &b[0] = bp - 12,那么p + 2就是bp - 4,即a;惊奇的发现b[2]就是a,所以本例输出的结果是10。能把这题看透彻,指针应该学的不会太差。
就写这些了,不写不知道,一写发现真难,举例子很难举。