C语言程序设计-基于计算思维的培养 课件 第10章 指针与数组_第1页
C语言程序设计-基于计算思维的培养 课件 第10章 指针与数组_第2页
C语言程序设计-基于计算思维的培养 课件 第10章 指针与数组_第3页
C语言程序设计-基于计算思维的培养 课件 第10章 指针与数组_第4页
C语言程序设计-基于计算思维的培养 课件 第10章 指针与数组_第5页
已阅读5页,还剩44页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第十章指针与数组目录/Contents指针运算指针与一维数组、二维数组的关系一维数组、二维数组作函数参数指针数组、命令行参数动态数组、动态内存分配指针运算int

a[10]={72,56,89,74,86,100,40,63,95,78};int

*p=a;等价于int*p=&a[0];pa当指针指向数组元素时,可以使用指针代替数组下标进行操作。80*p=80;对指针变量执行算术运算,访问数组的相关元素。对指针变量可以执行哪些算术运算呢?---加整数、减整数、两个指针相减。指针加一个整数int

a[10]={72,56,89,74,86,100,40,63,95,78};int

*p,

*q;p=&a[i];q=p+j;指针指向a[i],则p+j指向a[i+j](前提是a[i+j]必须存在)。paqap+j表示指向a的第j个元素,不是加j个字节,具体依赖于p的基类型。指针加一个整数pa指针的算术运算允许通过对指针变量循环自增来访问数组的元素。for(p=a;p<a+10;p++){ printf(“%4d”,*p);}指针减一个整数int

a[10]={72,56,89,74,86,100,40,63,95,78};int

*p,

*q;p=&a[i];q=p-j;指针p指向a[i],则p-j指向a[i-j](前提是a[i-j]必须存在)。只有当指针指向数组时,指针的算术运算才有意义。qapaint

a[10]={72,56,89,74,86,100,40,63,95,78};int

*p,

*q;p=&a[i];q=p-j;指针相减char

a[10];char

*p,

*q;p=&a[i];q=&a[j];当两个指针相减时,则p-q的结果为指针间的距离。通过这种方法可以计算数组中的元素个数。qapa注意:只有当两个指针指向同一个数组时,指针相减才有意义。指针的关系比较运算qapa指针p在前,q在后,则p>=q为真(q>=p为假)。只有当指针指向数组时,指针的比较运算才有意义。比较的结果依赖于数组中两个元素的相对位置。char

a[10];char

*p,

*q;p=&a[i];q=p-j;指针小结指针变量与其它类型变量的共性:-内存中占据一定大小的存储单元(通常4个字节)-先定义,后使用。指针变量:指针类型的变量,保存地址型数据。特殊性:-指针变量保存的内容只能是地址(变量、数组、函数的地址)。-必须先初始化后才能使用,否则指向不确定的存储单元。-只能指向同一类型的变量。-指针运算:加、减整数,自增、自减,相减,比较,赋值。问题的提出inta[4]={1,2,3,4};0x0037b000a[0]0x0037b0040x0037b0080x0037b00Ba….…...1int

*pa=a;paint

*pa=&a[0];234a[1]a[2]a[3]数组名是一个常量指针不能修改该指针的指向指针可当数组名使用指针与一维数组的关系inta[4]={1,2,3,4};0x0037b000a[0]0x0037b0040x0037b0080x0037b00Ba….…...1int

*pa=a;paint

*pa=&a[0];234a[1]a[2]a[3]数组元素的等价引用形式a[i]*(a+i)pa[i]*(pa+i)a+1*(a+1)pa[0]*(pa+2)*pa&a[1]pa+1a+i&a[i]pa+ia+2&a[2]pa+2用下标访问数组元素的本质:-计算该元素在内存中的地址指针与一维数组的关系inta[N];0x0037b000a[0]0x0037b0040x0037b0080x0037b00Ba….…...1p234a[1]a[2]a[3]for(i=0;i<N;i++)scanf("%d",&a[i]);

for(i=N-1;i>=0;i--)printf("%d",a[i]);for(p=a;p<(a+N);p++)scanf("%d",p);

for(p=a;p<(a+4);p++)printf("%d",*p);*p*pa+4for(i=0;i<N;i++)scanf("%d",a+i);

for(i=N-1;i>=0;i--)printf("%d",*(a+i));p=a;for(i=0;i<N;i++)scanf("%d",&p[i]);for(i=N-1;i>=0;i--)printf("%d",p[i]);#include<stdio.h>#defineN10intmain(){inta[N],i;printf("Enter%dnumbers:",N);for(i=0;i<N;i++){ scanf("%d",&a[i]);}printf("Reverseorder:");for(i=N-1;i>=0;i--){ printf("%d",a[i]);}printf("\n");return0;}#include<stdio.h>#defineN10intmain(){inta[N],i;printf("Enter%dnumbers:",N);for(i=0;i<N;i++){ scanf("%d",a+i);}printf("Reverseorder:");for(i=N-1;i>=0;i--){ printf("%d",*(a+i));}printf("\n");return0;}【例10.1】

实现数组元素的逆序显示。数组下标法数组下标法#include<stdio.h>#defineN10intmain(){inta[N],*p;printf("Enter%dnumbers:",N);for(p=a;p<a+N;p++){ scanf("%d",p); }printf("Reverseorder:");for(p=a+N-1;p>=a;p--){ printf("%d",*p); }printf("\n");return0;}#include<stdio.h>#defineN10intmain(){inta[N],*p,i;printf("Enter%dnumbers:",N);p=a;for(i=0;i<N;i++){ scanf("%d",&p[i]);}printf("Reverseorder:");for(i=N-1;i>=0;i--){ printf("%d",p[i]);}printf("\n");return0;}指针与一维数组的关系指针下标法指针法指针、一维数组作函数参数【例10.2】

编写程序将数组中的元素按相反顺序存放。#include"stdio.h"#defineN10voidInv(intx[],intn);intmain(){inti,a[N]={3,7,9,11,0,6,7,5,4,2};Inv(a,N);printf("Thearrayhasbeenreverted:\n");for(i=0;i<N;i++)printf("%d,",a[i]);printf("\n");return0;}voidInv(intx[],intn){intt,i,j,m=(n-1)/2;for(i=0;i<=m;i++){j=n-1-i;t=x[i];x[i]=x[j];x[j]=t;}}数组下标法被调函数的形参声明为数组类型,用下标法访问数组元素指针与一维数组的关系#include"stdio.h"#defineN10voidInv(int*x,intn);intmain(){inti,a[10]={3,7,9,11,0,6,7,5,4,2};Inv(a,10);printf("Thearrayhasbeenreverted:\n");for(i=0;i<10;i++)printf("%d,",a[i]);printf("\n");return0;}voidInv(int*x,intn){intt,i,j,m=(n-1)/2;for(i=0;i<=m;i++){j=n-1-i;t=x[i];x[i]=x[j];x[j]=t;}}指针下标法被调函数的形参声明为指针类型,指针下标法访问数组元素指针与一维数组的关系#include"stdio.h"#defineN10voidInv(int*x,intn);intmain(){inti,a[10]={3,7,9,11,0,6,7,5,4,2},*p=a;p=a;Inv(p,10);printf("Thearrayhasbeenreverted:\n");for(p=a;p<a+10;p++)printf("%d,",*p);return0;}voidInv(int*x,intn){intt,*i,*j,*p,m=(n-1)/2;i=x;j=x+n-1;p=x+m;for(;i<=p;i++,j--){t=*i;*i=*j;*j=t;}}指针法被调函数的形参声明为指针类型,用指针法访问数组元素#include"stdio.h"#defineN10voidInv(intx[],intn);intmain(){inti,a[10]={3,7,9,11,0,6,7,5,4,2},*p=a;p=a;Inv(p,10);printf("Thearrayhasbeenreverted:\n");for(p=a;p<a+10;p++)printf("%d",*p);return0;}voidInv(intx[],intn){intt,*i,*j,*p,m=(n-1)/2;i=x;j=x+n-1;p=x+m;for(;i<=p;i++,j--){t=*i;*i=*j;*j=t;}}指针与一维数组的关系指针法被调函数的形参声明为数组类型,用指针法访问数组元素指针与二维数组的关系可将二维数组看做一维数组,其每个数组元素又是一个一维数组按行顺序存放所有元素a[0]a[1]a[0]+1a[0]+2&a[0][0]&a[1][0]&a[1][1]a[1]+1&a[1][2]&a[0][1]&a[0][2]

a[0][0]

a[0][1]

a[0] a[0][2] a[0][3] a[1][0]

a[1] a[1][1] a[1][2]a[1][3]

a

a[1]+2shorta[2][4];aa+1a[0]+3&a[0][3]&a[1][3]a[1]+3指针与二维数组的关系

a[0][0]

a[0][1]

a[0] a[0][2] a[0][3] a[1][0]

a[1] a[1][1] a[1][2]a[1][3]

a

shorta[2][4];aa+1a代表二维数组的首地址,第0行的地址,行地址a+i代表第i行的地址但并非增加i个字节!指针与二维数组的关系

a[0][0]

a[0][1]

a[0] a[0][2] a[0][3] a[1][0]

a[1] a[1][1] a[1][2]a[1][3]

a

shorta[2][4];aa+1a[0]a[1]&a[0][0]&a[1][0]*(a+i)即a[i]代表第i行第0列的地址,列地址*(a+i)+j即a[i]+j代表第i行第j列的地址&a[i][j]&a[1][2]a[1]+3*(*(a+i)+j)即a[i][j]代表第i行第j列的内容指针与二维数组的关系shorta[2][4];aa+1二维数组的行指针int(*p)[4];p=a;//用行地址初始化逐行查找-〉逐列查找for(i=0;i<m;i++)

for(j=0;j<n;j++)printf("%d",*(*(p+i)+j));pp指针与二维数组的关系二维数组的列指针int*p;p=*a;//用列地址初始化逐个查找——相对偏移量for(i=0;i<m;i++)

for(j=0;j<n;j++)printf("%d",*(p+i*n+j));shorta[2][4];a[0]*app[i*n+j]指针与二维数组的关系【例10.3】

编写程序,定义一个3行4列的二维数组,然后用列指针和行指针分别输出这个数组中的元素。#include<stdio.h>intmain(){inta[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};int*p;for(p=a[0];p<a[0]+12;p++){if((p-a[0])%4==0)printf("\n");printf("%4d",*p);}return0;}运行结果:(屏幕显示)

1357911131517192123列指针指针与二维数组的关系#include"stdio.h"intmain(){inta[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};intj,(*p)[4];for(p=a;p<a+3;p++)for(j=0;j<4;j++){if(j%4==0)printf("\n");printf("%4d",*(*p+j));}printf("\n");return0;}运行结果:(屏幕显示)

1357911131517192123行指针指向二维数组的指针作函数参数【例10.4】

编写程序,从键盘输入若干学生4门课的成绩,计算总平均分,查找并输出某个学生的成绩,查找一门以上课不及格的学生,并输出其各门课的成绩。#include"stdio.h"#defineROW10#defineCOL4voidTotalAverage(float*p,intn); voidSearchScore(float(*p)[COL],intn);voidSearchFailScore(float(*p)[COL],intn);voidReadScore(float(*p)[COL],longnum[],intm,intn);intmain(){floatscore[ROW][COL];longnum[ROW];intn;printf("Inputtotalstudents:");scanf("%d",&n);ReadScore(score,num,n,4);TotalAverage(*score,n*COL);SearchScore(score,2);SearchFailScore(score,2);return0;}指针与二维数组的关系voidReadScore(float(*p)[COL],longnum[],intm,intn){inti,j;printf("Inputstudent'sID&scoreas:MTENCPDSSE:\n");for(i=0;i<m;i++){scanf("%ld",&num[i]);for(j=0;j<n;j++){scanf("%f",*(p+i)+j);}}}voidTotalAverage(float*p1,intn){float*p_end,sum=0,aver;p_end=p1+n-1;for(;p1<=p_end;p1++)sum=sum+(*p1);aver=sum/n;printf("average=%5.2f\n",aver);}形参声明为指向二维数组的列指针指针与二维数组的关系voidSearchScore(float(*p)[COL],intn){inti;printf("No.%d:\n",n);for(i=0;i<COL;i++)printf("%5.2f",*(*(p+n-1)+i));putchar('\n');}voidSearchFailScore(float(*p)[COL],intn){inti,j,flag;for(i=0;i<n;i++){flag=0;for(j=0;j<COL;j++)if(p[i][j]<60)flag=1;if(flag==1){printf("No.%disfail,hisscoresare:\n",i+1);for(j=0;j<COL;j++)printf("%5.1f",p[i][j]);printf("\n");}}}形参声明为指向列数已知的二维数组的行指针指针和数组作函数参数通过指针或数组参数,使调用者获得修改后的数据通过一个参数把大量的数据送到函数内如果只向内传送数据,就把参数定义为const,防止意外修改数据,也让函数的功能更明确voidPrintArray(const

int*p,intn)

{

......

}voidPrintArray(const

inta[],intn)

{

......

}指针与二维数组关系小结指针与二维数组间关系的关键理解二维数组的行指针与列指针二维数组在内存中按行存储,但可以用两种方式来处理它

a[0][0]

a[0][1]

行指针

a[0] a[0][2] a[0][3] a[1][0]

a[1] a[1][1] a[1][2]a[1][3] pp++int(*p)[4];p=a;//&a[0]int*p;p=*a;//a[0]pp++p++p++a[i][j]*(*(p+i)+j)p不动a[i][j]*(*p+j)p动a[i][j]*(p+i*n+j)p不动a[i][j]*pp动指针数组及其应用指针数组元素均为指针类型数据的数组定义格式为:

数据类型*数组名[数组长度];

char*ptr[5];

int*p[5];

问题的提出:存储一个长短不一字符串集合的最佳方式是什么?存储一个字符串集合需要使用二维字符数组字符指针数组,每个数组元素都是一个指向一个字符串的指针指针数组及其应用问题的解决:如何访问指针数组指向的字符串呢?如何访问二维字符数组中的字符串?charcountry[][10]={“China”,”Japan”,”France”,”Australia”,””England};for(i=0;i<5;i++){ printf(“%s\n”,country[i]);}访问指针数组指向的字符串与访问二维字符数组中的字符串相同的。Char*country[]]={“China”,”Japan”,”France”,”Australia”,””England};countrycountry基本数据类型int、long、char、short、float、double……数组是一种数据类型是从其他类型派生的类型每个元素都有一个类型指针是一种数据类型是从其他类型派生的类型XX类型的指针任何类型都可以作指针或者数组的基类型如指针作为数组的基类型---指针数组char*ptr[5];指针、数组以及其他的类型混合【例10.5】

编写程序,从键盘输入若干字符串,并按字典顺序将它们排序输出。指针数组及其应用charstr[N][MAX_LEN];...for(i=0;i<n-1;i++) {

for(j=i+1;j<n;j++) {

if(strcmp(str[j],str[i])<0) {

strcpy(temp,str[i]); strcpy(str[i],str[j]); strcpy(str[j],temp); } }}MAX_LENN交换字符数组中的字符串物理排序字符串排序前字符串排序后指针数组及其应用char

*ptr[N];...for(i=0;i<n-1;i++){

for(j=i+1;j<n;j++){

if(strcmp(ptr[j],ptr[i])<0){temp=ptr[i];ptr[i]=ptr[j];ptr[j]=temp;} }}交换指针数组中的字符串指针索引排序N指针数组及其应用#include<stdio.h>#include<string.h>#defineM20#defineN10voidReadLine(char*str[],intn);voidSortName(char*str[],intn);voidPrint(char*str[],intn);intmain(){ inti,n; charname[M][N]; char*ptr[M]; printf("Inputthenumberofpersons:"); scanf("%d",&n); for(i=0;i<n;i++) { ptr[i]=name[i]; } getchar(); printf("Inputtheirnames:\n"); ReadLine(ptr,n); SortName(ptr,n); printf("Aftersortedresults:\n"); Print(ptr,n); return0;}在使用指针数组之前必须对数组元素进行初始化指针数组及其应用voidSortName(char*str[],intn){inti,j,k;char*temp=NULL;for(i=0;i<n-1;i++){k=i;for(j=i+1;j<n;j++){ if(strcmp(str[k],str[j])>0) { k=j; }}if(k!=i){ temp=str[i]; str[i]=str[k]; str[k]=temp;}}}voidReadLine(char*str[],intn){ inti; for(i=0;i<n;i++) gets(str[i]);}voidPrint(char*str[],intn){ inti; for(i=0;i<n;i++) printf("%s\n",str[i]);}指针数组作为main的命令行参数什么是命令行参数?Unix、Linux等操作系统都是使用字符式命令行界面,Windows下的Dos也是如此。例如:在Linux下创建一个目录的命令为mkdirmypythoncdmypython不仅是操作系统,所有程序也都有命令行信息。指针数组作为main的命令行参数通过命令行参数,使用户可以根据需要来决定程序干什么、怎么干如何访问命令行参数?main(intargc,char*argv[])argc的值为:命令行参数的数目(包括程序名在内)argv[0]为指向命令名的字符指针argv[x](x>1)为字符指针数组,指向每个参数的字符指针指针数组作为main的命令行参数【例10.6】

下面的程序用于演示命令行参数与main()的形参之间的关系。#include<stdio.h>intmain(intargc,char*argv[]){printf("Thenumberofcommandlineargumentsis:%d\n",argc);printf("Theprogramnameis:%s\n",argv[0]);argc--;printf("Theotherargumentsarefollowing:\n");while(argc>0){ printf("%s\n",*++argv); argc--;}return0;}运行结果:(屏幕显示)Thenumberofcommandlineargumentsis:5Theprogramnameis:argc.exeTheotherargumentsarefollowing:CProgramandComputer在DOS命令提示符下输入如下命令行:argc.exeCProgramandComputer动态数组C程序中变量的内存分配方式从静态存储区分配全局变量和静态变量在栈上创建存放函数参数值、局部变量值等在执行函数调用时,系统在栈上为函数内的局部变量及形参分配内存,函数执行结束时,自动释放这些内存从堆上分配在程序运行期间,用动态内存分配函数来申请的内存都是从堆上分配的,动态内存的生存期由程序员自己来决定

动态内存分配函数

两个主要的内存分配函数:void*malloc(unsigned

intsize);void*calloc(unsignedintnum,unsigned

intsize);#include<stdlib.h>

#include<alloc.h>void*类型的指针可以指向任意类型的变量,通常强转(Type*)为其他类型向系统申请num个size大小的内存块把首地址返回,若申请不成功则返回NULL向系统申请大小为size的内存块把首地址返回,若申请不成功则返回NULL动态内存分配函数void*free(void*p);释放由malloc()和calloc()申请的内存块p是指向此块内存的指针free时系统标记此块内存为未占用,可被重新分配内存释放函数:一维动态数组的内存分配【例10.7】

编写程序,从键盘输入某班学生一门课的成绩,计算并显示该门课的平均分和最高分。#include<stdio.h>#include<stdlib.h>voidReadScore(float*pt,intn);floatGetAverage(float*pt,intn);floatGetMax(float*pt,intn);intmain(){intn;float*p=NULL,av,max;printf("Enterthenumberofstudents:");scanf("%d",&n);p=(float*)malloc(n*sizeof(float));if(p==NULL){printf("Error:mallocfailed,noenoughmemory!\n");exit(1);}printf("Enter%dscore:",n);ReadScore(p,n);av=GetAverage(p,n);max=GetMax(p,n);printf("average=%.1f,max=%.1f\n",av,max);free(p);return0;}确保指针使用前是非空指针释放向系统申请的存储空间

pnvoidReadScore(float*pt,intn){inti;for(i=0;i<n;i++){scanf("%f",&pt[i]);}}floatGetAverage(float*pt,intn){inti;floatsum=0.0;for(i=0;i<n;i++){sum+=pt[i];}returnsum/n;}ptn像使用一

温馨提示

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

评论

0/150

提交评论