概念
1 指针也是一个变量,做为指针变量的值是另一个变量的地址。指针存放的内容是一个地址,该地址指向一块内存空间
其一般形式为:
类型说明符 *变量名;
其中,*表示这是一个指针变量,变量名即为定义的指针变量名,类型说明符表示本指针变量所指向的变量的数据类型。
例如: int *p1;
表示p1是一个指针变量,它的值是某个整型变量的地址。或者说p1指向一个整型变量。至于p1究竟指向哪一个整型变量,应由向p1赋予的地址来决定。
2 图例解释
int i = 10;//一个int变量,名字叫i int *p;//定义了一个指向整数的指针变量
注意:
//在以下中 int i = 10;//一个int变量,名字叫i int *p;//定义了一个指向整数的指针变量 //p = 10;//错误,不可以把一个整数直接赋值给指针变量. //c语言当中每个变量都有自己的内存地址。&符号就是取变量地址操作符. printf("%x",&i); //输出i的16进制地址 printf("%d",*p); //输出i的值 printf("%x",&*p); //输出i的16进制地址 printf("%x",&p); //输出p的地址,注意,指针也有自己的内存地址 printf("%x",p); //输出i的16进制地址
切记,指针变量只能存放地址,不能将一个int型变量直接赋值给一个指针。
3 指针变量的引用
指针变量同普通变量一样,使用之前不仅要定义说明,而且必须赋予具体的值。未经赋值的指针变量不能使用,否则将造成系统混乱,甚至死机。指针变量的赋值只能赋予地址, 决不能赋予任何其它数据,否则将引起错误。在C语言中,变量的地址是由编译系统分配的,对用户完全透明,用户不知道变量的具体地址。
两个有关的运算符:
1) &:取地址运算符。
2) *:指针运算符(或称“间接访问” 运算符)。
C语言中提供了地址运算符&来表示变量的地址。
其一般形式为:
&变量名;
如&a表示变量a的地址,&b表示变量b的地址。变量本身必须预先说明。
设有指向整型变量的指针变量p,如要把整型变量a 的地址赋予p可以有以下两种方式:
(1) 指针变量初始化的方法
int a;
int *p=&a;
(2) 赋值语句的方法
int a;
int *p;
p=&a;
不允许把一个数赋予指针变量,故下面的赋值是错误的:
int *p;
p=1000;
4 野指针
定义了一个指向int的指针变量;没有赋初值,就是个野指针,指向什么内存地址不知道
int *p3;
* 野指针的危害只是程序本身,不会影响到操作系统。
* 如果你做的是一个驱动程序或者内核代码,那么可能是致命的,操作系统崩溃
* 野指针也叫悬空指针,不能给野指针指向的内存区域赋值。
注意:一个指向NULL的指针,我们称之为空指针(也就是说野指针),意味着这个指针不指向任何一个变量。
5 无类型指针
定义一个指针变量,但不指定它指向具体哪种数据类型。可以通过强制转化将void *转化为其他类型指针,也可以用(void *)将其他类型指针强制转化为void类型指针。
void *p
在C语言当中,可以将任何一种地址赋值给void *指针
例如:
void *p4;//定义了一个无类型的指针。 p4 = &i;//可以将任意类型的地址赋值给void * //p1 = p4;//(在C语言中可以将void *赋给任意类型的指针变量).但C++这个语句是非法的
6 指针变量作为函数参数
函数的参数不仅可以是整型、实型、字符型等数据,还可以是指针类型。它的作用是将一个变量的地址传送到另一个函数中。
例:输入的两个整数按大小顺序输出
swap(int *p1,int *p2) {int temp; temp=*p1; *p1=*p2; *p2=temp; }
main() { int a,b; int *pointer_1,*pointer_2; scanf("%d,%d",&a,&b); pointer_1=&a;pointer_2=&b; if(a<b) swap(pointer_1,pointer_2); printf("\n%d,%d\n",a,b); }
说明:
swap是用户定义的函数,它的作用是交换两个变量(a和b)的值。swap函数的形参p1、p2是指针变量。程序运行时,先执行main函数,输入a和b的值。然后将a和b的地址分别赋给指针变量pointer_1和pointer_2,使pointer_1指向a,pointer_2指向b。
7 数组指针
一个变量有地址,一个数组包含若干个元素,每个元素在内存中都有地址。
int a[10]; int *p = a; p和&a[0]的地址是否相同?
相同
在C语言当中数组的名称代表数组的首地址,如果取数组名称的地址,C语言认为就是取数组的首地址。
int array[10] = { 6, 8, 9, 1, 3,4 };//array[0]的值是6 int *p = &array[0];//p指向了数组的第一个元素的地址 int *p1 = array;//p1指向了数组的首地址. //*p和*p1是一样的。
8 通过指针引用数组元素
如果指针变量p已指向数组中的一个元素,则p+1指向同一数组中的下一个元素。
如果p的初值为&a[0],则:
1) p+i和a+i就是a[i]的地址,或者说它们指向a数组的第i个元素。
2) *(p+i)或*(a+i)就是p+i或a+i所指向的数组元素,即a[i]。例如,*(p+5)或*(a+5)就是a[5]。
3) 指向数组的指针变量也可以带下标,如p[i]与*(p+i)等价。
根据以上叙述,引用一个数组元素可以用:
1) 下标法,即用a[i]形式访问数组元素。在前面介绍数组时都是采用这种方法。
2) 指针法,即采用*(a+i)或*(p+i)形式,用间接访问的方法来访问数组元素,其中a是数组名,p是指向数组的指针变量,其处值p=a。
例:输出数组中的全部元素。(下标法)
main(){ int a[10],i; for(i=0;i<10;i++) a[i]=i; for(i=0;i<5;i++) printf("a[%d]=%d\n",i,a[i]); }
输出数组中的全部元素。(通过数组名计算元素的地址,找出元素的值)
main(){ int a[10],i; for(i=0;i<10;i++) *(a+i)=i; for(i=0;i<10;i++) printf("a[%d]=%d\n",i,*(a+i)); }
输出数组中的全部元素。(用指针变量指向元素)
main(){ int a[10],I,*p; p=a; for(i=0;i<10;i++) *(p+i)=i; for(i=0;i<10;i++) printf("a[%d]=%d\n",i,*(p+i)); }
main(){ int a[10],i,*p=a; for(i=0;i<10;){ *p=i; printf("a[%d]=%d\n",i++,*p++); } }
注意:
1) 指针变量可以实现本身的值的改变。如p++是合法的;而a++是错误的。因为a是数组名,它是数组的首地址,是常量。
【感谢谭浩强老师的《C语言》】