C语言程序设计第八章指针.ppt
《C语言程序设计第八章指针.ppt》由会员分享,可在线阅读,更多相关《C语言程序设计第八章指针.ppt(106页珍藏版)》请在三一办公上搜索。
1、第八章 指针,8.1 概 述,C程序设计中使用指针可以:使程序简洁、紧凑、高效有效表示复杂的数据结构动态分配内存方便使用字符串有效使用数组调用函数时可以得到多于1个的值直接处理内存地址,8.2 指针的概念,一、数据的存取,1、内存地址,内存的每个字节都有一个编号,这个编号称为“内存地址”。,程序中的每个数据都对应着内存中的一个地址,从该地址开始的一个或多个字节用来存放该数据。,int i,j,k;,i,j,k,2、内存单元的地址和内存单元的内容的区别:,若i=3,j=5;,从图中可以看出它们的区别。,程序编译后已经没有i、j、k这些变量名了,而是将变量名转换为变量的地址,计算机通过内存地址对变
2、量进行存取。,二、直接访问和间接访问,1、直接访问方式:,、i=3;,、j=i+2;,、printf(%d,i);,、scanf(%d,、k=i+j;如何执行?,按变量的地址存取变量的方式,2、间接访问方式:,语言中可以定义整型变量、实型变量、字符型变量,各自存放相应类型的数据;另外还可以定义和使用一种特殊类型的变量,用来存放变量的地址。,假设已经定义变量 ip 用来存放整型变量的地址,它被分配到内存单元3000和3001。,ip,通过执行语句:ip=将整型变量i 的地址存放到变量ip中,即ip的值为变量i所对应的内存单元的起始地址2000。,2000,现在要存取i的值可以这样做:先找到存放i
3、的地址的内存单元地址(3000和3001),从中取出变量i的地址(2000),然后再对2000和2001单元进行存取这就称为间接访问。,通过变量ip知道变量i的地址,从而找到变量i的内存单元,因此说变量ip指向变量i,用箭头表示这种“指向”关系。,变量ip的值为2000,即变量i的地址,这样就在ip和 i 之间建立了一种联系:,3、关于“指向”的含义:,4、为了表示将数值10送到变量i中,可以有两种表示方法:,、将10送到变量i所标志的单元中;,10,、将10送到变量ip所指向的单元中;,10,三、指针与指针变量,通过地址能找到所需的变量单元,可以说:地址“指向”该变量单元。因此,把一个变量的
4、地址称为该变量的“指针”。,如果一个变量专门用来存放另一个变量的地址,则称它为“指针变量”。指针变量的值(即指针变量中存放的值)是指针(地址)。,注意区分“指针”和“指针变量”这两个概念。,指针与指针变量指针:一个变量的地址指针变量:专门存放变量地址的变量,2000,指针,指针变量,变量的内容,变量的地址,、数据所占有的内存单元个数是由其数据类型决定的;,、首地址:即第一个单元的地址;,、表示地址的数与整数的区别;,、变量i、j的地址可能相邻,也可能不相邻,是由系统分配的,我们不必关心。,、程序中定义的每个变量在编译后都占有各自的内存单元,系统是通过内存地址对变量进行存取的;,四、说明,8.3
5、 指针变量的定义和引用,指针运算符:*,为了表示指针变量和它所指向的变量之间的联系,用“*”表示指向的关系。,如:ip代表指针变量,*ip表示ip所指向的变量。即*ip也代表一个变量。,例:,、若:ip=&i;,i=5;,*ip=5;,结论:*ip与i等价。,、x=i+1;,x=*ip+1;,取地址运算符:&,它与一个变量连用,以得到该变量的内存地址。,说明:,、取地址运算符只能作用于变量:,不能作用于常量、表达式或寄存器变量:,、不能把整数赋值给一个指针变量:ip=3000;,、不能把一个指针变量的值赋值给一个整型变量:x=ip;,&与*运算符含义,含义:取变量的地址单目运算符优先级:2结合
6、性:自右向左,含义:取指针所指向变量的内容单目运算符优先级:2结合性:自右向左,两者关系:互为逆运算理解,i_pointer-指针变量,它的内容是地址量*i_pointer-指针的目标变量,它的内容是数据&i_pointer-指针变量占用内存的地址,i_pointer&i&(*i_pointer)i*i_pointer*(&i),i_pointer=&i=&(*i_pointer)i=*i_pointer=*(&i),8.3.1 指针变量的定义与赋值,一、指针变量的定义,合法标识符,指针变量本身的存储类型,指针的目标变量的数据类型,表示定义指针变量不是*运算符,例 int*p1,*p2;flo
7、at*q;static char*name;,存储类型 数据类型*指针变量名;,说明:,“*”只表示定义的变量为指针变量,但指针变量名中并不包含“*”;*是指针变量的标志,不可丢掉;,指针变量定义时,指定了它所指向的变量的数据类型;指针变量定义时必须指定其所指向的变量的数据类型,而且使用过程中只能指向同一种类型的变量。,指针变量定义后,系统为变量分配一个存储单元,用来存放地址;根据存储单元的长度分为大存储模式(长指针,4 Byte)和小存储模式(短指针,2 Byte);,指针变量定义后,若不赋值,其值是不确定的。,二、指针变量的赋值,1、赋值语句:,int i,j,*p1,*p2;,p1=,c
8、har ch,*cp1,*cp2;,cp1=,2、初始化:,int i,*p1=,int i,*p1;p1=,一般形式:存储类型 数据类型*指针变量名=初始地址值;,赋给指针变量,不是赋给目标变量,例 int i;int*p=,变量必须已说明过类型应一致,例 int i;int*p=,用已初始化指针变量作初值,例 main()int i;static int*p=.(),不能用auto变量的地址去初始化static型指针,3、说明:,、指针变量定义后,若不赋值,其值是不确定的;,、可以给指针变量赋空值(NULL),使指针变量不指向任何变量;,ip=NULL;,#define NULL 0,、指
9、针变量的值为空值(NULL)与未对指针变量赋值,意义不同;,、只能是同类型变量的地址进行赋值;,int i,*ip;char ch,*cp;,ip=,ip=,、可以将数组名或函数名赋给某些类型的指针变量;,int a10,*ip;,ip=,ip=a;,、不能将一个整型量(或任何其它非地址类型的数据)赋给一个指针变量;,int*ip;,ip=3000;,8.3.2 指针变量的引用,int a,*p1,*p2;p1=,int a,*p1,*p2;,p1=,&a,printf(%x,p1);,p2=p1;,&a,*p1=3;,3,printf(%d,*p1);,1、两个运算符:&和*,&:取地址运算
10、符;,*:指针运算符(间接访问符);,2、说明:,、&既可作用于一般变量,也可作用于指针变量;,、*只能作用于指针变量;,、表达式中的*p与变量定义中的*p含义不同;,int i,*p=,、int a,*p=,int a,*p;p=,int a,*p;*p=,3、指针变量可以进行的操作:,int a,*p1,*p2;,、赋值:,p1=,p2=p1;,、输出:,printf(%x,p1);,、取内容:,*p1=5;,a=5;,printf(%d,*p1);,例8.1,#include void main()int a1=11,a2=22;int*p1,*p2;p1=,&a1,&a2,*p1,*p
11、2,&a1,*p2,*p2,多个指针可以指向同一个存储单元。但在某一时刻,一个指针变量只能指向一个存储单元,因为指针变量在某一时刻只能存放一个变量的地址值。,例8.2,#include void main()int a1=11,a2=22;int*p1,*p2,*p;p1=,&a1,&a2,*p1,*p2,&a1,&a2,*p1,*p1,&a1,*p2,*p2,使两个指针交换指向,例8.3,#include void main()int a1=11,a2=22,t;int*p1,*p2;p1=,&a1,*p1,&a2,*p2,11,22,11,交换两个指针变量所指向变量的值,反映了指针变量的引
12、用方法:、将变量的地址赋给指针变量(p1=&a1)、将一个指针变量赋给另一个指针变量(p2=p1)、通过指针变量间接访问它所指向的变量(*p1),4、*和&运算符的进一步说明:,、若有:p1=则*p1等价于a;,&*p1,&(*p1),&a,、*&a,*(&a),*p,a,、(*p)+,等价于:a+,不同于:*p+,*p+,*(p+),指针作为函数参数,输入两个整数a、b,按大小顺序输出。,#include void swap(int x,int y)int temp;temp=x;x=y;y=temp;void main()int a,b;printf(nInput a,b:);scanf(
13、%d%d,注意:语言中的函数调用采用“传值”方式,即单向传递方式。,即:主调函数可以将实参的值传递给被调函数的形参,但不能通过改变形参的值而改变实参的值。,Eg804.cpp,#include void swap(int*px,int*py)int temp;temp=*px;*px=*py;*py=temp;void main()int a,b,*p1,*p2;printf(nInput a,b:);scanf(%d%d,&a,&b,8,5,#include void swap(int*px,int*py)int*temp;*temp=*px;*px=*py;*py=*temp;void m
14、ain()int a,b,*p1,*p2;printf(nInput a,b:);scanf(%d%d,*temp是指针变量temp所指向的变量,但temp中并无确定的地址值,其值不确定;*temp所指向的单元也不确定。因此,对*temp赋值可能会破坏系统的正常工作状况。,应该将*px的值赋给一个整型变量,用整型变量作为临时存储空间实现*px和*py的交换。,#include void swap(int*px,int*py)int*p;p=px;px=py;py=p;void main()int a,b,*p1,*p2;printf(nInput a,b:);scanf(%d%d,&a,&b,
15、&b,&a,如果想通过函数调用得到几个要改变的值,可以:、在主调函数中设n个变量;、将n变量的地址作为实参传给所调用的函数的形参;、通过形参指针变量,改变该n个变量的值;、主调函数就可以使用这些改变了的值;,8.4 指针与数组,一个变量有地址,称变量的地址为该变量的指针;指针变量可以指向变量,当然也可以指向数组和数组元素;每个数组都有一个起始地址,数组的起始地址称为数组的指针;一个数组包含若干元素,每个数组元素都在内存中占用一定的存储单元,即都有相应的地址,数组元素的地址称为数组元素的指针;数组元素的指针变量就是专门用来存放数组元素地址的变量。,指针与数组,指针可以指向数组和数组元素当一个指针
16、指向数组后,对数组元素的访问,既可以使用数组下标,也可以使用指针用指针访问数组元素,程序的效率更高(占内存少,运行速度快)用下标访问数组元素程序更清晰,8.4.1 指向数组元素的指针变量,定义类型名*指针变量名例:int a10;/*定义包含10个整型元素的数组a*/int*p;/*定义指向整型变量的指针变量p*/指向数组元素的指针变量,其类型应与数组元素相同为了让指针p指向数组a,应把数组a的地址赋给指针变量p,赋值:,p=,&a0,说明:,、语言中的数组名代表数组首地址,即第0号元素的地址;,p=,p=a;,、定义时可以进行初始化:,int*p=,int*p;p=,int*p;*p=,in
17、t*p=a;,8.4.2 通过指针访问一维数组,int a10;int*p;如果:p=a;(或 p=)则,*p=5;,a0=5;,p=,*p=5;,a3=5;,又如果:,当指针p指向数组a后,可用指针p访问数组的各个元素。,通过指针访问一维数组,C规定:若指针变量p已指向数组中的一个元素,则p1指向该数组中的下一个元素,如果指针p指向数组a(指向数组第一个元素a0),则:p+1指向下一个元素a1,注意不是将p值简单加1。如果数组元素是整型,p+1表示p的地址加2;如果数组元素是实型,p+1表示p的地址加4;如果数组元素是字符型,p+1表示p的地址加1,通过指针访问一维数组,p+i指向元素ai。
18、可以使用*(p+i)访问元素aip+i也可以记作a+i。指向元素ai。指向数组的指针变量也可以带下标,如,pi与*(p+i)等价,表示元素ai。,指针的运算,指针变量的赋值运算p=(指针变量p2值p1)不能把一个整数p,也不能把p的值整型变量,指针的运算,指针的算术运算pi p id(i为整型数,d为p指向的变量所占字节数)p+,p-,p+i,p-i,p+=i,p-=i等若p1与p2指向同一数组,p1-p2=两指针间元素个数(p1-p2)/dp1+p2 无意义,指针的运算,例 p指向float数,则 p+1 p+1 4,例 p指向int型数组,且p=则p+1 指向a1,例 int a10;in
19、t*p=,例 int a10;int*p1=,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a数组,p,p+1,a+1,p+i,a+i,p+9,a+9,1,指针的运算,指针变量的关系运算若p1和p2指向同一数组,则p1p2 表示p1指的元素在后p1=p2 表示p1与p2指向同一元素若p1与p2不指向同一数组,比较无意义p=NULL或p!=NULL,数组元素表示方法,变址运算符ai*(a+i),ai pi*(p+i)*(a+i),通过指针访问一维数组,例10.1输出有10个元素的整型数组a中的全部元素1、下标法(常用,很直观)main()int a10;int i;for(i=0;
20、i10;i+)scanf(%d,例10.1输出有10个元素的整型数组a中的全部元素1、下标法(常用,很直观)main()int a10;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、2费时,编译系
21、统先将ai转换为*(a+i),即先计算元素地址;方法3不用每次计算地址,执行效率高;下标法直观。,通过指针访问一维数组,使用指针指向数组,应注意以下问题:1.若指针p指向数组a,虽然p+i与a+i、*(p+i)与*(a+i)意义相同,但仍应注意p与a的区别(a代表数组的首地址,是不变的;p是一个指针变量,可以指向数组中的任何元素,实现使自身的值改变)for(p=a;a(p+10);a+)printf(%d,*a)a代表数组的首地址,是不变的,a+不合法,通过指针访问一维数组,2.指针变量可以指向数组中的任何元素,在程序运行期间,要始终注意指针变量当前所指向的是哪一个元素main()int*p,
22、i,a10;p=a;for(i=0;i10;i+)scanf(%d,p+);printf(n);for(i=0;i10;i+,p+)printf(%d,*p);,p=a;,通过指针访问一维数组,3.使用指针时,应特别注意避免指针访问越界。在上例中,第二次for循环,p已经越过数组的范围,但编译器不能发现该问题。避免指针访问越界是程序员自己的责任。,通过指针访问一维数组,4.指针使用的几个细节:设指针p指向数组a(p=a),则:p+(或 p+=1),p指向下一个元素a1。如执行*p,则取出a1的值*p+,相当于*(p+)。因为,*和+同优先级,+是右结合运算符(p375)。则先得到*p,再执行p
23、=p+1。*(p+)与*(+p)的作用不同。*(p+):先取*p,再使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。,例 int a=1,2,3,4,5,6,7,8,9,10,*p=a,i;数组元素地址的正确表示:(A)&(a+1)(B)a+(C)&p(D)&pi,void main()int a=5,8,7,6,2,7,3;int y,*p=,输出:5 6,例 注
24、意指针变量的运算,6,通过指针在函数间传递一维数组,2、数组名作为函数参数:,void f(int x,int n);,f(a,10);,数组名代表数组首地址。用数组名作实参,调用函数时是把数组首地址传递给形参,而不是把数组的值传给形参。这样,实参数组和形参数组共占同一段内存区域。从而在函数调用后,实参数组的元素值可能会发生变化。,x,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,实际上能够接受并存放地址值的只能是指针变量,编译系统都是将形参数组名作为指针变量来处理的。,void f(int*x,int n);,通过指针在函数间传递一维数组,变量名与数组名作函数参数时的比较:,变
25、量名,变量的值,不能,数组名或指针变量,数组的起始地址,能,需要说明的是:语言的函数调用都是采用“值传递”方式;当用变量名作函数参数时传递的是变量的值;用数组名作函数参数时,由于数组名代表的是数组首地址,因此传递的是数组首地址,所以要求形参为指针变量。,归纳起来,实参与形参的对应关系有:,、形参和实参都用数组名:,f(int x,int n);,f(a,10);,把实参数组首地址传给形参作为形参数组首地址;,、实参用数组名,形参用指针变量:,f(int*x,int n);,f(a,10);,把实参数组首地址传给形参(指针变量),函数中用指针访问实参数组,、形参和实参都用指针变量:,f(int*
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 语言程序设计 第八 指针

链接地址:https://www.31ppt.com/p-6504161.html