指针对于C语言来说是非常重要的一环,可以说如果不会使用指针就说明没有真正掌握C语言。现在进一步总结指针,希望对其有更深层次的理解。
★别名陷阱
●什么是别名?
int temp = 3; int *p,*q; p = &temp; q = &temp;
对于一块内存来说,有多个指针同时指向这块内存,这多个指针中的每一个指针都是其他指针的别名。想上面这段代码,其中p是q的别名;同样q也是p的别名。
●别名陷阱
对于指针来讲,对指针操作就会直接操作指针指向的内存的内容。例如上面代码,如果对p指向的内存进行赋值*p = 5;那么该内存的值就会变成5,这样一来q指向的内存中的数值也会发生变化,内存中的值由3变成5。尤其在优化程序的时候,会造成一些比较隐蔽的错误,因此要十分的小心。
#include <stdio.h> #define a *p #define b *q int main(void) { int x; int *p,*q; p = &x; q = &x; a = 2; b = 3; printf("%d",a + b); return 0; }
像上面这个程序a+b的值为6,就是因为b=3;这条语句修改了变量x存储的内容,而p和q都同时指向x,使*p = 3,最后使得a+b=6
★数组指针
C语言中,一个指针变量可以指向一个数组,这样的指针叫做数组指针。例如:
int (*p)[5];表示p是一个指针,指向一个数组对象,该数组是一个拥有5个整形元素的数组。因此,p+1时p移动的字节数应该等于p所指向的数组对象的字节数。像上面这个指针应当移动sizeof(int)*5。
个字节。
#include<stdio.h> int main(void) { int a[5] = {1,2,3,4,5}; int (*p)[5]; int *ptr; p = &a; ptr = (int *)(p + 1); printf("%d",*(ptr - 1)); return 0; }
输出的结果是:5。分析一下原因,p是数组指针,则p+1指向的是a[5]。那么*(ptr-1)为什么是4呢?是因为ptr并非是数组指针而是整形指针。ptr = (int *)(p +1)就是将数组指针转换成整形指针。
区别:数组指针和指针数组
数组指针是一个指针,它指向数组;指针数组是一个数组,只不过数组中的每个元素都是指针。
★指针的指针
C语言中,指针可以指向指针,成为指针的指针。
int **p;表示定义一个指针变量,它指向的是另一个指针变量,这个指针变量又指向一个整形变量。
#include <stdio.h> int main(void) { int a; int *p; int **q; a = 100; p = &a; q = &p; printf("%d\n",a); printf("0x%x\n",*p); printf("0x%x\n",*q); //system("pause"); return 0; }
★指针类型的意义
指针的本质是一个无符号的整数,代表一个内存单元的单元号。但是在定义一个指针变量的同时,往往会声明该指针变量所指向的数据类型:int *p,表示该指针变量p指向的是一个整形。其作用是告知编译器需要从该地址处向后看多少个字节,把这些字节当做一个对象来看待。
★void*型指针
void*指针表示一个任意类型的指针,其可以指向任意一个类型的内存单元。
指针类型的意义在于使编译器可以知道从该指针所表示的地址开始,向后把多少个字节看成一个整体。任意类型的指针不能告诉编译器该向后看多少个字节,那么也就无法引用任意类型指针所指向的数据,void*类型似乎没有什么意义。但如果编译器不知道用户要把指针指向的内容作什么用途的时候,void*指针就起到作用了。编译器认为一块内存用户做什么都是合法的,那么这块内存的指针就是任意类型的。
有一个例子是:malloc函数分配一块内存后,得到这块内存的首地址,返回的就是void*类型的指针。
指针的本质是一个无符号的整数,从理论上将指针和一个整数的比较应该是没有问题的,但是C语言编译器同样不允许两者进行比较。因此在比较一个指针和一个整形数据时,首先要做的就是将整形数据转换为该指针类型,之后再进行比较。
指针的应用