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

下载本文档

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

文档简介

第8章指针第8章指针本章主要内容 1.指针的概念 2.指针与变量的关系 3.指针的使用方法和运算 4.指针的作用 5.指针与函数的关系 6.指针与数组的关系8.1指针的概念重要概念:

指针也是变量。

指针变量只能存放变量的地址。

指针变量也分别有不同的类型,用来保存不同类型变量的地址。变量存储的概念:假设有:inti=−5;

charch='A';

floatx=7.34;

各变量占用内存单元的概念

情况如图所示:8.1指针的概念8.1.1指针变量的定义

指针变量的定义形式:

[存储类型]数据类型*指针变量名[=初始值];如:inta,*p=&a;

p为指向整型变量的指针,p指向了变量a的地址。

char*s=NULL;

s为指向字符型变量的指针,p指向一个空地址。

float*t;

t为指向单精度浮点型变量的指针。8.1指针的概念基本概念:

指针变量的值是某个变量的地址。

地址是内存单元的编号,每一个在生命周期内的变量在内存中都有一个地址,该地址不会因为其变量值的变化而变化。

内存单元编号通常用无符号的长整型表示,亦即指针变量的值是无符号的长整型。

特别提示:要区分指针变量所指的值和变量的值。8.1指针的概念8.1.2指针变量的使用

必须先将指针与变量的地址相关联,然后才能使用指针。

关联方式:①初始化;②赋值

赋值格式:

<指针变量名>=&<普通变量名>;例如:inti,*p;

p=&i;或:

inti,*p=&i;

——→初始化方式

关联结果:指针p指向了变量i,(变量i的地址赋给了指针p)。若:int*p=NULL;则表示p不指向任何存储单元。8.1指针的概念

指针的引用格式:

①*指针变量名——代表所指变量的值;②指针变量名——代表所指变量的地址。例如:

inti,*p;

floatx,*t;

p=&i;

/*指针p指向了变量i的地址*/

t=&x;

/*指针t指向了变量x的地址*/

*p=3;

/*相当于i=3*/

*t=12.34;

/*相当于x=12.34*/8.1指针的概念对于:inti,*p;

floatx,*t;

p=&i;

t=&x;

*p=3;

*t=12.34;

变量及指针的存储关系示意图如图所示:8.1指针的概念对于:inti,*p;

floatx,*t;

p=&i;

t=&x;

*p=3;

*t=12.34;

变量i的地址:p、&i、&(*p)

变量i的值:*p、i、*(&i)小结8.1指针的概念8.1.3指针变量与简单变量的关系

变量的地址值是有系统分配的,不允许改变。

改变变量值的途径有3个。例1:阅读程序example8_1.c,了解简单变量与指针的关系。例2:阅读程序,分析程序错误的原因。/*example8_2.c,有问题的程序*/#include<stdio.h>intmain(){int*p,*s,a;a=*p+*s;printf("a=%d\n*p=%lu\n*s=%lu",a,p,s);return0;}

将程序放到不同的环境下运行,观察结果,思考。8.2指针的运算

对指针的运算,实际是对地址进行操作。8.2.1指针的算术运算

指针的运算通常只限于:算述运算符:+、−、++、−−。关系运算符:<、<=、>、>=、!=、==、

①+、++代表指针向前移(地址编号增大)。

②−、−−代表指针向后移(地址编号减小)。设p、q为某种类型的指针变量,n为整型变量。则:p+n、p++、++p、p−−、−−p、p−q的运算结果仍为指针。8.2指针的运算若有:inta=3,*p=&a;假设a的地址为3000,则p=3000。变量a与指针p的存储关系如图(a)所示。执行语句:p=p+1;后,指针p向前移动一个位置。如果a是用2个字节,则p的值为3002,如图(b)所示;如果a占用4个字节,则p的值为3004,如图(c)所示。注意:指针p指向下一个单元,但*p的值未知。8.2指针的运算例3:

阅读【例8-3】的程序example8_3.c,了解指针的值的变化。#include<stdio.h>intmain(){inti=108,*pi=&i;doublef=12.34,*pf=&f;longk=123,*pk=&k;printf("1:---------------------------------\n");printf("变量i的值:\t\t变量i的地址:\n");printf("*pi=%d,\t\tpi=%lu\n",*pi,pi);printf("变量i下一单元的值:\t下一单元的地址:\n"); printf("*(pi+1)=%d,\tpi+1=%lu\n",*(pi+1),pi+1); /*未知单元的值*/printf("2:---------------------------------\n");printf("变量f的值:\t\t变量f的地址:\n");

<见后页>

8.2指针的运算<接前页> printf("*pf=%f,\t\tpf=%lu\n",*pf,pf); printf("变量f下一单元的值:\t下一单元的地址:\n");pf++;printf("*(pf++)=%lf,\t(pf++)=%lu\n",*pf,pf);/*未知单元的值*/printf("3:---------------------------------\n");printf("变量k的值:\t\t变量k的地址:\n");printf("*pk=%ld,\t\tpk=%lu\n",*pk,pk);printf("变量k上一单元的值:\t上一单元的地址:\n");pk--;printf("*(pk--)=%ld,\t(pk--)=%lu\n",*pk,pk);/*未知单元的值*/return0;}思考和分析程序的运行结果8.2指针的运算8.2.2指针的关系运算

指针的关系运算常用于比较两指针是否指向统一变量。假设有:inta,*p1,*p2;

p1=&a;则:p1==p2的值为0(假)。例4:阅读【例8-4】程序example8_4.c,了解指针变量的关系运算。

#include<stdio.h> intmain() { inta,b,*p1=&a,*p2=&b; printf("Theresultof(p1==p2)is%d\n",p1==p2); p2=&a; printf("Theresultof(p1==p2)is%d\n",p1==p2);return0; }思考和分析程序的运行结果8.3指针与数组的关系重要概念:

C语言规定:数组名就是数组的首地址。

数组元素在内存中是连续存放的。引申:

指针可以指向数组元素的地址,也可以指向数组名。8.3.1指向一维数组的指针若有:inta[5],*p;

p=a;

8.3指针与数组的关系指针p与数组a的存储关系如图所示:a、&a[0]都是数组的首地址。8.3指针与数组的关系若有:inta[5],*p;

p=a;

则:

表示数组a的地址:p、a、&a[0]。

引用数组元素a[i]:*(a+i)、*(p+i)、a[i]、p[i]。思考:

a[1]的地址描述;

a[i]的地址描述;数组元素a[1]的引用;数组元素a[i]的引用。(指针与一维数组的关系参见表8-2)小结8.3指针与数组的关系例5:阅读【例8-5】的程序

,了解指针与数组的关系,学会正确使用指针。#include<stdio.h>intmain(){inta[2]={1,2},i,*pa;charch[2]={'a','b'},*pc;pa=a;pc=&ch[0];printf("1:--------------------------\n");for(i=0;i<5;i++)printf("a[%d]=%d,ch[%d]=%c\n",i,a[i],i,ch[i]);<见后页>

8.3指针与数组的关系例5:阅读【例8-5】的程序

,了解指针与数组的关系,学会正确使用指针。<接前页>

printf("2:--------------------------\n");for(i=0;i<5;i++)printf("*(pa+%d)=%d,pc[%d]=%c\n",i,*(pa+i),i,pc[i]);printf("3:--------------------------\n");for(i=0;i<5;i++)printf("*a[%d]=%ld,*ch[%d]=%ld\n",i,pa+i,i,ch+i);return0;}

思考与分析程序的运行结果。8.3指针与数组的关系

注意:指向数组的指针和指向简单变量的指针的区别。例6:阅读【例8-6】的程序,了解指向数组的指针和指向变量的指针的关系。#include<stdio.h>intmain(){inta1=123,a2=234,a3=345,i;int*p1,*p2,*p3;intas[3]={1,2,3},*ps;p1=&a1;p2=p1+1;p3=p2+1;<见后页>8.3指针与数组的关系例6:阅读【例8-6】的程序,了解指向数组的指针和指向变量的指针的关系。<接前页>printf("p1=%lu\np2=%lu\np3=%lu\n",p1,p2,p3);printf("a1=%d\na2=%d\na3=%d\n",a1,a2,a3);printf("*p1=%d\n*p2=%d\n*p3=%d\n",*p1,*p2,*p3);ps=as;for(i=0;i<3;i++)printf("ps[%d]=%d\n",i,ps[i]);return0;}

思考与分析程序的运行结果。8.3指针与数组的关系8.3.2指向多维数组的指针

对多维数组而言,数组名同样代表着数组的首地址。若有:inta[3][4];则:数组首地址的表示:a、a[0]、&a[0][0]它们的区别:

a代表的是“行指针”,指向具有4个元素的指针;

a[0]、&a[0][0]代表的是第1个元素的地址。因此,若有:inta[3][4],*p;则p=a[0];或p=&a[0][0];是将指针p指向数组的首地址。请注意:

p=a;这个语句在概念上容易混淆,有些编译时会有警告提示:“SuspiciousPointerConversion”;应避免这种情况。8.3指针与数组的关系对于inta[3][4],*p=a[0];指针p的使用方法同一维数组的指针。p++的结果为指向下一个元素的地址。

指针p与数组的地址关系:p=a+1

→移到下一行的地址p=a[0]+1p=&a[0][0]+1p=p+1p++

指针p与二维数组a的关系详见表8-4移到下一个元素的地址8.3指针与数组的关系例7:阅读【例8-7】的程序example8_7.c,了解指针与二维数组地址的关系。思考和分析程序的运行结果。

分析程序中指针变量、数组名之间的地址关系,掌握指针与二维数组的联系。8.3指针与数组的关系例8:阅读【例8-8】的程序example8_8.c,了解指针与数组元素的关系。思考和分析程序的运行结果。

分析程序中用指针引用数组元素的表达式。

结论:①引用同一个数组元素,有多种不同的方法。②使用时选择一种自己认为最合适的。8.3指针与数组的关系

C语言还提供了一个指向多个元素的指针,它具有与数组名相同的特征,可以更方便地用指针来处理数组。

指向多个元素指针的定义形式为:

数据类型(*指针变量名)[N];其中,N是一整型常量。例如:

int(*p)[4];/*指向具有4个整型元素的数组*/float(*pt)[3];/*指向具有3个浮点型元素的数组*/若有:p=p+1;,则p的值增加16。pt=pt+1;,则p的值增加12。

理解关键点:将多个元素视为一个整体。8.3指针与数组的关系例9:阅读【例8-9】的程序example8_9.c,了解指向简单变量的指针p和指向多个元素的指针t的特性。掌握它们的使用方法。思考和分析程序的运行结果。

注意程序中指针p与指针t的不同特性。例10:阅读【例8-10】的程序example8_10.c,了解用指针引用数组元素的方法。思考和分析程序的运行结果。8.3指针与数组的关系8.3.3字符指针

指向字符型变量的指针具有另外的特性。如:char*sp;sp可以指向字符、字符数组,也可以指向一个字符串。如有:

char*sp="Howareyou?";

char*cp;cp=sp;则:指针sp和cp之间的关系如图示。8.3指针与数组的关系若有:char*sp="Howareyou?";

引用字符串中某个字符,可以通过以下两种方式。 ①*(sp+i) ②sp[i]注意:

上面的第②种情况:sp并不是数组。

如果用字符指针指向了某个字符串时,可以像引用数组元素那样,用sp[i]来引用字符串中的字符;但不可以改变字符串中sp[i]所代表的这个字符。

如果改变指针变量的值,实际上是改变了指针的指向。8.3指针与数组的关系例11:阅读【例8-11】的程序example8_11.c,了解字符指针输出数组中的字符方法。思考和分析程序的运行结果。

分析程序中指针p引用字符数组元素的方法。利用字符指针,可以很方便地完成许多字符串问题的处理。

修改程序,采用直接输出数组元素的方法,输出字符数组中的内容,并与上面的程序进行比较。8.3指针与数组的关系8.3.4指针数组

指针数组:数组中的每一个元素都是指针。

指针数组的定义形式:

[存储类型]数据类型*数组名[元素个数]例如:int*p[5];则:p为指针数组,共有5个元素:p[0]、p[1]、p[2]、p[3]、p[4]

每一个元素都是指向整型变量的指针。

通常可用指针数组来处理字符串和二维数组。例12:阅读【例8-12】的程序example8_12.c,了解用指针数组访问二维数组中的每一个元素的方法。思考和分析程序的运行结果。8.3指针与数组的关系例13:编写程序,对一组英文单词字符串进行按字典排列方式(从小到大)进行排序。分析:可以用字符指针数组来保存每一个字符串,这样数组中的每一个元素就可以指向一个字符串,通过对数组元素中的字符进行比较,就可以完成字典排序。设计一个排序函数:voidsort(char*words[],intn),可以对words中的n个字符串进行排序。

参考程序:example8_13.c

分析程序中排序函数voidsort(char*words[],intn)的实现算法。

思考:其他的算法。8.4指针作为函数的参数

指针作为变量,也可以用来作为函数的参数。

若函数的参数类型为指针型,则实参与形参的传递是一种“传址”方式。

如果函数中有对形参值的改变,实际上也就是修改了实参的值。例14:从键盘输入任意两个整数作为两个变量的值,编写程序,将这两个变量的值进行交换。分析:可设计函数voidswap(int*p1,int*p2),通过指针与变量的关系,交换指针p1和p2所指变量的值。

参考程序:example8_14.c思考和分析程序的运行结果。8.4指针作为函数的参数例15:用字符指针指向从键盘输入的字符串,编写程序,计算输入的字符串的长度。输入结束时的换行符不作为字符计入其长度。分析:

用字符指针来表示字符串时,指针指向的是字符串的首地址。输入结束时,系统会将结束标志‘\0’置于字符串的尾部。计算字符串的长度时,结束标志是不计数的。

若输入的字符串为“abcdefg”,则占用的内存单元为8个,但字符串的长度为7。

设计函数intgetlength(char*str),计算str所指字符串的长度。字符串的结束标志和输入的换行符均不计入字符的长度。参考程序:example8_15.c8.4指针作为函数的参数思考和分析程序的运行结果。请写出统计字符串长度函数的算法。

问题:

程序中结束标志(‘\0’)和换行符(‘\n’)均不计入字符的长度,若用如下的程序语句: while(*p!='\0'||*p!='\n') p++;来统计字符串的长度,是否能达到要求?为什么?8.5函数的返回值为指针指针作为一种变量,也可以作为函数的返回值。

若函数的返回值为指针,则称其为指针函数。

指针函数的定义形式为: [存储类型]数据类型*函数名([形参表]);例如:

int*fun1();

/*函数返回一个指向整型变量的指针*/ char*fun2();

/*函数返回一个指向字符型变量的指针*/8.5函数的返回值为指针例16:编写程序,从键盘输入一个字符ch,在字符串string中查找是否存在有该字符,若存在,给出该字符在字符串中第1次出现的位置。分析:对于指定的字符串string,在内存中会分配一段连续的空间存储string中每一个字符的值;

将输入的字符ch与字符串string中的每一个字符逐一进行比较,如果相等,则返回字符串中与字符ch相等的字符的位置(地址)。

设计函数char*search(char*str,charc),功能:在str所指的字符串中,查找是否有字符变量c的字符,如果有,返回字符串中相同字符的地址。参考程序:example8_16.c思考和分析程序的运行结果。请写出函数char*search(char*str,charc)的算法。*8.6指向函数的指针

函数指针就是指向函数的指针,用函数指针存放函数的入口地址。

函数指针的定义形式:

[存储类型]数据类型(*变量名)();

数据类型为指针所指函数的返回值的数据类型。

请注意定义中的两个圆括号。

如:int(*p)();

p是一个函数指针变量,所指函数的返回值为int型。

为函数指针赋值:

函数指针变量=函数名;

用函数指针调用函数,调用形式为:

(*函数指针变量名)(实参表);*8.6指向函数的指针例17:阅读【例8-17】的程序example8_17.c,了解函数指针的使用。思考和分析程序的运行结果。

提示:仅仅用函数指针替代函数名去调用函数(如程序exam8-17.c),就失去了函数指针本身的意义。

使用函数指针的意义:将函数指针设计成函数的形参,调用函数时,参数传递的是函数名。*8.6指向函数的指针例如:

intsub(int(*p1)(),int(*p2)(),inta,intb){intm,n;m=(*p1)(a,b);n=(*p1)(m,a+b);returnm+n; }若有两函数:fun1、fun2,则:调用函数:sub(fun1,fun2,x,y),达到调用其他函数的目的。

这种方法主要表现提高程序设计的模块化程度。

例18:阅读【例8-18】的程序exmaple8_18.c,了解函数指针作为函数参数的作用。思考和分析程序的运行结果。*8.7main函数的参数

C语言规定:main函数也可以带参数,参数的个数最多为3个。

(注:参数名及参数的顺序和类型是固定不变的)。

main函数的参数形式如下:

main(intargc,char*argv[],char*env[])几点说明:

①main函数的形参是具有特定的意义的。

疑问:

每一个C语言程序都是从main函数开始执行的,参数是怎样传递给main函数的?②带有main函数参数的程序,执行方式应有所不同。

执行方式:以输入命令方式执行程序。

(不适合在集成开发环境下运行)③参数来自于命令方式下执行程序时输入的一些信息。*8.7main函数的参数对于main(intargc,char*argv[],char*env[])各参数的含义如下:①第1个参数(intargc):执行该程序时输入的参数个数。每个参数都用字符串来表示,字符串之间由空格分开。②第2个参数(char*argv[]):指针数组,每一个元素分别指向执行该程序时输入的每一个参数。元素个数输入的的参数个数(argc)相等。③第3个参数(char*env[]):指针数组,每一个元素分别指向系统的环境变量字符串。元素个数与系统的环境变量个数相等。

设程序exam.c中main函数中带有参数;生成的执行程序为:exam.exe;*8.7main函数的参数

执行该程序时,输入的命令方式为:

exam<参数1><参数2>……<参数(n−1)>

参数1至参数(n−1)必须是合法的字符串。main函数中的参数值为:argc=n;argv[0]="exam“argv[1]="参数1“…argv[n-1]="参数(n-1)"。env[0]~env[m]:系统环境变量。一般而言,不同的机器会有不同的结果。*8.7main函数的参数

根据C语言的规则,main函数参数的个数允许有不同,但参数的顺序不允许变化。

因此,main函数参数的形式就只有如下4种:1.main()2.main(intargc)3.main(intargc,char*argv[])4.main(intargc,char*argv[],char*env[])例19:阅读【例8-19】的程序example8_19.c,了解main函数参数的特点,分别在命令方式下(如DOS模式)和集成开发环境下运行该程序,看看有什么变化与不同。*8.8指向指针的指针

指针作为一种变量,也是要占用内存空间的。

C语言提供另一种变量来保存指针变量的地址。

指向指针变量的指针,它的值为指针变量的地址。

定义形式为: [存储类型]数据类型**指针变量名;例如:

inta=6,*p,**pp; p=&a; pp=&p; …则:*pp的值为p的地址值。 **pp的值等于*p(变量a的值)。 a、p、pp的关系如图所示。8.8指向指针的指针例20:【例8-20】的程序example8_20.c是利用指向指针的指针变量,访问二维字符数组,请阅读程序,了解指向指针的指针变量的作用和使用方法。思考和分析程序的运行结果。提示:

要注意区分指向指针的指针与二维数组名的关系。程序中语句:ppw=pw;的作用是将指针数组的首地址传递给指向指针的指针变量。因此,表示第i行的首地址应该用*(ppw+i)而不是ppw+i。8.10程序范例例22:【例8-22】的程序是一种变化的约瑟夫问题,有30个人围坐一圈,从1到M按顺序编号,从第1个人开始循环报数,凡报到7的人就退出圈子,请按照顺序输出退出人的编号。分析:设置两个整型数组:person和pout。person用来表示30个人围成的一个队列圈。pout用来表示出队的结果。规定person元素的值只有两种情况:0和非0。非0表示该元素还在队列内;0表示该元素已出队列。从person的第1个元素开始报数,报到第7的时候,将该元素的值改为0,同时将该元素的下标值按顺序赋给另一个整型数组pout,当数组person中的所有元素的值为0时,输出顺序就生成了。设计函数:voidgoout(intpp[],intpo[],intn),从数组pp的第1个元素开始,按n循环报数出队,出队顺序保存到数组po中。

8.10程序范例参考答案:example8_22.c请写出函数voidgoout(intpp[],intpo[],intn)的算法。

算法的关键有两个地方值得注意:1.当队列报数到达最后1个元素的时候,要让指针回到数组的起始位置;2.对已经出队的元素值要赋0值。

思考:

分析程序的算法思想;

设计其他算法,并编写程序验证。8.10程序范例例23:编写程序,采用冒泡法对一组从键盘输入的任意个整数(个数≤50)进行升序排序,输出排序后的结果。分析:冒泡排序就是将最小的数放在最前面。可以将输入的数据保存到数组,再对数组元素进行排序。参考答案:example8_24.c

思考:

分析程序的算法思想;

设计其他算法,并编写程序验证。8.10程序范例例24:编写两个函数,分别完成洗牌和发牌。

温馨提示

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

最新文档

评论

0/150

提交评论