C语言精品课程电子课件模板.ppt_第1页
C语言精品课程电子课件模板.ppt_第2页
C语言精品课程电子课件模板.ppt_第3页
C语言精品课程电子课件模板.ppt_第4页
C语言精品课程电子课件模板.ppt_第5页
已阅读5页,还剩67页未读, 继续免费阅读

下载本文档

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

文档简介

1、第10章:指针,重点及要求: 掌握指针的概念、定义、指针变量的引用,掌握地址与指针的关系,掌握指针与数组的关系。 掌握指针与函数的关系。 熟悉指针的运算,了解指向void类型的指针。,10.1 地址和指针的概念,一、指针概述: 1、地址的概念与取地址运算: 内存以字节编码,每个编码都是一个地址。我们原先学过的变量、数组、函数等都放在内存中,至于它们放在内存的什么地方,这都是机器的事,我们只要知道它们是以怎样的顺序放在内存中的,以便一一按顺序引用。我们怎样知道机器将某种数据放在内存的什么地方呢?可用求地址运算符 看出其地址。注意,这个地址并不是始终不变的,这是由机器和操作系统来安排的,我们无法预

2、先知道。,则a表示的地址和 如: int *p, a = 3; int *q, b=5;,基类型,即该指针变量所指向的变量的类型,如何使一个指针变量指向另外一个变量呢?,P=,为什么要为指针变量定义类型:由于不同的数据有不同的数据类型,如 char仅占一个字节、int 占两个字节、float型占三个字节,而内存又是以字节为单位进行地址编号,因而对char型,只要地址数加减1,取出里面的数据就是char型的完整数据。对int型就不同了,要取出其中的数据需2字节,就不能对地址进行简单的加减1了。怎样取出一个完整的int型数据或float型数据呢?如果能够将指针变量也定义为具有同样的数据类型,那么对

3、指针进行加1或减1运算,就是让指针移动相应基类型对应的字节数。,指针变量赋值(这里要用到取地址运算符“,2byte,也可以在定义指针变量的同时指定其初值,如、 int a; int *p = (*表示乘法运算符),printf(“%d n” ,*p) ; p= /* 给指针p所指向的变量赋值,这里是给变量a赋值 */,例l0_1.cmain( ) int *p1, *p2, a1, a2; scanf(“%d %d” , 这里有一个运算符*,其作用是:加在指针变量的前面,取出该指针变量所指对象的内容。,例l0_2.c 使两个指针变量交换指向。 main( ) int *p1, *p2, *p,

4、 a1=10, a2=20; p1=,交换前,下面表示p1和p1交换所指内容,交换后,交换后,交换前,例l0_3.c 交换两个指针变量所指向的变量的值。 main( ) int *p1, *p2, a1, a2, a; a1=10; a2=20; p1= ,10.3 指针与数组,10.3.1 指向数组元素的指针 复习:一维数组在内存中的存放方法?,例10_4.cmain( ) int a 5 =1, 3, 5, 7, 9, *p; for(i=0;i5;i+) printf(“%d”,*(a+i);Printf(“n”);/*地址法*/ for (p=a; pa+5; p+) printf(“

5、%d” , *p);/*指针法*/ ,如何用一个指针变量将数组中的元素取出并显示出来?,当p=a后,有: p=a= int i; for(i=0;i10;i+) scanf(%d, ,2、用数组名计算数组元素的地址。(效率与下标法相同,不常用) main() int a10; int i; for(i=0;i10;i+) scanf(%d, ,3、用指针访问各元素。(常用,效率高) main() int a10; int *p, i; for(i=0;i10;i+) scanf(%d, ,使用指针指向数组,应注意以下问题: 1、若指针p指向数组a,虽然p+i与a+i、*(p+i)与*(a+i)

6、意义相同,但仍应注意p与a的区别(a代表数组的首地址,是不变的;p是一个指针变量,可以指向数组中的任何元素),例、 for(p=a; a(p+10); a+) a代表数组的首地址,是不变的,a+不合法 printf(%d, *a) 2、指针变量可以指向数组中的任何元素,注意指针变量的当前值。,例10_6 输出数组a的10个元素。 程序: main() int *p, i, a10; p = a; for(i=0;i10;i+) scanf(%d, p+); printf(n); for(i=0;i10; i+,p+) (p的值不对) printf(%d, *p); ,main() int *p

7、,i,a10; p = a; for(i=0;i10;i+) scanf(%d, p+); printf(n); p = a; for(i=0;i10; i+,p+) printf(%d,*p); 此程序正确,3、使用指针时,应特别注意避免指针访问越界。在上例中,第二次for循环,p已经越过数组的范围,但编译器不能发现该问题。避免指针访问越界是程序员自己的责任。 4、指针使用的几个细节。 设指针p指向数组a(p=a),则: p+(或 p += 1),p指向下一个元素。 *p+,相当于*(p+)。因为,*和+同优先级,+是右结合运算符。 *(p+)与*(+p)的作用不同。 *(p+):先取*p,

8、再使p加1。 *(+p):先使p加1,再取*p。, (*p)+表示,p指向的元素值加1。 如果p当前指向数组a的第i个元素,则: *(p-)相当于ai-,先取*p,再使p减1。 *(+p)相当于a+i,先使p加1,再取*p。 *(-p)相当于a-i,先使p减1,再取*p。 10.3.3 数组名作函数参数 数组名代表数组首地址,因此,它作实参在函数调用时,是把数组首地址传送给形参。这样,实参数组和形参数组共占同一段内存区域。从而在函数调用后,实参数组的元素值可能会发生变化。,例10_7 将数组a中n个元素按相反顺序存放。 算法:a0与an-1交换,a1与an-2交换,.,a(n-1)/2与an-

9、int(n-1)/2)交换。 实现:用i,j作元素位置变量,开始i=0,j=n-1。将ai与aj交换,然后i加1,j减1,直到i=(n-1)/2。,程序: Void inv(int x, int n) /* 形参是数组 */ int t,i,j,m=(n-1)/2; for(i=0; i=m; i+) j = n - 1 - i; t = ai; ai = aj; aj = t; return; /* 函数的返回值类型是void,不返回任何值 */ main() ,static int i, a10 = 3,7,9,11,0,6,7,5,4,2; printf(the original arr

10、ay:n); for(i=0; i10; i+) printf(%d , ai); printf(n); inv(a,10); printf(the array has been inverted:n); for(i=0; i10; i+) printf(%d , ai); printf(n); ,函数inv()可以用指针作形参,运行情况与用数组作形参相同。 void inv(int *x, int n) int *p, t, *i, *j, m=(n-1)/2; i = x; /* 指针i指向数组第一个元素 */ j = x + n - 1;/* 指针j指向数组最后一个元素 */ p = x

11、 + m; /* 指针p指向数组中间一个元素 */ for(;i=p;i+,j-) t = *i; *i = *j; *j = t; ,小结:数组作函数的参数,实参和形参之间传送数组的首地址,首地址可以用指针表示,也可以用数组名表示。,10.3.4 指向多维数组的指针和指针变量,若再定义 int *p; p= 这时 p+1=? int *p; for (p= a0 ; pa0+10 ; p+) printf(“ %d ”, *p); printf(“ n ”); 从中可看出,这样用p指针表示二维数组很不直观,指向时不知指在哪一行、哪一列。如果我们这样来理解二维数组,把二维数组看作是由若干行向量

12、(一维数组)组成的:如下图所示:,通过上一节的讨论,我们可以得出两点接结论: 1、在C语言中,一维数组名代表了该数组的起始地址,或者说,它是一个指向所代表数组,即指向其起始单元的指针。 2、在C语言中,一维数组的任何一个元素的地址,都可以用其数组名加上一个偏移量来表示,这个位移量的单位不是字节,而是数组元素的大小。 这两点可以推广到二维 乃至多维数组。 二维数组amn可以看做是由m个一维数组a0、a1、am-1组成。由此我们可以推导,用指向一维数组的指针(行指针)来表示二维数组元素:,*p0 *(p0+1) *(p0+2) *(p1) *(p1+1) *pi *(pi+j) *(p2+2),p

13、,例10_8.cmain( ) int a 3 5=1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15;int j, k, (*p) 5; p=a; for (j=0; j3; j+) for (k=0; k5; k+) printf(“ % d ” , *(*(p+j)+k); printf(“ n ”); ,P实际上是一个二级指针,必须对它施加两次*运算,才能得到相应的数组元素值。,10.4 字符串的指针,10.4.1 字符串的表现形式 C语言中,有两种方式可以实现字符串:字符数组、字符指针。,例10_16 main() char strin

14、g=“I love China!” Printf(“%sn”,string); ,例10_17 main() char *string=“I love China!” Printf(“%sn”,string); ,以上两程序输出结果均为: I love China!,从以上两个例子中,可以看到: 1、字符数组和字符指针的概念不同。 2、字符指针指向字符串,而C语言中,字符串按数组方式处理,因此,字符数组和字符指针的访问方式相同。例如,均可以使用%s格式控制符进行整体输入输出。但应注意,如果不是字符数组,而是整型、实型等数字型数组,不能用%s,只能逐个元素处理。,例10.18 将字符串a复制到字

15、符串b。 main() char a = I am a boy.“; char b20; int i; for(i=0; *(a+i) !=0; i+) *(b+i) = *(a+i); *(b+i) = 0; printf(string a is: %sn,a); printf(string b is: %sn,b);,for(i=0; bi !=0; i+) printf(%c,bi); printf(n); 例10.19 将字符串a复制到字符串b。(用指针处理) main() char a=I am a boy., b20, *p1, *p2; int i; p1 = a; p2 = b

16、; for(;*p1 != 0; p1+, p2+),*p2 = *p1; *p2 = 0; printf(string a is: %sn, a); printf(string b is: %sn,b); for(i=0; bi !=0; i+) printf(%c,bi); printf(n); ,10.4.2 字符串指针作函数参数 将一个字符串从一个函数传递到另一个函数,可以使用传地址的方式,即用字符数组名或字符指针变量作参数。有以下四种情况: 实参 形参 数组名 数组名 数组名 字符指针变量 字符指针变量 字符指针变量 字符指针变量 数组名 例10.20 用函数调用实现字符串的复制。

17、(1)用字符数组作参数。,Void copy_string(char from, char to) int i=0; while(fromi != 0) toi = fromi; i+; toi = 0; main() char a = I am a teacher.; char b = you are a student.; printf(string_a =%sn string_b =%sn,a,b); copy_string(a,b); printf(string_a =%sn string_b=%sn,a ,b); ,main()函数可以改写为(使用字符指针): main() char

18、 *a = I am a teacher.; char *b = you are a student.; printf(string_a =%sn string_b =%sn, a,b); copy_string(a,b); printf(string_a =%sn string_b =%sn, a,b); ,(2)形参用字符指针。 Void copy_string(char *from, char *to) for(; *form != 0; from+, to+) *to = *from; *to = 0; main() char *a = I am a teacher.; char *b

19、 = you are a student.; printf(string_a =%sn string_b =%sn, a,b); copy_string(a,b); printf(string_a =%sn string_b =%sn, a,b); ,10.4.3 字符串指针变量与字符数组的区别 字符数组 字符指针变量 由若干元素组成,每个元素中放一个字符。 存放字符串的首地址。 static char str=I love China!; char *a = I love China!; char str14; char * a; str = I love China! a = I love

20、 China!; 字符数组一个元素占一字节内存,且在编译时分配。指针变量中只可以放一个地址值(近指针=2字节,远指针=4 字节)。且编译时未指定 char str10; char *a; scanf(“%s”,str); scanf(“%s”,a);尚未指向任何变量 字符数组名是地址常量 指针变量可以进行、等运算 不允许进行、等运算 指针的变量的值允许改变 书上例题(p154,155),10.5 指向函数的指针变量 10.5.1 使用函数指针调用函数。 指向函数的指针变量 函数的指针:函数的入口地址(函数的首地址)。C语言规定函数的首地址就是函数名,所以函数名就是函数的指针。 指向函数的指针变

21、量:存放函数入口地址(函数指针)的变量,称为指向函数的指针变量。简称函数的指针变量。 函数可以通过函数名调用,也可以通过函数指针调用。 通过函数指针实现函数调用的步骤: 1、指向函数的指针变量的定义: 类型 (* 函数指针变量名)(); 例如 int (*p)(); 注意:两组括号()都不能少。int表示被指向的函数的类型,即被指向的函数的返回值的类型。,2、指向函数的指针变量的赋值,指向某个函数: 函数指针变量名=函数名; 3、利用指向函数的指针变量调用函数: (* 函数指针变量名)(实参表) 例10_21:输入10个数,求其中的最大值。P155. /* 使用函数名调用函数 */ main(

22、) int i,m,a10; for(i=0; i10; i+) scanf(%d, ,int max(int *p) /* max在10个整数中选择最大值 */ int i,t=*p; for(i=1; it)t=*(p+i); return t; 结果: -52 87 29 79 -32 94 23 -112 46 67 max=94 声明函数 /* 使用函数指针变量调用函数 */,main() int i,m,a10,max(int *); /* declare func */ int (*pf)(); /* define func pointer */ for(i=0; imax()

23、*/ m=(*pf)(a); /* call max */ printf(max=%dn,m); ,声明函数,指针的定义: 定义函数指针变量pf (返回整型数),指针的初始化: 函数指针pf指向max,指针的引用: 调用函数指针pf指向的函数max,int max(int *p) int i,t=*p; for(i=1; it)t=*(p+i); return t; 说明: (1)定义函数指针变量时,两组括号()都不能少。如果少了前面的一组括号=返回值类型 * 函数名();-返回值为地址值(指针)的函数。 (2)函数指针变量的类型是被指向的函数的类型,即返回值类型。 (3)函数指针的赋值,只要

24、给出函数名,不必给出参数。(不要给出实参或形参)。 (4)用指针变量调用函数时,(* 函数指针)代替函数名。参数表与使用函数名调用函数一样。,(5)可以看出,定义的函数指针变量可以用于一类函数,只要这些函数返回值类型(函数类型)相同。 函数可以通过函数名调用,也可以通过函数指针调用。函数指针常常用在函数需要作为函数参数的情况。 10.5.2 用指向函数的指针作为函数的参数(常用于编制“通用”的函数) 函数的参数除了可以是变量、指向变量的指针,数组(实际是指向数组的指针)、指向数组的指针以外,还可以是函数的指针。 函数的指针可以作为函数参数,在函数调用时可以将某个函数的首地址传递给被调用的函数,

25、使这个被传递的函数在被调用的函数中调用(看上去好象是将函数传递给一个函数)。函数指针的使用在有些情况下可以增加函数的通用性,特别是在可能调用的函数可变的情况下。,例10_22:编制一个对两个整数a,b的通用处理函数process,要求根据调用process时指出的处理方法计算a,b两数中的大数、小数、和。 解:int max(int ,int ); int min(int ,int ); int add(int ,int ); int add1(int); main() int a,b; printf(“enter two num to a,b:”); scanf(%d%d,声明3个处理函数(

26、只需要形参类型),printf(max=%dn,process(a,b,max); /* 调用通用处理函数 */ printf(min=%dn,process(a,b,min); printf(add=%dn,process(a,b,add); printf(add1=%dn,process(a,b,add1); int max(int x,int y) return xy?x:y; /* 返回两数之中较大的数 */ int min(int x,int y) return xy?x:y; /* 返回两数之中较小的数 */ int add(int x,int y) return x+y; /*

27、返回两数的和 */ int add1(int x) return x+1; ,否则编译器不知道max,min是变量还是什么其它符号,虚实结合时,函数指针赋值,int process(int x,int y, int (*f)() /* 通用两数的处理函数 */ return (*f)(x,y); 结果: Enter two num to a,b:3 8 max=8 min=3 add=11 add1=4 说明:,定义函数指针变量,调用函数指针指向的函数,(1)函数process处理两个整数数,并返回一个整型值。同时又要求process具有通用处理能力(处理求大数、小数、和),所以可以考虑在调用

28、process时将相应的处理方法(“处理函数”)传递给process。 (2)process函数要接受函数作为参数,即process应该有一个函数指针作为形式参数,以接受函数的地址。这样process函数的函数原型应该是: int process(int x,int y,int (*f)(); (3)“函数指针作为函数参数”的使用与1、4、1节介绍的步骤完全相同,即函数指针变量的定义-在通用函数process的形参定义部分实现;函数指针变量的赋值-在通用函数的调用的虚实结合时实现;用函数指针调用函数-在通用函数内部实现。 (4)main函数调用通用函数process处理计算两数中大数的过程是这

29、样的:,l将函数名max(实际是函数max的地址)连同要处理的两个整数a,b一起作为process函数的实参,调用process函数。 lprocess函数接受来自主调函数main传递过来的参数,包括两个整数和函数max的地址,函数指针变量f获得了函数max的地址。 l在process函数的适当位置调用函数指针变量f指向的函数,即调用max函数。本例直接调用max并将值返回。这样调用点就获得了两数大数的结果,由main函数printf函数输出结果。 同样,main函数调用通用函数process处理计算两数小数、和的过程基本一样。,(5)教材:P244,process函数头部:函数指针定义中不需

30、要指定形参个数。但是一般情况函数指针指向的函数参数个数一般是数量类型相同的,以便用统一的格式如(*f)(x,y)去调用。 process函数是一个“通用”整数处理函数,它使用函数指针作为其中的一个参数,以实现同一个函数中调用不同的处理函数。 10.6 返回指针值的函数 函数可以返回整型、实型、字符型等类型的数据,还可以返回地址值-即返回指针值。 返回指针值的函数定义:类型名 * 函数名(参数表) 例如: int *fun(int x,int y)表示func是返回整型指针的函数,返回的指针值指向一个整型数据。该函数还包含两个整型参数x,y。,系统内存分配函数void *malloc(size_

31、t size);也是一个返回指针值的函数。返回的指针指向一片分配好的内存空间。 例10_23:返回两个数中大数地址的函数。 int *fun(int,int); main() int i,j,*p; printf(enter two num to i,j:); scanf(%d%d, /* 打印p指向的数据 */ ,int *fun(int x,int y) /* fun函数返回形参x,y中较大数的地址(指针) */ int *z; if(xy)z= 结果: enter two num to i,j:12 38 max=38,说明: (1)main函数从键盘获得两个整数i,j(本例12,38)

32、。将i,j作为实参调用fun。 (2)通过虚实结合,fun函数的形参x,y获得了这两个整数(本例12,38),将大数的地址返回(本例是 定义一个4个元素的数组p,其中每个元素是一个整型指针,也即数组p是一个4元素整型指针数组。 又如:char *p4; 定义一个4个元素的字符指针数组p,其中每个数组元素是一个字符指针,可以指向一个字符串。也就是说利用此字符指针数组可以指向4个字符串。 指针数组用得最多的是“字符型指针数组”,利用字符指针数组可以指向多个长度不等的字符串,使字符串处理更加方便、灵活,节省内存空间。,Name 使用二维字符数组存储多个字符串(上图) 指针数组name 字符串,使用字

33、符型指针数组指向多个字符串 (上页下图) 使用字符型指针数组指向多个字符串与使用两维字符数组存储多个字符串的比较: (1)节省存储空间(二维数组要按最长的串开辟存储空间) (2)便于对多个字符串进行处理,节省处理时间。(使用指针数组排序各个串不必移动字符数据,只要改变指针指向的地址) 说明: (1)main()中定义了指针数组name,它有4个元素,其初值分别是C Program,BASIC,Computer English,Word四个字符串常量的首地址。 (2) 函数sort使用选择排序法对指针数组指向的字符串进行排序(按字母顺序),在排序过程中不交换字符串本身,只交换指向字符串的指针(n

34、ameknamei)。,(3)排序前后指针数组的指向参看教材p161图10-12,p162图10-13。 (4)利用字符指针数组进行字符串排序。 10.7.2 指针的指针 、指针的指针:指向指针变量的指针变量。指针的指针存放的是指针变量地址. 指针变量的指针变量(指针的指针)的定义: 类型 *指针变量名; 例如:,int i=2; /* 定义整型变量i */ int *p1,*p2; /* 定义p1为整型指针,定义p2为整型指针的指针 */ p1= /* 指针p1的地址=p2,即,指针p2指向指针p1 */ 对变量i的访问可以是i,*p1,又因为*p2=p1,即,*p2=*p1,所以对变量i的访问可以是i,*p1,*p2。 2、 指针的指针与指针数组的关系,我们知道,数组的指针是指向数组元素的指针(整型、实型、字符型一维数组的指针分别是指向整型、实型、字符型指针,二维数组的指针是指向一维数组的指针);同理: 指针数组的指针,也是指向其数组元素的指

温馨提示

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

最新文档

评论

0/150

提交评论