《计算机二级C语言辅导_第八章.ppt》由会员分享,可在线阅读,更多相关《计算机二级C语言辅导_第八章.ppt(54页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。
1、第八章第八章地址和指针指针的概念指针的概念指针的概念指针的概念 指针类型是C语言中使用十分普遍的数据类型,它与一般的变量不同之处是它包含的不是数据的值,而是另一变量的地址。指针是C语言中的一个重要概念,正确而熟练地掌握了指针的概念和指针的使用,就能设计出复杂的数据结构和高效的程序,没有掌握指针就没有掌握C语言的精华。凡是程序中定义的变量,在编译时系统都给他们分配相应的存贮单元,VC6.0系统给短整型分配2个字节,给整形和实型分配4个字节,每个变量所占的存贮单元都有确定的地址,具体地址在编译时分配。指针的概念指针的概念指针的概念指针的概念 C程序的变量所存放的数据:数值型数据:整数、实数通过前面
2、的学习,我们已知道:字符型数据:字符、字符串 占有一定长度的内存 单元 如:int x;x占4字节、4个单元 每一个变量都有一个地址,为无符号整数,它不同于一般的整数。问题:问题:能否对地址运算?能否用一个变量保存地址?这些变量具有的性质:这些变量具有的性质:例例:short int a=3,b=4;float c=4.5,d=8.6;char e=x,f=y;101010121014a101810221023bcdef344.58.6xy 要访问内存中的变量,在程序中是通过变量名来引用变量的值。但实际上,在编译时将每个变量名对应一个地址,在内存中不再出现变量名而只有地址。若程序中引用变量若程
3、序中引用变量a,系统找到对应地址,系统找到对应地址1010,然后从然后从1010,1011两个字节中取出其中的值。两个字节中取出其中的值。一、数据在内存中的存放一、数据在内存中的存放设:系统分配i的起始地址为2000的单元内存:为一个连续编号(连续地址)且以一个单元为一个字节的连续存贮区。若程序中定义了三个int变量i,j,k short int i=5,j=5,k=10;则:j的起始地址有可能为为2002的单元k的起始地址有可能为2004的单元2000200120022003200420053001 5+5102000ijk当程序中要用它们的值时:y=i+j+k;找到j的地址2002,将20
4、02,2003中的数据5读出;找到k的地址2004,将2004,2005中的数据10读出。分别 找到i的地址2000,将2000,2001中的数据5读出;则系统通过一张变量名与地址对应关系表:上述过程称为变量的“直接访问”然后把这些数据进行算术运算。直接访问:直接使用存放该数据的变量名。i相当于使用 5使用变量如如:用pi,pj,pk来存放i,j,k的地址200020022004 55103001300330053007200020022004pipjpkijk 若要得到变量i的值,可以先访问pi,得到i的地址,再通过该地址找到它i的值。显然,pi与i是通过i的地址联系起来的。间接访问:如果将
5、某一变量的地址(如i的地址2000)存放到另一个变量x,则可通过x来存取i的值。直接访问直接访问:通过变量名或地址访问一个变量的方式通过变量名或地址访问一个变量的方式为为“直接访问直接访问”。间接访问:间接访问:把地址存放在一个变量中,然后通过先找把地址存放在一个变量中,然后通过先找出地址变量中的值出地址变量中的值(一个地址一个地址),再由此地址找,再由此地址找 到最终要到最终要访问的变量的方法称为访问的变量的方法称为“间接访问间接访问”注:注:存放地址的变量是一种特殊的变量,它只存放地址的变量是一种特殊的变量,它只能用来存放地址而不能用来存放其它类型的数据,能用来存放地址而不能用来存放其它类
6、型的数据,需要专门加以定义。需要专门加以定义。8.2 8.2 8.2 8.2 指针和地址指针和地址指针和地址指针和地址指针变量定义指针变量定义:一个变量的地址称为该变量的指针。因此,i的指针的值为2000。而存放地址(指针)的变量叫做指针变量。200020022004 55103001300330053007200020022004pipjpkijkPi就是指针变量指针变量的定义与初始化:指针变量的定义与初始化:表示该变量为指向某类型变量的指针变量。存储类型 类型名 变量名注注1.标识符前面的“*”标示该变量为指针变量。2.一个指针变量只能指向同一类型的变量。指针变量指针变量的定义的定义int
7、 *p,i=3;P3i如:int p;(p为指向整型变量的指针)char*s;(s为指向字符型变量的指针)float*t;(t为指向浮点型变量的指针)p中只能存放整型变量的地址习惯用语:若指针变量p存放了变量a的地址,我们称“p指向a”请区别:请区别:指针:就是地址指针:就是地址 变量的指针:就是变量的地址变量的指针:就是变量的地址 指针变量:存放地址的变量指针变量:存放地址的变量重要概念:重要概念:指针变量也有各种类型(如上面所示),但指针变量的值只能是整型值。指针变量的引用方式:指针变量的引用方式:*变量名-表示所指变量的值。变量名-表示指向变量的指针(地址)。如 int*p;char*s
8、;float*t;*p=5;*s=a;*t=3.6;但 p=p+1;并不代表p=6,它代表的是地址1若有:float*t;且*t=3.6;设t的地址为2000,则t+12004例:例:若有:int*p 且 *p=5;设p的地址为2000,则p+12004若有:char*s 且*s=a;设s的地址为2000,则s+12001三、引用指针变量三、引用指针变量将一个变量的地址(指针)赋给一个指针变量,用取地址运算符:&int i,j,p;i=3;p=&i;求出整型变量i的地址付给指针变量p例:例:&k&k 取变量取变量k k地址地址&c2&c2 取数组元素取数组元素c2c2的地址的地址&(st.na
9、me)&(st.name)取结构取结构stst变量变量namename项的地址项的地址&233,&(i+233)&233,&(i+233)&:(取地址运算符取地址运算符)取当前变量的地址取当前变量的地址 运算对象不能是运算对象不能是常量表达式常量表达式或或寄存器变量寄存器变量 p=&i;3i&iP存取指针变量所指向变量(目标变量)的值:用指针运算符“*”,即:*p 为 i。,&为同级运算符,结合性自右至左。当&或&在一起时,具有抵消作用。则:p=&i相当于p=i 如上例:int i,p;i=3;p=&i;指针变量不要谈”指”色变指针是C语言学习中的一大难点。难难在概念。main()int a,
10、*p1,*p2=&a;a=100;p1=p2;*p1=*p2;首先搞定*p请看以下变量声明语句 int a,*p1;char b,*p2;a,b 普通变量(存放某个数值或字符)p1,p2 指针变量(存放某个实体的地址)变量声明时,如果变量名前带*号,表示该变量是个指针变量有关*p的小结变量声明时,*p表示定义了一个用来存放变量地址而非数据(数值、字符等)的指针变量。程序中引用时,*p表示取指针变量p所指变量的值。main()int a,*p1,*p2=&a;a=100;p1=p2;*p1=*p2;int *p;p=&a;小考一下,如何?以下程序的运行结果是什么?main()float x,y;
11、int*p;x=3.14;p=&x;y=*p;printf(y=%fn,y);结果:y=-2621.000000 把int*p改为float*p后,结果正确:y=3.140000 指针变量能参加运算吗?指针变量和其他变量一样,可以在各种表达式中参加运算。但指针变量和普通变量不同,只能进行以下三种运算:u赋值运算u算术运算 u指针比较C C语言中有关指针的运算符语言中有关指针的运算符&运算符运算符:取地址运算符取地址运算符 *运算符运算符:指针运算符或指明运算符,指针运算符或指明运算符,*p p代表代表p p所指变量所指变量注意:此处的注意:此处的*p p与定义指针变量时用的与定义指针变量时用的
12、*p p的含义是不同的。的含义是不同的。定义定义 int*p;中的中的*不是运算符不是运算符,它只是表示其后的变量是它只是表示其后的变量是 一指针变量一指针变量 程序中的程序中的*p,其中的,其中的*是一个指针运算符,是一个指针运算符,*p表示表示p指向的变量指向的变量如:如:printf(printf(“%d%d”,*p);,*p);printf(printf(“%d%d”,a);,a);结果都为结果都为P3a&aP3a 3指针运算指针运算指针变量初始化 变量声明时赋值 main()int a=5,*p=&a;printf(“%d,%d,%dn”,p,*p,a)指针变量一般赋值 程序处理时赋
13、值结果:2000,5,5 1.指针变量赋值运算例例 指针赋值运算。#include main()int a,b;a=100;b=200;int*pa,*pb;/*定义int类型的指针变量*/pa=&a;/*将变量a的地址赋给指针变量 pa*/pb=&b;/*将变量b的地址赋给指针变量pb*/printf(*pa=%d,*pb=%dn,*pa,*pb);pa=pb;/*将指针pb赋给pa,两者都指向变量b*/printf(*pa=%d,*pb=%dn,*pa,*pb);运行结果:*pa=100,*pb=200*pa=200,*pb=2002.指针变量算术运算(1)指针变量与整数相加减 指针变量加
14、上或减去一个整数n,相当于指针变量从当前的位置向后或向前移动m个内存单元,其中m的值为:m=n*指针数据类型的长度指针数据类型的长度 不同数据类型占据不同的长度,char类型占1个字节,short int类型占2个字节,int,float类型占4个字节。(2)指针和整数可以进行加减例如:例如:p p是指向某数组的第一个元素的指针,则是指向某数组的第一个元素的指针,则p+np+n就表就表示这数组第示这数组第n+1n+1个元素的位置。个元素的位置。一般说来:一般说来:p+np+n表示超过指针表示超过指针p p的当前位置的第的当前位置的第n n个对象的地址。在计算具体地址时,编译程序根据个对象的地址
15、。在计算具体地址时,编译程序根据p p所指对象的长度所指对象的长度(sizeof)(sizeof)将将n n放大。放大。(3)空指针不能指向任何对象3.指针变量的关系运算 p和q是两个相同类型的指针变量,则它们之间存在p=q,p!=q,pq,p=q等关系。例如:int*p,i=2;p=&i;假设i地址为3000,则p的值为3000,p=p+2;执行后,p的内容是多少呢?因为p是int类型的变量,所以占的长度为4个字节,不难得出p的值为3000+243008。要注意,这里不是简单的p加2就行了,所以p的值不是3002。指针变量的初始化和指针所指的变量一般形式:存储类型 数据类型 *指针名=初始地
16、址值;赋给指针变量,不是赋给目标变量例 int i;int *p=&i;变量必须已说明过类型应一致例 int *p=&i;int i;例 int i;int *p=&i;int *q=p;用已初始化指针变量作初值注:指针变量的使用例 main()int i=10;int *p;*p=i;printf(“%d”,*p);危险!例 main()int i=10,k;int *p;p=&k;*p=i;printf(“%d”,*p);指针变量必须先赋值,再使用.2000200420062005整型变量i10指针变量p200120022003随机空指针 空指针:int*p;p=NULL;NULL是什么?
17、在stdio.h中,定义#define NULL 0所以 p=NULL;相当于 p=0;内存使用常识:任何C程序的变量在内存中的地址均由操作系统自动分配,不能由编程者通过赋值指定。p=NULL 表示p不指向任何变量。内存的低端只供由操作系统使用(相当于政府机关,普通百姓不能使用)。例例main()main()int*p1,*p2,i1,i2;int*p1,*p2,i1,i2;scanf(scanf(“%d,%d%d,%d”,i1,i2);,i1,i2);p1=&i1;p2=&i2;p1=&i1;p2=&i2;printf(printf(“%d,%dn%d,%dn”,*p1,*p2);,*p1,
18、*p2);p2=p1;p2=p1;printf(printf(“%d,%dn%d,%dn”,*p1,*p2);,*p1,*p2);&i1P13i1&i2P25i2运行情况运行情况:3:3,5 5&i1P13i1&i1P25i23,53,3main()main()int*p1,*p2,*p,i1=3,i2=5;int*p1,*p2,*p,i1=3,i2=5;p1=&i1;p2=&i2;p1=&i1;p2=&i2;p=p1;p1=p2;p2=p;p=p1;p1=p2;p2=p;printf(printf(“%d,%dn%d,%dn”,*p1,*p2);,*p1,*p2);例例运行情况运行情况:5,
19、3P13i1P25i2*p1*p1*p2*p2p1=&i1p1=&i1p2=&i2p2=&i2p=p1p=p1P P*p*p&i1p1=p2p1=p2&i2p2=p;p2=p;&i1&i1&i2main()main()int*p1,*p2,i,i1,i2;int*p1,*p2,i,i1,i2;i1=3;i2=5;i1=3;i2=5;p1=&i1;p2=&i2;p1=&i1;p2=&i2;i=*p1;*p1=*p2;*p2=i;i=*p1;*p1=*p2;*p2=i;printf(printf(“i1=%d,i2=%dni1=%d,i2=%dn”,i1,i2);,i1,i2);例 交换两指针变量
20、所指向的值运行情况运行情况:i1=5,i2=3P13i1P25i2*p1*p1*p2*p2i i*p*p35&i1&i2p1=&i1p1=&i1p2=&i2p2=&i2i=*p1i=*p1*p1=*p2*p1=*p2*p2=i;*p2=i;34、指针使用的几个细节。设指针p指向变量a则:p+(或 p+=1),p指向下一个元素。*p+,相当于*(p+)。因为,*和+同优先级,+是右结合运算符。*(p+)与*(+p)的作用不同。*(p+):先取*p,再使p加1。*(+p):先使p加1,再取*p。(*p)+表示,p指向的元素值加1。8.2 指针与函数指针与函数指针和函数的关系主要有三个方面:一是指针
21、可以作为函数的参数 二是函数的返回值可以是指针 三是指针可以指向函数 在前面介绍函数时,已经介绍了C语言的函数的参数传递是以“传值”方式进行变量参数的信息传递,被调函数不能直接改变主调函数中参数的值。当引入指针的概念后,我们可以在主调函数中将要改变内容的变量地址作为参数传递给被调函数,而被调函数执行时,就按这个地址去访问变量参数的值,相应的参数要被说明成指针类型。一、指针作为函数参数一、指针作为函数参数例如:例如:main()void sub(int*px,int*py);int x,y;sub(&x,&y);printf(“%d,%dn”,x,y);void sub(int*px,int*p
22、y)*px=10;*py=20;xypxpy101210141020运行结果:运行结果:10,20结论:用指针作函数的参数,可以实现结论:用指针作函数的参数,可以实现“通过被通过被调函数改变主调函数中变量的值调函数改变主调函数中变量的值”的目的。的目的。101210141.指针作形参,实参为变量地址或指针例例 9.4 编写一程序,通过函数输出两个数中的最大值。#include void max(int*i,int*j)/*定义指针作形参的函数max*/if(*i*j)printf(max:%dn,*i);else printf(max:%dn,*j);main()int i=100,j=200
23、;int*pi,*pj;pi=&i;pj=&j;max(&i,&j);/*用变量地址作为函数的实参*/max(pi,pj);/*用指针作为函数的实参*/运行结果:max:200max:200(1)数据复制方式 例例 9.5 通过函数交换数据程序a。2.参数的传递方式 函数的参数传递方式有两种,数据复制(亦称为按值传递)和地址传递。main()int a=5,b=9;swap(a,b);printf(a=%d,b=%d,a,b);运行结果:a=5,b=9#include void swap(int x,int y)int temp;temp=x;x=y;y=temp;参数的参数的传递传递方向:方
24、向:单向值传递,而且是由调用者传给子函数.swap(int x,int y)int temp;temp=x;x=y;y=temp;main()int a=5,b=9;swap(a,b);printf(a=%d,b=%d,a,b);.20002008200A2002200420065变量a 变量b(main)9 变量temp 变量y 变量x(swap)559 59COPYswap(int x,int y)int temp;temp=x;x=y;y=temp;main()int a=5,b=9;swap(a,b);printf(n%d,%dn,a,b);值传递.20002008200A200220
25、0420065变量a 变量b(main)9运行结果:5,9分析分析:函数调用时,程序把a,b的值5,9传递给x,y,在swap()函数中x,y交换之后,没有把它们的结果返回给实参a,b,所以a,b并没有交换,交换的只是x,y。a与x,b与y占用的是不同的内存单元。数据复制方式传递数据时,由于数据在传递方和被传递方占用不同的内存空间,所以被调用函数中的变量不管怎么变化,都不会影响到调用函数中的实参的值。这就是上面程序中两个数没有交换的根本原因。(2)地址传递方式main()int a=5,b=9;int*pa,*pb;pa=&a;pb=&b;swap(pa,pb);printf(n%d,%dn,
26、a,b);运行结果:a=9,b=5#include void swap(int*p1,int*p2)int p;p=*p1;*p1=*p2;*p2=p;swap(int *p1,int *p2)int p;p=*p1;*p1=*p2;*p2=p;main()int a=5,b=9;int*pa,*pb;pa=&a;pb=&b;swap(pa,pb);printf(n%d,%dn,a,b);.20002008200A200220042006200C200E2010.59整型变量a 整型变量b(main)指针pa指针pb20002002(swap)指针p1指针p2整型p5920002002COPY
27、5例 8.5 将数从大到小输出swap(int *p1,int *p2)int p;p=*p1;*p1=*p2;*p2=p;main()int a=5,b=9;int*pa,*pb;pa=&a;pb=&b;swap(pa,pb);printf(n%d,%dn,a,b);.20002008200A200220042006200C200E2010.59整型变量a 整型变量b(main)指针pa指针b2000200259例 将数从大到小输出运行结果:9,5地址传递分析分析:在调用swap(pa,pb);函数时,就把变量a的地址给了指针pa,变量b的地址给了pb,也就是,指针pa访问的就是变量a,指针
28、pb访问的就是变量b;a与*pa共用同一内存单元,b与*pb也是共用的同一内存单元。所以,当用指针pa和pb将数据交换了之后,实际上a和b内的数据也被交换了。&与*组合使用时 若 int a,*p;p=&a;则&*p =&a =p;*&a =a =*p返回指针值的函数返回指针值的函数返回指针值的函数返回指针值的函数(指针函数指针函数指针函数指针函数)一个函数可以带回一个整型值、字符型值、实型值等,一个函数可以带回一个整型值、字符型值、实型值等,也可以带回指针型的数据,即地址。也可以带回指针型的数据,即地址。返回指针值的函数的一般定义形式为返回指针值的函数的一般定义形式为:类型标识符类型标识符
29、*函数名函数名(参数表参数表)例如:例如:int*fun(int a,int b)int*fun(int a,int b)fun fun是函数名是函数名,调用它以后得到一个指向整型数据的调用它以后得到一个指向整型数据的指针指针(地址地址)。a a,b b是函数是函数funfun的形参。的形参。例如:int*fun(int a,int b)上面这个函数fun()即是一个指针函数,要求返回值是int类型。在指针型函数中,使用return语句返回的可以是变量的地址、数组的首地址或指针变量,还可以是后面几章介绍的结构体、共用体等构造数据类型的首地址等。例例 指针型函数来找出两个数中的最大值。#include int*max(int*i,int*j)return(*i*j?i:j);/*返回最大数的指针*/main()int a,b,*p;scanf(%d,%d,&a,&b);p=max(&a,&b);/*调用指针函数得到最大数 的指针值*/printf(max=%d,*p);运行结果:输入:12,2输出:max=12
限制150内