北京交通大学C语言课件中_第1页
北京交通大学C语言课件中_第2页
北京交通大学C语言课件中_第3页
北京交通大学C语言课件中_第4页
北京交通大学C语言课件中_第5页
已阅读5页,还剩43页未读 继续免费阅读

下载本文档

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

文档简介

高级语言程序设计主讲教师:丁丁计算机与信息技术学院dding@2023/2/4高级语言程序设计2主要内容:指针7.1地址与指针7.2指针变量的定义和使用7.3指针与数组7.4指针数组7.5多维数组作为参数的通用函数7.6动态存储管理7.7定义类型7.8指向函数的指针3要点回顾如何定义一个指针变量?指针变量在使用时为什么一定要指定指向的数据类型?指针变量在使用时为什么一定要初始化?未经初始化的指针变量称为?指针变量上的两种主要操作是什么?变量的两种访问方式是什么?指针变量做函数参数时传递的是什么?通过使用指针变量做为函数参数可以返回多于一返回值改变函数调用时的环境变量空指针有什么用?2023/2/4高级语言程序设计4主要内容:指针7.1地址与指针7.2指针变量的定义和使用7.3指针与数组7.4指针数组7.5多维数组作为参数的通用函数7.6动态存储管理7.7定义类型7.8指向函数的指针指针(数值型/字符型)与一维数组(数值型数组/字符串)的关系5C指针与数组关系密切,以指针为媒介可以完成各种数组操作用指针做数组操作同样要特别注意越界错误。指针和数组的关系是C语言特有的,除了由C派生出的语言(如C++),一般语言中没有这种关系。如何利用指针访问数组。6int*p1,*p2,*p3,*p4;inta[10]={1,2,3,4,5,6,7,8,9,10};

1指向数组元素的指针可以写:p1=&a[0];p2=p1;p3=&a[5];p4=&a[10];

这个地址存在,但写*p4是错误的。P4没有指向合法元素p1=&a[0];可简写为:p1=a;数组名是表示数组首地址的地址常量区别?7当指针p指向数组元素时说p指到了数组里。这时由p可以访问被p指的元素,还可访问数组的其他元素。例:p1=&a[0],则p1+1合法,为a[1]的地址

p1+2、p1+3、…也合法,分别为a[2]、a[3]的地址使用:*(p1+2)=3;/*给a[2]赋值*/ p2=p1+5;/*使p2指向a[5]*/*(p2+2)=5;/*给a[7]赋值*/*(p2-2)=4;/*给a[3]赋值*/p2=p2-2;/*这使p2改指向a[3]*/通过指针访问数组元素时必须保证不越界。

2指针运算8指针运算原理一个指针指向某数组里的元素时,为什么能算出下一元素位置?(这是指针运算的基础)指针有指向类型,p指向数组a时,由于p的指向类型与a的元素类型一致,数据对象的大小可以确定。p+1的值可根据p的值和数组元素大小算出。由一个数组元素位置可以算出下一元素位置,或几个元素之后的元素位置。指针运算的基础。通用指针即使指到数组里,因没有确定指向类型,因此不能做一般指针计算,只能做指针比较。9可进行增/减量操作(指针应指在数组里):

p3=p2;++p3;--p2;p3+=2;如果两指针指在同一个数组里,可以求差,得到它们间的数组元素个数(带符号整数)。

n=p3–p2;/*也可以求p2–p3*/在同一个数组里的指针可以比较大小:

if(p3>p2)....当p3所指的元素在p2所指的元素之后时条件成立(值为1),否则不成立(值为0)。两个指针不指在同一数组里时,比较大小没有意义。3其他常用指针运算10两个同类型指针可用==和!=比较相等或不等;任何指针都能与通用指针比较相等或不等;任何指针可与空指针值(0或NULL)比较相等或不等两指针指向同一数据元素,或同为空值时它们相等。11当一个指针指向数组时的数组写法与指针写法:指针的两种用法设p1=&a[0],p3=&a[5]p1和p3相当于数组名

可写:p1[3]=5;相当于*(p1+3)=5;或a[3]=5;

p3[2]=8;相当于*(p3+2)=8;或a[7]=8;

p1[3]称为数组写法,*(p1+3)称为指针写法两类写法有等价效力,可以自由选用。12a[0]a[1]a[2]a[3]a[9]...aa+9a+1a+2地址元素下标法a[0]a[1]a[2]a[9]a[0]a[1]a[2]a[3]a[9]...pp+9p+1p+2地址元素指针法*p*(p+1)*(p+2)*(p+9)[]变址运算符a[i]

*(a+i)a[i]p[i]

*(p+i)*(a+i)*a*(a+1)*(a+2)*(a+9)p[0]p[1]p[2]p[9]13对数组名求值得到指向数组首元素的指针值数组名可以“看作”常量指针,可参与一些指针运算,与其他指针比大小,比较相等与不相等。通过数组名的元素访问也可以采用指针写法。

a[3]可写为*(a+3)。注意:数组名不是指针变量,特别是不能赋值,不能更改。若a为数组,下面操作都是错误的:

a++; a+=3; a=p;有些运算虽不赋值但也可能没意义。如a–3不可能得到合法指针值,因其结果超出数组界限14a[0]a[1]a[2]a[3]a[4]intmain(){inta[5],*pa,i;for(i=0;i<5;i++) a[i]=i+1;pa=a;for(i=0;i<5;i++) printf("*(pa+%d):%d\n",i,*(pa+i));

//通过指针找地址法

for(i=0;i<5;i++) printf("*(a+%d):%d\n",i,*(a+i));

//通过指针找地址法

for(i=0;i<5;i++) printf("pa[%d]:%d\n",i,pa[i]);

//下标法

for(i=0;i<5;i++) printf("a[%d]:%d\n",i,a[i]); //下标法

return0;}12345pa例数组元素的引用方法(1)15//指针法intmain(){ inta[10]; int*p,i; for(i=0;i<10;i++) scanf(“%d”,&a[i]); printf(“\n”); for(p=a;p<a+10;p++) printf(“%d,”,*p); return0;}例数组元素的引用方法(2)三种方法的比较:下标法和地址法的执行效率相同,都是先计算数组元素的地址,再访问数组元素的值,费时。指针法利用指针变量直接访问数组元素的值,不必计算数组元素的地址,执行效率高。下标法直观,指针法与地址法不够直观。16基于指针的数组程序设计指针运算是处理数组元素的一种有效方式。设有int数组a和指针p1,p2,下面代码都打印a的元素:for(p1=a;p1<a+10;++p1)

printf("%d\n",*p1);for(p1=a;p1-a<10;++p1) printf("%d\n",*p1);for(p1=a,p2=a+10;p1<p2;++p1)printf("%d\n",*p1);for(p1=p2=a;p1-p2<10;++p1)printf("%d\n",*p1);17数组参数的意义C规定,数组参数就是相应类型的指针参数:

intf(intn,intd[]){......}和intf(intn,int*d){......}

意义相同。数组参数就是利用指针实现的!这也使采用数组参数的函数能修改实参数组。18函数里也可用指针方式做元素访问。intintsum(intn,inta[]){inti,m=0;for(i=0;i<n;++i)m+=*(a+i);returnm;}函数里不能用sizeof确定数组实参大小:函数的数组形参实际是指针,求sizeof算出的是指针的大小。另一方面,sizeof的计算是在编译中完成的。实参是动态运行中确定的东西。m+=a[i];intintsum(intn,int*a){inti,m=0;for(i=0;i<n;++i)m+=*(a+i);returnm;}19使用数组的一段元素以数组为参数的函数可处理一段元素。求元素和:doublesum(intn,doublea[]);设有双精度数组b,40个元素已有值:用sum可求b所有元素之和/前一段元素之和:

x=sum(40,b); y=sum(20,b);sum不知道b的大小,它由参数得到数组首元素地址,从这里开始求连续40或20个元素的和。也可用sum求b中下标12到24的一段元素之和。

z=sum(13,b+12);

20例1下面的程序的输出结果是什么?#include<stdio.h>inta[]={2,4,7,8,9};intmain(){inti,*p=a;for(i=0;i<4;i++)a[i]=*(++p);printf("%d\n",a[2]);return0;}运行结果为:821例2inta[]={1,2,3,4,5,6,7,8,9,10},*p=a,i;

数组元素地址的正确表示:

(A)&(a+1)(B)a++(C)&p(D)&p[i]数组名是地址常量p++,p--()a++,a--()a+1,*(a+2)()22例intmain(){inta[]={5,8,7,6,2,7,3};inty,*p=&a[1];

y=(*--p)++;printf(“%d”,y);printf(“%d”,a[0]);return0;}输出:56pp58762730123456a6例3注意指针变量的运算*p++(*p)++:*++p:*p++*(p++):*p++先取p指向变量的值再指针变量加1(*p)++:(*p)++使p指向的元素值加1*++p:*++p先使指针变量加1再取*p23intmain(){inti,*p,a[7];p=a;for(i=0;i<7;i++)scanf("%d",p++);printf("\n");for(i=0;i<7;i++,p++)printf("%d",*p);return0;}p=a;pp58762730123456apppppp指针变量可以指到数组后的内存单元例4

注意指针的当前值24要点:1、指针变量可以实现自身值的改变:如:p++;但数组名则不能进行改变:a++是错误的用法。2、应注意指针变量的当前值。3、指针变量可以指向数组以后的内存单元。4、注意以下的指针运算:若:inta[10],*p=a;则:p++

等价于

&a[1]

*p++

等价于

*(p++)

*(p++)与*(++p)却不同

(*p)++等价于

a[0]++25例1利用指针,输出int数组里一段元素:voidprt_seq(int*begin,int*end){for(;begin!=end;++begin)printf("%d\n",*begin);}prt_seq(a,a+10);prt_seq(a+5,a+10);prt_seq(a,a+3);prt_seq(a+2,a+6);prt_seq(a+4,a+4);prt_seq(a+10,a+10);最后两个调用对应空序列。完备吗?26例2:“设置”函数:voidset_seq(int*b,int*e,intv){ for(;b!=e;++b)*b=v;

}例3:把序列中每个元素都用其平方根取代:voidsqrt_seq(double*b,double*e){for(;b!=e;++b)*b=sqrt(*b);}例4:求平均值:doubleavrg(double*b,double*e){double*p,x=0.0;if(b==e)return0.0;for(p=b;p!=e;++p)x+=*p;returnx/(e-b);}27数组名作函数参数,是地址传递数组名作函数参数,实参与形参的对应关系实参形参数组名指针变量数组名指针变量数组名数组名指针变量指针变量数组名作函数参数28ij379110675420123456789ijijijji11760594723实参与形参均用数组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;}}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;}m=4例5将数组a中的n个整数按相反顺序存放(1)29voidinv(int*x,intn){intt,*p,*i,*j,m=(n-1)/2;i=x;j=x+n-1;p=x+m;for(;i<=p;i++,j--){t=*i;*i=*j;*j=t;}}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;}实参用数组,形参用指针变量37911067542a[0]a[1]a[2]a[3]a[4]a[5]a[6]a[7]a[8]a[9]xp=x+ma数组60711594723ijijijjiji例5将数组a中的n个整数按相反顺序存放(2)30voidinv(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;}}intmain(){inti,a[10],*p=a;for(i=0;i<10;i++,p++)scanf("%d",p);

p=a;

inv(p,10);printf("Thearrayhasbeenreverted:\n");for(p=a;p<a+10;p++)printf("%d",*p);return0;}实参与形参均用指针变量例5将数组a中的n个整数按相反顺序存放(3)31voidinv(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;}}intmain(){inti,a[10],*p=a;for(i=0;i<10;i++,p++)scanf("%d",p);

p=a;

inv(p,10);printf("Thearrayhasbeenreverted:\n");for(p=a;p<a+10;p++)printf("%d",*p);return0;}实参用指针变量形参用数组例5将数组a中的n个整数按相反顺序存放(4)32#include<stdio.h>#defineMAX5voidfun1();voidfun2(int[]);inta[MAX];intmain(){fun1();fun2(a);printf("\n");return0;}voidfun1(){intk,t=0;for(k=0;k<MAX;k++,t++)a[k]=t+t;}voidfun2(intb[]){intk;for(k=0;k<MAX;k+=2)printf("%4d",*(b+k));}例6分析程序写出结果

运行结果为:04833#include<stdio.h>voidfun(int*s){staticintj=0;do{s[j]+=s[j+1];}while(++j<2);}intmain(){intk,a[10]={1,2,3,4,5};for(k=1;k<3;k++)fun(a);for(k=0;k<5;k++)printf(“%4d”,a[k]);return0;}例7分析程序写出结果

运行结果为:3574534int*p与intq[10]数组名是指针(地址)常量p=q;p+i是q[i]的地址数组元素的表示方法:下标法和指针法,即若p=q,则p[i]q[i]*(p+i)*(q+i)

形参数组实质上是指针变量,即intq[]int*q在定义指针变量(不是形参)时,不能把int*p写成intp[];系统只给p分配能保存一个指针值的内存区(一般2字节);而给q分配sizeof(int)*10字节的内存区一级指针变量与一维数组的关系35定义字符指针时可用字符串常量初始化,如:char*p="Programming";1)定义了指针p2)建立了一个字符串常量,内容为"Programming"3)令p指向该字符串常量。图(a)chara[]="Programming";

1)定义了一个12个字符元素的数组2)用"Programming"各字符初始化a的元素,图(b)字符指针与字符数组常用字符指针指向字符数组元素361)指针p可重新赋值(数组不能赋值:a=“…”):

p="ProgrammingLanguageC";2)p和a类型不同,大小不同。a占12个字符的空间。3)a的元素可以重新赋值。如:a[8]='e';a[9]='r';a[10]='\0'; a的内容现在变成“Programmer”37IloveChistring[0]string[1]string[2]string[3]string[4]string[5]string[6]string[7]string[8]string[9]stringstring[10]string[11]string[12]string[13]n!a\0//字符串用字符数组实现intmain(){charstring[]=“IloveChina!”;printf(“%s\n”,string);printf(“%s\n”,string+7);return0;}//字符串用字符指针实现intmain(){char*string=“IloveChina!”;printf(“%s\n”,string);

string+=7;while(*string){putchar(string[0]);string++;}return0;}IloveChina!China!38#include<stdio.h>intmain(){ chararr[]="ABCDE"; char*ptr; for(ptr=arr;ptr<arr+5;ptr++) printf("%s\n",ptr); return0;}运行结果:ABCDE

BCDE

CDE

DE

E例1分析以下程序的运行结果39#include<stdio.h>intmain(){ char*p1="programming",*p2="language"; inti; for(i=0;i<7;i++) if(*(p1+i)==*(p2+i)) printf("%c",*(p1+i)); return0;}运行结果:ga例2分析以下程序的运行结果

40例3,输入一行到数组里:enum{NLINE=256};charline[NLINE];intcount;char*p;/*-----------------------------------------*/p=line;while(p–line<NLINE-1&&(*p=gerchar())!='\n')++p;*p='\0';/*做成字符串*//*-----------------------------------------*/for(count=0,p=line;*p!='\0';++p)if(*p=='e')++count;/*统计e的个数*/41例1,用指针方式实现字符串长度函数。一种方式:intstrLength(constchar*s){intn=0;/*通过局部指针扫描串中字符*/while(*s!='\0'){s++;n++;}returnn;}另一实现:intstrLength(constchar*s){char*p=s;while(*p!='\0')p++;returnp-s;}参数类型(char*),实参应是字符串或存字符串的数组指针与数组操作函数实例指针使用非常灵活42voidstrCopy(char*s,constchar*t){while((*s=*t)!='\0'){s++;t++;}}把指针更新操作也写在循环测试条件里,voidstrCopy(char*s,constchar*t){while(*s++=*t++);//空语句}赋值表达式有值,'\0'就是0,可简化:voidstrCopy(char*s,constchar*t){while(*s=*t){s++;t++;}}例2,用指针实现字符串复制函数。43例用函数调用实现字符串复制(1)用字符数组作参数aIamateaceh\0r.fromabyuarasutndetoboet.\0Iaaeceh\0r.t.\0mtavoidcopy_string(charfrom[],charto[]){inti=0;while(from[i]!='\0'){to[i]=from[i];i++;}to[i]='\0';}intmain(){chara[]="Iamateacher.";charb[]="Youareastudent.";printf("string_a=%s\nstring_b=%s\n",a,b);

copy_string(a,b);printf("\nstring_a=%s\nstring_b=%s\n",a,b);return0;}字符指针作函数参数44例用函数调用实现字符串复制(2)用字符指针变量作参数aIamateaceh\0r.fromabyuarasutndetoboet.\0Iaaeceh\0r.t.\0mtavoidcopy_string(char*from,char*to){for(;*from!='\0';from++,to++)*to=*from;*to='

温馨提示

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

评论

0/150

提交评论