1 / 35

§10.3 指针数组和指向指针的指针

§10.3 指针数组和指向指针的指针. 10.3.1 指针数组 指针数组 数组的每个元素均存放地址 , 即每个元素是一个指针变量. 格式 类型标识符 *数组名 [ 数组长度 ] 例如 int *p[4]; 定义了 p 是数组 , 有 4 个元素 , 每个元素均为整型指针变量. 操作 指针数组的元素使用同单个指针变量。. 例 10-9 指针数组示例. main() {int i=1,j=2,k=3,m=4; int *p[4],n; p[0]=&i; p[1]=&j;

redford
Download Presentation

§10.3 指针数组和指向指针的指针

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. §10.3 指针数组和指向指针的指针 10.3.1指针数组 指针数组数组的每个元素均存放地址,即每个元素是一个指针变量 格式 类型标识符 *数组名[数组长度] 例如 int *p[4]; 定义了 p是数组,有4个元素,每个元素均为整型指针变量 操作 指针数组的元素使用同单个指针变量。

  2. 例10-9 指针数组示例 main() {int i=1,j=2,k=3,m=4; int *p[4],n; p[0]=&i; p[1]=&j; p[2]=&k; p[3]=&m; for(n=0;n<4;n++) printf("%d ",*p[n]); for(n=0;n<4;n++) printf("%x ",p[n]); } i 1 p p[0] j 2 p[1] p[2] k 3 p[3] m 4 输出 1 2 3 4 i、j、k、m的地址

  3. i i 1 1 p p p[0] p[0] &i &m j j 2 2 p[1] p[1] &j &j p[2] p[2] &k &k k k 3 3 p[3] p[3] &i &m m m 4 4 i 1 p p[0] &i j 2 p[1] &j p[2] &k k 3 p[3] &m m 4 例10-10写出下列程序的运行结果 void main() {int i=1,j=2,k=3,m=4,n,t; int *p[4],*pt; p[0]=&i;p[1]=&j;p[2]=&k;p[3]=&m; pt=p[0];p[0]=p[3];p[3]=pt; for(n=0;n<4;n++) printf("%d ",*p[n]); printf("\n"); p[0]=&i;p[1]=&j;p[2]=&k;p[3]=&m; t=*p[0];*p[0]=*p[3];*p[3]=t; for(n=0;n<4;n++) printf("%d ",*p[n]); printf("\n"); } 输出:4 2 3 1 运行结果如下: 4 2 3 1 4 2 3 1 输出:4 2 3 1

  4. 10.3.2指向指针的指针变量 指向指针的指针变量一个指针变量指向另一个指针变量 如设 i 为整型变量,p为指针变量,pp为指向指针的指针变量 a=10; p=&a; pp=&p; 则 p pp a &p &a 10 指向指针的指针变量的定义 格式 类型标识符 **指针变量名; 如 int **pp; char **gg; 使用时有三种形式 pp, *pp, **pp pp表示指向指针的指针变量的地址值 如 &p *pp表示指向指针变量的地址值 如 &a **pp表示指向指针变量所指单元的值 如 10

  5. 例10-11 写出运行结果 #include<stdio.h> void main() {int a,*p,**pp; p=&a; pp=&p; a=10; printf("a=%d,*p=%d,**pp=%d\n",a,*p,**pp); **p=20; printf("a=%d,*p=%d,**pp=%d\n",a,*p,**pp); **pp=30; printf("a=%d,*p=%d,**pp=%d\n",a,*p,**pp); } p pp a &p &a *pp **pp 运算输出 a=10,*p=10,**pp=10 a=20,*p=20,**pp=20 a=30,*p=30,**pp=30

  6. ppa pa a &pb &a 10 pb ppb b &pa &b 20 例10-12对如下变量定义和初始化,依次执行操作(1)~(3)后,请分析部分变量的值。 pa ppa a int a=10,b=20,t; int *pa=&a,*pb=&b,*pt; int **ppa=&pa,**ppb=&pb,**ppt; &pa &a 10 pb ppb b **ppa **ppb *pa *pb a b 10 20 10 20 10 20 &pb &b 20 操作(1): ppt=ppb;ppb=ppa;ppa=ppt; pa ppa a &pa &a 10 pb ppb b &pb &b 20 **ppa **ppb *pa *pb a b 20 10 10 20 10 20

  7. pa ppa a &pb &b 10 pb ppb b &pa &a 20 pa pa ppa ppa a a &pb &pb &b &b 10 20 pb pb ppb ppb b b &pa &pa &a &a 20 10 再操作(2): pt=pb;pb=pa;pa=pt; pa ppa a &pb &a 10 pb ppb b &pa &b 20 **ppa **ppb *pa *pb a b 10 20 20 10 10 20 再操作(3): t=b;b=a;a=t; **ppa **ppb *pa *pb a b 20 10 10 20 20 10

  8. 间接访问利用指针变量访问另一个变量 利用指针变量访问一个变量值,称为间接访问,叫单级间址 利用指向指针的指针变量访问一个变量值称为间接的间接访问, 叫二级间址。依次类推可以延伸更多的多级间址。 指针变量 变量 单级间址 地址 变量值 指向指针的指针 指针变量 变量 二级间址 地址1 地址2 变量值 指向指针的指针的指针 三级间址 地址1 指针变量 变量 指向指针的指针 地址3 变量值 地址2

  9. main() {int i,*q,**p,***s; i=10; q=&i; p=&q; s=&p; printf("s=%o\n",s); printf("*s=%o\n",*s); printf("**s=%o\n",**s); printf("***s=%o\n",***s); } 运行结果 s=4577564 *s=4577570 **s=4577574 ***s=12 注使用三级间址在二级间址的“**”再加上一个“*”,多级 间址依次类推。

  10. 10.3.3指针数组、二维字符数组和字符串 存储多个字符串,通常使用二维字符数组(字符串数组 )。 如 char a[][6]={"Wang","Li","Zheng","Jin","Xian"}; a 字符串具有两个要点: 起始地址和结束符'\0' 二维数组的行元素是行起始地址 显然二维数组一行是一个字符串 a[0] a[1] a[2] a[3] a[4] 例 main() {int i;char a[5][6]={"Wang","Li","Zheng","Jin","Xian"}; for(i=0;i<5;i++) printf("%s",a[i]); } 输出: Wang Li Zheng Jin Xian

  11. pname W a n g \0 L i \0 Z h e n g \0 J i n \0 X i a n \0 由于二维数组的列必须确定长度, 要按字符串中的最大长度确定列数,这样做浪费了内存资源 a 如改用指向字符串的指针数组 char *pname[] ={"Wang","Li","Zheng","Jin","Xian"}; 例 main() {int i; char *pname[] ={"Wang","Li","Zheng","Jin","Xian"}; for(i=0;i<5;i++) printf("%s", pname[i]); } 输出: Wang Li Zheng Jin Xian

  12. month_name[0] month_name[1] month_name[2] month_name[3] month_name[4] month_name[5] month_name[6] month_name[7] month_name[8] month_name[9] 例10-13输入月份,输出对应的英文名称。例如,输入5,输出May 分析 定义一个有13个元素的指针数组month_name,首元素指向一个空字符串,其系元素依次指向一个英文月份的名称,数组下标对应月份,输出对应的字符串 void main() {int month; char *month_name[]={"","January","February","March","April", "May","June","July","August","September","October","November", "December"}; printf("Enter month:\n"); scanf("%d",&month); if(month>=1&&month<=12) printf("%s\n",month_name[month]; else printf("Illegal month"); }

  13. 例10-14将5个字符串从小到大排序后输出。(用冒泡法)例10-14将5个字符串从小到大排序后输出。(用冒泡法) 分析 与整数排序类同,但数据类型不同 void sort(char*a[],int n) {int i,j; char*t; for(i=0;i<n-1;i++) for(j=0;j<n-1-i;j++) if(strcmp(a[j],a[j+1])>0) {t=a[j];a[j]=a[j+1];a[j+1]=t;} } main() {int i;char*a[5]={"Wang","Li", "Zheng","Jin","Xian"}; sort(a,5); for(i=0;i<5;i++) printf("%s ",a[i]); } void sort(int a[],int n) {int i,j;intt; for(i=0;i<n-1;i++) for(j=0;j<n-1-i;j++) if(a[j]>a[j+1]) {t=a[j];a[j]=a[j+1];a[j+1]=t;} } main() {int i;inta[5]={6,5,2,81}; sort(a,5); for(i=0;i<5;i++) printf("%d ",a[i]); }

  14. 注:指针数组的元素所指向各自的字符串的,需要交换时,直接交换指针数组元素的值,即改变它们的指向。注:指针数组的元素所指向各自的字符串的,需要交换时,直接交换指针数组元素的值,即改变它们的指向。 void sort(char*a[],int n) {int i,j;char*t; for(i=0;i<n-1;i++) for(j=0;j<n-1-i;j++) if(strcmp(a[j],a[j+1])>0) {t=a[j];a[j]=a[j+1];a[j+1]=t;} } main() {int i;char*a[5]={"Wang","Li", "Zheng","Jin","Xian"}; sort(a,5); for(i=0;i<5;i++) printf("%s ",a[i]); } a W a n g \0 a[0] a[1] L i \0 Z h e n g \0 a[2] a[3] J i n \0 a[4] X i a n \0 a W a n g \0 a[0] a[1] L i \0 Z h e n g \0 a[2] a[3] J i n \0 a[4] X i a n \0

  15. 指针数组做 改为二维字符数组做 void sort(char *a[],int n) {int i,j;char *t; for(i=0;i<n-1;i++) for(j=0;j<n-1-i;j++) if(strcmp(a[j],a[j+1])>0) {t=a[j];a[j]=a[j+1];a[j+1]=t;} } main() {int i;char *a[5]={"Wang","Li", "Zheng","Jin","Xian"}; sort(a,5); for(i=0;i<5;i++) printf("%s",a[i]); } void sort(char a[][6],int n) {int i,j;char t[6]; for(i=0;i<n-1;i++) for(j=0;j<n-1-i;j++) if(strcmp(a[j],a[j+1])>0) {strcpy(t,a[j]); strcpy(a[j],a[j+1]); strcpy(a[j+1],t);} } main() {int i;char a[5][6]={"Wang","Li", "Zheng","Jin","Xian"}; sort(a,5); for(i=0;i<5;i++) printf("%s",a[i]); }

  16. 二维字符数组做 指针数组做 a a a[0] W a n g \0 a[0] a[1] a[1] L i \0 a[2] Z h e n g \0 a[2] a[3] a[3] J i n \0 a[4] a[4] X i a n \0 a W a n g \0 a[0] a[0] a[1] a[1] L i \0 Z h e n g \0 a[2] a[2] a[3] J i n \0 a[3] a[4] X i a n \0 a[4] 注二维字符数组多用了内存 二维字符数组直接改变存储单元字符串内容,而指针数组改变指针所指的方向

  17. 1 a[0] p n[0] &i a[1] 3 &j n[1] &k n[2] a[2] 5 &m n[3] a[3] 7 10.3.4指针数组和二级指针 指针数组的每个元素是指针变量,指向指针数组元素的指针变量 必须是二级指针 例 main() {int a[5]={1,3,5,7}; int *n[4]={&a[0],&a[1], &a[2],&a[3]}; int **p,i; p=n; for(i=0;i<4;i++) { printf("%d\t",**p);p++; } } 运算结果 1 3 5 7

  18. main() {int i,j;char *a[5]={"Wang","Li","Zheng","Jin","Xian"},**p; p=a; for(i=0;i<5;i++) printf("%s %s %s %s\n ",a[i],*(a+i),p[i],*(p+i)); i=0;j=2; printf("%c %c %c %c\n",*(a[i]+j),*(*(a+i)+j),*(p[i]+j),*(*(p+i)+j)); } 输出: Wang Wang Wang Wang Li Li Li Li Zheng Zheng Zheng Zheng Jin Jin Jin Jin Xian Xian Xian Xian n n n n a[0]+2 p,a, a+0 a+1 W a n g \0 a+2 L i \0 a+3 Z h e n g \0 a+4 J i n \0 X i a n \0

  19. 改为二维数组存放字符串组 char a[][6]={"Wang","Li","Zheng","Jin","Xian"}; a[0]+2,&a[0][2] a, a+0 a+1 a+2 a+3 a+4 注:a+i,a[i]是行指针,也可用*(a+i)表示 但不能用指向指针的指针变量(二级指针)指向二维数组的字符串 char a[5][6],**p; p=a; 不允许 而是用要用行指针指向字符串,行指针定义: char (*p)[6]; 下标表示字符串的长度

  20. main() {int i,j;char a[5][6]={"Wang","Li","Zheng","Jin","Xian"},(*p)[6]; p=a; for(i=0;i<5;i++) printf("%s %s %s %s %s\n ",a+i,*(a+i),a[i],p[i],*(p+i)); i=0;j=2; printf( "%c %c %c %c %c\n",a[i][j],*(a[i]+j),*(*(a+i)+j),*(p[i]+j),*(*(p+i)+j)); } 输出: Wang Wang Wang Wang Wang Li Li Li Li Li Zheng Zheng Zheng Zheng Zheng Jin Jin Jin Jin Jin Xian Xian Xian Xian Xian n n n n n

  21. 10.3.5命令行参数(指针数组作为main( )函数的形参) 一般使用main函数无参数 定义main( ) {... } 其实 main( )函数可以带2个参数 定义main( int argc, char *argv[]) {... } 其中 argc 是整型变量 *argv[] 是指向字符串的指针数组 注argc,argv这两个参数是系统规定的;但参数名可以任取,习惯上 按上述名取。

  22. 利用命令行传递参数 格式 命令名 参数1,参数2,...,参数n C语言程序经过编译、连接产生执行文件 文件名.exe 则文件名就是命令名,而后的实参相应传递给这两个参数 其中 argc 存放命令行的字符串个数,包括命令名 n+1 argv[0] 存放命令名(tc包括路径) argv[1] 存放参数1 argv[2] 存放参数2 ... argv[n] 存放参数n

  23. void main(argc,argv) int argc; char *argv[]; {int i; for(i=0;i<argc;i++) printf("%s\n",argv[i]); } 存于文件file.c,经过编译、连接产生执行文件file.exe 运行:D:\c_now\10\file\debug>file China Beijing argc=3 argv 输出:file China Beijing

  24. 对于如下程序test.c, 编译后运行 test hello world 将输出_________: #include <stdio.h> main(int agrc, char *argv[]) { printf("%d %s", argc, argv[1]+1); } 答案: 3 ello 将程序prog.c编译后运行:prog –nla hello world 则 *(*(argv+2)) 是______。 A、'p' B、'-' C、'h' D、'w' 答案: C

  25. §10.4 指针和函数 10.4.1 指针作为函数的返回值 函数返回值可以是数值、字符同样也可以返回地址值(指针) 1.返回指针的函数的定义 格式 类型标识符 *函数名(参数表) 参数说明; { return(指针); } 与一般函数定义区别 (1)在函数名前多了* (2)在 return语句中要求地址值 例如 int *a(x,y) int x,y; {int *p; … return(p); } 2.返回指针的函数调用形式同一般函数调用 函数名(实参表)

  26. 例10-18输入一个字符串和一个字符,如果该字符在字符串中,就从该字符首次出现的位置开始输出字符串中的字符。例10-18输入一个字符串和一个字符,如果该字符在字符串中,就从该字符首次出现的位置开始输出字符串中的字符。 例如,输入字符r和字符串program后,输出rogram。 要求定义函数match(s,ch)在字符串,中查找字符ch,如果找到,返回第一次找到的该字符在字符串中的位置(地址);否则,返回空指针NULL。 分析:match(s,ch)返回一个地址,所以函数返回值的类型是指针。 char *match(char *s,char ch) {while(*s!='\0') if(*s==ch) return s; else s++; return(NULL); } main() {char ch,str[80],*p=NULL; scanf("%s",str);ch=getchar(); if((p=match(str, ch))!=NULL) printf("%s\n",p); else printf("Not found\n");} 输入: program r str s 输出: rogram

  27. 例10-19定义函数mystrcpy(char *s,char *t),将t复制到s,并返回s的值。 分析:要求返回s的值,即返回字符串的起始地址。 char *mystrcpy(char *s,char *t) { char *ss=s; while(*s++=*t++) return ss; } 例10-8 void strcpy(char *to,char *from) /*第2.2版*/ { while(*to++=*from++) } 注: 由于在函数中改变了指针s的值,又定义了一个指针ss保存s的初值

  28. 10.4.2函数指针和指向函数的指针变量 函数指针函数在编译时分配内存给一个入口地址,这个入口地址以 函数名表示,称为函数指针。所谓入口地址函数编译后成为若干条 指令依次存储在内存,第一条指令存储的单元地址称为入口地址 指向函数的指针变量指针变量的值是函数的入口地址 1.用指向函数的指针变量调用函数 例 求a和b的大值 max max(x,y) int x,y; {int z; if(x>y) z=x; else z=y; return(z); } main() {int a,b,c; scanf("%d,%d",&a,&b); c=max(a,b); printf("%d\n",c); }

  29. 若使用指向函数指针变量调用函数 main() {int a,b,c,(*p)(); scanf("%d,%d",&a,&b); p=max; c=p(a,b); printf("%d\n",c); } max(x,y) int x,y; {int z; if(x>y) z=x; else z=y; return(z); } max p 2.指向函数的指针变量定义 格式 类型标识符 (*指针变量名)( ); 其中 (1)类型标识符为指向函数的返回值的类型 如 int (*p)( ); 返回值为整型 (2) (*指针变量名)( )表示定义一个指向函数的指针变量,专门 用来存放函数的入口地址

  30. 3.指向函数的指针变量调用函数 (1)将函数的入口地址赋于指针变量 格式 指针变量名=函数名; 如上例中 p=max; (2)调用形式 格式(*指向函数的指针变量名)(函数实参表) 或 指向函数的指针变量名(函数实参表) 如上例中 c=p(a,b); 或 c= (*p)(a,b); 注 函数的指针变量只能用于调用函数,而不能进行指针变量的个各 种运算。如 p++,p+i,*p+i 是不允许

  31. 例10-20函数指针示例 #include <stdio.h> int odd(int x) {return x%2!=0;} int even(int x){return x%2==0;} void main() {int r1,r2,r3,r4; int (*fp)(); /*定义函数指针*/ fp=odd; /*将函数odd的入口地址赋给函数指针*/ rl=odd(5); /*通过函数名调用函数odd*/ r2=(*fp)(5); /*通过函数指针调用函数odd*/ printf("%d,%d\n",r1,12); fp=even; /*将函数even的入口地址赋给函数指针*/ r3=even(5); /*通过函数名调用函数even*/ r4=(*fp)(5); /*通过函数指针调用函数even*/ printf("%d,%d\n",r3,r4); } 运行 1,1 0,0

  32. 4. 函数指针作为函数参数 形参为指向函数的指针变量(函数指针) 实参可为函数名或已赋值的函数指针 虚实结合:形参指向实参所代表函数的入口地址。 指向函数的指针变量作为函数参数给模块编程带来较大的灵活性 例10-21编一个求任意函数的定积分,用梯形公式积分 然后计算 分析:先编一个任意函数的定积分 函数模块 然后调用函数实现定积分。

  33. 编函数,按积分的几何意义采取数值积分 分析 对 f(a+i*h) f(a+(i-1)h) 等分n个小梯形 f(x) 小梯形宽: h 小梯形面积: n i 1 2 x a+2h a b a+(i-1)h 0 a+h a+i*h 则梯形积分公式 函数的参数决定: 已知a,b,n和f(x) 求积分值

  34. 则梯形积分公式 double calc(f,a,b,n) double (*f)(),a,b;int n; {int i; double h,s; s=((*f)(a)+(*f)(b))/2; h=(b-a)/n; for(i=1;i<n;i++) s=s+(*f)(a+i*h); s=s*h; return(s); } double f1(double x) {return(x*x);} double f2(double x) {return(sin(x)/x);} double f3(double x) {return(x/(1+x*x));} void main() {float y1,y2,y3; y1=calc(f1,0.0,1.0,100); y2=calc(f2,1.0,2.0,100); y3=calc(f3,0.0,1.0,100); printf("y1=%f\n",y1); printf("y2=%f\n",y2); printf("y3=%f\n",y3); } 运行: y1=0.333350 y2=0.659329 y3=0.346565

  35. 习题10(2) 1.选择题 (5)、(6) 2.阅读题 (4)、(5) 编程题 7, 9,11 概念题 12

More Related