C语言程序设计6-指针B-New

上传人:努力****83 文档编号:193007133 上传时间:2023-03-07 格式:PPT 页数:70 大小:403KB
收藏 版权申诉 举报 下载
C语言程序设计6-指针B-New_第1页
第1页 / 共70页
C语言程序设计6-指针B-New_第2页
第2页 / 共70页
C语言程序设计6-指针B-New_第3页
第3页 / 共70页
资源描述:

《C语言程序设计6-指针B-New》由会员分享,可在线阅读,更多相关《C语言程序设计6-指针B-New(70页珍藏版)》请在装配图网上搜索。

1、指针指针1)1)变量与指针变量与指针2)2)数组与指针数组与指针3)3)函数与指针函数与指针变量与指针变量与指针指针变量的定义:指针变量的定义:数据类型标识符数据类型标识符 *变量名变量名;注意注意:1):1)*是指针型变量是指针型变量,意为,意为:指向指向的指针的指针 2)2)指针变量类型是指它所指向实体的类指针变量类型是指它所指向实体的类型型注意:注意:变量可以存放数值或字符,也可以存放地址变量可以存放数值或字符,也可以存放地址指针变量的理解指针变量的理解1 1、指针变量的地址指针变量的地址:指针变量都是有地址的:指针变量都是有地址的:&指针指针变量变量2 2、指针变量的值指针变量的值:所

2、指向变量的地址:所指向变量的地址:&变量变量3 3、指向值指向值:指针:指针(地址地址)对应的内存空间的值:对应的内存空间的值:*指针变量指针变量、*内存地址内存地址4 4、取值运算符取值运算符*与与取址运算符取址运算符&的的结合性自右向左结合性自右向左,优先级处于第优先级处于第2 2位位。&*p=p,*&a=a5 5、野指针野指针:定义指针变量,但没有赋给它确定地址定义指针变量,但没有赋给它确定地址 值。它对于系统或程序都是危险的,务必避免!值。它对于系统或程序都是危险的,务必避免!指针变量的赋值指针变量的赋值 1 1、指针变量的初始化指针变量的初始化 int a=10,b=20;int a

3、=10,b=20;int int *p=&a,p=&a,*q=&b;q=&b;2 2、指针变量的赋值指针变量的赋值 int a=10,b=20;int a=10,b=20;int int *p;p;p=&a;p=&a;*p=b;p=b;1020FFC0FFC2FFC0FFC2FFC4FFC6abpq变量值变量值变量名变量名变量地址变量地址sizeof(char sizeof(char*),sizeof(int),sizeof(int*),sizeof(float),sizeof(float*),sizeof(double),sizeof(double*)sizeof(p),sizeof(siz

4、eof(p),sizeof(*p)p)推广:指向指针的指针二级指针推广:指向指针的指针二级指针指针变量可以保存普通变量的内存地址指针变量可以保存普通变量的内存地址还可以保存指针变量的内存地址还可以保存指针变量的内存地址p是一级地址是一级地址,*p是是p中存放的值中存放的值q是二级地址是二级地址,*q是是q中存放的值中存放的值(一级地址一级地址),*q是是*q中存放的值中存放的值 int a=10,b=20,c=30;int *p;int *q;p=&a;/把变量把变量a的地址赋值给一级指针的地址赋值给一级指针p q=&p;/把指针变量把指针变量p的地址赋值给二级指针的地址赋值给二级指针p指针变

5、量或地址作为函数参数指针变量或地址作为函数参数1 1、地址常量或指针变量作为实际参数地址常量或指针变量作为实际参数(函数调用函数调用)如如:int x=10,y=20,z;:int x=10,y=20,z;z=change z=change(&a,&b&a,&b);/函数调用函数调用2 2、指针变量作为形式参数指针变量作为形式参数(函数原型声明或函数定义函数原型声明或函数定义)如如:int change:int change(int int*a,int a,int*b b)/函数定义函数定义 (*a)+,(a)+,(*b)+;return b)+;return*a+a+*b;b;注意:注意:用

6、指针变量用指针变量(或或地址地址)作函数参数作函数参数,可以实现:,可以实现:通过被调用函数,改变形参中指针变量所指向的通过被调用函数,改变形参中指针变量所指向的实参地址内存放的值,因此返回函数调用时,可以得实参地址内存放的值,因此返回函数调用时,可以得到多个由被调函数形参指向改变的实参值,从而间接到多个由被调函数形参指向改变的实参值,从而间接突破了函数调用仅有一个返回值的局限。突破了函数调用仅有一个返回值的局限。#include void main()int change(int*,int*);/函数原型声明函数原型声明 int x=10,y=20,z;printf(x=%d,y=%dn,x

7、,y);z=change(&x,&y);/函数调用函数调用 printf(x=%d,y=%dn,x,y);printf(x+y=%dn,z);int change(int*a,int*b)/函数定义函数定义(*a)+,(*b)+;return(*a+*b);示例示例#include void main()int change(int*,int*);/函数原型声明函数原型声明 int x=10,y=20,z;int *px=&x,*py=&y;printf(x=%d,y=%dn,x,y);z=change(px,py);/函数调用函数调用 printf(x=%d,y=%dn,x,y);print

8、f(*px=%d,*py=%dn,*px,*py);int change(int*a,int*b)/函数定义函数定义(*a)+,(*b)+;return(*a+*b);void swap1(int a,int b)int t;t=a;a=b;b=t;void swap2(int a,int b)int*t;t=&a;&a=&b;&b=t;辨析函数语法是否正确?功能如何?辨析函数语法是否正确?功能如何?void swap3(int *a,int*b)int t;t=*a;*a=*b;*b=t;void swap4(int*a,int*b)int*t;*t=*a;*a=*b;*b=*t;void

9、swap5(int*a,int*b)int*t;t=a;a=b;b=t;指针变量或地址作为函数参数指针变量或地址作为函数参数 通过实参和形参共同指向同一块存储单元,通过实参和形参共同指向同一块存储单元,实现实参和形参之间的数据共享。实现实参和形参之间的数据共享。在被调用函数在被调用函数中对于形参所指向的值进行改变,而后可以在主中对于形参所指向的值进行改变,而后可以在主调函数中由实参看到这种值的变化,即,调函数中由实参看到这种值的变化,即,被调用被调用函数通过指针变量函数通过指针变量(或或地址共享地址共享),可以改变主可以改变主调调函数实参指针函数实参指针(或地址或地址)所指向所指向(或或存储存

10、储)变量值变量值。因此,调用这种用指针变量或地址作参数因此,调用这种用指针变量或地址作参数的的函数时,得到多个由被调函数改变了的指针变量函数时,得到多个由被调函数改变了的指针变量或地址所指向的值,而不局限于仅仅被调函数可或地址所指向的值,而不局限于仅仅被调函数可能的一个返回值。但是注意:能的一个返回值。但是注意:实参和形参的结合实参和形参的结合是单向值是单向值(地址地址)传递传递,这是不变的。,这是不变的。对于对于同类型同类型的的一维数组一维数组aM和和指针指针*p,若赋值若赋值p=a或或p=&a0,则:,则:数组元素数组元素ai的地址的地址可以等价用:可以等价用:&ai,a+i,&pi,p+

11、i 数组元素数组元素ai的值的值可以等价用:可以等价用:ai,*(a+i),pi,*(p+i)一维数组与一级指针一维数组与一级指针(1)p n:p向前或后移动向前或后移动n sizeof(Type)字节字节(2)指向同数组元素的指针允许关系运算与相减运算。指向同数组元素的指针允许关系运算与相减运算。指针引用数组元素不必每次计算数组元素地址,读写指针引用数组元素不必每次计算数组元素地址,读写 效率比下标法高,但要注意下标是否越界,也要特别效率比下标法高,但要注意下标是否越界,也要特别 注意指针变量当前值注意指针变量当前值(当前指向地址当前指向地址)。理解二维数组理解二维数组aMN为一维数组为一维

12、数组a0a1aiaM-1 a00 a01 a0j a0N-1 a10 a11 a1j a1N-1 ai0 ai1 aij aiN-1 aM-10 aM-11 aM-1i aM-1N-1a一维数组名表示数组首元素地址一维数组名表示数组首元素地址a0=&a00,ai=&ai0a0=&a00,ai=&ai0*a=a0=&a00 a=a0=&a00(a=&a0=&a00)(a=&a0=&a00)注意:地址在数值上即使是一样的,但基类型也可能不同注意:地址在数值上即使是一样的,但基类型也可能不同对于同类型的对于同类型的二维数组二维数组aMN和和一级指针一级指针*p,若赋值若赋值p=&a00、a0、*a

13、,则:,则:数组元素数组元素aij的地址的地址&aij可以可以等价用等价用(二维数组元素按行存放二维数组元素按行存放):&a00+N*i+j a0+N*i+j p+N*i+j 数组元素数组元素aij的值的值可以等价用:可以等价用:*(&a00+N*i+j)*(a0+N*i+j)*(p+N*i+j)二维数组与一级指针二维数组与一级指针示示例例1 1#include void main()int a10=10,20,30,40,50,60,70,80,90,100;int *p=a,*q=a+9,t;for(p=a;p=a+9;p+)printf(%4d,*p);printf(n);/当前当前p指

14、向?指向?*p值?值?p=a;/当前当前p指向?指向?可以省略这一行吗?可以省略这一行吗?while(pq)t=*p;*p=*q;*q=t;p+;q-;/当前当前p,q指向?指向?*p,*q值?值?for(p=a;pa+10;p+)printf(%4d,*p);printf(n);#include void main()void process(int*p);/函数原型声明函数原型声明 int a10=10,20,30,40,50,60,70,80,90,100;int *p=a;for(p=a;p=a+9;p+)printf(%4d,*p);printf(n);/当前当前p指向?指向?p=a

15、;/当前当前p指向?指向?可以省略这一行吗?可以省略这一行吗?process(p);/当前当前p指向?若指向?若process(a)吗?吗?for(p=a;pa+10;p+)/可以省略可以省略p=a吗?吗?printf(%4d,*p);printf(n);/当前当前p指向?指向?void process(int*p)int t,*q=p+9;while(pq)t=*p;*p=*q;*q=t;p+;q-;/当前当前p,q指向?指向?#include void main()void copy_string(char*from,char*to);char a=I am a teacher.;/字符串

16、是地址常量字符串是地址常量char b=You are a student.;/字符串是地址常量字符串是地址常量char*pa=a,*pb=b;puts(a);/若输出若输出pa呢?呢?puts(b);/若输出若输出pb呢?呢?printf(Copy.n);copy_string(pa,pb);/若调用若调用copy_string(a,b)呢?呢?puts(a);/若输出若输出pa呢?呢?puts(b);/若输出若输出pb呢?呢?void copy_string(char*from,char*to)for(;*from!=0;from+,to+)*to=*from;*to=0;/注意处理字符串

17、结束符注意处理字符串结束符,去掉如何?去掉如何?示示例例2 2The string b is:I am a teacher.nt.#include void main()void select_sort(int*,int);/(int*x,int n);int*p,i,a10;p=a;printf(Input 10 numbers:n);for(i=0;i10;i+)scanf(%d,p+);/p p当前指向?当前指向?p=a;/可以省略吗?可以省略吗?select_sort(p,10);/select_sort(a,10);可以吗可以吗?printf(The sorted numbers:n

18、);for(p=a,i=0;i10;i+)/p p当前指向?可以省略当前指向?可以省略p=ap=a吗?吗?/printf(%d,*p),p+;printf(%d,*p+);printf(n);示示例例3 3void select_sort(int*x,int n)int i,j,k,temp;for(i=0;in-1;i+)k=i;for(j=i+1;jn;j+)if(*(x+k)*(x+j)k=j;if(k!=i)temp=*(x+i);*(x+i)=*(x+k);*(x+k)=temp;#include int main()void average_grade(float*,int);/(

19、float*p,int n)float score4=65,57,70,60,58,87,90,81,90,99,100,98;average_grade(*score,12);/注意实参与形参基类型匹配一致注意实参与形参基类型匹配一致 return 0;/计算平均分计算平均分:二维数组用一维指针处理二维数组用一维指针处理void average_grade(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(The average score

20、 of all students=%5.2fn,aver);return;示示例例4 4理解二维数组理解二维数组aMN为一维数组为一维数组a0a1aiaM-1 a00 a01 a0j a0N-1 a10 a11 a1j a1N-1 ai0 ai1 aij aiN-1 aM-10 aM-11 aM-1i aM-1N-1a一维数组名表示数组首元素地址一维数组名表示数组首元素地址ai=&ai0=ai=&ai0=*(a+i),ai+j=&aij=(a+i),ai+j=&aij=*(a+i)+j(a+i)+j*a=a0=&a00 a=a0=&a00(a=&a0=&a00)(a=&a0=&a00)注意注意

21、1 1:地址在数值上即使一样,但基类型可能不同:地址在数值上即使一样,但基类型可能不同 注意注意2 2:i i 和和 j j 移动的数据类型长度单位或基类型不同移动的数据类型长度单位或基类型不同指向二维数组的数组指针行指针指向二维数组的数组指针行指针定义格式:定义格式:数据类型数据类型 (*变量名变量名)每行元素个数每行元素个数 定义了定义了指向二维数组的指针变量指向二维数组的指针变量,该指针变,该指针变量可以保存量可以保存二维数组的行地址二维数组的行地址。例如例如:int int a43a43;int int(*p)3p)3;p=ap=a;054a2765a31032a1981a0210a

22、p问题:定义中的中圆括号可以省略吗?为什么?问题:定义中的中圆括号可以省略吗?为什么?FFCC获取二维数组获取二维数组下标下标ii行地址行地址(行指针或行地址行指针或行地址)p p 二维数组二维数组a a下标下标0 0行地址;行地址;p+1 p+1 二维数组二维数组a a下标下标1 1行地址;行地址;p+2 p+2 二维数组二维数组a a下标下标2 2行地址;行地址;p+i p+i 二维数组二维数组a a下标下标ii行地址行地址。获取获取下标下标ii行行0 0列元素地址列元素地址(变量指针或变量地址变量指针或变量地址)*p p 二维数组二维数组a a下标下标0 0行下标行下标0 0列元素地址;

23、列元素地址;*(p+1)(p+1)二维数组二维数组a a下标下标1 1行下标行下标0 0列元素地址;列元素地址;*(p+2)(p+2)二维数组二维数组a a下标下标2 2行下标行下标0 0列元素地址;列元素地址;*(p+i)(p+i)二维数组二维数组a a下标下标ii行下标行下标0 0列元素地址列元素地址。获取获取下标下标ii行行j j列元素地址列元素地址(变量指针或变量地址变量指针或变量地址)*(p+0)+j(p+0)+j 下标下标0 0行下标行下标j j列元素的地址;列元素的地址;*(p+1)+j(p+1)+j 下标下标1 1行下标行下标j j列元素的地址;列元素的地址;*(p+i)+j

24、(p+i)+j 下标下标ii行下标行下标j j列元素的地址列元素的地址。*(*(p+0)+j)(p+0)+j)a0j a0j元素值;元素值;*(*(p+1)+j)(p+1)+j)a1j a1j元素值;元素值;*(*(p+i)+j)(p+i)+j)aij aij元素值元素值。获取获取第第ii行第行第j j列元素值列元素值(变量值变量值)简单示例简单示例#include void main()int a43;int (*p)3;/指向二维数组的行指针指向二维数组的行指针 int i,j;p=a;/基类型一致基类型一致 for(i=0;i4;i+)for(j=0;j3;j+)scanf(%d,*(p

25、+i)+j);for(i=0;i4;i+)for(j=0;j3;j+)printf(%4d,*(*(p+i)+j);printf(n);1)1)当把当把a a的地址赋给的地址赋给p p后,就可用后,就可用p p来访问来访问二维数组二维数组a a。2)2)*(p+i)+j(p+i)+j与与pi+jpi+j都都表示表示ii行行j j列元素的地址列元素的地址。3)3)(*(p+i)j(p+i)j、*(*(p+i)+j)(p+i)+j)、*(pi+j)(pi+j)都表示都表示ii行行j j列元素列元素。#include int main()/注意一维数组指针方括号中必须是常量表达式注意一维数组指针方括

26、号中必须是常量表达式,且不能省略且不能省略 void search_fail(float(*)4,int);/(float(*p)4,int n)float score4=65,57,70,60,58,87,90,81,90,99,100,98;search_fail(score,3);return;复杂应用复杂应用/查询并输出不及格者的成绩查询并输出不及格者的成绩:二维数组用一维数组指针或行指针处理二维数组用一维数组指针或行指针处理void search_fail(float(*p)4,int n)int i,j,flag;for(i=0;in;i+)flag=0;/注意对每一个学生注意对每

27、一个学生,标志数重新赋初值标志数重新赋初值0 0for(j=0;j4;j+)if(*(*(p+i)+j)60)flag=1;break;if(flag)/flag=1 printf(No.%d fails,his scores are:n,i+1);for(j=0;j4;j+)printf(%6.1ft,*(*(p+i)+j);printf(n);#include#include void main()void select_sort(char(*)20,int);/(char(*p)20,int n)void print(char(*)20,int);/(char(*p)20,int n)c

28、har name20=China,England,France,Germany,America;int n=5;printf(The original sequence:n);print(name,n);select_sort(name,n);printf(nThe sorted sequence:n);print(name,n);void print(char(*p)20,int n)int i;for(i=0;in;i+,p+)/printf(%sn,*p);puts(*p);选择法排序选择法排序/选择法排序选择法排序(按照按照ACSII码值大小排序码值大小排序)void select_s

29、ort(char(*p)20,int n)/char temp20;/等价于下面的两行等价于下面的两行!char array20;char*temp=array;/char*temp;/可以省略可以省略array,直接使用字符指针变量吗?直接使用字符指针变量吗?int i,j,k;for(i=0;in-1;i+)k=i;for(j=i+1;j0)k=j;if(k!=i)strcpy(temp,pk);strcpy(pk,pi);strcpy(pi,temp);指针数组指针数组定义格式:定义格式:数据类型数据类型 *数组名数组名 元素个数元素个数 作用:定义一个数组,数组中每个元素都是指作用:定

30、义一个数组,数组中每个元素都是指针变量,保存指定数据类型的变量的地址针变量,保存指定数据类型的变量的地址(数组数组名是二级指针名是二级指针)。int a43;int*q4;/行数行数q0=a0;q1=a1;q2=a2;q3=a3;054a2765a31032a1981a0210aFFD8q3FFD2q2FFCCq1FFC6q0q 由于数组由于数组q q中的每个元素保存了数组中的每个元素保存了数组a a中中的每行首元素的地址,即,的每行首元素的地址,即,qiqi保存了保存了a a中下中下标标i i行首元素的地址,则:行首元素的地址,则:qi+jqi+j表示表示a a中下标中下标ii行行j j列元

31、素地址,列元素地址,*(qi+j)(qi+j)表示表示a a中下标中下标ii行行j j列元素列元素aijaij。又根据又根据一维数组与指针一维数组与指针的关系,有:的关系,有:q+iq+i是指针数组下标是指针数组下标ii个元素的地址,则个元素的地址,则*(q+i)(q+i)是是指针数组下标指针数组下标ii个元素的值,个元素的值,qiqi与与*(q+i)(q+i)等价等价。因此,因此,*(qi+j)(qi+j)可以写成可以写成*(*(q+i)+j)(q+i)+j)。简单示例简单示例#include void main()int a43;int *q4;/指针数组指针数组 int i,j;for(

32、i=0;i4;i+)qi=ai;for(i=0;i4;i+)for(j=0;j3;j+)scanf(%d,qi+j);for(i=0;i4;i+)for(j=0;j3;j+)printf(%4d,*(*(q+i)+j);printf(n);结论:结论:1 1、利用指针数组可、利用指针数组可以访问二维数组。以访问二维数组。2 2、在访问二维数组在访问二维数组之前,必须先使指针之前,必须先使指针数组的每个元素保存数组的每个元素保存二维数组中每行的首二维数组中每行的首地址地址(行首元素地址行首元素地址)。3 3、访问二维数组元、访问二维数组元素的等价方法。素的等价方法。#include void m

33、ain()int a5=1,3,5,7,9;int*num5=&a0,&a1,&a2,&a3,&a4;int*p;for(p=num;pnum+5;p+)printf(%3d,*p);printf(n);return;一维指针数组与二级指针变量一维指针数组与二级指针变量#include void main()char*name=China,England,France,Germany,America;char*p;int i;for(i=0;i5;i+)p=name+i;printf(%sn,*p);/*p是指针数组元素值是指针数组元素值,即字符串首地址即字符串首地址 一维指针数组与二级指针变

34、量一维指针数组与二级指针变量#include#include void main()void select_sort(char*,int);/(char*name,int n)void print(char*,int);/(char*name,int n)char*name=China,England,France,Germany,America;int n=5;printf(The original sequence:n);print(name,n);select_sort(name,n);printf(nThe sorted sequence:n);print(name,n);void p

35、rint(char*name,int n)/形参是指针数组形参是指针数组 int i;for(i=0;in;i+)printf(%sn,namei);/puts(namei);选择法排序选择法排序/选择法排序选择法排序(按照按照ACSII码值大小排序码值大小排序)/注意注意:传递指针数组时传递指针数组时,处理的应该是指针数组元素的值。处理的应该是指针数组元素的值。/而指针数组的每个元素都是指针变量而指针数组的每个元素都是指针变量,值都是地址。值都是地址。void select_sort(char*name,int n)char*temp;int i,j,k;for(i=0;in-1;i+)k=

36、i;for(j=i+1;j0)k=j;if(k!=i)/是否可以用是否可以用strcpy,为什么?为什么?/指针变量的互换指针变量的互换:交换地址交换地址 temp=namei;namei=namek;namek=temp;格式:格式:数据类型数据类型 *数组名数组名 元素个数元素个数 作用:定义一个数组,其中每个元素保存指作用:定义一个数组,其中每个元素保存指定数据类型的变量地址定数据类型的变量地址(指针数组名是二级指针指针数组名是二级指针)。指针数组指针数组 格式:格式:数据类型数据类型 (*变量名变量名)元素个数元素个数 作用:定义了一个指针变量,该变量可以指作用:定义了一个指针变量,该

37、变量可以指向一个二维数组或二维数组的一行。向一个二维数组或二维数组的一行。指向二维数组的指针指向二维数组的指针 数组数组(行行)指针指针 注意:运算符的优先级与结合性注意:运算符的优先级与结合性 圆括号圆括号()()和数组下标运算符和数组下标运算符的优先级为第的优先级为第1 1级,级,同时使用结合方向自左向右。指针同时使用结合方向自左向右。指针(取值取值)运算符运算符*、取址运算符取址运算符&的优先级为第的优先级为第2 2级,同时使用结合方向级,同时使用结合方向自右向左。自右向左。区别:区别:(*p)N、*qM (*p)N是二是二维数组指针或行指针维数组指针或行指针,指向一,指向一个包括个包括

38、N个元素的二维数组或二维数组的一行,指个元素的二维数组或二维数组的一行,指针的值是该二维数组或其中某行的行地址,而针的值是该二维数组或其中某行的行地址,而*qM是是一维指针数组一维指针数组,该数组有,该数组有M个元素,每一个元素,每一个元素都是指针变量,可以存放地址值。个元素都是指针变量,可以存放地址值。概括概括1 1用指针理解和引用用指针理解和引用二维数组二维数组aMNaMN,可按步进行:,可按步进行:1)1)获得下标获得下标ii行地址行地址:a+ia+i ;2)2)获得下标获得下标ii行行0 0列元素的地址列元素的地址:*(a+i)(a+i);3)3)获得下标获得下标ii行行j j列元素的

39、地址列元素的地址:*(a+i)+j(a+i)+j;4)4)获得下标获得下标ii行行j j列元素的值列元素的值:*(*(a+i)+j)(a+i)+j)。进而,若定义进而,若定义数组行指针数组行指针(*p)Np)N或或指针数组指针数组*qMqM,p=a;p=a;或或 for(i=0;iM;i+)qi=ai;for(i=0;iM;i+)qi=ai;则二维数组则二维数组a a中元素可以用中元素可以用q q或或p p等价引用。等价引用。注意:地址在数值上即使是一样的,但基类型也可能不同注意:地址在数值上即使是一样的,但基类型也可能不同 注意:注意:i i 和和 j j 移动的数据类型长度单位或基类型是不

40、同的!移动的数据类型长度单位或基类型是不同的!概括概括2 2 二维数组、指向一维数组的指针变量二维数组、指向一维数组的指针变量(一维数组一维数组指针或行指针指针或行指针)、指针数组都可以引用二维数组元素。、指针数组都可以引用二维数组元素。因此,因此,二维数组元素的引用方法二维数组元素的引用方法有有3 3种。种。int aMN,i;int (*p)N;列数列数int *qM;行数行数p=a;for(i=0;iM;i+)qi=ai;aij,*(ai+j),*(*(a+i)+j),(*(a+i)jpij,*(pi+j),*(*(p+i)+j),(*(p+i)jqij,*(qi+j),*(*(q+i)

41、+j),(*(q+i)j 对于同类型的对于同类型的二维数组二维数组aMN、二、二维数组行指针维数组行指针(*p)N 、一维指针数组一维指针数组*qM、二级指针二级指针*r,注,注意它们的相互关系:意它们的相互关系:p=a;/正确,正确,二维数组二维数组a基类型是行指针基类型是行指针(*)N for(i=0;im;i+)qi=ai;/正确,正确,符合指针数组的定义符合指针数组的定义 r=q;/正确,正确,q本质上是二级指针本质上是二级指针 q=a;/错误,错误,q数组名是常量,且基类型也不一致数组名是常量,且基类型也不一致 r=a;/错误,基类型不一致错误,基类型不一致 注意:注意:理解二维数组

42、理解二维数组a为一维数组,则作为一维数组为一维数组,则作为一维数组的值,有的值,有ai=*(a+i)。注意:注意:理解理解q是一维数组,则是一维数组,则q+i是数组第是数组第ii个元素的个元素的地址地址qi,而,而*(q+i)是数组第是数组第i个元素的值个元素的值qi,故故q+i与与*(q+i)不同不同,但,但qi与与*(q+i)等价等价。对于同类型的对于同类型的二维数组二维数组aMN和和二维数组指针二维数组指针(*p)N和和一维指针数组一维指针数组*qM,若进行赋值,若进行赋值p=a和和for(i=0;im;i+)qi=ai,则:,则:数组数组行地址行地址(行指针行指针)可以等价用:可以等价

43、用:a+i,p+i 数组数组行首元素的地址行首元素的地址(变量地址变量地址)可以等价用:可以等价用:ai,*(a+i),pi,*(p+i),qi,*(q+i)数组数组元素元素aij的地址的地址(变量地址变量地址)可以等价用:可以等价用:&aij,ai+j,*(a+i)+j&pij,pi+j,*(p+i)+j&qij,qi+j,*(q+i)+j 数组数组元素元素aij的值的值(变量值变量值)可以等价用:可以等价用:aij,*(ai+j),*(*(a+i)+j),(*(a+i)jpij,*(pi+j),*(*(p+i)+j),(*(p+i)jqij,*(qi+j),*(*(q+i)+j),(*(q

44、+i)j 对于同类型的对于同类型的二维数组二维数组aMN和和一维指针数组一维指针数组*qM和二级指针和二级指针*r,若赋值,若赋值for(i=0;im;i+)qi=ai和和r=q,则:,则:数组数组行首元素的地址行首元素的地址(变量地址变量地址)可以等价用:可以等价用:ai,qi,*(q+i),ri,*(r+i)数组数组元素元素aij的地址的地址(变量地址变量地址)可以等价用:可以等价用:&qij,qi+j,*(q+i)+j&rij,ri+j,*(r+i)+j 数组数组元素元素aij的值的值(变量值变量值)可以等价用:可以等价用:pij,*(pi+j),*(*(p+i)+j),(*(p+i)j

45、rij,*(ri+j),*(*(r+i)+j),(*(r+i)jchar string=Welcome you!;char string20;/string=Welcome you!;Error?scanf(%s,string);printf(%sn,string);char *p=Welcome you!;/初始化初始化为字符串首地址为字符串首地址char *p;p=“Welcome you!”;/赋值赋值为地址为地址gets(p);puts(p);/区别区别scanf,printf调用语法和功能调用语法和功能char*string3=Welcome,you,!;char*p=string;

46、/指针数组首元素地址指针数组首元素地址&string0指针与字符串指针与字符串示例示例:注意字符指针的当前指向注意字符指针的当前指向#include void main()char*str=I love China!;/char str=I love China!;/OK?str+=7;puts(str);China!辨辨别别A A:字字符符串串复复制制#include void main()char a=I am a teacher.;char b=You are a student.;char*pa=a;/字符指针指向字符数组字符指针指向字符数组 char*pb=b;puts(a),put

47、s(b);puts(pa),puts(pb);for(;*pa;pa+,pb+)/*pa!=0*pb=*pa;*pb=0;/注意注意pa,pb当前指向当前指向.注释掉会如何呢?注释掉会如何呢?puts(a),puts(b);pa=a,pb=b;/注释掉会如何呢?注释掉会如何呢?puts(pa),puts(pb);字符指针指向变量或字符数组,相应的地址可写字符指针指向变量或字符数组,相应的地址可写辨辨别别B B:字字符符串串复复制制#include void main()/字符指针指向字符串常量字符指针指向字符串常量 char*pa=I am a teacher.;char*pb=You are

48、 a student.;puts(pa),puts(pb);for(;*pa;pa+,pb+)*pb=*pa;*pb=0;puts(pa),puts(pb);字符指针指向字符串,相应的地址是常量,不可写!字符指针指向字符串,相应的地址是常量,不可写!/Error!/Error!第第4 4节节 函数指针与指针函数函数指针与指针函数 函数是一段程序,和数据一起放在内存中的。函数是一段程序,和数据一起放在内存中的。任何一段程序也有一个首地址。函数的调用,实任何一段程序也有一个首地址。函数的调用,实际上是靠一个转向指令使程序转向被调用函数所际上是靠一个转向指令使程序转向被调用函数所在的内存地址而执行的

49、。在的内存地址而执行的。称一个函数在内存中的称一个函数在内存中的首地址首地址(入口地址入口地址)为该函数的指针为该函数的指针,可以用函数,可以用函数指针变量指向它指针变量指向它(函数名函数名)。函数指针变量函数指针变量的定义格式:的定义格式:数据类型数据类型 (*指针指针变量名变量名)()(函数函数参数表列参数表列)这里这里“数据类型数据类型”为函数返回值的数据类型。为函数返回值的数据类型。定义了函数指针变量后,可以把函数名直接赋给定义了函数指针变量后,可以把函数名直接赋给它,使函数指针变量指向了该函数。而后引用函它,使函数指针变量指向了该函数。而后引用函数指针变量,实际上就是数指针变量,实际

50、上就是“调用调用”函数。函数。用函数指针变量调用函数用函数指针变量调用函数#include int add(int x,int y)return x+y;int sub(int x,int y)return x-y;void main()int x,y;int (*fun)(int x,int y);fun=add;x=(*fun)(30,40);fun=sub;y=(*fun)(50,20);printf(x=%d,y=%dn,x,y);定义函定义函数指针数指针变量变量给指针变量给指针变量赋值,并引赋值,并引用指针变量用指针变量函数指针变量指向返回值和参数序列一致的一类函数函数指针变量指向返

51、回值和参数序列一致的一类函数#include void main()int max(int,int);int min(int,int);void process(int,int,int(*fun)(int,int);/函数声明函数声明int a,b;printf(please input two integer:a,bn);scanf(%d,%d,&a,&b);printf(max=);process(a,b,max);/函数调用函数调用printf(min=);process(a,b,min);/函数调用函数调用int max(int x,int y)return(xy?x:y);int m

52、in(int x,int y)return(xy?y:x);void process(int x,int y,int(*fun)(int,int)/函数定义函数定义 int z=(*fun)(x,y);printf(%dn,z);/函数指针变量指向返回值函数指针变量指向返回值,参数序列一致的一类函数参数序列一致的一类函数用用指指向向函函数数的的指指针针作作函函数数参参数数 1 1、函数返回值的类型:、函数返回值的类型:一个函数在被调用之后可以带回一个值返一个函数在被调用之后可以带回一个值返回给主调函数,这个值可以是整型、浮点型、回给主调函数,这个值可以是整型、浮点型、字符型等,当然也可以是指针

53、类型。字符型等,当然也可以是指针类型。2 2、返回指针值函数声明的语法格式如下:、返回指针值函数声明的语法格式如下:类型标识符类型标识符 *函数名函数名(形参列表形参列表)指针型函数返回指针值的函数指针型函数返回指针值的函数#include char*string_name(int n)char*string=illegal string,string 1,string 2,string 3;return(n3)?string0:stringn;void main()int i;char*string;printf(Input one integer i(1=i=3):);scanf(%d,&

54、i);string=string_name(i);printf(The string%d is:n,i+1);printf(%sn,string);指针型函数示例指针型函数示例#include void main()void average_grade(float*,int);/(float*p,int n)/注意注意:一维数组指针方括号中必须是常量表达式,且不能省略一维数组指针方括号中必须是常量表达式,且不能省略 void search_fail(float(*)4,int);/(float(*p)4,int n)float score4=65,57,70,60,58,87,90,81,90

55、,99,100,98;average_grade(*score,12);/注意注意:实参与形参基类型匹配一致实参与形参基类型匹配一致 search_fail(score,3);/计算平均分计算平均分:二维数组用一维指针处理二维数组用一维指针处理void average_grade(float*p,int n)float*p_end=p+n-1;float sum=0,aver;for(;p=p_end;p+)sum=sum+(*p);aver=sum/n;printf(The average score of all students=%5.2fn,aver);方法方法1/查询并输出不及格者的

56、成绩查询并输出不及格者的成绩:二维数组用一维数组指针或行指针处理二维数组用一维数组指针或行指针处理void search_fail(float(*p)4,int n)int i,j,flag;for(i=0;in;i+)flag=0;/注意:对每一个学生,标志数重新赋初值注意:对每一个学生,标志数重新赋初值0 0for(j=0;j4;j+)if(*(*(p+i)+j)60)flag=1;break;if(flag)/flag=1 printf(No.%d fails,his scores are:n,i+1);for(j=0;j4;j+)printf(%6.1ft,*(*(p+i)+j);pr

57、intf(n);/问题:问题:flagflag可以省略吗?可以省略吗?#include void main()float*search(float(*pointer)4);float score4=60,70,80,90,56,89,67,88,34,78,90,66;float*p;int i,j;for(i=0;i3;i+)p=search(score+i);/调用函数查看该学生是否有不及格课程调用函数查看该学生是否有不及格课程if(p=*(score+i)/判断地址以否一致判断地址以否一致 printf(No.%d scores:,i+1);for(j=0;j4;j+)printf(%6

58、.2f,*(p+j);printf(n);方法方法2/函数返回值是地址函数返回值是地址float*search(float(*pointer)4)/注意:这里方括号内注意:这里方括号内4不能省略不能省略 int i;float*pt;pt=*(pointer+1);/问题:该语句作用是什么?问题:该语句作用是什么?for(i=0;i4;i+)if(*(*pointer+i)60)pt=*pointer;break;/问题:该语句作用和下一行语句等价吗?问题:该语句作用和下一行语句等价吗?/return(pt);return(pt);/问题:这一行语句可以省略吗?问题:这一行语句可以省略吗?函数

59、指针变量函数指针变量 指针型函数指针型函数函数是一段程序,和数据一起放在内存中的。函数是一段程序,和数据一起放在内存中的。函数名代表函数的首地址函数名代表函数的首地址(入口地址入口地址)。称一个函称一个函数在内存中的首地址为该函数的指针数在内存中的首地址为该函数的指针。可以定义。可以定义函数指针变量函数指针变量,把函数名直接赋给它,使函数指把函数名直接赋给它,使函数指针变量指向该函数针变量指向该函数。然后。然后引用函数指针变量引用函数指针变量,实,实际上就是际上就是调用函数调用函数。数据类型数据类型 (*指针指针变量名变量名)()(函数函数参数表列参数表列)返回值为指针变量的函数,称为返回值为

60、指针变量的函数,称为指针型函数指针型函数。类型标识符类型标识符 *函数名函数名(形参列表形参列表)注意:注意:运算符的优先级与结合性运算符的优先级与结合性 圆括号圆括号()和数组下标运算符和数组下标运算符的优先级为第的优先级为第1 1级,同时使用结合方向自左向右。级,同时使用结合方向自左向右。区别:区别:指针函数指针函数*fun()和和函数指针函数指针(*fun)()*fun()是指针型函数,即函数返回值是指是指针型函数,即函数返回值是指针型数据,而针型数据,而(*fun)()是指向函数的指针,指针是指向函数的指针,指针的值是函数的入口地址。的值是函数的入口地址。函数指针函数指针 指针函数指针

61、函数命令行参数命令行参数 分析分析DOSDOS状态时以下命令:状态时以下命令:copy c:autoexec.bat d:copy c:autoexec.bat d:dir dir 上面两行都称为上面两行都称为命令行命令行,每个命令行由多个参,每个命令行由多个参数构成,参数之间用空格分隔。数构成,参数之间用空格分隔。第第1 1个命令行的参数分别为个命令行的参数分别为:copy copy、c:autoexec.batc:autoexec.bat、d:d:第第2 2个命令行的参数分别为:个命令行的参数分别为:dirdir mainmain函数中的命令行参数函数中的命令行参数 main main函数

62、也可以定义形式参数,其形参值可以由函数也可以定义形式参数,其形参值可以由命令行参数获取。命令行参数由两部分构成:第命令行参数获取。命令行参数由两部分构成:第1 1个参个参数为数为“可执行程序可执行程序”,第,第2 2个以后参数为个以后参数为“行参数行参数”,行参数往往由多个字符串构成。行参数往往由多个字符串构成。1 1、mainmain函数的一般形式:函数的一般形式:1 1)main(argc,argv)main(argc,argv)int argc;int argc;char char*argv;argv;2 2)main(int argc,char main(int argc,char*a

63、rgv);argv);2 2、mainmain函数参数的来源:命令行函数参数的来源:命令行 3 3、mainmain函数的形参的含义:函数的形参的含义:1 1)argcargc表示命令行中字符串的总个数;表示命令行中字符串的总个数;2 2)argvargvi i 指向第指向第i+1i+1个字符串;个字符串;示例示例1#include void main(int argc,char*argv)int i;for(i=0;iargc;i+)printf(argv%d:%sn,i,argvi);printf(argc=%dn,i);命令行参数的使用:命令行参数的使用:1 VC+1 VC+环境下编译建

64、立可执行程序:环境下编译建立可执行程序:mytest.exemytest.exe2 2 运行运行cmdcmd,在,在DOSDOS下执行程序:下执行程序:mytest welcomemytest welcome(回车回车)#include#include#include void main(int argc,char*argv)int x,s=0,i;if(argc2)printf(input error!n);exit(0);for(i=1;iargc;i+)x=(int)strlen(argvi);s+=x;printf(s=%dn,s);示例示例2指针小结:常用指针类型指针小结:常用指针类

65、型(以整型为例以整型为例)int int*p;p;p p为为指向整型数据的指针变量。指向整型数据的指针变量。变量指针变量指针int(int(*p)n;p)n;p p为为指向含指向含n n个元素的一维个元素的一维数组的指针变量。数组的指针变量。数组指数组指针针int int*pn;pn;定义定义了指针数组了指针数组p p,含有,含有n n个元素,每个元素个元素,每个元素 都是一个都是一个整型指针变量。整型指针变量。指针数组指针数组int(int(*p)();p)();p p为为指向函数的指针,函数返回值为整型。指向函数的指针,函数返回值为整型。函数指针函数指针int int*p();p();p

66、p为返回值是为返回值是整型指针的函数。整型指针的函数。指针函数指针函数int int*p;p;p p为二重为二重指针,它指向一个指向整型数据的指针指针,它指向一个指向整型数据的指针 变量。变量。指针指针指针指针 指向指向voidvoid类型的指针类型的指针1 1、定义:、定义:允许使用允许使用空类型空类型(void)void)指针指针,即不指定该指针指向,即不指定该指针指向 一个固定的类型。一个固定的类型。2 2、语法格式:、语法格式:void void *p;p;3 3、作用:、作用:void void 类型指针不指向一个确定的类型数据,其作用类型指针不指向一个确定的类型数据,其作用 存放一个地址,但该地址存放数据类型不确定存放一个地址,但该地址存放数据类型不确定。注意:注意:1 1)若想将一个若想将一个变量的地址存放到一个变量的地址存放到一个voidvoid指针指针中,中,需进行需进行强制类型的转换强制类型的转换。2 2)也可以定义一个也可以定义一个返回空类型指针返回空类型指针的函数。的函数。动态分配内存空间动态分配内存空间使用使用mallocmalloc函数可以申请动态内存,函数

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!