版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第十章 指针,内容提要 指针的概念 指针变量的定义和引用 数组与指针 字符串与指针 指向函数的指针(了解) 返回指针值的函数(了解) 指针数组和指向指针的指针(了解),A、B、C三人欲使用某旅馆的房间。A先到达旅馆,在服务台登记房间,房号是518。然后A电话通知B,但没有通知C。 B和C该怎样找到A呢? B可以直接到518找到A。 C可以从旅馆的服务台查询到A的房号是518,再找到A。,例子,10.1 指针的概念,一、变量的地址 计算机中,数据的存储在内存中。 内存可划分若干存储单元,每个单元可以存放8位二进制数,即一个字节。 内存单元采用线性地址编码,每个单元具有唯一的地址编码。,1、变量的
2、地址:系统为变量分配的内存单元的地址 一个无符号的整数 int a; float b; a=3; b=5;,存储区间,变量i的地址 2000 变量j的地址 2002 变量k的地址 2004,数组a的指针元素a0的地址 2030 元素a1的地址 2032 元素a2的地址 2034,i j k,a0 a1 a2,变量i、j、k以及数组a的地址分配:,例:若定义int i,j,k,a3;,2、变量的有关概念 存储内容:数据值 空间大小:数据类型 空间位置:地址 生存周期:存储类别,二、变量的访问方式,1、直接访问:通过变量名进行访问;,int a; float b; a=3; b=5;,将3送入a所
3、占用的内存单元,a b p,2、间接访问:通过一个变量来访问另一个变量,定义一个变量p,存放a的地址,通过p访问a, 若将变量p的值改为3AB8(b的地址),则可以通过p访问b。,如何定义p? 如何获得变量a的地址? 通过p访问a?,例:int i,j,k,*p; /*定义p为指针变量*/ i=3; j=i*2; /*变量的直接访问*/ p= /*以p的值作为地址对i间接访问*/ ,2000 2002 2004 3010,i j k p,3 6 9 2000,三、指针变量,指针变量就是存放地址的变量。 如p为指针变量,它存放整型变量a的地址,则称指针变量p指向整型变量a,a b p,地址也称为
4、“指针”,变量的地址就是变量的指针。 数组、函数也都有指针。数组的指针是数组的起始地址,函数的指针是函数的入口地址。,指针变量的性质 定义后,编译时为其分配一个存储单元,该单元的字节数与编译系统存储模式有关:隐含的小模式下为2字节,大模式为4字节; 指针变量中只能存放指针(地址); 按指针变量所指向的对象,指针变量可分类为: 指向变量/数组元素的指针变量(存放变量指针) 指向数组行的指针变量(存放数组某行指针) 指向函数的指针变量(存放函数入口地址),10.2 指针变量的定义和引用,一、指针变量的定义方法 类型标识符 *指针变量名,指针说明符,指针变量的类型 所指向的数据的类型。,int *p
5、1,*p2; float *pf; char *ps;,注意: 1)每个指针变量都要加*号,表明指针变量, *本身不是变量的一部分; 2)类型标识符,不是指针变量本身的类型,指针变量为整型,存储长度:2 / 4字节。 3)某种类型的指针变量只能指向同类型的变量。如:pf只能指向float型的变量。 4)每个指针变量有各自的存储单元,在未赋值前其值不定。,二、指针变量的赋值,指针变量的值是个无符号整数。 不能直接将整常量赋给指针变量。,用变量的地址给指针变量赋值(求地址运算符 p=,用相同类型的指针变量赋值 注:若不赋值,指针变量的值是随机的,赋空值NULL,如:int a; int *p1,*
6、p2; p1=,如:int *p; p=NULL; 或 p=0;,指针变量初始化的方法: 赋空值NULL 用已定义变量的地址,如:int *p=NULL; float a; float *p2=,赋值规则: 1)赋值的指针单位要一致; 指向变量的指针变量=变量或数组元素的指针 指向数组行的指针变量=数组行的指针 指向函数的指针变量=函数的指针 2)赋值的指针类型要一致; 如:指向整型指针变量=整型变量的地址 注意: 不能随意将一个整数赋给指针变量,只能将有效的指针值赋给指针变量。 如:p1=100; 使p1指向了100号存储单元,而100号单元对用户是不透明的,若出现利用p1向100号单元赋值
7、的情况将导致对系统或用户程序的破坏。,三、指针变量的应用,1、两个有关的运算符 p=,访问所指变量 取内容:b=*p; printf(“%dn”,*p); 存内容:*p=100;,viod main() int a=5,b=3; int *p; p=,注意:*P若出现在“”的左边则为存内容 *P若出现在“”的右边或其他表达式中为取内容,2 、运算规则,*、*p=,结果是: 2 2 3 2,从右向左计算参数值,例:计算一个数的倍数。 #include stdio.h void main( ) int a, b; int *p1, *p2; p1= 5 a=5,b=10 int *pa, *pb,
8、 *pc; pa= ,2 3 a=2,b=3 c=5 c=5 c=6 c=6 c=7 a=4,b=4,(*pa)+)+*pb,例:利用指针变量将a、b按先大后小的顺序输出。 方法1:不改变a、b的值,而使p1指向值大的变量。 #include stdio.h void main( ) int *p1, *p2, *p, a, b; scanf(%d,%d, ,5,8, scanf(%d,%d, ,5,8, t=x;x=y;y=t; main( ) int a=3,b=5; swap(a,b); printf(”%d,%dn”, a,b); ,#include viod swap(int *x,
9、int *y) int t; t=*x;*x=*y;*y=t; main( ) int a=3,b=5; swap( ,a b x y,3,5,3,5,2000 2040 2400 2470,2000,2040,viod swap(int *x,int *y) int *t; t=x; x=y; y=t;,错误,错误,viod swap(int *x,int *y) int *t; *t=*x; *x=*y; *y=*t;,有问题(t没指向变量),#include void swap(int *p1, int *p2) int t; t=*p1; *p1=*p2; *p2=t; void ma
10、in( ) int a, b,c; scanf(“%d,%d,d, ,形参 p1,形参 p2,例:输入三个数,按大小顺序输出。 利用指针作为函数的参数,将a、b按a大b小的顺序存储。,结论: 为使在函数中改变了的变量值能被main函数所用,用指针变量作为函数参数,在函数执行过程中使指针变量所指向的变量值发生变化,函数调用结束后,这些变量值的变化依然保留,这样就实现了“通过调用函数使变量的值发生变化,在主调函数中使用这些改变了的值”的目的。,想通过函数调用得到n个要改变的值: 在主调函数中设n个变量,用n个指针变量指向它们; 然后将指针变量作实参,将这n个变量的地址传给所调用的函数的形参; 通过
11、形参指针变量,改变该n个变量的值; 主调函数中就可以使用这些改,思考: 1)若以基本类型变量为形参是否可实现交换? void main( ) ; if(ab) swap(a, b); ; void swap(int x, int y) int t; t=x; x=y; y=t; ,实参a,8,形参x,实参b,5,形参y,t,5,2)改变形参指针变量的指向是否可实现交换? void main( ) ; if(ab) swap( ,a,实参 char c1, c2, *p1; c1=getchar( ); c2=getchar( ); p1= ,2010,c1,第一次调用:,实参p1,E,2011
12、,c2,第二次调用:,实参p1,F,形参 p,*p=*p-32,形参 p,*p =*p-32,例:编写一个简化的模拟scanf(“%d”, 分析:这个例子可以使我们了解两点: scan_exa 函数怎样将字符串转换成整数; scanf 函数参数中地址表的意思,为什么要用变量地址,而不用变量名。, 计算机接收键盘信息,接收的是ASCII码。例如键入 123 1 2 3 转换整型数的方法:循环读字符,赋给字符变量c,用公式t=10*t+(c-0)将各位字符拼成一个整数。 为了使拼好的整数能够传回主函数,函数形参p应是指针变量,实参是地址,拼好的整数赋给p所指向的变量,就是实参地址所指的变量,这样主
13、函数就能得到转换好的整数了。,#include stdio.h void main() int i,k; void scan_exa(int *); scan_exa( ,10.3 数组与指针,一、一维数组与指针,1、数组是连续存放若干各元素的集合 2、数组名就是指向此数组第1各元素的指针(首地址) 如:int a10,*p; 则p=a等价于 p= int *p= ,3 5 4, 6,#include void main( ) int i, a5; int *p; for (i=0;i5;i+) p= ,#include void main( ) int i, a5; int *p=a; fo
14、r (i=0;i5;i+,p+ ) *p = i; printf(“%3dn, *p); printf(“n); ,0 1 2 3 4,注意:数组首地址、元素地址、下一个元素地址,数组指针、指针变量和数组元素之间的关系,设有int a10,*p; p=a;则,地址关系,内容关系,例 :数组的使用,#include void main( ) int i, a5, *pa; printf(“Input 5 numbers:n“); for (i=0;i5;i+) sacnf(“%d”, ,sacnf(“%d”, a+i );,sacnf(“%d”, p+i );,printf(“%d”, *(a+
15、i);,printf(“%d”, *(p+i);,二、指针的运算,1、赋值运算 如:p= int bM; for(i=0; iM; i+) bi=ai; printf(“Output numbers:n“); for(i=0; iM; i+) printf(dn, bi); printf(n); ,#include #define M 7 void main( ) int i, aM=12,22,35,4,25,8,7; int bM; int *p=a,*q=b; for(i=0; iM; i+) *q=*p;q+;p+; printf(“Output numbers:n“); for(i=
16、0; iM; i+) printf(dn, bi); printf(n); ,#include #define M 7 void main( ) int i, aM=12,22,35,4,25,8,7; int bM; int *p=a,*q=b; for(i=0; iM; i+) *q+=*p+; printf(“Output numbers:n“); for(i=0; iM; i+) printf(dn, bi); printf(n); ,printf(dn, *q+);,q=b;,例 用指针变量输出一维数组各元素及各元素和。 #include void main( ) int i, su
17、m, a5=1,2,3,4,5,*p; p= ,p,2030 2032 2034 2036 2038 2040,说明: 1)p+的增量取决于p所指向的类型所占字节数; double *p; 增量为8 float *p; 增量为4 int *p; 增量为2 char *p; 增量为1 2)若p=则 *p+ *(p+) 先访问a0,再使p指向a1 (*p)+ a0+ 先访a0,再使a0自加 *(+p) p先自加,再访问*p,*p为a1 +(*p) +a0 先使a0自加,再访问a0,例 用指针查找一维数组最大元素值。 #include void main( ) int i, max, a5, *p;
18、 p=a; for(i=0; imax) max= *(p+i) ; printf(nmax=%dn, max); 注意:循环中p始终保持指向a0不变。,p,2030 2032 2034 2036 2038,P+1:,P+2:,P+3:,P+4:,总结: 1)p+i的含义:p后第i个变量的地址 p= 该循环过程中p不断改变指向,分别指向各元素a0,a1,a2,a3,a4。,三、数组的指针与函数的参数,数组作为函数参数,实参和形参的对应关系可归纳一下四种情况:,int f(int x,int n) viod main() int a10; f(a,10); ,int f(int *x,int n
19、) viod main() int a10; f(a,10); ,int f(int *x,int n) viod main() int a10;*p=a; f(p,10); ,int f(int x,int n) viod main() int a10;*p=a; f(p,10); , ,例:编写一函数求一维数组最大元素值及其下标位置(要求使用指针),已知:数组首地址p,元素个数n; (作为函数参数) 结果:下标k(左返回值),int max(int *p,int n) 设最大值放在max中。则初始状态为: max=*p,k=0 如果*(p+i)max 则 max=*(p+i) 且k=i,#
20、include int max_array(int *p,int n) int i,k,max; max=*(p);k=0; for(i=0; imax) max= *(p+i) ;k=i; return k; void main( ) int a10=12,22,35,4,25,8,7,2,1,9; int i *p=a,k; for(i=0; i10; i+) printf (“%5d”,*(p+i) ; k=max_array(a,10); printf(nmax=a%d=%dn, k,*(p+k); ,i+,p+),*( p ),*( p ),指针p变化吗?,例 :定义函数,用指针作为
21、函数参数,实现一维数组的倒置存储和输出。,已知:一维数组,元素个数n; (作为函数参数) 结果:倒置后的一维数组,算法: 两个指针初始指向数组的两头,交换所指向的元素,并逐渐向中间靠拢,#include stdio.h #define N 5 void turn(float x ) float *p1,*p2, t; p1=x; p2=x+(N-1); for( ; p1p2; p1+, p2-) t=*p1; *p1=*p2; *p2=t; return; void main( ) float aN, *p; int i; for(i=0; iN; i+) scanf(%f, a+i); p
22、=a; turn(p); for( ; pa+N; p+) printf(%4.0f, *p);,a0 a1 a2 a3 a4,x0 x1 x2 x3 x4,实参p,形参x,局部t,局部p1,局部p2,1,5,1,例 方法1:实参是已指向数组的指针变量,形参为数组,方法2:实参是已指向数组的指针变量,形参也为指针变量;,实参p,形参p1,局部p2,a0 a1 a2 a3 a4,void turn(float *p1) float *p2, t; p2=p1+(N-1); for( ; p1p2; p1+, p2-) t=*p1; *p1=*p2; *p2=t; return; ,四、二维数组与
23、指针,1、二维数组是数组的数组,即是由3个一维数组组成。 2、数组名a代表整个二维数组的首地址,也就是第0行的首地址。 a+1是第1行的地址,a+2代表第2行的首地址。,若有定义: int a34=1,3,5,7,9,11,13,15,17,19,21,23,4、某一元素的地址: 0行第1列元素的地址a0+1 i行第j 列元素的地址ai+j 数组元素的地址可以用: int *p,*ps,*pe, i, j, sum; ps=,p-ps的值不是指针量,是两指针间相隔的数据个数,#include stdio.h“ #define N 3 #define M 4 void main( ) int a
24、NM=1,2,3,4,5,6,7,8,9,10,11,12; int *p, i, j; p= ,例 输出二维数组i行j列元素值。,10.4 字符串与指针,一、字符串的指针,C语言的字符串是以0作结束符的字符序列 用字符数组组存放字符串( 含0 的字符数组可以看作字符串) 字符串指针就是字符数组的首地址,如:char a=“Apple” char b=C,h,i,n,e,0,二、字符串指针变量,定义:char *指针变量,如:char *p,*q=“Language”; p=“This is a book.”;,int *p,*q; p=123; p=,如:char *p,c10; p=c;,
25、注意:C语言对字符串常量按字符数组处理,内存中开辟一个字符数组存放该常量。P指向字符串的首地址,不是存放字符串,用指针变量访问字符数组(与数值型数组相同),例:char str320, *p; p= 则:p+i*20+j p=str; 则:p+i for (p=q;*p!=0;)p+; for (p-;p=q;p-) putchar(*p); putchar(0); ,#include void main( ) char *p,*q=“language”; int n; n=strlen(q);p=q+n; for (p-;p=q;p-) putchar(*p); putchar(0);,P指
26、向串的0,例 写一函数判断一个字符串是否回文(顺读和逆读相同),已知:字符串指针变量p(作参数)结果: 是(1)或否(0)(返回值),算法: 1 令q指向最后一个字符 2 若*p=*q,则指针向中间靠拢,直到p=q,则return 1,否则return 0,int ishuiwen (char *p) char *q=p; while (*q!=0) q+; q-; while (pq) if (*p=*q)p+;q-; else return 0; return 1;,int ishuiwen (char *p) char *q=p; while (*q!=0) q+; q-; while
27、(pq) if (*p+!=*q-) return 0; return 1; ,例:不用strcpy函数,实现字符串的拷贝。,pa,pb,b,a,#include stdio.h void main( ) char a =Hello!, b20,*pa,*pb; pa=a; pb=b; for(;*pa!=0;pa+,pb+) *pb=*pa; *pb=*pa; printf(nA string: %s, a); printf(nB string: %s, b); ,总结: 1)编译时对字串常量的处理如同字符数组,将其存放在连续存储区域,末尾自动加入空字符; 2)p=“China”; 字串常量
28、存储区的起始地址赋给指针变量p,使p指向该字串首字符,不是把一串字符赋给p; 3)p的指向可用赋值语句确定,也可在定义时确定; 如:char *p=China; p=Hello, Wang.; 4)已指向字串的指针变量p保持不变时,p可带下 标使用; 如:pi代表字串中的第i+1个字符。 5)p+i的值为:p+i类型长=p+i p+i的含义:第i+1个字符的地址,三、字符数组与字符指针比较,char a=“I love this game ”,*p=a;,1、存储的内容不同: 字符数组可以存字符串,存的是字符; 字符指针变量存的是字符串在内存的首地址,I love this game,300A
29、,数组a,变量p,300A,2、赋值方式不同:,字符数组只能对各个元素赋值; (一次只能赋一个字符) 字符指针变量值赋值一次,赋的是地址,如:char a10,*p p=“China”; a=“Hello”;,3、当没有赋值时: 字符数组名代表一个确切的地址; 字符指针变量中的地址是不确定的。,如:char a10,*p scanf(“%s”,a); scanf(“%s”,p);,4、字符数组名是常量,不能改变值; 字符指针变量可以改变值。,5、 可用下标的形式引用指针变量所指字符串中的字符。,如:a+ p+,如:char *p=“abcd”; putchar(p3); p2=x;,6、字符串
30、指针变量的应用: 例如:可以用指针变量指向一个格式字符串,在printf中直接使用此指针变量。,如:char *fmt=“a=%d,b=%d,c=%dn”; 则printf (fmt,a,b,c);等价于 printf (“a=%d,b=%d,c=%dn”,a,b,c);,7、注意使用的区别,char d10,*q; int x=5, *p=,10.5 指向函数的指针,C 源程序经编译后,每个函数都被编译成一段执行代码,这段执行代码第一条指令的地址就叫作该函数的指针(函数入口地址); 在源程序中函数名就代表函数的指针。,一、 用函数的指针变量调用函数,1、指向函数的指针变量的定义与赋值 定义一
31、般形式:类型标识符 (*指针变量名)( );,赋值形式:指向函数的指针变量=函数指针,其中:类型标识符指明了指针变量所指向函数返回值的类型;,其中:函数指针用函数名表示,可以是库函数名或用户自定义函数名。,表示指针变量指向函数,2、利用指向函数的指针变量调用函数,调用形式: (*指针变量名)(实参表);,其中:指针变量必须已指向需要调用的函数;实参表中列出需要调用函数所要求的参数。,例:#include stdio.h void main( ) int max(int, int); int a, b, (*p)(int,int ); scanf(%d,%d, ,说明: 指向函数这个整体,不能做
32、加、减、关系运算。 不同类型指针变量的区别 定义形式、指向的对象、 运算及运算规则不同。,max(a,b),二、 用函数的指针作为函数的参数 当函数中要调用其它函数,而调用的函数名不是固定的,则应采用函数指针变量作为形参。,(已指向某函数),函数的指针,实参与形参的对应关系: 实参 形参 函数名 函数指针变量 指向函数的指针变量,float t(double (*f1)( ), double (*f2)( ), float x) float y; y=(*f1)(x)/(*f2)(x); return(y);,sin代码,cos代码,f1,f2,cos入口,sin入口,#include mat
33、h.h void main( ) float t(double (*f1)( ), double (*f2)( ), float x); float y1, y2, x; int j; printf(nInput:); scanf(%d, ,例:利用指向函数的指针变量作为形参,编写一函数,使其即能求正切值、也能求余切值。,#include math.h void out(double (*f)(double),double x1, double x2,double step) double x; int i=1; for(x=x1;x=x2;x=x+step,i+) printf(%lf , (*f)(x) ); if(i%5=0)printf(nt); printf(ntx=%lfn,x-step); ,例:利用指向函数的指针变量调用函数,根据菜单选择实现输出f1(x)、f2(x)、exp(x)函数在区间x1,x2内的函数值,x的步长为step的值。,分析:将输出函数值的功能定义为一个函数out,由于
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年盐行业分析报告及未来发展趋势报告
- 2026年白乳胶行业分析报告及未来发展趋势报告
- 2026年添加剂行业分析报告及未来发展趋势报告
- 2026年米面类行业分析报告及未来发展趋势报告
- 2026年HVAC专用变频器行业分析报告及未来发展趋势报告
- 2026年印刷包装材料行业分析报告及未来发展趋势报告
- 2026年陶瓷滤波器行业分析报告及未来发展趋势报告
- 2026年医用CT机行业分析报告及未来发展趋势报告
- 2026四川广安市中医医院招聘6人备考题库含答案详解(综合卷)
- 2026北京市地质矿产勘查院所属事业单位招聘36人备考题库附答案详解(综合题)
- (2025版)国家基层高血压防治管理指南2025版解读课件
- 颅内动脉粥样硬化性急性大血管闭塞血管内治疗中国专家共识课件
- 风电场设备运输与储存方案
- 老年人术后谵妄预防与质量控制方案
- 2025年摇滚音乐节举办项目可行性研究报告及总结分析
- (已压缩)广东省工程勘察设计服务成本取费导则(2024版)
- 给孩子立规矩课件
- 2025广东初级会计试题及答案
- 地下管廊施工围挡与隔离方案
- 冠脉介入治疗常见并发症
- 公安保密培训课件教学
评论
0/150
提交评论