2023年中央电大C语言A课程辅导资料_第1页
2023年中央电大C语言A课程辅导资料_第2页
2023年中央电大C语言A课程辅导资料_第3页
2023年中央电大C语言A课程辅导资料_第4页
2023年中央电大C语言A课程辅导资料_第5页
已阅读5页,还剩10页未读 继续免费阅读

下载本文档

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

文档简介

C语言程序设计A课程辅导(5)---第5章指针重要内容:一、指针的概念二、指针变量三、指针运算四、指针与数组五、动态存储分派六、使用指针和动态存储分派的程序举例一、指针的概念指针:计算机内部存储器中一个存储(单元)字节的地址。该地址是一个32位的二进制编码,所占有的字节数(指针类型长度)与int类型长度相同。指针是一种特殊的数据,即不是字符和常数,而是内存单元的编码(地址)。指针与数据类型:在C语言中每个指针都与一个具体的数据类型相联系,即为内存中存储该类型的一个数据的地址,具体为数据所占用存储空间(又称为存储单元或数据单元)的首字节地址。如intx=10;则x的地址就是一个指针,它是存储x的值10的4个存储字节的第一个字节的地址。指针类型:就是它所指向的存储单元中所存数据的类型。如一个指针指向一个整型数(即所指向的存储单元中存储的是整数),则称为整型指针;若指向一个字符,则成为字符指针。数据地址的表达:在一个变量前加上&字符,就表达取该变量的地址,该地址(指针)的类型就是该数据的类型。如intx;&x就表达x的地址,其类型为int指针类型,可表达为int*。空指针:其值为0的指针称为空指针。空指针不指向任何数据,在stdio.h头文献中已经把NULL定义为0,所以符号常量NULL也表达为空指针。二、指针变量可以保存存储单元地址的变量。一般变量保存的是字符或常数。定义格式:<类型关键字>*<指针变量名>[=<指针表达式>],...;与一般变量定义语句格式基本相同,只要在变量标记符前加上*即为指针变量。格式举例:(1)intx,*p;//定义x为int型一般变量,p为int*型指针变量(2)inta=10,*pa=&a;//定义int变量a并初始化10,同时定义pa为//int*类型的指针变量,并初始化为a的地址,即整数变量的地址(3)char*p1=0,*p2="pointer";//p1为空,p2指向字符串"pointer"//把"pointer"的第1个字符的地址赋给指针变量p2,类型为char*(4)char*d[5]={0};//字符数组d[5]中每个元素均为指针变量,其值为空(5)intx=5,*px=&x,**pp=&px;//px:int*类型,pp:int**类型pppxx&px&x5//px的地址具有int**类型(6)char*rp[3]={"front","middle","rear"};//定义指针数组和初始化(7)inta[10],*ps=a;//数组名a的值是第1个元素的地址,//即a[0]元素的地址&a[0],类型为int*输出一般指针和输出字符指针所指向的字符串:输出一般指针时使用的格式符为"%p",输出字符指针所指向的字符串时使用的格式符为"%s"。例如:#include<stdio.h>voidmain(){inta=30;char*cp;//可以保存一个字符变量或数组元素的地址cp="output";//cp指向字符串常量"output"printf("%p%p\n",&a,cp);//输出指针,分别为a和'o'的地址printf("%d%s\n",a,cp);//输出a的值和cp所指向的字符串}运营结果:0013FF7C0042023C//十六进制8位30output向字符指针输入字符串:chara[30];scanf("%s",a);//gets(a);chara[30],*p=a;scanf("%s",p);//gets(p);运用typedef语句定义指针数据类型:(1)typedefint*inPointer;//定义inPointer为int*类型,//若用inPointers1=NULL;等价于int*s1=NULL;(2)typedefchar*chPointer;//定义chPointer为char*类型(3)typedefchar*AA[10];//定义AA为char*[10]指针数组类型,//若用AAaa;等价于char*aa[10];三、指针运算

涉及赋值、取地址、间接访问、增减1等。赋值(=)双目运算,把赋值号右边的指针(地址)值赋给左边的同类型的指针变量。intx=30,*px,*py;px=&x;py=px;//把x的地址赋给px,把px值赋给py,它们均指向x取地址(&)单目运算,使用在一般变量的前面,表达取变量的地址。charch='+',*p=&ch;//取ch变量的地址赋给p,p指向chchars[30]="Apple",*ps=s;//字符数组s的地址赋给ps,ps指向s,//s和ps的值均为s数组中第1个元素'A'的存储地址间接访问(*)在指针前面使用*运算符可以访问到指针所指向的对象。如:intx=12,*px=&x;//px指向x,px所指向的对象x的值为12printf("%d\n",*px+10);//22,使用*px+10等同于x+10*px+=15;//27,使用*px+=15等同于x+=15,*px即x的值变为27增1(++)和减1(--)单目运算,可使用在指针变量的前面或后面,使指针变量的值增1或减1。inta[5]={10,15,20,25,30},x,y;int*p=a;//p指向a[0]元素,即p的值为a[0]的地址x=*p++;//x的值为10,p加1后赋给p,p指向下一个元素a[1]x=*++p;//x的值为20,p指向元素a[2]y=(*p)++;//y的值为20,a[2]被加1后赋给a[2],a[2]的值变21p--;//运算前p指向a[2],运算后p指向a[1]printf("%d\n",*p--);//输出a[1]的值15,然后p减1后指向a[0]p=&a[3];printf("%d\n",--*p);//*p的值25,输出减1后的a[3]的值24注意:当指针变量p指向数组中的一个元素时,p++或++p则使p指向其下一个元素,p—或—p则使p指向其前一个元素。若p指向a[i],则进行p++或++p运算后,p指向a[i+1];若p指向a[i],则进行p--或--p运算后,p指向a[i-1]。加(+)和减(-)双目运算,使指针向后或向前移动若干个数据位置。intb[6]={1,3,5,7,9,11};int*p=b,*q=p+5;//p指向b[0],q指向b[5],p+5等同于b+5printf("%d\n",*(q-3));//输出b[2]的值5p=b+6;//p指向b[6]数组后面的一个数据单元,即b[5]后的位置*--p;//取b[5]元素的值11加赋值(+=)和减赋值(-=)双目运算,左边的指针变量加上或减去右边相应的值。chara[20]="wbcdefghi";char*p=a;//p指向a[0],即字符wp+=7;//运算后p指向a[7],即字符hp-=4;//运算后p指向a[3],即字符d*p-=3;//运算后使a[3]的值减3,由100(d的ASCII码)变为97(a的码)比较(==,!=,<,<=,>,>=)双目运算,比较左右两个指针(地址)的大小。数组中后面元素的指针大于前面元素的指针,即&a[i+1]>&a[i]。inta[5]={20,15,32,48,46};int*p;for(p=a;p<a+5;p++)printf("%d",*p);//依次输出a中每个元素值for(p=a+4;p>=a;p--)printf("%d",*p);//逆序输出a中每个元素值这一讲就到这里,同学们再见!四、指针与数组1.指针与一维数组一维数组名是指向该数组第一个元素的指针常量12251830634450inta[7]={12,25,18,30,63,44,50};0123456a*a表达a[0]元素,*a的值即为a[0]的值。a的值等于&a[0],类型int*。a为指针常量,即其值不可修改,所以使用a++是错误的。道理很简朴,假如允许修改数组名的值,以后就无法访问该数组了。数组元素的下标和指针访问方式a[i]等价于*(a+i),分别为下标和指针访问方式。*a与a[0],*(a+1)与a[1]等价。假定int*p=a+i;则*p与a[i],*p++与a[i++]等价。for(i=0;i<7;i++)printf("%5d\n",a[i]);//下标方式等价于:for(i=0;i<7;i++)printf("%5d\n",*(a+i));//指针方式等价于:for(p=a;p<a+7;p++)printf("%5d\n",*p);//指针方式等价于:for(p=a,i=0;i<7;i++)printf("%5d\n",p[i]);//下标方式//p初始指向数组a中第1个元素,p[i]与a[i]等价,均为*(a+i)2.指针与二维数组二维数组名是指向该数组第一行元素的指针常量,其值为整个二维数组空间的首地址intb[3][4]={{1,2,3,4},{2,4,6,8},{3,6,9,12}};b为指向b[0]行4个元素的指针常量,其值为&b[0],亦即&b[0][0]的值,但类型为int(*)[4],而不是int*。b[i]为i行元素(一维数组)的数组名,b[i]的值为b[i][0]元素的地址。它们的类型均为int*。而&b[i]的值虽然也等于b[i][0]元素的地址,但类型为int(*)[4],由于它是该行元素的首地址。同一维数组名同样,不允许修改二维数组名的值,如进行b++操作是错误的。二维数组名的值可以赋给同类型的指针变量int(*pb)[4]=b;//把b的值赋给同类型的指针变量pb,pb也指向此数组,//此后pb也可以作为数组名使用,访问任何元素pb[2][3]等价与b[2][3],值为12。注意:int(*pb)[4]与int(*pb)[5]不同,由于pb所指向的元素个数不同。若int*pb[4]的则定义pb为具有4个元素的整型指针数组,而不是定义指向具有4个整型元素的数组的指针。二维数组元素的下标和指针访问方式b[i][j](*(b+i))[j]或*(b[i]+j)或*(*(b+i)+j)//均等价for(i=0;i<3;i++){for(j=0;j<4;j++)printf("%d",b[i][j]);//*(*(b+i)+j)printf("\n");}使用指针和数组的程序举例例1:#include<stdio.h>voidmain(){inta[8]={3,5,7,9,11,13,15,17};inti,*p=a;//p的值为&a[0]for(i=0;i<8;i++){printf("%5d",*p++);//先*p,后p的值加1if((i+1)%4==0)printf("\n");//输出4个元素后换行}}输出结果:357911131517例2:#include<stdio.h>voidmain(){inta[8]={46,38,72,55,24,63,50,37};intmax=*a,min=*a;//a[0]的值赋给max和minint*p;for(p=a+1;p<a+8;p++){//扫描整个数组if(*p>max)max=*p;//大放maxif(*p<min)min=*p;//小放min}printf("%5d%5d\n",max,min);//输出最大和最小值}输出结果:7224五、动态存储分派1.动态存储分派的概念变量和数组在计算机内存中都有相应的存储空间,该存储空间的分派时机有两种:一种在编译阶段,或者说在程序运营前;另一种在程序运营之中。前者称为静态存储分派方式,后者称为动态存储分派方式。变量的静态存储分派方式通过一般的变量定义语句定义的变量,采用的是静态存储分派方式。如:intx,y;//x和y分别相应的4个字节的存储空间是静态分派的inta[10];//数组a所需要的40个字节的存储空间是静态分派的charb[20],*p=b;//数组b的20个字节和指针变量p的4字节是静态分派的doublec[M][N]={{0}};//数组c的M*N*8个字节的存储空间是静态分派的变量的动态存储分派方式变量的动态存储分派需要调用在系统头文献stdlib.h中声明的动态存储分派函数来实现,这些函数为malloc()、calloc()和realloc()三种。2.动态存储分派函数的原型格式和功能malloc()函数原型格式void*malloc(unsignedintk);功能:调用它时可以分派k个字节的存储空间,并把第1个字节的地址返回,该返回值具有void*类型,可以赋给任一具体类型的指针变量。calloc()函数原型格式void*calloc(unsignedintn,unsignedintk);功能:调用它时可以分派n*k个字节的存储空间,并把第1个字节的地址返回,该返回值具有void*类型,可以赋给任一具体类型的指针变量。通常用n表达数组长度,k表达元素类型的长度。realloc()函数原型格式void*realloc(void*ptr,unsignedintk);功能:调用它时可以分派k个字节的存储空间,接着把ptr已经指向的动态分派的存储空间的内容复制到新分派的存储空间中,最后把新分派的存储空间的第1个字节的地址返回。由于该返回值具有void*类型,所以可以赋给任一具体类型的指针变量,通常仍赋给ptr所相应的实参指针变量,使得通过该调用后增长或缩小动态存储空间。3.动态存储分派的调用格式举例(1)int*pn=malloc(sizeof(int));//分派一个整数存储空间由指针变量pn所指向,此动态分派的变量//为*px,可用它保存一个整数,如:*px=25;*px+=30;//其值为55(2)double*pa=calloc(10,sizeof(double));//分派一个具有10个双精度元素的一维数组空间,由指针变量pa//所指向,pa也就是该动态数组的数组名(但有区别,它是变不是常),//通过它可以访问该数组中的任何元素。如:*pa=12;把12赋给//pa[0]元素;又如:pa[i]<pa[j]进行两元素大小的比较(3)pa=realloc(pa,20*sizeof(double));//增长pa指针所指向的存储空间的大小,由10个双精度元素变为//20个双精度元素,同时原有的存储内容被复制过来。(4)int**top=calloc(M+1,sizeof(int*));//top动态数组具有M+1个元素,每个元素可以存储一个整数的地址。4.动态存储分派的优点允许在程序运营过程中随时拟定待使用的存储空间的大小,不必象静态分派那样需要事先拟定。一般定义一个数组时,必须确切给出数组的每一维的尺寸,如:inta[10],b[M][N];//M和N必须是已经定义的符号常量动态分派定义一个数组时,所分派的存储空间的大小可以是常量,也可以是变量。如:(1)inta=calloc(10,4);//两个参数都为常量(2)inta=calloc(x,4);//第1个参数为变量,分派x个整数元素的空间(3)charb=malloc(n1+n2);//n1和n2为变量,分派n1+n2个字节的空间(4)charc=malloc(sizeof(d));//根据另一个对象d的大小分派空间5.动态存储空间的释放释放动态存储空间的free()函数的原型格式voidfree(void*ptr);功能:调用它时可以把指针变量ptr所指向的动态存储空间释放掉,即归还给操作系统。free()函数原型声明也包含在stdlib.h系统头文献中当动态存储空间保存的内容不再使用时,可调用该free()函数及时释放掉,若没有调用它,则一直到程序运营结束时该动态存储空间才被自动释放给操作系统。对于一般静态分派的变量,其占有的存储空间只能由C语言系统在运营时自动释放,其时机为所在的模块(复合语句)刚执行完毕。下面看一个程序例子#include<stdio.h>//支持调用标准输入和输出操作的函数#include<stdlib.h>//支持调用动态存储分派和释放函数voidmain(){int*a=calloc(10,sizeof(int));//动态分派得到a[10]数组,//为40字节的存储空间,同时静态分派得到a指针变量,4字节inti;//静态分派得到i整数变量,4字节for(i=0;i<10;i++)a[i]=i*i;//给a数组中每个元素赋值for(i=0;i<10;i++)printf("%d",a[i]);//输出a中每个元素值printf("\n");//输出一个换行符free(a);//a[10]数组的40个字节的动态存储空间被交还给操作系统}//此主函数执行结束时,自动把a和i各占有的4字节交还给操作系统程序运营结果:0149162536496481六、使用指针和动态存储分派的程序举例例1:以指针方式访问数组元素的例子#include<stdio.h>#include<stdlib.h>voidmain(){inta[5]={3,6,9,12,15};int*p=a;//把数组a的首地址赋给指针变量pinti;for(i=0;i<5;i++)printf("%5d",*p++);//指针方式访问数组aprintf("\n");//换行for(p=a+4;p>=a;p--)printf("%5d",*p);//从后向前访问数组元素printf("\n");//换行}输出结果:36912151512963例2:进行简朴变量动态存储分派的例子#include<stdio.h>#include<stdlib.h>voidmain(){intx=23,y=40,z;int*p1=malloc(sizeof(int));//为*p1动态分派4字节存储空间int*p2=malloc(sizeof(int));//为*p2动态分派4字节存储空间*p1=x;*p2=y;//分别把x值23和y值40赋给动态变量*p1和*p2printf("%d%d\n",*p1,*p2);//输出*p1和*p2的值为2340z=*p1;*p1=*p2;*p2=z;//互换*p1和*p2所保存的值printf("%d%d\n",*p1,*p2);//输出*p1和*p2的值为4023free(p1);free(p2);//释放p1和p2各自所指向的动态存储空间}程序运营结果:23404023例3:动态存储分派任意大小的一维数组的例子#include<stdio.h>#include<stdlib.h>voidmain(){intn,i,sum=0;int*a;printf("从键盘给n输入一个正整数(1-10):");while(1){scanf("%d",&n);//输入1-10之间的数到n中if(n>=1&&n<=10)break;elseprintf("重输:");}a=calloc(n,sizeof(int));//动态分派a[n]数组空间,n是变量a[0]=0;a[1]=1;//给a数组的前2个元素赋值for(i=2;i<n;i++)a[i]=a[i-1]+a[i-2];//从元素a[2]起,每个元素值等于前2个元素值之和//0+1=1,1+1=2,1+2=3,2+3=5,…for(i=0;i<n;i++){sum+=a[i];//计算出n个元素之和printf("

温馨提示

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

评论

0/150

提交评论