指针是C语言的重要概念.ppt
第十章 指针,指针是C语言的重要概念,是C语言的特色,是C语言的精华。10.1 地址和指针的概念内存中的每一个字节都有一个地址。内存单元的地址与内存单元的内容是两个完全不同的概念。在编译时给出了变量名和地址的对应关系。,以前在程序中定义整形等变量。如int a,b;表示a和b申请整形单元,分别存放两个整形值。我们也可以定义一种特殊的变量,它用来存放内存单元地址。这种变量的值是一个地址,它的作用是:根据地址去找相应的单元,因此,这种装载地址的变量又可称为“指针变量”。指针变量的值就是指针即地址。,10.2 变量的指针和指向变量的指针变量变量的指针就是变量的地址。存放地址的变量称谓指针变量。为了表示指针变量和它所指向的变量之间联系,程序中用*符号表示“指向”如用i_point表示指针变量,而*i_point就表示i_point指向的变量。10.2.1 定义一个指针变量C语言规定所有变量在使用前必须定义,指定其类型,并按此分配内存单元。,int i,j;int*point1,*point2;定义了两个指向整形变量的指针变量。定义指针变量要指定“基类型”基类型是指针变量指向的变量的类型。指针变量的定义形式:基类型*指针变量名那么如何给指针变量赋值呢?point1=,10.2.2 指针变量的引用指针变量只能存放地址(指针),有两个有关的运算符:(1),point1=,10.2.3 指针变量作为函数参数函数参数可以是指针变量swap(int*p1,int*p2)int temp;temp=*p1;*p1=*p2;*p2=temp;main()int a,b,*point1,*point2;a=10;b=90;point1=,10.3 数组的指针和指向数组的指针变量,一个变量有地址,一个数组包括若干个元素,每个元素都有地址.数组的指针是指数组的起始元素的地址.引用数组元素可用下标法,也可用指针法,即用指针指向所引用的元素.,10.3.1 指向数组元素的指针int a10;int*p;p=,10.3.2 通过指针引用数组元素按C语言规定:如果指针变量p已指向数组中的一个元素,则p+1指向同一数组中的下一个元素(而不是将的p的值简单加1).如果p的初值为&a0,则(1)p+i和a+i就是ai的地址(2)*(p+i)和*(a+i)是p+i和a+i所指向的数组元素,即ai。可以看出,实际上是变址运算符(3)指向数组的指针变量也可以带下标,如pi与*(p+i)等价.,10.3.3 用数组名作函数参数例:main()inv(int arr,int n)int array10;:inv(array,10);:用数组名作参数时,如果形参数组中各元素值发生变化,实参数组值随之变化.,void inv(int arr,int n)int t,i,j,m=(n-1)/2;for(i=0;i=m;i+)j=n-1-i;t=arri;arri=arrj;arrj=t;main()int i,a10=2,4,54,6,7,3,31,56,23,65;inv(a,10);for(i=0;i=9;i+)printf(“%d”,ai);,f(int arr,int n)等价于f(int*arr,int n)例:函数定义为:函数调用为:void swap(int x,int y)swap(a1,a2);请大家注意:(1)“值传递”和“地址传递”(2)两者之间的异同点,int m1,m2;void m_value(int array,int n)int*p,*array_end;array_end=array+n;m1=m2=*array;for(p=array+1;pm1)m1=*p;else if(*pm2)m2=*p;main()int i,num10;for(i=0;i10;i+)scanf(“%d”,函数参数为数组时:(1)形参和实参都是数组名,如:main()f(int arr,int n)int a10;:f(a,10);:(2)实参是数组名,形参是指针变量,如:main()f(int*arr,int n)int a10;:f(a,10);:,(3)形参和实参都是指针变量,如:main()f(int*arr,int n)int a10,*p=a;:f(p,10);:(4)实参是指针变量,形参是数组名,如:main()f(int arr,int n)int a10,*p=a;:f(p,10);:,选择法排序sort(int x,int n)int i,j,k,t;for(i=0;ixk)k=j;if(k!=i)t=xi;xi=xk;xk=t;,10.3.4 指向多维数组的指针和指针变量1、多维数组的地址 考查:int a34;a是一个数组名。a数组包含3行,即看成3个元素:a0、a1、a2。而一个元素又是一个一维数组,包含4个元素。a0所代表的一维数组包含的4个元素是:a00、a01、a02、a03从二维数组来看,,a代表整个二维数组的首地址,也就是第0行的首地址,即a0地址a+1代表第1行的首地址,即a1地址a+2代表第2行的首地址,即a2地址实际上a0、a1和 a2分别表示的是二维的第0行、第1行和第2行。基于这种认识,把a0、a1和 a2看成是一维数组名,C语言又规定数组名代表数组的首地址,因此a0代表第0行一维数组中第0列元素的地址,即&a00,依此类推a1的值是&a10依此类推a2的值是&a20第0行第1列元素的地址可表示为:a0+1在一维数组中,a0和*(a+0)等价,a1和*(a+1)等价,等理解:a是二维数组的首地址 a1即*(a+1)是第二行的首地址,用地址法如何得到a01呢?它的地址表示为 a0+1,值表示为*(a0+1)进一步表示为:*(*(a+0)+1)说明:对二维数组来说,ai表示的是一维数组名,ai本身不占实际的内存单元,它只是一个地址,表示地址的一种计算方法,如同一维数组x10的数组名.,2、指向多维数组的指针变量(1)指向数组元素的指针变量main()int a34=1,3,5,7,9,11,13,15,17,19,21,23;int*p;for(p=a0;pa0+12;p+)if(p-a0)%4=0)printf(“n”);printf(“%4d”,*p);,(2)指向由m个元素组成的一维数组指针变量输出二维数组任一行任一列元素的值main()int a34=1,3,5,7,9,11,13,15,17,19,21,23;int(*p)4,i,j;p=a;scanf(“i=%d,j=%d”,注意(1).*p4是指针数组(2).int a4;a有四个元素(3).int(*p)4;*p有4个元素,每个元素都是整型.p所指的对象是有4个整型元素的数组,即p是行指针.应该记住此时p只能指向一个包含4个元素的一维数组,p的值就是该一维数组的首地址.p不能指向一维数组中的第j个元素.,3、多维数组的指针作函数参数用指针变量作形参以接受实参数组名传来的地址时,有两种方法:(1)用指向变量的指针变量(2)用指向一维数组的指针变量通过指针变量存取数组元素速度快,程序简明.用指针变量作形参,可以允许数组的行数不同.因此数组与指针常常是紧密相联的.,10.4 字符串的指针和指向字符串的指针变量,10.4.1 字符串的表示形式在C中有两种方法(1)用字符数组存放一个字符串,然后输出该字符串(2)用字符指针指向一个字符串显然用%s可以对一个字符串进行整体的输入与输出,main()char a=“I am a boy.”,b20,*p1,*p2;int i;p1=a;p2=b;for(;*p1!=0;p1+,p2+)*p2=*p1;*p2=0;printf(“string a is:%sn”,a);printf(“string b is:”);for(i=0;bi!=0;i+)printf(“%c”,bi);printf(“n”);,10.4.2 字符串指针作函数参数将一个字符串从一个函数传递到另一个函数,可以用地址传递,用数组名或指针.void str(char*f,char t)main()char a10,*b;str(a,b);10.4.3 对使用字符指针变量和字符数组的讨论字符指针变量和字符数组实现字符串的存贮与运算,两者之间是有差别的.char str10;scanf(“%s”,str);char*a;scanf(“%s”,a);,10.5 函数的指针和指向函数的指针变量,10.5.1 用函数指针变量调用函数可以用指针变量指向整型变量,字符串,数组,也可以指向一个函数.一个函数在编译时被分配一个入口地址,这个入口地址就称为函数的指针,可以用一个指针变量指向函数,然后通过该指针变量调用此函数.,main()int a,b,c;scanf(“%d,%d”,将main函数改写为:main()int max(int,int);int(*p)();int a,b,c;p=max;/将max的入口地址赋给p scanf(“%d,%d”,int(*p)()定义p是一个指向函数的指针变量,此函数带回整型的返回值.,定义指向函数的指针变量的一般形式数据类型(*指针变量)();其它注意事项见教材,10.5.2 用指向函数的指针作函数参数 函数的参数可以是变量,指向变量的指针变量,数组名,指向数组的指针变量,等等函数指针变量常用的用途之一是把指针作为参数传递到其他函数,是C语言中深入的部分.sub(int(*x1)(int),int(*x2)(int,int)int a,b,i=1,j=2;a=(*x1)(i);b=(*x2)(i,j);.,10.6 返回指针值的函数,一个函数可以带回一个整型值,字符值,实型值等,也可带回指针型的数据,即地址.其本质与以前类似,只是带回的值是指针类型而已带回指针值的函数,可定义为:基类型*函数名(参数表);如:int*a(int x,int y);,main()float score4=60,70,80,90,50,89,67,88,34,78,90,66,*p;float*search(float(*ptr)4);int i,j;for(i=0;i3;i+)p=search(score+i);if(p=*(score+i)printf(“No.%d scores:”,i);for(j=0;j4;j+)printf(“%5.2f”,*(p+j);printf(“n”);,float*search(float(*ptr)4)int i;float*pt;pt=*(ptr+1);for(i=0;i4;i+)if(*(*ptr+i)60)pt=*ptr;break;return(pt);,10.7 指针数组和指向指针的指针,10.7.1 指针数组的概念一个数组其元素均为指针类型数据,称为指针数组.指针数组中的每一个元素都相当于指针变量.一维指针数组的定义为:类型名*数组名数组长度主要用于指向若干个字符串,使字符串的处理更加灵活,如:char*name=“Tom”,”Bill”,”David”;,10.7.2 指向指针的指针指针数组的数组名就是一个指针的指针.char*p;相当于 char*(*p);指针p是指向一个字符指针变量的变量.*p就是p指向的另一个指针变量变量的直接访问,间接访问(单级间址,二级间址,多级间址).,10.7.3 指针数组作main函数的形参指针数组的一个重要作用就是作main函数的形参.main函数的一般形式为:main()实际上main函数可以有形参,如main(argc,argv)main函数是系统调用的,它的形参对应的实参从何而来呢?从OS命令中得到:,命令名 参数1 参数2参数n利用指针数组作main函数的形参,可以向程序传送命令行参数(这些参数是字符串).由于参数的长度和个数都是不定的,所以用指针数组恰好能满足这一要求.,10.8 有关指针的数据类型和指针运算的小结,10.8.1 有关指针的数据类型的小结 int i;int*p;int an;int*pn;int(*p)n;int f()int*p()int(*p)()int*p;,10.8.2 指针运算小结(1)指针变量加(减)一个整数 如:p+,p-i等(2)指针变量赋值 p=,(3)指针变量赋空值,表示不指向任何变量 p=NULL;(4)两个指针变量可以相减 指向同一数组的两个不同元素的指针相减是什么意义,而相加呢?(5)两个指针变量可以比较,10.8.3 void指针类型ANSI增加void指针类型,可定义一个指针变量,但不指定它是指向哪一种类型数据的,将它的值赋给另一指针变量时要进行强制类型转换.char*p1;void*p2;p1=(char*)p2;,总结指针变量的优点:1.提高程序效率2.可以实现函数改变多个值3.可以实现灵活的和动态的存贮分配缺点:难理解,灵活难以把握,容易出错作业:10.2 10.3 10.9 10.13,