指针是什么? 是地址。这个大家都知道。但是理解得未必深刻。我们以一条条活生生的代码来分析。
int *pointer;
声明一个指针。 pointer是一个指向Int型的指针的变量。
而变量里面的值是一个内存地址(在大部分操作系统中不是物理地址,是经过地址映射后的虚拟地址)。
而这个pointer只在程序文件(.c,.cpp)里存在,当编译成可执行文件后,它被替换成一个难看的符号,比如LLC012什么的。这点与java相反,所以C程序是没有办法反编译的。
当运行一个C程序时,操作系统分配给LLC012一块32位大小内存地址,以后你改变指针的值时,改变的就是这块内存地址的值了。
int 是指针的类型,刚才说过,指针变量占用的内存空间永远是32位,相当于一个int的大小。但是,指针是有类型的,它不是用来给指针变量本身分配内存,它是用来做什么的呢? 它是 用来寻址 的。看下面的代码。
(int*)pointer = malloc(sizeof(int) * 5);
printf("%d",*(pointer + 1));
这段代码中先申请5个int大小的内存空间,把这段内存空间的首地址付给pointer。然后打印出第2个int元素的值。
如果这里的pointer是char类型的,那么pointer+1指向的不是第2个Int,而是第一个int的中间部分。也就是说对于不同变量类型的指针来说,+1跨过的内存单元数是不同的。指针的类新也可以是自定义的结构的类型。
与java不同,C语言的函数是不允许以引用的方式传值的,也就是说对于所有的C函数,传入的参数都是一个复制的值。
比如这样一个交换数值的函数
void switch(int a ,int b)
{
int c =a;
a = b;
b = c;
}
这个函数调用后实际上并没有交换两个参数的值,因为是传值的,而非传地址(引用)的。
那么我们如何实现累类似引用传值的功能呢? 答案是,用指针。
void switch(int* a ,int* b)
{
int c =*a;
*a = *b;
*b = c;
}
从本质上说指针也是被复制后传到函数体内的。
我们以上面这个函数为例分析一下
函数一 : 当调用 switch(intA,intB)时
假设 :
intA 地址 0X0000000A 值 1
intB 地址 0X0000000B 值 2
经过复制之后实际上传入函数的是另外两个。
a 地址 0X000000AA 值 1
b 地址 0X000000BB 值 2
当函数执行后,intA,intB的值没变,他们从头到尾都没进入函数,进入的是他们的副本。变的是a , b的值(如下),但是函数执行结束后a , b都已经被丢弃了。没有达到预期目的。
a 地址 0X000000AA 值 2
b 地址 0X000000BB 值 1
函数二 : 当调用 switch(*intA,*intB)时
假设 :
intA 地址 0X0000000A 值 0X00000A0A
intB 地址 0X0000000B 值 0X00000B0B
地址 0X00000A0A 值 1
地址 0X00000B0B 值 2
当函数执行时,先复制参数,结果如下
a 地址 0X000000AA 值 0X00000A0A
b 地址 0X000000BB 值 0X00000B0B
而地址0X00000A0A 和 0X00000B0A 的值没有变化
传入函数后用的都是指针变量的值,也就是说改变的是0X00000A0A 和0X00000B0B的值,而指针intA和intB的值没有变化,始终指向0X00000A0A 和0X00000B0B 所以最终达到交换数值的预期效果。