C语言程序设计教程课件第8章_第1页
C语言程序设计教程课件第8章_第2页
C语言程序设计教程课件第8章_第3页
C语言程序设计教程课件第8章_第4页
C语言程序设计教程课件第8章_第5页
已阅读5页,还剩39页未读 继续免费阅读

下载本文档

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

文档简介

第8章

指针2主要内容

8.2指针变量8.3指针与数组8.1指针的基本概念8.4指针与函数3学习目标了解指针与指针变量的概念。掌握不同类型指针的定义、初始化和引用。了解指向函数的指针和指针型函数的区别和使用。了解指向数组的指针和指针数组的区别和使用。了解main函数的参数。48.1指针的基本概念8.1.1指针与地址在计算机中,所有的数据都是存放在存储器中的。为了正确地访问这些内存单元,必须为每个内存单元编上号。根据一个内存单元的编号即可准确地找到该内存单元。内存单元的编号也称为地址。地址就像被寻找的存储区域的路标,在程序设计语言中称为指针。指针可以指向变量、数组及其元素、结构体和联合体和指针等,它不能用来指向表达式、常量和寄存器变量,因为这些量没有地址。

58.1.2指针的目标指针代表内存的一个地址,而这个地址开始的内存单元存放的内容就是该指针的目标。假如指针所指的内存单元是一个变量的存储空间,那么这个变量称为指针的目标变量。

指针与指针目标的区别

68.1.3地址与指针运算符

“&”是地址运算符。例如:inta;p=&a;这里p就是一个指针变量,而“&”的功能就是把变量a的地址取出来赋给指针变量p。“*”运算符称为指针运算符,例如:inta,b;p=&a;b=*p;“*”的功能是访问p所指向地址存放的内容,即指针p所指的目标变量。78.2指针变量8.2.1指针变量的定义指针变量的定义形式如下:类型说明符*变量名;其中,“*”表示这是一个指针变量,变量名即为定义的指针变量名,类型说明符表示本指针变量所指向的变量的数据类型。例如:int*p;表示p是一个指针变量,它的值是某个整型变量的地址。或者说p指向一个整型变量。至于p究竟指向哪一个整型变量,应由向p赋予的地址来决定。应该注意的是,一个指针变量只能指向同类型的变量,如p只能指向整型变量,不能时而指向一个整型变量,时而又指向一个实型变量。

88.2.2指针变量的类型

1.指针变量的类型指针变量也是具有类型的,它的类型和它所指向的目标的类型是有区别的。从语法的角度看,只要把指针定义语句里的指针名字去掉,剩下的部分就是这个指针的类型,这是指针本身所具有的类型。例如:int*p;去掉p,剩下“int*”。它表示p是一个存放整型变量的地址的变量。当通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译器将把那片内存的内容当做什么来看待。从语法上看,只须把指针声明语句中的指针名字和名字左边的指针声明符“*”去掉,剩下的就是指针所指向的类型。例如:float*p;去掉*p,剩下“float”。它表示指针p指向的是一个实型的数据。

92.指向指针的指针一个指针变量可以指向整型变量、实型变量、字符类型变量,当然也可以指向指针类型变量。当这种指针变量用于指向指针类型变量时,称之为指向指针的指针变量。指向指针的指针变量定义如下:类型标识符**指针变量名例如:float**ptr;其含义为定义一个指针变量ptr,它指向另一个指针变量(该指针变量又指向一个实型变量)。由于指针运算符“*”是自右至左结合,所以上述定义相当于:float*(*ptr);108.2.3指针变量的初始化

在指针变量定义的同时,可以给它赋初值,叫做指针变量的初始化。初始化的一般形式为:类型说明符*变量名=初始值地址;例如:int*p=&a;8.2.4指针变量的引用

定义指针变量之后可以对指针变量进行各种操作,称为指针变量的引用。例如:定义p为一个指针变量。printf("%o",p); 将指针变量的值以八进制的形式输出。p=&a; 将变量a的地址赋给p。*p=1; 将1赋给指针p所指向的目标变量。11指针变量引用举例。交换两个指针的指向。#include<stdio.h>main(){float*p1,*p2,*p;floata=3.14,b=6.28;p1=&a;p2=&b;printf("*p1=%f,p2=%f\n",a,b);p=p1;p1=p2;p2=p;printf("afterswap,*p1=%f,*p2=%f\n",*p1,*p2);printf("afterswap,a=%f,b=%f\n",a,b);getchar();}输出结果为:*p1=3.140000,*p2=6.280000afterswap,*p1=6.280000,*p2=3.140000afterswap,a=3.140000,b=6.280000128.2.5指针变量的运算

1.赋值运算指针变量的赋值运算有以下几种形式:(1)指针变量初始化赋值,前面已作介绍。(2)把一个变量的地址赋予指向相同数据类型的指针变量。例如:inta,*p;p=&a;(3)把一个指针变量的值赋予指向相同类型变量的另一个指针变量。例如:inta,*p1,*p2;*p1=&ap2=p1;(4)把数组的首地址赋予指向数组的指针变量。例如:inta[5],*p;p=a;数组名表示数组的首地址,故可赋予指向数组的指针变量p。也可写为:p=&a[0];因为数组第一个元素的地址也是整个数组的首地址。当然也可采取初始化赋值的方法:inta[5],*p=a;13(5)把字符串的首地址赋予指向字符类型的指针变量。例如:char*p;p="clanguage";或用初始化赋值的方法写为:char*p="CLanguage";这里应说明的是并不是把整个字符串装入指针变量,而是把存放该字符串的字符数组的首地址装入指针变量。这些内容在后面还将详细介绍。(6)把函数的入口地址赋予指向函数的指针变量。例如:int(*pf)();pf=f;其中f为函数名。142.指针的算术运算指针的算术运算分为指针与整数的加减运算以及指针间的相减运算。(1)指针与整数的加减运算。指针变量与整数的加减运算包括指针变量加上或减去一个整数n,以及指针变量的自增自减运算。假如p是一个指针变量,则pa+n,pa-n,pa++,++pa,pa--,--pa运算都是合法的。(2)指针间的相减运算。对同一类型的指针变量,两指针变量相减所得之差是两个指针之间的数据个数。实际上是两个指针值(地址)相减之差再除以该数组元素的长度(字节数)。

153.指针的关系运算

关系运算符形式含义<p1<p2若关系成立,表示p1的目标变量在p2的目标变量之前<=p1<=p2若关系成立,表示p1的目标变量不在p2的目标变量之后>p1>p2若关系成立,表示p1的目标变量在p2的目标变量之后>=p1>=p2若关系成立,表示p1的目标变量不在p2的目标变量之前==p1==p2若关系成立,表示p1的目标变量和p2的目标变量位置相同!=p1!=p2若关系成立,表示p1的目标变量和p2的目标变量位置不同16指针变量的运算举例。#include<stdio.h>main(){inta[3],*pmax,*pmin,*p;pmax=a;pmin=a;p=a;printf("inputthreenumbers:\n");scanf("%d,%d,%d",&a[0],&a[1],&a[2]);pmin++;if(*pmax<*pmin){p=pmax;pmax=pmin;pmin=p;}p=p+2;if(*p>*pmax)pmax=p;if(*p<*pmin)pmin=p;printf("max=%d\nmin=%d\n",*pmax,*pmin);}假如输入:4,1,6输出为:max=6min=1178.3指针与数组8.3.1指向一维数组的指针变量

1.指向数组的指针变量的定义和赋值我们知道,一个数组在内存中会有系统分配的一个存储空间,其数组的名字就是数组在内存的首地址。若再定义一个指针变量,并将数组的首址传给指针变量,则该指针就指向了这个一维数组。我们说数组名是数组的首地址,也就是数组的指针。而定义的指针变量就是指向该数组的指针变量。例如:floata[3],*p1,*p2;p1=&a[0];p1=a;p1,p2就得到了数组的首址。其中,a是数组的首地址,&a[0]是数组元素a[0]的地址,由于a[0]的地址就是数组的首地址,所以,两条赋值操作效果完全相同。指针变量p1,p2就是指向数组a的指针变量。

182.通过指针引用数组元素引入指针变量后,就可以用两种方法来访问数组元素。(1)下标法,即用a[i]形式访问数组元素。在第5章中介绍数组时都是采用这种方法。(2)指针法,即采用*(p+i)或*(a+i)形式,用间接访问的方法来访问数组元素。在这里要注意,a是数组名,它表示数组首地址,它的值在程序运行期间是固定不变的,a虽然看起来像一个指针变量,但实质上它是常量。所以假如出现“a++;”或“a=a+i;”这样的语句是不合法的。

19从键盘输入10个数,以一维数组的不同引用形式输出数组各元素的值。下标法:#include<stdio.h>main(){intn,a[10],*ptr=a;printf("input:\n");for(n=0;n<=9;n++)scanf("%d",&a[n]);printf("output:\n");for(n=0;n<=9;n++)printf("%4d",a[n]);}指针法:#include<stdio.h>main(){intn,a[10],*ptr=a;printf("input:\n");for(n=0;n<=9;n++)scanf("%d",ptr++);printf("output:\n");ptr=a;for(n=0;n<=9;n++)printf("%4d",*(ptr++));}假如输入:1,2,3,4,5,6,7,8,9,0输出:1234567890208.3.2指向二维数组的指针变量

1.二维数组的地址表示方法

inta[3][4];

a[0]1234a[1]5678a[2]910111221二维数组地址表示方法应用举例。#definePF"%d,%d,%d,%d,%d,\n"#include<stdio.h>main(){staticinta[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};printf(PF,a,*a,a[0],&a[0],&a[0][0]);printf(PF,a+1,*(a+1),a[1],&a[1],&a[1][0]);printf(PF,a+2,*(a+2),a[2],&a[2],&a[2][0]);printf("%d,%d\n",a[1]+1,*(a+1)+1);printf("%d,%d\n",*(a[1]+1),*(*(a+1)+1));}运行结果为:404,404,404,404,404412,412,412,412,412420,420,420,420,420412,4126,6222.二维数组的指针变量二维数组指针变量说明的一般形式为:类型说明符(*指针变量名)[长度];其中“类型说明符”为所指数组的数据类型。“*”表示其后的变量是指针类型。“长度”表示二维数组分解为多个一维数组时,一维数组的长度,即二维数组的列数。应注意“(*指针变量名)”两边的括号不可少,如缺少括号则表示是指针数组(本章后面介绍),意义就完全不同了。例如把二维数组a[3][4]分解为一维数组a[0],a[1],a[2]之后,设p为指向二维数组的指针变量。可定义为:int(*p)[4];它表示p是一个指针变量,指向二维数组a或指向第一个一维数组a[0],其值等于a,a[0],或&a[0][0]等。而p+i则指向一维数组a[i]。分析可得出*(p+i)+j是二维数组i行j列的元素的地址,而*(*(p+i)+j)则是i行j列元素的值。

238.3.3指针与字符串

1.字符指针与字符串指针字符串指针变量的定义说明与指向字符的指针变量说明是相同的。所以只能按对指针变量的赋值不同来区别。对指向字符变量的指针变量应赋予该字符变量的地址。如:charc,*p=&c;表示p是一个指向字符变量c的指针变量。而:char*s="CLanguage";则表示s是一个指向字符串的指针变量。把字符串的首地址赋予s。【例8-7】字符指针与字符串指针举例。#include<stdio.h>main(){char*p1,*p2;p1="CLanguage";*p2='C';printf("%s,%c",p1,*p2);}输出结果为:CLanguage,C

242.字符串指针与字符数组字符数组不仅可以用来存放字符,也可以用来存放字符串。字符串指针变量也可以实现字符串的存储和运算,但两者是有区别的。在使用时应注意以下几个问题:(1)本质上是有区别的。字符串指针变量本身是一个变量,用于存放字符串的首地址。字符数组是由于若干个数组元素组成的,可用来存放整个字符串。(2)变量的初始化上有区别。对字符数组作初始化赋值,必须采用外部类型或静态类型,例如:staticcharst[]={"CLanguage"};而对字符串指针变量则无此限制,如:char*p="CLanguage";(3)两者赋值方式上有区别。对字符串指针方式,例如:char*p="CLanguage";可以写为:char*p;p="CLanguage";而对数组方式:staticcharst[]={"CLanguage"};不能写为:charst[20];st={"CLanguage"};而只能对字符数组的各元素逐个赋值。

253.字符串指针应用举例【例8-8】查找输入的字符串中有无字母“a”。#include<stdio.h>main(){charst[20],*p;inti;printf("inputastring:\n");p=st;scanf("%s",p);for(i=0;*(p+i)='\0';i++){if(*(p+i)=='a'){printf("thereisa'a'inthestring\n");break;}}if(*(p+i)=='\0')printf("Thereisno'a'inthestring\n");}268.3.4指针数组

1.指针数组的定义与引用一个数组的元素值为指针则是指针数组。指针数组是一组有序的指针的集合。指针数组的所有元素都必须是具有相同存储类型和指向相同数据类型的指针变量。指针数组说明的一般形式为:类型说明符*数组名[数组长度]例如:int*p[3];表示pa是一个指针数组,它有三个数组元素,每个元素值都是一个指针,指向整型变量。通常可用一个指针数组来指向一个二维数组。指针数组中的每个元素被赋予二维数组每一行的首地址,因此也可以理解为指向一个一维数组。

272.指针数组与字符串指针数组在指向一般数据类型的变量上没有太多的用处,但在处理字符串上,它却具有很大的优势。假设有若干字符串“wangning”,“zhanglin”,“lisu”,“panwei”,“hejing”需要存储,可以用一个二维数组存储,例如:charname[5][10]={"wangning","zhanglin","lisu","panwei","hejing"};则定义了一个5×10的数组,数据在内存中的存放情况如图所示。1000wangning\01010zhanglin\01020lisu\01030panwei\01040hejing\028【例8-10】利用指针数组输入输出国名。#include<stdio.h>main(){staticcharn[5][10];char*p[5]={n[0],n[1],n[2],n[3],n[4]};inti;printf("pleaseinputthecountrynames:");for(i=0;i<5;i++)scanf("%s",p[i]);for(i=0;i<5;i++)printf("%s\n",p[i]);}输入:china,japan,france,germany,denmark。输出:chinajapanfrancegermanydenmark293.指针数组应用举例【例8-11】存储2004年欧洲杯4强的国家名称,输入一个国家名称,看是否该国进入了2004年欧洲杯4强。源程序:#include<stdio.h>#include<string.h>main(){inti;char*name[4]={"Greece","Portugal","Netherland","Czechic"};charname1[20];printf("enterthecountry'sname:");gets(name1);for(i=0;i<5;i++)if(strcmp(name[i],name1)==0){printf("itisinthefourcountries.");break;}if(strcmp(name[i],name1)!=0)printf("itisnotinthefourcountries.");}30【例8-12】按字母顺序输出3个字符串。源程序:#include<stdio.h>#include<string.h>main(){char*st[5]={"apple","pear","orange","banana","bean"};char*p;inti,j;for(i=0;i<4;i++)for(j=i+1;j<5;j++){if(strcmp(st[i],st[j])>0){p=st[i];st[i]=st[j];st[j]=p;}}for(i=0;i<5;i++)printf("%s\n",st[i]);}318.4指针与函数8.4.1指针作为函数参数

函数的参数可以是前面学过的简单数据类型,也可以是指针类型。使用指针类型做函数的参数,实际向函数传递的是变量的地址。由于函数中获得了所传递变量的地址,在该地址空间的数据当函数调用结束后被物理地保留下来。32【例8-13】从键盘输入两个整数,按从大到小的顺序输出。#include<stdio.h>main(){voidchange();int*p1,*p2,a,b,*t;printf("pleaseinputtwonumbers:");scanf("%d,%d",&a,&b);p1=&a;p2=&b;change(p1,p2);printf("theresultis:");printf("%d,%d\n",*p1,*p2);}voidchange(int*pt1,int*pt2){intt;if(*pt1<*pt2){t=*pt1;*pt1=*pt2;*pt2=t;}}运行结果为:pleaseinputtwonumbers:1,2theresultis:2,1338.4.2指向函数的指针

1.指向函数的指针的定义一个函数总是占用一段连续的内存区,而函数名就是该函数所占内存区的首地址。我们可以把函数的这个首地址(或称入口地址)赋予一个指针变量,使该指针变量指向该函数。然后通过指针变量就可以找到并调用这个函数。这种指向函数的指针变量称为“函数指针变量”。一个指向函数的指针变量的定义的一般形式如下:类型标识符(*指针变量名)();其中“类型标识符”表示被指函数的返回值的类型。“(*指针变量名)”表示“*”后面的变量是定义的指针变量。最后的空括号表示指针变量所指的是一个函数。例如:int(*p)();表示pf是一个指向函数入口的指针变量,该函数的返回值是整型。

342.指向函数的指针的引用在定义了指向函数的指针之后,可以将一个函数的入口地址给它,这样就实现了这个指针指向了一个特定的函数。例如:voidfun();void(*p)();p=fun;这样就使p指向了函数fun。在指针指向函数后,就可以调用指针,从而来调用函数。调用的一般形式为:(*指针变量)(实参表列)例如:(*p)(a,b)相当于fun(a,b)。35【例8-15】指向函数的指针的引用。#include<stdio.h>intmax(intx,inty){if(x>y)returnx;elsereturny;}main(){int(*pmax)();inta,b,c;pmax=max;printf("pleaseinputtwonumbers:\n");scanf("%d,%d",&a,&b);c=(*pmax)(a,b);printf("max=%d",c);}368.4.3指针型函数

一个函数的返回值可以是整型、实型、字符型等,同时它也可以返回一个指针型的数据。而一个函数的类型又是由它返回值的类型所决定的,所以称这种返回值为指针型的函数为指针型函数。定义指针型函数的一般形式为:类型标识符*函数名(形参表){函数体}其中函数名之前加了“*”号表明这是一个指针型函数,即返回值是一个指针。类型标识符表示了返回的指针值所指向的数据类型。例如:int*fun(intx,inty){函数体}表示fun是一个返回指针值的指针型函数,它返回的指针指向一个整型变量。

37【例8-16】通过指针函数,输入一个1~7之间的整数,输出对应的星期名。#include<stdio.h>main(){inti;char*day_name(intn);printf("inputDayNo:\n");scanf("%d",&i);printf("DayNo:%d-->%s\n",i,day_name(i));}char*day_name(intn){staticchar*name[]={"Illegalday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"};return((n<1||n>7)?name[0]:name[n]);}388.4.4main函数的参数

1.带参数的main函数的定义前面介绍的main函数都是不带参数的,因此main后的括号都是空括号。实际上,main函数可以带参数,这个参数可以认为是main函数的形式参数。加上形参说明后,main函数的函数头应写为:main(argc,argv)intargv;char*argv[];或写成:main(intargc,char*argv[])main函数的参数只能有两个,习惯上这两个参数写为argc和argv。argc是整型变量,argv是指向字符串的指针数组。392.操作系统的命令行main函数不能被其他函数调用,因此不可能在程序内部取得实际值。那么,在何处把实参值赋予main函数的形参呢?实际上,main函数的参数值是从操作系统命令行上获得的。当要运行一个可执行文件时,在DOS提示符下键入文件名,再输入实际参数即可把这些实参传送到main的形参中。在操作系统环境下,一条完整的运行命令应包括两部分:命令与相应的参数。其格式为:命令参数1参数2……参数n<CR>(<CR>表示回车键)此格式称为命令行。命令行中的命令就是可执行文件的文件名,其后所跟参数须用空格分隔,作为对命令的进一步补充,也就是传递给main()函数的参数。

403.带参数的main函数的执行知道了main函数中两个参数与命令行的关系,就可以像处理一般函数一样调用main函数的参数,从而实现一些功能。【例8-17】输出带参主函数的参数。main(intargc,char*arg[]){inti;for(i=0;i<a

温馨提示

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

评论

0/150

提交评论