




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
5第五章指针1
指针的基本概念指向变量的指针变量
指向数组的指针变量
指向字符串的指针变量指向指针的指针第五章指针25.1地址和指针的概念3地址和指针的概念首先回忆一下:内存单元的组织形式?“位”和“字节”;“内存单元的内容”和“内存单元的地址”4内存储器的组织形式存储器101100110101011000011000……11010110100100101“位”:bit
最小的电子线路单元,只能保存一位二进制数即一个0或一个1。因此一“位”单元可以保存的最大的十进制数据是1。01110100“字节”:byte,由若干个“位”组成。微机中,1字节=8位
最基本的数据存储单元,即数据在内存中的存储是以“字节”为基本单位的。任何数据总是占据整数个“字节”单元。5内存单元的地址和内容101100110101011000011000……1101011010010010计算机怎么知道到哪一个内存单元去找需要的数据?00000001000200030004……099809991000内存储器从第一个字节开始到最后一个字节为止,每一个字节单元依次有一个“编号”,这个编号就叫内存单元的“地址”。该地址所指向的内存单元中存放的数据就叫内存单元的“内容”。计算机首先找到所需数据的地址(编号),再到该地址所指向的内存单元去读取内存单元的内容(所需数据的值)计算机的主存储器被分成一个个存储单元,为了区分各存储单元,要为每个存储单元编号,这个编号即地址。6地址和指针的概念再回忆一下:数据在内存中是如何存储和如何读取的?程序定义变量
inta;编译系统为每一个定义的变量分配相应数目的字节单元同时,编译系统把每个变量所占字节单元的地址信息和变量名对应起来程序中访问该变量
a=234;编译系统首先根据变量名与地址的对应关系,找到变量a的地址然后,把常量234放到由该地址所指向的内存单元去1.定义变量,系统分配内存单元:2.访问变量:首先确定变量的地址7变量C允许把值存放在变量中,每个变量都由一个变量名来标识。程序运行期间,值可以被改变的量称为变量每个变量都必须有一个变量类型。每个变量根据它的类型不同,在内存中占据一定数目的字节单元,该变量的值就存放在这些内存单元中。123a变量名
a实际上是一个符号地址变量a
所占据的内存单元123是变量
a的变量值内存单元的地址内存单元的内容在对程序编译时由系统给每一个变量按其类型分配内存单元,同时,系统内部维护着变量名和它的内存单元地址的对应信息。变量就是命名的内存单元8地址和指针的概念这种利用变量名及其对应的地址信息(该信息由系统自动维护,无法操纵)存取变量值的方式称之为“直接访问”方式。我们也可以采取另一种称之为“间接访问”的方式,即把某个变量的地址保存在另一个变量里。“直接访问”方式:a=234;“间接访问”方式:*p=234;*p=234;首先取出变量p的值(实际上就是a的地址)然后把常量234放到该值(地址)所指向的内存单元去程序定义普通变量inta;程序定义指针变量int*p;把变量a的地址保存到指针变量中p=&a;9话说福尔摩斯派华生到威尔爵士居住的城堡去取回一个重要的数据。白天,在书房里,威尔爵士当着福尔摩斯和华生的面亲自将数据锁入了书柜中编号为3010的抽屉。夜里,华生悄悄地潜入了威尔爵士地书房。他轻手轻脚地打开了编号为3010的抽屉,用电筒一照,只见里面只有一张纸条,上面赫然6个大字:地址2000。华生眼睛一亮,迅速找到编号为2000的抽屉,取出重要数据123,完成了任务。地址和指针的概念10
是将3送给i所在的空间。“间接访问”方式例:将3送到变量I_pointer所“指向”的单元(即I所标志的单元)。所谓“指向”,是通过地址来体现的,I_pointer中的值为2000,它是变量I的地址,这样就在I_pointer和变量之间建立起一种联系,即通过I_pointer能知道I的地址,从而找到变量I的内存单元。因而在C语言中,将地址形象化地称为“指针”。意思是通过它能找到以它为地址的内存单元。一个变量的地址称为该变量的“指针”。例:i=3;或scanf(“%d”,&i);“直接访问”方式11指针是一种特殊的数据类型。指针概念是C语言中较难理解和较难掌握的概念之一。本章介绍指针的概念、定义、运算等内容。
指针变量是一种特殊的变量,变量中存放的不是某种数据类型的数据,而是另一个变量或常量的地址。5.1指针概念如有定义:
intvalue=150;charch=‘M’;
并执行赋值语句:
pv=&value;pc=&ch;
由于pv中存放的是value变量的地址,pc中存放的是ch变量的地址,故称pv和pc为指针变量。简称为指针(Pointer)。12指针指向的对象称为目标或目标变量(常量)。如图5.1所示:…
150…
‘M’…
…valuechpvpcint*pvchar*pc图5.1内存空间1000H1050H
0000H&value1000H1001H&ch1050H&pc11A2H
11A3H
11A1H&pv11A0H地址和指针的概念13C规定:在操作运算和流程控制语句中,目标或目标变量可以用指针变量名前加上运算符“*”表示。因此,
pv的目标变量value可表示为*pv,pc的目标变量ch可表示为*pc,即*pv和value等效,*pc和ch等效而&pv和&pc表示指针变量本身的地址,14总结
内存单元的地址和内存单元的内容是两个不同的概念。指针:就是内存单元的地址,即内存单元的编号。指针变量:用来存放另一变量的地址(即指针)的变量。即专门用于保存地址的变量叫做指针变量。如:地址2000是变量i的指针;i_pointer是指针变量,其值就是指针2000。
指针变量的值就是地址。指针变量指向该地址所指向的单元。155.1.2指针的定义及初始化变量的指针和
指向变量的指针变量16变量的指针和指向变量的指针变量变量的指针就是变量的地址(编译系统分配给该变量的内存单元的地址)用于保存变量的指针的变量就是指向变量的指针变量。
定义指针变量定义的一般形式:类型说明符*指针变量名;如:int *pa, *pb;float *pf1,*pf2;char*ch1,*ch2;指针变量与普通变量一样,在程序中需先定义再使用。17②在现有的32位微机系统中,指针变量在内存中占4个字节,其最大访问地址为:变量的指针和指向变量的指针变量①“类型说明符”表示该指针变量可以指向的变量的类型,而不是其自身的类型,即该指针变量可以而且只能保存这种类型的变量的地址;③一个“*”号表示定义的变量是一个能够保存普通变量地址的指针变量,而不是一个保存具体数据的普通变量。说明:185.1.3指针变量的赋值1.使用取地址运算符&,把地址值赋给指针变量比如:int*pa,*pb,a,b;pa=&a;pb=&b;2.把另一个指针变量的值赋给指针变量比如:int*pa,*pb,a,b;pa=&a;pb=pa;
3.给指针变量赋NULL值(NULL是在stdio.h头文件中定义的符号常量,该常量代表整数0),表示该指针变量本身的值为0,它不指向任何内存单元。比如:int*pa,*pb,*pc;pa=NULL;
pb=0;pc=‘\0’;
不指向任何变量的指针是无用的。仅当存储了变量的地址后,指针才有用。指针变量只能保存地址。可以用下面的三种方式给它赋值:19&apaa使一个指针变量指向同类型的变量方法:只需把某个同类型变量的地址(指针)赋值给该指针变量即可。然后,我们就可以说,该指针变量指向了某个普通变量。比如:?定义指针变量后,怎样使它指向一个同类型的普通变量呢int*pa,*pb,a,b;pa=&a;pb=&b;&bpbb20使一个指针变量指向同类型的变量注意:某个类型的指针变量只能保存同类型的变量的指针(即一个指针变量只能指向同类型的变量)int*pa,*pb,a,b;float*p1,*p2,f1,f2;pa=&a;pb=&b;/*正确的赋值*/p1=&a;p2=&b;/*错误的赋值*/p1=a;p2=1234;/*错误的赋值*/比如:Error:Cannotconvert'int*'to'float*'Error:Cannotconvert'int'to'float*'21指针置初始化值的格式:指向类型*指针名=初始化值;如:main()
{inta;
int*p=&a,*p1=p;
……}再如:int*p=0;
或int*p=NULL;
指针变量的初始化22指针变量的初始化语句int*pointer=0;定义了一个名为pointer的指针,该指针“指向”的目标为整型,且被初始化为0。说明:①一旦指针pointer被定义,系统会为pointer分配一个内存单元,该单元地址可以用&pointer表示(运算符&表示取变量的地址);②在这里整数0是C/C++系统唯一一个允许赋给指针类型变量的整数值。除0以外的整数值是不允许赋给指针变量的,因为指针变量中存放的是内存的地址,而不是任何整数③注意:值为0的指针不指向任何变量235.2指针运算:两个有关指针的运算符①取地址运算符:&
(只能取变量或数组元素的地址)比如:inta,*pa;pa=&a;则:&a为变量a的地址;等价于pa*pa代表指针变量pa所指向的存储单元,等价于a②指针运算符(间接访问运算符):*(单目)优先级:与取地址运算符&同级结合性:右结合性用法:*指针变量名&apaa*pa24所以,若有:intx,y,*px=&x;
则下面的运算均是正确的:
y=*px+1;/*把x的内容加1送变量y*/
printf(“%d\n”,*px);/*打印当前x的内容*/
d=sqrt((double)*px);/*把x的平方根送变量d*/
*px=0;/*把x置为0*/
*px+=1;/*把x的值加1*/
(*px)++;/*使x的值加1*/
y=(*px)++;/*即y=x,x++*/25#include“stdio.h”voidmain(){inta,b;int*pa,*pb;a=100;b=200;pa=&a;pb=&b;printf(“a=%d,b=%d\n”,a,b);printf(“a=%d,b=%d\n”,*pa,*pb);}通过指针变量访问变量:例5-1让pa和pb分别指向变量a和b使用变量名访问变量:输出变量a和b的值使用变量的地址访问变量:输出pa和pb指向的内存单元的值。实际上就是变量a和b的值运行结果:a=100,b=200
a=100,b=20026#include“stdio.h”voidmain(){inta,b;int*pa,*pb;pa=&a;pb=&b;a=100;b=200;printf(“a=%d,b=%d\n”,a,b);printf(“a=%d,b=%d\n”,*pa,*pb);}通过指针变量访问变量先让pa和pb分别指向变量a和b再给变量a和b赋值。实际上是给pa和pb指向的内存单元赋值。使用变量的地址访问变量:输出pa和pb指向的内存单元的值。实际上就是变量a和b的值27#include“stdio.h”voidmain(){inta,b;int*pa,*pb;pa=&a;pb=&b;*pa=100;*pb=200;printf(“a=%d,b=%d\n”,a,b);printf(“a=%d,b=%d\n”,*pa,*pb);}通过指针变量访问变量先让pa和pb分别指向变量a和b再给pa和pb指向的内存单元赋值。
实际上就是给变量a和b赋值使用变量的地址访问变量:输出pa和pb指向的内存单元的值。实际上就是变量a和b的值28评注:
1、在第4行虽然定义了两个指针变量,只是提供了两个指针变量,但并未指向任何一个整型变量。称为指针“悬空”。
2、从上例中可看出,*pa等价于a,*pb等价于b,故凡在程序中出现a的地方均可用*pa代替。。最后一行的*pa和*pb就是变量a和b。
3、程序中两处出现*pa等,含义不同。程序第4行中的*pa表示定义指针变量pa。它前面的*只是表示该变量是指针变量。程序最后一行中的*pa则代表变量,即pa所指向的变量。
4、第5行中的pa=&a是将a的地址赋给指针变量pa,而不是*pa。29有关指针变量的说明①一个指针变量可以指向任何一个同类型的普通变量;但是,在某一个时刻,它只能指向某一个同类型的变量②让指针变量指向某个同类型普通变量的方法是:把该普通变量的地址保存到指针变量中。③必须对指针变量进行了正确合法的初始化后,才能使用该指针变量访问它所指向的内存单元。int*pa,*pb,a,b;pa=&a;pb=&b;pa=&b;pb=&a;int*pa,*pb,a,b;*pa=100;或printf(“*pa=%d\n”,*pa);30有关指针变量的说明④即使对指针变量进行了正确合法的初始化后,也只能用该指针变量访问合法的允许访问的内存单元。不能使用该指针变量去随意访问其它不确定的内存单元,否则,结果是不可预料的。int*pa,*pb,a,b;pa=&a;*pa=100;pb=&b;*pb=200;printf(“valueaftera=%d\n”,*(pa+1));printf(“valueafterb=%d\n”,*(pb+1));*(pa+1)=1000;*(pb+1)=2000;正确安全使用指针变量错误使用指针变量错误使用指针变量而且可能很危险31小结有关运算符*和&的说明①假设有inta,*pa;pa=&a;则:
&*pa相当于&a,因为*pa就相当于a*&a相当于*pa,因为&a就相当于pa(*pa)++相当于(a++)100200pa*(pa++):得到100,pa自增(*pa)++:得到101,pa所指向的单元变成101,而pa不变②注意(*pa)++和*pa++的区别由于++和*为同一运算级别,则根据结合性,*pa++相当于*(pa++),与(*pa)++是完全不同的。*(pa++)
:先得到pa当前指向的单元的值,再使pa自增(*pa)++
:是pa所指向的单元的值自增32课堂练习◆
1.下若有语句char*p1,*p2,*p3,*p4,ch;则不能正确赋值的语句是()。(A)p1=&ch;scanf(“%c”,p1);(B)*p2=getchar();(C)p3=&ch;*p3=getchar();(D)scanf(“%c”,p4);答案:(B)(D)332、有如下语句inta=10,b=20,*p1,*p2;p1=&a;p2=&b;如图1所示;若要实现图2所示的存储结构,可选用的赋值语句是——。课堂练习1020p1p2ab1020p2bp1aA)*p1=*p2;B)p1=p2;C)p1=*p2;D)*p1=p2;3、已有定义intk=2;int*ptrl,*ptr2;且ptr1和ptr2均已指向变量k,下面不能正确执行赋值语句是()。k=*ptr1+*ptr2;B)ptr2=k;C)ptr1=ptr2;D)k=*ptr1*(*ptr2);答案:(B)答案:(B)344、若有语句int*point,a=4;和point=&a;
下面均代表地址的一组选项是———
a)a,point,*&ab)&*a,&a,*pointC)*&point,*point,&aD)&a,&*point,point课堂练习答案:
(D)5、若需要建立如图所示的存储结构,且已有说明
float*p,m=3.14;则正确的赋值语句是:
a)p=m;b)p=&m;C)*p=m;D)*p=&m;&m3.14答案:
(b)p356.执行以下程序后,a的值为【1】,b的值为【2】main(){inta,b,k=4,m=6,*p1=&k,*p2=&m;a=p1==&m;b=(-*p1)/(*p2)+7;printf(“a=%d\n”,a);printf(“b=%d\n”,b);}【1】a)-1b)1c)0d)4【2】a)5b)6c)7d)10课堂练习答案:C,C365.3指针和数组
数组的指针和
指向数组的指针变量指针与一维数组指针与结构数组37数组的指针和指向数组的指针变量◆数组的指针就是数组的首地址(即数组第一个元素的地址)◆用于保存数组的指针的变量就是指向数组的指针变量。◆数组的每一个元素都相当于一个同类型的变量,也都在内存中占据存储单元,也都有相应的地址。◆引用数组元素既可以用数组名加下标法,也可以用指针法。其本质都是使用数组的指针。◆既然可以定义指向变量的指针变量,当然也可以定义指向数组元素的指针变量,它保存的是数组中某一个元素的地址。而如果该指针变量保存数组第一个元素的地址,也就是数组的指针,那么它就成了指向数组的指针变量。38指向数组的指针变量的定义指向数组的指针变量的定义定义方法:类型说明符*指针变量名;可见,定义指向变量的指针变量和定义指向数组的指针变量的方法是一样的。因为,所谓指向数组的指针变量实际上就是指向数组元素的指针变量,而数组元素就相当于一个同类型的普通变量。int*pa,*pb,a[10],b[10];float*pf1,*pf2;char*str1,*str2;39使一个指针变量指向同类型的数组方法:只需把某个同类型的数组的首地址(指针)赋值给该指针变量即可。然后,我们就可以说,这个指针变量指向了该数组。比如:?定义指针变量后,怎样使它指向一个同类型的数组呢int*pa,*pb,a[10],b[10];pa=&a[0];pb=&b[0];/*数组首地址就是数组第一个元素的地址*/或者:int*pa,*pb,a[10],b[10];pa=a;pb=b;
/*数组名代表首地址*/40通过指针变量引用数组元素能够通过指针变量引用数组元素的前提:已经定义了一个指针变量,并且已经给它赋值使它指向某个同类型的数组。(也就是说,必须要在保证指针变量指向的是合法有效的数据单元时,才可以使用指针访问该单元的内容)访问方法:指针法或下标法如果指针变量p的初值为&a[0],则:①p+i或a+i
就是a[i]的地址,即它们指向a数组中下标为i的元素
p+i==&a[i]==a+i②*(p+i)或*(a+i)
就是它们所指向的数组元素,即a[i]*(p+i)==*(a+i)==a[i]③指针变量也可以使用下标法,如p[i]和*(p+i)等价41通过指针变量引用数组元素…a[0]a[1]a[2]a[9]←←←←&a[0]&a[1]&a[2]&a[9]如有:inta[10],*p;p=a;或p=&a[0];=a+0=a+1=a+2=a+9=p+0=p+1=p+2=p+9*(a+0)=*(a+1)=*(a+2)=*(a+9)=*(p+0)=*(p+1)=*(p+2)=*(p+9)=
注意:1、在对指向连续存储单元的指针变量进行加减运算时,数字1并不代表加减一个字节,而是代表该指针变量所属数据类型的数据所占的字节单元的长度。如int型指针变量加减1时,指针实际移动2个字节;float形指针变量加减1时,指针实际移动4个字节;依次类推。2、参看教材P136页;42通过指针变量引用数组元素:例5-4-1◆编程从键盘接收数组中的全部元素并输出。/*方法1:用数组名和下标*/#include“stdio.h”voidmain(){inta[10],n;for(n=0;n<10;n++)scanf(“%d”,&a[n]);printf(“\n”);for(n=0;n<10;n++)printf(“%d”,a[n]);}特点:直观易懂。系统内部计算元素地址。每访问一个新的元素就重新计算一次地址。速度较慢。43通过指针变量引用数组元素:例5-4-2◆编程从键盘接收数组中的全部元素并输出。/*方法2:用数组名+偏移量得到元素地址*/#include“stdio.h”voidmain(){inta[10],n;for(n=0;n<10;n++)scanf(“%d”,a+n);printf(“\n”);for(n=0;n<10;n++)printf(“%d”,*(a+n));}特点:利用数组名这个指针常量加上一个变化的地址偏移量来得到元素地址。每访问一个新的元素就重新计算一次地址。速度较慢。44通过指针变量引用数组元素:例5-4-3◆编程从键盘接收数组中的全部元素并输出。/*方法3:用指针变量得到元素地址*/#include“stdio.h”voidmain(){inta[10],n;int*pa=a;for(n=0;n<10;n++)scanf(“%d”,pa+n);printf(“\n”);for(n=0;n<10;n++)printf(“%d”,*(pa+n));}特点:利用一个指向数组的指针变量加上一个变化的地址偏移量来得到元素地址。指针变量本身的值没有变化。45通过指针变量引用数组元素:例5-4-4◆编程从键盘接收数组中的全部元素并输出。/*方法4:用指针变量得到元素地址*/#include“stdio.h”voidmain(){inta[10],n;int*pa=a;for(n=0;n<10;n++)scanf(“%d”,pa++);printf(“\n”);pa=a;for(n=0;n<10;n++)printf(“%d”,*(pa++));}特点:利用一个指向数组的指针变量来得到元素地址。指针变量本身的值在变化。使用普通变量作循环控制变量。要时刻注意指针变量的当前值。46通过指针变量引用数组元素:例5-4-5◆编程从键盘接收数组中的全部元素并输出。/*方法5:用指针变量得到元素地址*/#include“stdio.h”voidmain(){inta[10],n;int*pa=a;for(n=0;n<10;n++)scanf(“%d”,pa++);printf(“\n”);for(pa=a;pa<a+10;pa++)printf(“%d”,*(pa++));}特点:指针变量本身的值在变化。使用指针变量作循环控制变量。要时刻注意指针变量的当前值。要正确确定循环控制变量初值和终值。47通过指针变量访问数组时的注意事项注意:在利用指针变量本身的值的改变来访问数组元素时,要时刻注意指针变量的当前值。#include“stdio.h”voidmain(){inta[10],n;int*pa=a;for(n=0;n<10;n++)scanf(“%d”,pa++);printf(“\n”);pa=a;for(n=0;n<10;n++)printf(“%d”,*(pa++));}这一句不能少,否则后面输出的结果就不对了。因为此时指针已经指向数组的有效范围之外去了。48通过指针变量访问数组时的注意事项注意:利用指针变量可以指到合法的数组范围之外去,而编译系统并不会报错。应由编程者保证不出现这种情况。#include“stdio.h”voidmain(){inta[10],n;int*pa=a;for(n=0;n<10;n++)scanf(“%d”,pa++);printf(“\n”);for(n=0;n<10;n++)printf(“%d”,*(pa++));}如果去掉pa=a这一句,程序一样会运行并给出结果,但显然不是正确的结果。49课堂练习◆
1.若有语句inta[]={1,2,3,4,5},*pa,n;pa=a;0≤n≤4,则()是对a数组元素地址的正确引用。(A)a+n (B)a++(C)&pa (D)&*pa答案:(A)(D)◆
2.若有语句inta[]={1,2,3,4,5},*pa,n;pa=a;0≤n≤4,则()是对a数组元素的错误引用。(A)*(a+n) (B)*(&a[n])(C)pa+n (D)pa[n]答案:(C)50◆
3.若有语句inta[5]={1,2,3,4,5},*pa=a;则()是对a数组元素地址的正确引用。(A)p+5 (B)*a+1(C)&a+1 (D)&a[0]课堂练习答案:(D)◆
4.若有语句inta[5]={1,2,3,4,5},*pa=a;则()是对a数组元素的正确引用。(A)*&a[5] (B)a+2(C)*(p+5) (D)*(a+2)答案:(D)515.4字符串的指针和
指向字符串的指针变量52字符串的指针和指向字符串的指针变量◆数组的指针就是数组的首地址(即数组第一个元素的地址)◆用于保存数组的指针的变量就是指向数组的指针变量。◆C语言是用字符数组来保存字符串的◆字符串的指针就是字符串中第一个字符所在内存单元的地址◆既然可以定义指向数组的指针变量,当然也可以定义指向字符串的指针变量,它保存的是字符串中第一个字符所在内存单元的地址。◆指向字符串的指针变量实际上就是一个指向字符型变量的指针变量,正如同指向整型数组的指针变量就是指向一个整型变量的指针变量一样,因为一个字符串就是一个字符数组。53指向字符串的指针变量的定义指向字符串的指针变量的定义由于指向字符串的指针变量,实际上就是指向字符型变量的指针变量,因此其定义方法就是:char*指针变量名;其中,string1和string2、str1和str2都是指针类型的数据,都可以保存地址信息,所不同的是:
string1和string2是指针常量,它们的值无法改变,指向固定的内存单元(即固定的字符串);而str1和str2是指针变量,值可以改变,从而指向不同的内存单元(即不同的字符串)。charstring1[80],string2[80];char*str1,*str2;54使一个指针变量指向字符串方法:只需把某个字符串的指针赋值给该指针变量即可。然后,我们就可以说,这个指针变量指向了该字符串。1.
先定义字符数组保存字符串,然后再定义字符型指针变量指向该数组,也就是指向该字符串;?定义指针变量后,怎样使它指向一个字符串呢2.
不定义字符数组,直接定义字符型指针变量,然后把字符串赋值给该指针变量。上述操作有两种情况:55使一个指针变量指向字符串:第一种情况1.
先定义字符数组保存字符串,然后再定义字符型指针变量指向该数组,也就是指向该字符串;#include“stdio.h”voidmain(){charstr[80]=“Hello,World”;
char*pstr=str;/*定义字符型指针变量*/printf(“%s\n”,str);/*用数组名访问*/printf(“%s\n”,pstr);/*用指针变量访问*/}str是字符数组名,包含了字符数组的首地址信息,相当于一个字符型数据的指针,所以可以把它赋值给一个字符型的指针变量。然后就可以用该指针变量来访问字符串。56使一个指针变量指向字符串:第二种情况2.
不定义字符数组,直接定义字符型指针变量,然后把字符串赋值给该指针变量。#include“stdio.h”voidmain(){/*定义字符型指针变量,同时用字符串常量初始化*//*表示把字符串的指针保存在指针变量里*/char*pstr=“Hello,World”;printf(“%s\n”,pstr);/*用指针变量访问*/}C语言把字符串常量处理成一个字符型指针常量,因此把一个指针常量赋值给一个指针变量当然是正确的。57……charstr[80];str=“Hello,World”;……使一个指针变量指向字符串:第二种情况◆也可以先定义字符型指针变量,然后再把字符串常量赋值给它,同样正确。比如:……char*pstr;pstr=“Hello,World”;……但是对字符数组却不能这样操作。比如:为什么不对?58通过指针变量访问字符串能够通过指针变量访问字符串的前提是:已经定义了一个字符型指针变量,并且已经把某个字符串的指针赋值给它。访问方法:指针法或下标法如果pstr的初值为字符串的第一个字符的地址,比如有char*pstr=“Hello,World”;则有以下事实:①pstr+i就是第i个字符的地址,即它指向字符串中的第i个字符②*(pstr+i)或者pstr[i]就是它所指向的字符③指针变量也可以使用下标法,即pstr[i]和*(pstr+i)是等价的59例如:main(){charbuffer[10]=“ABC”;char*pc;pc=“hello”;/*指针指向字符串常量*/
printf(”%s\n”,pc);/*输出指针指向字符串hello*/pc++;
printf(”%s\n”,pc);/*输出指针指向字符串ello*/
printf(”%c\n”,*pc);/*输出指针指向字符e*/pc=buffer;
printf(”%s\n”,pc);/*输出指针指向字符串ABC*/}通过指针变量引用数组元素:例5-4-160通过指针变量引用数组元素:例5-4-2◆编程把字符串s2复制到字符串s1中/*方法1:用数组名和下标*/#include“stdio.h”voidmain(){chars1[80]=“”,s2[]=“hello,world”;intn;for(n=0;s2[n]!=‘\0’;n++)
s1[n]=s2[n];s1[n]=‘\0’;printf(“s1=%s\ns2=%s”,s1,s2);}61通过指针变量引用数组元素:例5-4-3◆编程把字符串s2复制到字符串s1中/*方法2:用数组名+偏移量得到元素地址,访问元素*/#include“stdio.h”voidmain(){chars1[80]=“”,s2[]=“hello,world”;intn;for(n=0;s2[n]!=‘\0’;n++)
*(s1+n)=*(s2+n);*(s1+n)=‘\0’;printf(“s1=%s\ns2=%s”,s1,s2);}特点:数组名本身不变也不可能被改变62通过指针变量引用数组元素:例5-4-4◆编程把字符串s2复制到字符串s1中/*方法3:用指针变量+偏移量得到元素地址,访问元素*/#include“stdio.h”voidmain(){chars1[80]=“”,s2[]=“hello,world”;intn;char*p1=s1,*p2=s2;for(n=0;*(p2+n)!=‘\0’;n++)
*(p1+n)=*(p2+n);*(p1+n)=‘\0’;printf(“s1=%s\ns2=%s”,s1,s2);}特点:指针变量本身的值没有变化63通过指针变量引用数组元素:例5-4-5◆编程把字符串s2复制到字符串s1中/*方法4:用指针变量自身变化得到元素地址,访问元素*/#include“stdio.h”voidmain(){chars1[80]=“”,s2[]=“hello,world”;intn;char*p1=s1,*p2=s2;for(n=0;*p2!=‘\0’;n++)
*(p1++)=*(p2++);*p1=‘\0’;printf(“s1=%s\ns2=%s”,s1,s2);}特点:普通变量做循环控制变量64通过指针变量引用数组元素:例5-4-6◆编程把字符串s2复制到字符串s1中/*方法5:用指针变量自身变化得到元素地址,访问元素*/#include“stdio.h”voidmain(){chars1[80]=“”,s2[]=“hello,world”;char*p1=s1,*p2=s2;for(;*p2!=‘\0’;p1++,p2++)
*p1=*p2;*p1=‘\0’;printf(“s1=%s\ns2=%s”,s1,s2);}特点:指针变量做循环控制变量65通过指针变量访问字符串时的注意事项注意:在利用指针变量本身的值的改变来访问字符串时,要时刻注意指针变量的当前值。#include“stdio.h”voidmain(){chars1[80]=“”,s2[]=“hello,world”;
char*p1=s1,*p2=s2;for(;*p2!=‘\0’;p1++,p2++)*p1=*p2;*p1=‘\0’;printf(“s1=%s\ns2=%s”,p1,p2);}此处用p1和p2来输出字符串,是得不到正确结果的。66指向字符串的指针变量的有关运算如有:charstr[80],*ps;ps=str;或ps=&str[0];①ps++或ps+=1,是下一个字符的地址(即ps指向下一个字符)
ps--或ps-=1,是上一个字符的地址(即ps指向上一个字符)②
*ps++等价于*(ps++),即先得到ps当前指向的字符,然后再使ps自增,从而指向下一个字符③
*++ps等价于*(++ps),即先使ps自增,指向下一个字符,然后得到ps所指向的字符④
(*ps)++,则是表示ps当前指向的字符加1675.5指针数组68一、定义
一个数组中若每个元素都是一个指针,则称为指针数组。例如:定义一个指针数组并初始化
char*proname[]={“FORTRAN”,“C”,“C++”};
该数组的每个元素是指向字符串常量的字符指针,指针指向的字符串常量存放在dataarea的const存储区中,可能连续,也可能不连续。5.5指针数组69该字符数组的内存表示如下:0088:22510088:22590088:225B0067:44000067:44020067:44040088:2251‘F’‘O’‘R’‘T’‘R’‘A’‘N’‘\0’‘C’‘\0’‘C’‘+’‘+’‘\0’…0088:22522253225422552256225722582259225A225B225C0088:225D0088:225EChar*proname[]70二、指针数组与二维数组字符指针数组与字符二维数组的主要不同之处是:字符指针数组元素指向的字符串可以是不规则的长度。字符二维数组的每个元素的长度必须相同,在定义时已确定。例如:上例中
proname[0]→8个字节字符串
proname[1]→2个字节字符串
proname[2]→4个字节字符串总字节数为6+14=20在二维数组中:
charname[3][8]={“FORTRAN”,“C”,“C++”};共需3×8=24个字节。可见使用字符指针数组更灵活方便。71三、指向指针的指针如果在一个指针变量中存放的是另一个变量的指针的地址,称该指针为指向指针的指针,即二重指针。例如:下图中P是二重指针。变量v的地址放入指针q中,指针q的地址放入指针p中,P是二重指针。&q&v120p指针q指针v变量*p**p72如下面定义:
char*pc[]={“abc”,“def”,“hig”};
char**ppc;
/*定义ppc为二重指针*/
ppc=pc;
显然指针数组名pc就是一个二重指针。例:指向指针的指针的概念。main(){
intx,*q,**p;x=10;q=&x;p=&q;
printf(“”%d”,**p);}输出:1073例:用指针型指针输出数组元素。main(){
inta[5]={1,3,5,7,9};
int*num[5]={&a[0],&a[1],&a[2],&a[3],&a[4]};
int**p,i;p=num;for(i=0;i<5;i++){
printf(”%d\t”,**P);p++;}}输出结果:1 3 5 7 974四、NULL指针
NULL是空指针。在C中,NULL取值为0,常常用以表示指针不指向任何地方的一种状态。
void*表示指针指向的目标对象无数据类型。注意两者的区别。75例5.7.1任务:编辑手中有一篇英文文稿需付稿酬,稿酬按40元/万字计算。英文文稿的字按单词数量计,请计算文稿中有多少单词?问题分析与算法设计:根据题意可以将解题过程分为七步:假设文稿是从键盘输入(以后学了文件的处理后,可处理以文本文件等形式存放的文稿),最多不超过50个字符,将一个字符指针指向文稿的开头;从指针当前所指的字符开始逐个字符检查。如果该字符为’\0’,则结束统计,转⑦,否则,继续以下步骤;如果该字符是空格,则将指向字符的指针往下移动一个字符;重复该步直到指针当前所指的字符不为空格;检查指针当前所指的字符是否为结束标志’\0’,如果是,转②,否则,继续以下步骤;单词计数器加1;检查指针当前所指的字符。如果不是空格并且也不是结束标志’\0’,则将指向字符的指针往下移动一个字符;重复该步直到指针当前所指的字符为空格或结束标志’\0’;转②;输出统计出的单词数量;76(1)指针是—个变量,它存储的是另一个变量的地址。给指针赋值就是将一个内存地址装入指针变量。如果这个内存地址是某变量的地址,则该指针就指向了该变量。(2)指针变量的类型是指针所指向的变量的类型。(3)在定义一个指针变量时,将其初始化为空(NULL)是一个好习惯。(4)对指针赋值是将它所指向的变量的地址赋给指针变量。这时要用到取地址运算符&。&a表示取变量a的地址。(5)在赋值语句中可使用间接访问运算符*。如:inta=66;intb=0;int*p=&a;b=*p;则会将p指针所指向的变量a的值66赋给b变量。编译器如何知道*是被用作乘法运算符、间接运算符还是被用来声明指针呢?编译器根据上下文来解释星号的用途。如果*所在的语句以变量类型打头,则认为它被用户声明为一个指针;如果被用于一个已经声明过的指针,但不位于变量声明中,则被认为是间接运算符;如果被用于数学表达式中,且右边不是指针变量,则被认为是一个乘法运算符。第五章小结77(6)数组名可视为常量指针,它指向数组的第一个元素。将数组名赋给指针变量,则该指针就指向了该数组的首地址(即数组中的第一个元素所在地址)。(7)数组中的元素为指针的数组叫指针数组。这时数组中的元素不是普通的数值,而是内存中的地址。(8)字符数组就是字符串。字符数组只有在定义时才允许整体赋值。C库函数中有字符判断函数和字符串相关函数,在编程时可以选用。(9)如果对指针使用地址运算符,将得到指针的地址。指针也是—个变量,存储的是它指向的变量的地址。存放指针变量地址的变量叫双重指针。第五章小结78课堂练习◆
1.若有语句charstr[80],*pstr;则下列语句中错误的是()。(A)pstr=“Hello”; (B)*pstr=“World”;(C)pstr=str; (D)*str=‘Y’;(E)str=“”; (F)pstr=0;答案
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年绥化青冈县乡镇卫生院公开招聘医学毕业生5人考前自测高频考点模拟试题及答案详解参考
- 2025年江苏常州经济开发区社会保障和卫生健康局下属事业单位公开招聘卫技人员14人考前自测高频考点模拟试题及答案详解(夺冠)
- 2025年合肥庐阳科技创新集团有限公司招聘6人考前自测高频考点模拟试题及答案详解(典优)
- 2025广东广州市黄埔区人民政府长岭街道办事处招聘社区党建专职组织员和政府聘员3人模拟试卷及答案详解(易错题)
- 2025年春季中国邮政储蓄银行合肥市分行校园招聘考前自测高频考点模拟试题及答案详解(典优)
- 2025年马鞍山市消防救援局招聘政府专职消防员38人考前自测高频考点模拟试题及1套完整答案详解
- 2025广西玉林市福绵区福绵镇人民政府招聘代理服务记账中心编外人员2人模拟试卷有答案详解
- 2025河南信阳市潢川县退役军人事务局招聘3名全日制公益性岗位考前自测高频考点模拟试题及答案详解(夺冠)
- 2025辽宁沈阳盛京资产管理集团有限公司所属子公司沈阳中城天玺不动产有限公司招聘1人考前自测高频考点模拟试题及答案详解(名校卷)
- 2025春季四川省人民政府科学城办事处直属事业单位第二批次考核招聘教师6人模拟试卷及参考答案详解
- 2025年高考政治一轮复习:统编版必修一到必修四综合测试卷(含答案解析)
- 第三单元整体阅读之人物篇 统编版高中语文选择性必修上册
- 高二上学期第一次月考物理试卷(附答题卷和答案)
- 教育培训机构合作培训协议
- 2025年广东省春季高考学业水平考试数学试卷试题(含答案解析)
- 广州市越秀区人民街道办事处招聘辅助人员考试试题及答案
- 旅行社挂靠合同协议书模板
- 枫蓼肠胃康胶囊与其他肠胃药的协同作用研究
- 环境污染物对人体健康影响的研究
- 国家开放大学理工英语1边学边练
- 人工智能导论PPT完整全套教学课件
评论
0/150
提交评论