C语言chap8(指针).ppt_第1页
C语言chap8(指针).ppt_第2页
C语言chap8(指针).ppt_第3页
C语言chap8(指针).ppt_第4页
C语言chap8(指针).ppt_第5页
已阅读5页,还剩43页未读 继续免费阅读

下载本文档

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

文档简介

第8章 指针,8.1 指针概念,指针是C的一个重要概念。其特点是: 能有效地表示复杂的数据结构;能动态地分配内存,直接处理内存地址;能方便、有效地使用字符串和数组;能在调用函数后获得多个值。 C中定义的变量,在编译时按变量的类型来分配一定长度的内存单元。在运行时,根据变量名与地址的对应关系,相应地存取变量的数据。这种按变量地址存取变量值的方法称为“直接访问”方式。 如果变量的地址也存放在某一个内存单元,则存取方式为先找到存放变量的地址单元,再取变量的值,这种方式称为“间接访问”方式。如: 将变量 i 的地址保存到p中; 依据p当然可以访问到i,8.1.1. 变量的指针和指向变量的指针变量,变量的指针就是变量的地址,即p的值。也就是说, 指针变量的值就是该指针变量所指变量的内存首地址。 在p的前面加上一个“ * ”(称其为“间接引用运算符”),即*p就表示指针变量p所指向的变量。 从右图可知 : *p也是一个变量,且与变量 i 是同一回事。 i = 3;与p= 是同一回事 / 将3赋给指针变量p所指向的变量 /,8.1.2指针变量的定义,定义形式: 类型标识符 *标识符; 指针变量必须定义指针所指数据 类型。如: int i, j; int *p1,*p2; p1= 非法。,与指针有关的运算符: 是将变量j的值赋给目标变量*p(即i)。 * 运算和& 运算互为逆运算。 &(*p)的结果为p,即变量*p的地址; *(&i)表示访问变量 i 的地址,其结果就是 i 本身。 &p为指针变量p的地址。,8.1.3 指针变量的引用,运行结果: 100, 10 100, 10,例8.1 main( ) int a,b; int *p1,*p2; a=100; b=10; p1= / *p1和*p2就是变量a和b / , 若先执行p1= 是什么意思? 这里“&”和“*”的优先级相同,但按“自右至左”结合, 即&*p1与&a相同。, 若先执行p1= 则 *&a和*p1的作用相同。即:*&a与a是等价的。,说明:,而p2= 的作用是将&a 赋给p2。, (*p1)+ 等价于a+。,注意:括号是必须的,否则就成为*(p1+)。这时先按p1的原值进行 * 运算得到a的值。然后使p1的值改变,则p1不再指向a了。,注意:此例中a和b并未交换,而p1和p2的值改变。,例8.2 main( ) int *p1,*p2,*p,a,b; scanf(“%d,%d”, ,运行情况: 5,9 a=5,b=9 max=9,min=5,8.2 指针的运算 8.2.1 指针的算术运算 主要为 + - + - P+ 、 p 分别表示向后、向前移一个单元。 P+n、p-n 分别表示向后、向前移n个单元。 8.2.2 指针的关系运算 主要为 = 、 !=两种。 当两个指针p1与p2指向同一地址时,p1=p2为真, 当两个指针p1与p2不指向同一地址时,p1!=p2为真。,8.3.1 指向一维数组的指针 例:int a10, *p; p= 则*(p+i)或*(a+i)就是p+i或a+i所指向的数组元素,即ai。也就是说 *(p+i) = *(a+i) = ai。 指向数组的指针变量可以带下标,如:pi 与 *( p+i)是等价的。,8.3 指针与数组,也可写成如下: main( ) int a10, *p=a , i ; for ( i=0; i10; i+) scanf(“%d”,p+); printf(“n”); p=a; / 此语句必不可少 / for ( i=0; i10; i+, p+) printf(“%d”,*p); ,例8.3 输出有10个元素的整型数组a的元素值。 main( ) int a10, *p, i ; for (i=0; i10; i+) scanf(“%d”, , 要注意指针变量的运算。如果p指向数组a (即p=a),则: p+(或p+=1)表示p指向下一个元素;*p表示取得当前所指元素之值。 *p+等价于*(p+),相当于ai+,表示先*p,再p+1p。 *p 等价于*(p ),相当于ai ,表示先*p,再p1p。 *(+p) 相当于a+i,表示p+1p,再*p。 *( p) 相当于a i,表示p1p,再*p。 (*p)+ 表示p所指之元素的值加1,不是指针值加1。即ai+1。, 要注意指向数组的指针变量的当前值,因为指针可以指向数组最后一个元素以后的内存单元。,设二维数组a定义如下: static int a34=1,3,5,7,9,11,13,15,17,19,21,23; a 代表整个二维数组的首地址,也就是0行的首地址。a+1、a+2分别代表1行和2行的首地址。同样,a0或&a00、a1或&a10、a2或&a20也分别代表0行、1行、2行的首地址。 a0等价于*(a+0)、a1等价于*(a+1), ,ai等价于*(a+i)。因此,a0+1和*(a+0)+1的值都是&a01;a1+2和*(a+1)+2的值为&a12。 *(a+1)+2不能写成*(a+1+2),否则就变成*(a+3), 即a3。 因a0+1和*(a+0)+1是a01的地址,则*(a0+1)就是a01的值, 同理,*(*(a+0)+1)或*(*a+1)是a01的值,*(a i + j)或*(*(a+i)+j )是a i j的值。,8.3.2 指向多维数组的指针,务必记住:*( a + i ) 和 a i 是等价的。, 如果 a 是一维数组名,则a i 代表第 i+1个元素所占的内存单元。但如果a是二维数组,则a i 代表一维数组名,a i 本身是不占用内存单元的, 也不存放元素值,而只是一个地址。,a、a+i、a i 、*(a+i)、*(a+i)+j、a i +j都是地址,而*(a i +j)、*(*(a+i)+j)是二维数组元素a i j的值。, 在二维数组中&a i 并不是a i 单元的物理地址,但能得到i行的首地址。虽然&a i 和a i 的值是相同,但含义不同。&a i 或a+i表示行,而a i 或*(a+i)表示列。, 在一维数组中a+i所指的是第i个数组元素的存储单元;在二维数组中,a+i=a i =*(a+i)=&a i =&a i 0,都表示 i 行0列元素的地址。,例8.4 输出二维数组中任一行任一列的元素。 main( ) static int a34=1,3,5,7,9,11,13,15,17,19,21,23; int (*p)4, i, j; p=a; scanf(“i=%d, j=%d”, ,运行情况: i=1, j=2 /* 注意这里的输入格式 */ a1,2=13,程序中的“int (*p)4”表示 p 是一个指向包含4个元素的一维数组的指针变量,即p是一个行指针,指向一维数组的首地址。由于运算符优先级的关系,这里的(*p)4不能写成*p4。,一、 字符串的表示形式 用字符数组实现 static char str =“I love China !”; stri表示字符数组中的第i+1个字符。如: str8为字符h 用字符指针实现 char *a=“I love China!”; 尽管没有定义为字符数组,但实际在内存开辟了一个字符数组用来存放字符串常量。同样,a8为字符h。 注意: a不是字符串变量,只是将“I love China!”的首地址赋给指针变量a 。,8.3.3 字符串的指针,二、 字符串指针作函数参数,可以用地址传递的方式,即用字符数组名作参数或用指向字符串的指针变量作参数,将一个字符串从一个函数传递到另一个函数。,例8.5 用函数调用实现字符串的复制。, 用字符数组作参数,void copy_string( from , to ) char from , 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.” ; copy_string( a , b) ; printf( “string_a = %snstring_b = %sn”,a,b); ,运行结果: string_a = I am a teacher. string_b = I am a teacher., 形参用字符指针变量,void copy_string(from , to) char *from , *to ; for ( ; *from != 0; from+; to+) *to = *from ; *to = 0; main( ) char *a= “I am a teacher.”; char *b= “you are a student.”; copy_string(a,b); printf( “string_a = %snstring_b = %sn”,a,b) ; ,用字符数组和字符指针变量都能实现字符串的存储和运算,但二者之间是有区别的,不要混为一谈,必须注意以下几点: 字符数组由若干个元素组成,每个元素可存放1个字符,而字符指针变量存放的是字符串的首地址,绝不是将字符串存放到字符指针变量中。 对字符数组赋初值要用static存储类别,如: static str =“I love China!”; 而对字符指针变量不必加 static,如: char *a=“I love China!”; 这是因为它只是对指针变量初始化,而不是对数组初始化。 对字符数组只能对各个元素赋值,下列方式是错误的 char str15; str=“I love China!”;,三、 字符指针变量与字符数组, 对字符指针变量赋初值时:,char *a=“I love China!”; 等价于: char *a; a=“I love China!”;,而对于字符指针变量,可采用如下方法: char *a; a = “I love China!”; 这里赋给a的是字符串的首地址,而不是字符串。,即数组可以在变量定义时整体赋初值,但不能在赋值语句中整体赋值。,注意:对数组初始化时: static char str14=“I love China!”; 不等价于: char str14; str =“I love China!”;,char str14; scanf(“%s”,str); 是可以的。但如果写成如下形式: char *a; scanf(“%s”,a); 是非常危险的。因为指针变量没有确定的地址而指向程序区或其它数据区,从而会造成系统“冲突”。应当写成如下形式: char *a, str10; a=str; scanf(“%s”,a);, 数组在编译时被分配内存单元,有确定的地址。而指针变量必须赋给一个确定的地址值,否则,在程序运行时会发生意想不到的后果。如:,main( ) char *a=“I love China!”; a=a+7; printf(“%s”,a); 运行结果如下: China! 下面的写法是错误的: char str =“I love China!”; str=str +7; printf(“%s”,str); 若定义一个指针变量使它指向一个字符串后,可以用下标形式引用指针变量所指字符串中的字符。, 指针变量的地址值是可以改变的,而数组名的地址值是不能改变的。如:,例8.6 main( ) char *a=“I love China.”; int i=5; printf(“%cn”,ai); for (i=7; ai!=0; i+) printf(“%c”,ai); ,运行结果如下: e China., 可以用指针变量指向一个格式字符串来代替printf函数中的格式字符串。也可以在定义字符数组赋初值时赋予一个格式字符串代替printf函数中的格式字符串。如: char *format; format=“a=%d, b=%f n”; printf(format, a, b); 它相当于: printf(“a=%d, b=%f n”, a, b);,例8.7 顺读和倒读都一样的字符串称为“回文”,如:LEVEL。试编写一个判断输入的字符串是否为回文的程序。 #include “stdio.h” #include “string.h” main( ) char s81, *pi, *pj; int i, j, n; gets(s); n=strlen(s); pi=s; pj=s+n-1; while (*pi= ) pi+; / 跳过输入时的前导空格 / while (*pj= ) pj-; / 跳过输入时的尾随空格 / while (pipj) ,8.3.4 指针数组,char *p ; int i; for (i=0; i5; i+ +) p= name+i; printf(“%sn”,*p); , 指针数组的概念,指针数组的定义形式: 类型标识符 *数组名数组长度,例如:int *p4; 定义了有4个元素的指针数组,每个数组元素都可以指向一个整型变量。,例8.8 main( ) static char *name =“Follow me”, “BASIC”, “Great Wall”, “FORTRAN”, “Computer design”;,指向指针的指针,指针变量作为函数参数的作用是将一个变量的地址传送至另一个函数中 例8.9,8.4 指针变量作为函数参数,用指针变量作参数调用函数能获得多个值。此例中a和b的值交换,而s1和s2的值不变。,8.5 返回指针值的函数 返回指针值的函数也称为指针函数。调用指针函数后能得到一个指向指定类型数据的指针(地址)。指针函数的定义形式如下: 类型标识符 *函数名(参数表) 例如:int *fa(x, y); 定义了一个指针函数 fa 。 x , y 为函数 fa 的形参。,例:8e_1 在字符串中寻找关键字(演示) #include char *search(char *tagstr, char *c) char *p=tagstr; while(*p!=0) if (*p=*c) return p; p+; return NULL; ,main() char *string=“I am a student“,c; printf(“Please enter the character:“); scanf(“%c“, ,8.6 指向函数的指针,1.函数指针变量的定义,例:int (p) ( );,表示p为一个函数指针变量,用于存放一个函数的入口地址,但该函数的返回值必须为int型。,2.给函数指针变量赋值,3.通过函数指针变量调用函数的方法,它不是实参,不是调用,而是将入口地址赋给该变量。,函数指针变量函数名;,(函数指针变量名) (实参表列);,注意指针函数与指向函数的指针变量之间的区别。 int (*a)( ); 定义a为指向函数的指针变量。 例如: int *a(x,y); 定义a为整型指针函数。,一、 用函数指针变量调用函数,例8.10 求a、b 两数中较大者。 main( ) int max( ); int (*p)( ); / 说明p是指向函数的指针变量 / int a, b, c; p=max; scanf(“%d, %d”, ,二、函数指针变量作为函数参数,意义:当一个函数被调用后,执行过程中可以根据实参的函数名来调用不同的函数。,前面介绍过:简单变量、数组名、指针变量均可作为函数的参数。,可以用函数指针变量作为函数的参数。,例:sub (x1, x2) int (x1 )( ), (x2 )( ); int a, b, i, j; a=(x1) (i); b=(x2) (i, j) ,于是,可用 sub(f1, f2)或sub(f3, f4)调用sub,表示执行sub时,根据实参传递过来的函数入口地址而调用f1, f2或f3, f4。,例8e_2. 设计一个函数process, 每次实现不同的功能,当用不同的函数名作实参调用process时,process再去调用相应的函数。,程序如下(演示) #include main ( ) int max( ), min( ), add( ); int a, b; printf(“enter a and b:“); scanf(“%d, %d“, ,printf(“max=“); process(a, b, max); printf(“min=“); process(a, b, min); printf(“sum=“); process(a, b, add); ,每次调用同一个 函数名process 完成了不同功能,max(x, y) int x, y; int z; if (xy) z=x; else z=y; return(z); ,min(x, y) int x, y; int z; if (xy) z=x; else z=y; return(z); ,add(x, y) int x, y; int z; z=x+y; return(z); ,process (x, y, fun) int x, y; int (* fun) ( ); int result; result=(*fun) (x,y); printf(“%dn“, result); ,注:当用函数名作参数时,不论函数返值类型如何均应作说明,以与变量名相区别。,enter a and b:2, 6 max=6 min=2 sum=8,运行情况如下:,那么它的实参从何而来?实参代表的含义是什么? 观察DOS系统下的一种命令: c: copy FILE1.C FILE2.C,main( )既可为无参函数,也可为有参函数,有参函数形式: main (int argc, char *argv , char * env ) ,8.7 main函数参数,其中:copy为命令 , FILE1.C 和FILE2.C为其参数。,对于一个在DOS下运行的C程序,也可以给一些参数:,当以这种方式运行C程序,则argcn, argv为指针数组,每一个元素指向包含命令在内的n个字符串。,即: argv0“pop“ argv1 “参数1“ argvn 1 “参数n 1 “,如:c: pop 参数1 参数2 参数n1,#include main (argc, argv) int argc; char argv ; printf(“argc=%d“, argc); while (argc1) +argv; printf(“%sn“, argv); argc; ,例:8e_3编写main( )函数,将后面的参数输出(演示),file1 China Beijing Changsha argc=4 China Beijing Changsha,上述文件设为file1 则运行时:,指向指针数据的指针变量称为指向指针的指针。如: char *p; *运算符的结合性是从右至左,因此,*p相当于*(*p)。,8.8 指向指针的指针,例8.11 main( ) static int a5=1, 3, 5, 7, 9; static int *num5= /* 此处*p改为*p行吗?*/ ,注意:不得将第2、3行错写为如下的一行: static int *num5=1,3,5,7,9;,例8.12 输入一行字符,统

温馨提示

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

评论

0/150

提交评论