资源描述
8.1 指指针针是什么是什么8.2 指针变量指针变量8.3 通过指针引用数组通过指针引用数组8.4 通过指针引用字符串通过指针引用字符串 指向函数的指针指向函数的指针8.6 返回指针值的函数返回指针值的函数8.7 指针数组和多重指针指针数组和多重指针8.8 动态内存分配与指向它的指针变量动态内存分配与指向它的指针变量8.9 有关指针的小结有关指针的小结如果在程序中定义了一个变量,在对程序进如果在程序中定义了一个变量,在对程序进行编译时,系统就会给行编译时,系统就会给该该变量分配内存单元变量分配内存单元编译系统根据程序中定义的变量类型,分配编译系统根据程序中定义的变量类型,分配一定长度的空间一定长度的空间例如,例如,VC+为整型变量分配为整型变量分配4个字节,对个字节,对单精度浮点型变量分配个字节,对字符型单精度浮点型变量分配个字节,对字符型变量分配个字节变量分配个字节内存区的每一个字节有一个编号,这就是内存区的每一个字节有一个编号,这就是“地址地址”,它相当于旅馆中的房间号。,它相当于旅馆中的房间号。在地址所标在地址所标识识的内存单元中存放数据,这相的内存单元中存放数据,这相当于旅馆房间中居住的旅客一样。当于旅馆房间中居住的旅客一样。由于通过地址能找到所需的变量单元,我们由于通过地址能找到所需的变量单元,我们可以说,可以说,地址指向该变量单元地址指向该变量单元。将地址形象化地称为将地址形象化地称为“指针指针”务必弄清楚存储单元的务必弄清楚存储单元的地址地址和存储和存储单元的单元的内容内容这两个概念的区别这两个概念的区别例如:例如:int i=3,j=6,k;printf(“%d”,i);通过变量名通过变量名i找到找到i的地址的地址2000,从而,从而从从存存储单元储单元读读取取3int i=3,j=6,k;k=i+j;从这里取从这里取3将将9送到这里送到这里从这里取从这里取6直接存取直接存取int i=3,j=6,k;定义特殊变量定义特殊变量i_pointer将将i的地址的地址存到这里存到这里间接存取间接存取i_pointer=&i;*i_pointer=50;5050i200032000i_pointer*i_pointer20003直接存取直接存取间接存取间接存取为了表示将数值送到变量中,可以有两为了表示将数值送到变量中,可以有两种表达方法:种表达方法:(1)将将3直接送到变量直接送到变量i所标识的单元中,例所标识的单元中,例如:如:i=3;(2)将将3送到变量送到变量i_pointer所指向的单元所指向的单元(即变量(即变量i的存储单元),例如:的存储单元),例如:*i_pointer=3;其中其中*i_pointer表示表示i_pointer指向的对象指向的对象指向就是通过地址来体现的指向就是通过地址来体现的u假设假设i_pointer中的值是变量的地址中的值是变量的地址(2000),这样就在,这样就在i_pointer和变量之间和变量之间建立起一种联系,即通过建立起一种联系,即通过i_pointer能知道能知道i的地址,从而找到变量的地址,从而找到变量i的内存单元的内存单元由于通过地址能找到所需的变量单元,因由于通过地址能找到所需的变量单元,因此说,地址指向该变量单元此说,地址指向该变量单元将地址形象化地称为将地址形象化地称为“指针指针”。意思是通。意思是通过它能找到以它为地址的内存单元过它能找到以它为地址的内存单元一个变量的一个变量的地址地址称为该变量的称为该变量的“指针指针”例如,地址例如,地址2000是变量的指针是变量的指针如果有一个变量专门用来存放另一变量的如果有一个变量专门用来存放另一变量的地址(即指针),则它称为地址(即指针),则它称为“指针变量指针变量”i_pointer就是一个指针变量。指针变量就是一个指针变量。指针变量就是地址变量,用来存放地址的变量,指就是地址变量,用来存放地址的变量,指針变量的值是地址(即指针)針变量的值是地址(即指针)“指针指针”和和“指针变量指针变量”是是不同的不同的概念概念可以说变量可以说变量i的指针是的指针是2000,而不能说,而不能说i的的指针变量是指针变量是2000指针是一个地址,而指针变量是存放地址指针是一个地址,而指针变量是存放地址的变量的变量使用指针变量的例子使用指针变量的例子8.2.2 怎样定义指针变量怎样定义指针变量8.2.3 怎样引用指针变量怎样引用指针变量8.2.4 指针变量作为函数参数指针变量作为函数参数例例8.1 通通过指针变量访问整型变量。过指针变量访问整型变量。解题思路:先定义解题思路:先定义2个整型变量,再定个整型变量,再定义义2个指针变量,分别指向这两个整型个指针变量,分别指向这两个整型变量,通过访问指针变量,可以找到它变量,通过访问指针变量,可以找到它们所指向的变量,从而得到这些变量的们所指向的变量,从而得到这些变量的值。值。#include int main()int a=100,b=10;int*pointer_1,*pointer_2;pointer_1=&a;pointer_2=&b;printf(“a=%d,b=%dn”,a,b);printf(“*pointer_1=%d,*pointer_2=%dn”,*pointer_1,*pointer_2);return 0;定义两个指针变量定义两个指针变量使使pointer_1指向指向a使使pointer_2指向指向b直接直接输出变量输出变量a和和b的值的值间接间接输出变量输出变量a和和b的值的值#include int main()int a=100,b=10;int*pointer_1,*pointer_2;pointer_1=&a;pointer_2=&b;printf(“a=%d,b=%dn”,a,b);printf(“*pointer_1=%d,*pointer_2=%dn”,*pointer_1,*pointer_2);return 0;此处此处*与与类型名类型名在一起。在一起。此时共同定义指针变量此时共同定义指针变量此处此处*与指针变量一起使用。此与指针变量一起使用。此时时代表指针变量所指向的变量代表指针变量所指向的变量定义指针变量的一般形式为:定义指针变量的一般形式为:类型类型 *指针变量名指针变量名;如:如:int*pointer_1,*pointer_2;uint是是为为指针变量指定的指针变量指定的“基类型基类型”u基类型指定指针变量可指向的变量类型基类型指定指针变量可指向的变量类型u如如pointer_1可以指向整型变量,但不能指可以指向整型变量,但不能指向浮点型变量向浮点型变量下面都是合法的定义下面都是合法的定义和初始化和初始化:float *pointer_3;char *pointer_4;int a,b;int *pointer_1=&a,*pointer_2=&b;*pointer_1&a;错误错误pointer_3&a;错误错误pointer_1&a;正确正确pointer_32000;错误错误在引用指针变量时,可能有三种情况:在引用指针变量时,可能有三种情况:u给指针变量赋值。如:给指针变量赋值。如:p=&a;u引用指针变量指向的变量引用指针变量指向的变量。如如有有 p=&a;*p=1;则执行则执行printf(“%d”,*p);将输出将输出1u引用指针变量的值。如:引用指针变量的值。如:printf(“%o”,p);使使p指向指向a*p相当于相当于a以以八八进制输进制输出出a的地址的地址要熟练掌握两个有关的运算符:要熟练掌握两个有关的运算符:(1)取地址运算符。取地址运算符。&a是变量是变量a的地址的地址(2)*指针运算符(指针运算符(“间接访问间接访问”运算符)运算符)如果如果:p指向变量指向变量a,则则*p就代表就代表a。k=*p;(把把a的值的值赋给赋给k)*p=1;(把把1赋给赋给a)例例 输入输入a和和b两个整数,按先大后小的顺序两个整数,按先大后小的顺序输出输出a和和b。解题思路:用指针方法来处理这个问题。解题思路:用指针方法来处理这个问题。不交换整型变量的值,而是交换两个指针不交换整型变量的值,而是交换两个指针变量的值。变量的值。#include int main()int*p1,*p2,*p,a,b;printf(“integer numbers:);scanf(“%d,%d”,&a,&b);p1=&a;p2=&b;if(ab)p=p1;p1=p2;p2=p;printf(“a=%d,b=%dn”,a,b);printf(“%d,%dn”,*p1,*p2);return 0;abp1p2p59&a&b成立成立#include int main()int*p1,*p2,*p,a,b;printf(“integer numbers:);scanf(“%d,%d”,&a,&b);p1=&a;p2=&b;if(ab)p=p1;p1=p2;p2=p;printf(“a=%d,b=%dn”,a,b);printf(“%d,%dn”,*p1,*p2);return 0;abp1p2p59&a&b&b&a#include int main()int*p1,*p2,*p,a,b;printf(“integer numbers:);scanf(“%d,%d”,&a,&b);p1=&a;p2=&b;if(ab)p=p1;p1=p2;p2=p;printf(“a=%d,b=%dn”,a,b);printf(“%d,%dn”,*p1,*p2);return 0;abp1p2p59&a&b&b&a#include int main()int*p1,*p2,*p,a,b;printf(“integer numbers:);scanf(“%d,%d”,&a,&b);p1=&a;p2=&b;if(ab)p=p1;p1=p2;p2=p;printf(“a=%d,b=%dn”,a,b);printf(“%d,%dn”,*p1,*p2);return 0;abp1p2p59&a&b&b&a可否改为可否改为p1=&b;p2=&a;?注意注意:ua和和b的值并未交换,它们仍保持原值的值并未交换,它们仍保持原值u但但p1和和p2的值改变了。的值改变了。p1的值原为的值原为&a,后,后来变成来变成&b,p2原值为原值为&b,后来变成,后来变成&au这样在输出这样在输出*p1和和*p2时,实际上是输出变时,实际上是输出变量量b和和a的值,所以先输出的值,所以先输出9,然后输出,然后输出5 例例8.3 题目要求同例,即对输入的两个整题目要求同例,即对输入的两个整数按大小顺序输出。现用函数处理,而且用数按大小顺序输出。现用函数处理,而且用指针类型的数据作函数参数。指针类型的数据作函数参数。解题思路:定义一个函数解题思路:定义一个函数swap,将指向两,将指向两个整型变量的指针变量作为实参传递给个整型变量的指针变量作为实参传递给swap函数的形参指针变量,在函数中通过函数的形参指针变量,在函数中通过指针实现交换两个变量的值。指针实现交换两个变量的值。#include int main()void swap(int*p1,int*p2);int a,b;int*pointer_1,*pointer_2;printf(please enter a and b:);scanf(“%d,%d”,&a,&b);pointer_1=&a;pointer_2=&b;if(ab)swap(pointer_1,pointer_2);printf(“max=%d,min=%dn”,a,b);return 0;abpointer_159&a&bpointer_2void swap(int*p1,int*p2)int temp;temp=*p1;*p1=*p2;*p2=temp;abpointer_159&a&bpointer_2p1&ap2&b95void swap(int*p1,int*p2)int temp;temp=*p1;*p1=*p2;*p2=temp;void swap(int*p1,int*p2)int*temp;*temp=*p1;*p1=*p2;*p2=*temp;错!错!无确定的指向无确定的指向#include int main()if(ab)swap(a,b);printf(“max=%d,min=%dn”,a,b);return 0;void swap(int x,int y)int temp;temp=x;x=y;y=temp;错!错!无法交换无法交换a,bab59xy5995如果想通过函数调用得到个要改变的值如果想通过函数调用得到个要改变的值:在主调函数中设个变量,用个指针变量指在主调函数中设个变量,用个指针变量指向它们向它们 设计一个函数,有设计一个函数,有n个指针形参。在这个函数个指针形参。在这个函数中改变这个形参的值中改变这个形参的值 在主调函数中调用这个函数,在调用时将这在主调函数中调用这个函数,在调用时将这n个指针变量作实参,将它们的地址传给该函数个指针变量作实参,将它们的地址传给该函数的形参的形参 在执行该函数的过程中,通过形参指针变量,在执行该函数的过程中,通过形参指针变量,改变它们所指向的个变量的值改变它们所指向的个变量的值主调函数中就可以使用这些改变了值的变量主调函数中就可以使用这些改变了值的变量例例8.4 对输入的两个整数按大小顺序输出。对输入的两个整数按大小顺序输出。解题思路:尝试调用解题思路:尝试调用swap函数来实现题函数来实现题目要求。在函数中改变形参目要求。在函数中改变形参(指针变量指针变量)的的值,希望能由此改变实参值,希望能由此改变实参(指针变量指针变量)的值的值#include int main()void swap(int*p1,int*p2);int a,b;int*pointer_1,*pointer_2;scanf(%d,%d,&a,&b);pointer_1=&a;pointer_2=&b;if(ab)swap(pointer_1,pointer_2);printf(max=%d,min=%dn,a,b);return 0;void swap(int*p1,int*p2)int*p;p=p1;p1=p2;p2=p;错!错!只交换形参指向只交换形参指向注意:函数的调用可以(而且只可以)得注意:函数的调用可以(而且只可以)得到一个返回值(即函数值),而使用指针到一个返回值(即函数值),而使用指针变量作参数,可以得到多个变化了的值。变量作参数,可以得到多个变化了的值。如果不用指针变量是难以做到这一点的。如果不用指针变量是难以做到这一点的。要善于利用指针法。要善于利用指针法。例例8.5 输入输入3个整数个整数a,b,c,要求按由大,要求按由大到小的顺序将它们输出。用函数实现。到小的顺序将它们输出。用函数实现。解题思路:采用例的方法在函数中改变解题思路:采用例的方法在函数中改变这这3个变量的值。用个变量的值。用swap函数交换两个函数交换两个变量的值,用变量的值,用exchange函数改变这函数改变这3个变量的值。个变量的值。#include int main()void exchange(int*q1,int*q2,int*q3);int a,b,c,*p1,*p2,*p3;scanf(%d,%d,%d,&a,&b,&c);p1=&a;p2=&b;p3=&c;exchange(p1,p2,p3);printf(“%d,%d,%dn,a,b,c);return 0;调用结束后不会调用结束后不会改变指针的指向改变指针的指向void exchange(int*q1,int*q2,int*q3)void swap(int*pt1,int*pt2);if(*q1*q2)swap(q1,q2);if(*q1*q3)swap(q1,q3);if(*q2*q3)swap(q2,q3);void swap(int*pt1,int*pt2)int temp;temp=*pt1;*pt1=*pt2;*pt2=temp;交换指针指交换指针指向的变量值向的变量值8.3.1 数组元素的指针数组元素的指针8.3.2 在引用数组元素时指针的运算在引用数组元素时指针的运算8.3.3 通过指针引用数组元素通过指针引用数组元素8.3.4 用数组名作函数参数用数组名作函数参数8.3.5 通过指针引用多维数组通过指针引用多维数组一个变量有地址,一个数组包含若干元素一个变量有地址,一个数组包含若干元素,每个数组元素都有相应的地址,每个数组元素都有相应的地址指针变量可以指向数组元素(把某一元素指针变量可以指向数组元素(把某一元素的地址放到一个指针变量中)的地址放到一个指针变量中)所谓数组元素的指针就是数组元素的地址所谓数组元素的指针就是数组元素的地址可以用一个指针变量指向一个数组元素可以用一个指针变量指向一个数组元素 int a10=1,3,5,7,9,11,13,15,17,19;int *p;p=&a0;等价于等价于p=a;等价于等价于int*p=a;或或int*p=&a0;注意注意:数组名数组名a不代表整个数组,不代表整个数组,只代表数组首元素的地址。只代表数组首元素的地址。“p=a;”的作用是的作用是“把把a数组的首元素的地数组的首元素的地址赋给指针变量址赋给指针变量p”,而不是,而不是“把把数组数组a各元素的值赋给各元素的值赋给p”。在指针指向数组元素时,在指针指向数组元素时,允许允许以下运算:以下运算:u加一个整数加一个整数(用用+或或+=),如,如p+1u减一个整数减一个整数(用用-或或-=),如,如p-1u自加运算,如自加运算,如p+,+pu自减运算,如自减运算,如p-,-pu两个指针相减,如两个指针相减,如p1-p2(只有只有p1和和p2都都指向同一数组中的元素时才有意义指向同一数组中的元素时才有意义)(1)如果指针变量如果指针变量p已指向数组中的一个元已指向数组中的一个元素,则素,则p+1指向同一数组中的下一个元素指向同一数组中的下一个元素,p-1指向同一数组中的上一个元素。指向同一数组中的上一个元素。float a10,*p=a;假设假设a0的地址为的地址为2000,则,则up的值为的值为2000up+1的值为的值为2004uP-1的值为的值为1996越界越界(2)如果的初如果的初值为值为&a0,则则p+i和和a+i就就是数组元素是数组元素ai的地址,的地址,或者说,它们或者说,它们指向指向a数组序号数组序号为为i的元素的元素a0a1a2a3a4a5a6a7a8a9pp+1,a+1 p+i,a+i p+9,a+9(3)*(p+i)或或*(a+i)是是p+i或或a+i所指向所指向的数组元素,的数组元素,即即ai。a0a1a2a3a4a5a6a7a8a9pp+1,a+1 p+i,a+i p+9,a+9*(p+i)(4)如果指针如果指针p1和和p2都指向同一数组都指向同一数组 p2-p1的值的值是是4 不能不能p1+p2a0a1a2a3a4a5a6a7a8a9p1p2 引用一个数组元素,可用下面两种方法:引用一个数组元素,可用下面两种方法:()()下标法,如下标法,如ai形式形式 ()()指针法,如指针法,如*(a+i)或或*(p+i)其中其中a是数组名,是数组名,p是指向数组元素的指针是指向数组元素的指针变量,其初值变量,其初值p=a 例例8.6 有一个整型数组有一个整型数组a,有,有10个元素,个元素,要求输出数组中的全部元素。要求输出数组中的全部元素。解题思路:引用数组中各元素的值有解题思路:引用数组中各元素的值有3种种方法:方法:(1)下标法下标法;(2)通过数组名计算通过数组名计算数组元素地址,找出元素的值数组元素地址,找出元素的值;(3)用指用指针变量指向数组元素针变量指向数组元素分别写出程序,以资比较分析。分别写出程序,以资比较分析。(1)下标法。下标法。#include int main()int a10;int i;printf(“enter 10 integer numbers:n);for(i=0;i10;i+)scanf(%d,&ai);for(i=0;i10;i+)printf(“%d”,ai);printf(%n);return 0;(2)通过数组名计算数组元素地址,找出元素的值通过数组名计算数组元素地址,找出元素的值#include int main()int a10;int i;printf(“enter 10 integer numbers:n);for(i=0;i10;i+)scanf(%d,&ai);for(i=0;i10;i+)printf(“%d”,*(a+i);printf(n);return 0;scanf(%d,a+i);(3)用指针变量指向数组元素用指针变量指向数组元素#include int main()int a10;int*p,i;printf(“enter 10 integer numbers:n);for(i=0;i10;i+)scanf(%d,&ai);for(p=a;p(a+10);p+)printf(“%d”,*p);printf(n);return 0;for(p=a;p(a+10);p+)scanf(%d,p);for(p=a;p(a+10);a+)printf(“%d”,*a);错!错!3种方法的比较:种方法的比较:第第(1)和第和第(2)种方法执行效率相同种方法执行效率相同u编译系统是将编译系统是将ai转换为转换为*(a+i)处理的,处理的,即先计算元素地址。即先计算元素地址。u因此用第因此用第(1)和第和第(2)种方法找数组元素费时种方法找数组元素费时较多。较多。3种方法的比较:种方法的比较:第第(3)种方法比第种方法比第(1)、第、第(2)种方法快种方法快u用指针变量直接指向元素,不必每次都重新计用指针变量直接指向元素,不必每次都重新计算地址,像算地址,像p+这样的自加操作是比较快的这样的自加操作是比较快的u这种有规律地改变地址值这种有规律地改变地址值(p+)能大大提高能大大提高执行效率执行效率3种方法的比较:种方法的比较:用下标法比较直观,能直接知道是第几个用下标法比较直观,能直接知道是第几个元素。元素。用地址法或指针变量的方法不直观,难以用地址法或指针变量的方法不直观,难以很快地判断出当前处理的是哪一个元素。很快地判断出当前处理的是哪一个元素。例例8.7 通过指针变量输出整型数组通过指针变量输出整型数组a的的10个元素。个元素。解题思路:解题思路:用指针变量用指针变量p指向数组元素,通过改变指指向数组元素,通过改变指针变量的值,使针变量的值,使p先后指向先后指向a0到到a9各各元素。元素。#include int main()int*p,i,a10;p=a;printf(“enter 10 integer numbers:n);for(i=0;i10;i+)scanf(“%d”,p+);for(i=0;i10;i+,p+)printf(“%d”,*p);printf(n);return 0;退出循环时退出循环时p指向指向a9后面的存储单元后面的存储单元因此执行此因此执行此循环出问题循环出问题重新执行重新执行p=a;用数组名作函数参数时,因为实参数组名用数组名作函数参数时,因为实参数组名代表该数组首元素的地址,形参应该是一代表该数组首元素的地址,形参应该是一个指针变量个指针变量C编译都是将形参数组名作为指针变量来编译都是将形参数组名作为指针变量来处理的处理的int main()void fun(int arr,int n;int array10;fun(array,10);return 0;void fun(int arr,int n)fun(int*arr,int n)int main()void fun(int arr,int n;int array10;fun(array,10);return 0;void fun(int*arr,int n)array0arr0array数组数组arrarray3arr3arr+3 实参数组名是指针常量,但形参数组名是实参数组名是指针常量,但形参数组名是按指针变量处理按指针变量处理在函数调用进行虚实结合后,它的值就是在函数调用进行虚实结合后,它的值就是实参数组首元素的地址实参数组首元素的地址在函数执行期间,在函数执行期间,形参数组形参数组可以再被赋值可以再被赋值void fun(arr,int n)printf(%dn,*arr);arr=arr+3;printf(%dn,*arr);例例8.8 将数组将数组a中中n个整数按相反顺序存放个整数按相反顺序存放解题思路:将解题思路:将a0与与an-1对换,对换,将将a4与与a5对换。对换。ji例例8.8 将数组将数组a中中n个整数按相反顺序存放个整数按相反顺序存放解题思路:将解题思路:将a0与与an-1对换,对换,将将a4与与a5对换。对换。ji例例8.8 将数组将数组a中中n个整数按相反顺序存放个整数按相反顺序存放解题思路:将解题思路:将a0与与an-1对换,对换,将将a4与与a5对换。对换。ji例例8.8 将数组将数组a中中n个整数按相反顺序存放个整数按相反顺序存放解题思路:将解题思路:将a0与与an-1对换,对换,将将a4与与a5对换。对换。ji例例8.8 将数组将数组a中中n个整数按相反顺序存放个整数按相反顺序存放解题思路:将解题思路:将a0与与an-1对换,对换,将将a4与与a5对换。对换。ji#include int main()void inv(int x,int n);int i,a10=3,7,9,11,0,6,7,5,4,2;for(i=0;i10;i+)printf(“%d”,ai);printf(n);inv(a,10);for(i=0;i10;i+)printf(“%d”,ai);printf(n);return 0;void inv(int x,int n)int temp,i,j,m=(n-1)/2;for(i=0;i=m;i+)j=n-1-i;temp=xi;xi=xj;xj=temp;void inv(int x,int n)int temp,*i,*j;i=x;j=x+n-1;for(;ij;i+,j-)temp=*i;*i=*j;*j=temp;优化优化例例8.9 改写例,用指针变量作实参。改写例,用指针变量作实参。#include int main()void inv(int*x,int n);int i,arr10,*p=arr;for(i=0;i10;i+,p+)scanf(“%d”,p);inv(p,10);for(p=arr;parr+10;p+)printf(“%d”,*p);printf(n);return 0;不可少!不可少!例例8.10 用指针方法对用指针方法对10个整数按由大到个整数按由大到小顺序排序。小顺序排序。解题思路:解题思路:u在主函数中定义数组在主函数中定义数组a存放存放10个整数,定义个整数,定义int*型指针变量型指针变量p指向指向a0u定义函数定义函数sort使数组使数组a中的元素按由大到小的中的元素按由大到小的顺序排列顺序排列u在主函数中调用在主函数中调用sort函数,用指针函数,用指针p作实参作实参u用选择法进行排序用选择法进行排序#include int main()void sort(int x,int n);int i,*p,a10;p=a;for(i=0;i10;i+)scanf(“%d”,p+);p=a;sort(p,10);for(p=a,i=0;i10;i+)printf(“%d”,*p);p+;printf(n);return 0;void sort(int x,int n)int i,j,k,t;for(i=0;in-1;i+)k=i;for(j=i+1;jxk)k=j;if(k!=i)t=xi;xi=xk;xk=t;void sort(int*x,int n)if(*(x+j)*(x+k)k=j;t=*(x+i);*(x+i)=*(x+k);*(x+k)=t;指针变量可以指向一维数组中的元素,也指针变量可以指向一维数组中的元素,也可以指向多维数组中的元素。但在概念上可以指向多维数组中的元素。但在概念上和使用方法上,多维数组的指针比一维数和使用方法上,多维数组的指针比一维数组的指针要复杂一些。组的指针要复杂一些。1.多维数组元素的地址多维数组元素的地址int a34=1,3,5,7,9,11,13,15,17,19,21,23;1357911131517192123a0a1a2aa+1a+2a0 a0+1 a0+2 a0+3行指针行指针列指针列指针a代表第代表第0行首地址行首地址a+1代表第代表第1行首地址行首地址a+2代表第代表第2行首地址行首地址1357911131517192123a0a1a2aa+1a+2a0 a0+1 a0+2 a0+3行指针行指针列指针列指针行指针每加行指针每加1,走一行,走一行a+i代表行号为代表行号为i的行首地址(按行变化)的行首地址(按行变化)*(a+i)代表什么?代表什么?1357911131517192123a0a1a2aa+1a+2a0 a0+1 a0+2 a0+3行指针行指针列指针列指针相当于相当于aia0代表代表a00的地址的地址a0+1代表代表a01的地址的地址a0+2代表代表a02的地址的地址a0+3代表代表a03的地址的地址1357911131517192123a0a1a2aa+1a+2a0 a0+1 a0+2 a0+3行指针行指针列指针列指针列指针每加列指针每加1,走一列,走一列a1代表谁的地址?代表谁的地址?a1+1代表谁的地址?代表谁的地址?a1+2代表谁的地址?代表谁的地址?a1+3代表谁的地址?代表谁的地址?1357911131517192123a0a1a2aa+1a+2a0 a0+1 a0+2 a0+3行指针行指针列指针列指针ai+j代表谁的地址?代表谁的地址?1357911131517192123a0a1a2aa+1a+2a0 a0+1 a0+2 a0+3行指针行指针列指针列指针代表代表aij的地址的地址*(ai+j)代表什么?代表什么?代表元素代表元素aij*(*(a+i)+j)代表什么?代表什么?与与*(ai+j)等价等价例例8.11 二维数组的有关数据二维数组的有关数据(地址和值地址和值)#include int main()int a34=1,3,5,7,9,11,13,15,17,19,21,23;printf(“%d,%dn”,a,*a);printf(“%d,%dn”,a0,*(a+0);printf(“%d,%dn”,&a0,&a00);printf(“%d,%dn”,a1,a+1);printf(“%d,%dn”,&a10,*(a+1)+0);printf(“%d,%dn”,a2,*(a+2);printf(“%d,%dn”,&a2,a+2);printf(“%d,%dn”,a10,*(*(a+1)+0);printf(“%d,%dn”,*a2,*(*(a+2)+0);return 0;printf(“%d,%dn”,a,*a);printf(“%d,%dn”,a0,*(a+0);printf(“%d,%dn”,&a0,&a00);printf(“%d,%dn”,a1,a+1);printf(“%d,%dn”,&a10,*(a+1)+0);printf(“%d,%dn”,a2,*(a+2);printf(“%d,%dn”,&a2,a+2);printf(“%d,%dn”,a10,*(*(a+1)+0);printf(“%d,%dn”,*a2,*(*(a+2)+0);return 0;printf(“%d,%dn”,a,*a);printf(“%d,%dn”,a0,*(a+0);printf(“%d,%dn”,&a0,&a00);printf(“%d,%dn”,a1,a+1);printf(“%d,%dn”,&a10,*(a+1)+0);printf(“%d,%dn”,a2,*(a+2);printf(“%d,%dn”,&a2,a+2);printf(“%d,%dn”,a10,*(*(a+1)+0);printf(“%d,%dn”,*a2,*(*(a+2)+0);return 0;2.指向多维数组元素的指针变量指向多维数组元素的指针变量(1)指向数组元素的指针变量指向数组元素的指针变量 例例8.12 有一个有一个34的二维数组,要求的二维数组,要求用指向元素的指针变量输出二维数组各用指向元素的指针变量输出二维数组各元素的值。元素的值。解题思路:解题思路:u二维数组的元素是整型的,它相当于整型变二维数组的元素是整型的,它相当于整型变量,可以用量,可以用int*型指针变量指向它型指针变量指向它u二维数组的元素在内存中是按行顺序存放的二维数组的元素在内存中是按行顺序存放的,即存放完序号为,即存放完序号为0的行中的全部元素后,的行中的全部元素后,接着存放序号为接着存放序号为1的行中的全部元素,依此的行中的全部元素,依此类推类推u因此可以用一个指向整型元素的指针变量,因此可以用一个指向整型元素的指针变量,依次指向各个元素依次指向各个元素#include int 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);printf(n);return 0;控制换行控制换行逐个访问各元素时常用此类指针逐个访问各元素时常用此类指针(2)指向由个元素组成的一维数组的指针指向由个元素组成的一维数组的指针变量变量 例例8.13 输出二维数组任一行任一列元素的输出二维数组任一行任一列元素的值。值。解题思路:假设仍然用例程序中的二维数解题思路:假设仍然用例程序中的二维数组,例中定义的指针变量是指向变量或数组,例中定义的指针变量是指向变量或数组元素的,现在改用指向一维数组的指针组元素的,现在改用指向一维数组的指针变量。变量。#include int main()int a34=1,3,5,7,9,11,13,15,17,19,21,23;int(*p)4,i,j;p=a;printf(“enter row and colum:);scanf(“%d,%d”,&i,&j);printf(“a%d,%d=%dn”,i,j,*(*(p+i)+j);return 0;行指针行指针aij3.用指向数组的指针作函数参数用指向数组的指针作函数参数一维数组名可以作为函数参数,多维数组一维数组名可以作为函数参数,多维数组名也可作函数参数。名也可作函数参数。用指针变量作形参,以接受实参数组名传用指针变量作形参,以接受实参数组名传递来的地址。递来的地址。可以有两种方法:可以有两种方法:用指向变量的指针变量用指向变量的指针变量用指向一维数组的指针变量用指向一维数组的指针变量 例例8.14 有一个班,有一个班,3个学生,各学个学生,各学4门课,门课,计算总平均分数以及第计算总平均分数以及第n个学生的成绩。个学生的成绩。解题思路:这个题目是很简单的。本例用指解题思路:这个题目是很简单的。本例用指向数组的指针作函数参数。用函数向数组的指针作函数参数。用函数average求总平均成绩,用函数求总平均成绩,用函数search找找出并输出第出并输出第i个学生的成绩。个学生的成绩。#include int main()void average(float*p,int n);void search(float(*p)4,int n);float score34=65,67,70,60,80,87,90,81,90,99,100,98;average(*score,12);search(score,2);return 0;score00的地址的地址void average(float*p,int n)float*p_end;float sum=0,aver;p_end=p+n-1;for(;p=p_end;p+)sum=sum+(*p);aver=sum/n;printf(average=%5.2fn,aver);6567706080879081909910098pp_endp+1#include int main()void average(float*p,int n);void search(float(*p)4,int n);float score34=65,67,70,60,80,87,90,81,90,99,100,98;average(*score,12);search(score,2);return 0;二维数组首行地址二维数组首行地址void search(float(*p)4,int n)int i;printf(The score of No.%d are:n,n);for(i=0;i4;i+)printf(%5.2f,*(*(p+n)+i);printf(n);6567706080879081909910098pp+2 例例8.15 在上题基础上,查找有一门以上在上题基础上,查找有一门以上课程不及格的学生,输出他们的全部课程课程不及格的学生,输出他们的全部课程的成绩。的成绩。解题思路:在主函数中定义二维数组解题思路:在主函数中定义二维数组score,定义,定义search函数实现输出有一函数实现输出有一门以上课程不及格的学生的全部课程的成门以上课程不及格的学生的全部课程的成绩,形参绩,形参p的类型是的类型是float(*)4。在调。在调用用search函数时,用函数时,用score作为实参,作为实参,把把score0的地址传给形参的地址传给形参p。#include int main()void search(float(*p)4,int n);float score34=65,57,70,60,58,87,90,81,90,99,100,98;search(score,3);return 0;void search(float(*p)4,int n)int i,j,flag;for(j=0;jn;j+)flag=0;for(i=0;i4;i+)if(*(*(p+j)+i)60)flag=1;if(flag=1)printf(No.%d failsn,j+1);for(i=0;i4;i+)printf(“%5.1f”,*(*(p+j)+i);printf(n);65 57706058 87908190 99 10098pvoid search(float(*p)4,int n)int i,j,flag;for(j=0;jn;j+)flag=0;for(i=0;i4;i+)if(*(*(p+j)+i)60)flag=1;if(flag=1)printf(No.%d failsn,j+1);for(i=0;i4;i+)printf(“%5.1f”,*(*(p+j)+i);printf(n);发现发现不及格不及格,赋,赋1若有若有不及格不及格,则输出,则输出不用不用flag,而用,而用break语句如何改程序?语句如何改程序?8.4.1 字符串的引用方式字符串的引用方式8.4.2 字符指针作函数参数字符指针作函数参数8.4.3 使用字符指针变量和字符数组的比较使用字符指针变量和字符数组的比较字符串是存放在字符数组中的。引用一个字符串是存放在字符数组中的。引用一个字符串,可以用以下两种方法。字符串,可以用以下两种方法。(1)用字符数组存放一个字符串,可以通过数组用字符数组存放一个字符串,可以通过数组名和格式声明名和格式声明“%s”输出该字符串,也可以输出该字符串,也可以通过数组名和下标引用字符串中一个字符。通过数组名和下标引用字符串中一个字符。(2)用字符指针变量指向一个字符串常量,通过用字符指针变量指向一个字符串常量,通过字符指字符指针针变量引用字符串常量。变量引用字符串常量。例例8.16 定义一个字符数组,在其中存放定义一个字符数组,在其中存放字符串字符串“I love China!”,输出该字符,输出该字符串和第串和第8个字符。个字符。解题思路:定义字符数组解题思路:定义字符数组string,对它初,对它初始化,由于在初始化时字符的个数是确定始化,由于在初始化时字符的个数是确定的,因此可不必指定数组的长度。用数组的,因此可不必指定数组的长度。用数组名名string和输出格式和输出格式%s可以输出整个字可以输出整个字符串。用数组名和下标可以引用任一数组符串。用数组名和下标可以引用任一数组元素。元素。#include int main()char string=“I love China!”;printf(“%sn”,string);printf(“%cn”,string7);return 0;stringstring+7 例例8.17 通过字符指针变量输出一个字符串。通过字符指针变量输出一个字符串。解题思路:可以不定义字符数组,只定义一解题思路:可以不定义字符数组,只定义一个字符指针变量,用它指向字符串常量中的个字符指针变量,用它指向字符串常量中的字符。通过字符指针变量输出该字符串。字符。通过字符指针变量输出该字符串。#include int main()char*string=“I love China!”;printf(“%sn”,string);return 0;stringchar*string;string=”I love China!”;#include int main()char*string=“I love China!”;printf(“%sn”,string);string=”I am a student.”;printf(“%sn”,string);return 0;string#include int main()char*string=“I love China!”;printf(“%sn”,string);string=”I am a student.”;printf(“%sn”,string);return 0;string 例例8.18 将字符串将字符串a复制为字符串复制为字符串b,然后,然后输出字符串输出字符串b。解题思路:定义两个字符数组解题思路:定义两个字符数组a和和b,用,用“I am a student.”对对a数组初始化。数组初始化。将将a数组中的字符逐个复制到数组中的字符逐个复制到b数组中。可数组中。可以用不同的方法引用并输出字符数组元素以用不同的方法引用并输出字符数组元素,今用地址法算出各元素的值。,今用地址法算出各元素的值。#include int main()char a=“I am a student.”,b20;int i;for(i=0;*(a+i)!=0;i+)*(b+i)=*(a+i);*(b+i)=0;printf(“string a is:%sn”,a);printf(string b is:);for(i=0;bi!=0;i+)printf(“%c”,bi);printf(n);return 0;printf(string b is:%sn“,b);例例8.19 用指针变量来处理例问题。用指针变量来处理例问题。解题思路:定义两个指针变量解题思路:定义两个指针变量p1和和p2,分别指向字符数组分别指向字符数组a和和b。改变指针变量。改变指针变量p1和和p2的值,使它们顺序指向数组中的的值,使它们顺序指向数组中的各元素,进行对应元素的复制。各元素,进行对应元素的复制。#include int main()char a=I am a boy.,b20,*p1,*p2;p1=a;p2=b;for(;*p1!=0;p1+,p2+)*p2=*p1;*p2=0;printf(“string a is:%sn”,a);printf(“string b is:%sn”,b);return 0;如果想把一个字符串从一个函数如果想把一个字符串从一个函数“传递传递”到另一个函数,可以用地址传递的办法,到另一个函数,可以用地址传递的办法,即用字符数组名作参数,也可以用字符指即用字符数组名作参数,也可以用字符指针变量作参数。针变量作参数。在被调用的函数中可以改变字符串的内容在被调用的函数中可以改变字符串的内容在主调函数中可以引用改变后的字符串。在主调函数中可以引用改变后的字符串。例例8.20 用函数调用实现字符串的复制。用函数调用实现字符串的复制。解题思路:定义一个函数解题思路:定义一个函数copy_string用来实现字符串复制的功能,在主函数中用来实现字符串复制的功能,在主函数中调用此函数,函数的形参和实参可以分别调用此函数,函数的形参和实参可以分别用字符数组名或字符指针变量。分别编程用字符数组名或字符指针变量。分别编程,以供分析比较。,以供分析比较。(1)用字符数组名作为函数参数用字符数组名作为函数参数#include int main()void copy_string(char from,char to);char a=I am a teacher.;char b=you are a student.;printf(“a=%snb=%sn,a,b);printf(copy string a to string b:n);copy_string(a,b);printf(“a=%snb=%sn,a,b);return 0;void copy_string(char from,char to)int i=0;while(fromi!=0)toi=fromi;i+;toi=0;(2)用字符型指针变量作实参用字符型指针变量作实参copy_string不变,在不变,在main函数中函数中定义字符指针变量定义字符指针变量from和和to,分别指,分别指向两个字符数组向两个字符数组a,b。仅需要修改主函数代码仅需要修改主函数代码#include int main()void copy_string(char from,char to);char a=“I am a teacher.”;char b=“you are a student.”;char*from=a,*to=b;printf(“a=%snb=%sn,a,b);printf(ncopy string a to string b:n);copy_string(from,to);printf(“a=%snb=%sn,a,b);return 0;(3)用字符指针变量作形参和实参用字符指针变量作形参和实参#include int main()void copy_string(char*from,char*to);char*a=“I am a teacher.”;char b=“You are a student.”;char*p=b;printf(“a=%snb=%sn”,a,b);printf(ncopy string a to string b:n);copy_string(a,p);printf(“a=%snb=%sn”,a,b);return 0;void copy_string(char*from,char*to)for(;*from!=0;from+,to+)*to=*from;*to=0;函数体有多种简化写法,请见主教材函数体有多种简化写法,请见主教材 用字符数组和字符指针变量都能实现字符用字符数组和字符指针变量都能实现字符串的存储和运算,但它们二者之间是有区串的存储和运算,但它们二者之间是有区别的,不应混为一谈,主要有以下几点。别的,不应混为一谈,主要有以下几点。(1)字符数组由若干个元素组成,每个元素中字符数组由
展开阅读全文