1、第第8 8章章 指针指针 指针的概念简单,使用广泛、指针的概念简单,使用广泛、灵活、复杂灵活、复杂 正确使用指针,能有效使用各正确使用指针,能有效使用各种复杂数据结构,动态分配内种复杂数据结构,动态分配内存,高效使用数组和字符串,存,高效使用数组和字符串,编写通用程序等;但使用不当,编写通用程序等;但使用不当,可导致程序运行出错或死机可导致程序运行出错或死机 指针的概念、指针做函数参数、指针的概念、指针做函数参数、指针做函数返回值、数组做函指针做函数返回值、数组做函数参数已在第数参数已在第5 5章、第章、第7 7章介绍,章介绍,指针与结构体的关系、单向链指针与结构体的关系、单向链表将在第表将在
2、第9 9章介绍章介绍 学习建议:正确理解指针,多学习建议:正确理解指针,多用指针,多调试,不怕错用指针,多调试,不怕错8.1 8.1 指针的运算指针的运算8.2 8.2 指针与数组指针与数组8.3 8.3 指针数组和指向指指针数组和指向指针的指针变量针的指针变量8.4 8.4 指针与函数指针与函数8.5 8.5 newnew和和deletedelete运算符运算符8.6 8.6 指针参数传递与数指针参数传递与数据安全据安全8.1 8.1 指针的运算指针的运算 指针的运算:指针的运算:赋值、关系、算术和强制类型转换赋值、关系、算术和强制类型转换 指针的赋值:指针的赋值:将一个指针赋给一个指针变量
3、。合法的将一个指针赋给一个指针变量。合法的指针值是正确使用指针的基础指针值是正确使用指针的基础 只能将同类型变量的指针赋给指针变量只能将同类型变量的指针赋给指针变量。设:。设:intint a=1,*p1,*p2;a=1,*p1,*p2;p1=&a;/p1=&a;/将变量将变量a a的指针赋给的指针赋给p1p1p2=p1;/p2=p1;/同类型指针变量之间的赋值同类型指针变量之间的赋值使指针变量使指针变量p1p1和和p2p2都指向变量都指向变量a a,如图所示。如图所示。*p1*p1=*p1*p1+2;+2;使使p1p1所指变量所指变量(a)a)的值为的值为3 3p1=&aa=1p2=p1指针
4、变量赋值注意指针变量赋值注意事项事项 空指针:空指针:0 0或或NULLNULL。空指针不指向任何变量空指针不指向任何变量 空指针变量:空指针变量:值为空指针的指针变量值为空指针的指针变量 不允许对空指针变量所指内存做读写操作不允许对空指针变量所指内存做读写操作。如:。如:static static intint*p;/*p;/空指针空指针*p=100;/p=100;/出现运行错误并终止执行出现运行错误并终止执行 如何避免上述错误?如何避免上述错误?在操作前,先判断指针值是否合法:在操作前,先判断指针值是否合法:if(p)*p=100;if(p)*p=100;else else coutcou
5、tpp指针变量的值为空指针!指针变量的值为空指针!n;n;不同类型的指针变量间的赋值,需转换成同一类型后方可,不同类型的指针变量间的赋值,需转换成同一类型后方可,但应有明确的目的和意义但应有明确的目的和意义 对一个未初始化的指针变量所指存储单元赋值是极其危险对一个未初始化的指针变量所指存储单元赋值是极其危险的。这类问题在源程序编译时,会有警告提示的。这类问题在源程序编译时,会有警告提示 指针变量执行指针变量执行+或或-操作:操作:使指针变量指向下一个或使指针变量指向下一个或上一个变量,而指针变量的值实际加或减上一个变量,而指针变量的值实际加或减sizeofsizeof(指指针变量类型针变量类型
6、)指针变量加或减一个整型值指针变量加或减一个整型值n n,即:即:指针变量指针变量=指针变量指针变量n n使指针变量指向其后或其前的第使指针变量指向其后或其前的第n n个变量,指针变量个变量,指针变量的值实际增减为:的值实际增减为:指针变量指针变量=指针变量指针变量sizeofsizeof(该指针变量的类型该指针变量的类型)*)*n n 两个同类型指针值相减:两个同类型指针值相减:代表两个指针间的变量个数。代表两个指针间的变量个数。主要用于数组主要用于数组指针的算术运算指针的算术运算 例例8.18.1 指针变量的算术运算。指针变量的算术运算。#include#include using nam
7、espace std;using namespace std;intint main(void)main(void)intint a10=10,20,30,40,50,60,a10=10,20,30,40,50,60,*p1=&a0,*p2=&a5*p1=&a0,*p2=&a5;coutcout*p1=*p1*p1=*p1“,*p2=*p2;*p2=*p2;p1+;p2p1+;p2-;coutcout n*p1=*p1n*p1=*p1“,*p2=*p2;*p2=*p2;p1+=2;p1+=2;coutcout n*p1=*p1n*p1=*p1“,*(p2+1)=*(*(p2+1)=*(p2+1
8、p2+1););coutcout np2np2与与p1p1之间整型变量的个数之间整型变量的个数=p2p2-p1p1;return 0;return 0;程序运行结果:程序运行结果:*p1=10,*p2=60*p1=10,*p2=60*p1=20,*p2=50*p1=20,*p2=50*p1=40,*(p2+1)=60*p1=40,*(p2+1)=60p2p2与与p1p1之间整型变量的个数之间整型变量的个数=1=1指针的算术运算指针的算术运算(续续)所有关系运算均可用于同类型的指针比较所有关系运算均可用于同类型的指针比较 按指针值的大小按指针值的大小(作为无符号整数作为无符号整数)进行比较进行比
9、较 相等比较:判断两个指针是否指向相同的变量相等比较:判断两个指针是否指向相同的变量 不等比较:判断两个指针是否指向不同的变量不等比较:判断两个指针是否指向不同的变量 与与0 0比较:判断指针的值是否为空比较:判断指针的值是否为空 主要用于数组方面的应用主要用于数组方面的应用 例例8.28.2指针变量的关系运算。指针变量的关系运算。#includeinclude using namespace std;using namespace std;指针的关系运算指针的关系运算intint main(void)main(void)intint a5=10,20,30,40,50,*p1,*p2,sum
10、=0;a5=10,20,30,40,50,*p1,*p2,sum=0;for(p2=&a0;for(p2=&a0;p2=&a4p2=&a4;p2+);p2+)coutcout*p2*p2 t;/t;/问:问:forfor循环执行后,循环执行后,p2=p2=?p1=&a0+5;/p1=&a0+5;/使使p1p1指向数组指向数组a a的最后元素的后面的最后元素的后面p2=&a0;/p2=&a0;/使使p2p2再指向数组再指向数组a a的第的第0 0个元素个元素while(while(p2!=p1p2!=p1)/)/此处条件还可表示为:此处条件还可表示为:p2p1p2p1sum+=sum+=*p2+
11、*p2+;coutcout元素之和为:元素之和为:sumsum n;n;return 0;return 0;*p2+p2+:因运算符因运算符+和和*的优先级相同,的优先级相同,按从右到左的顺序计按从右到左的顺序计算,先做算,先做p2+p2+,即,即“*p2+;p2+;”等价于等价于“sum+=*p2,p2+;sum+=*p2,p2+;”程序输出:程序输出:10 20 30 40 5010 20 30 40 50元素之和为:元素之和为:150150指针的关系运算指针的关系运算(续续1)1)*既是乘法运算符,又是取变量运算符既是乘法运算符,又是取变量运算符&可表示可表示“按位与按位与”,又可表示取
12、指针,又可表示取指针注意下列几种运算符的混合运算:注意下列几种运算符的混合运算:取变量运算符取变量运算符“*”和取指针运算符和取指针运算符“&”的优先级相同,的优先级相同,按自右向左的方向结合。设有说明语句:按自右向左的方向结合。设有说明语句:intint a5=10,20,30,40,50,*p=&a0,b;a5=10,20,30,40,50,*p=&a0,b;&*&*p p:先做先做“*”运算,再做运算,再做“&”运算,即先取运算,即先取p p所所指变量,再取该变量的指针。该表达式的值为指变量,再取该变量的指针。该表达式的值为变量变量a0a0的指针的指针*&*&a0a0:先做先做“&”运算
13、,得到变量运算,得到变量a0a0的指针,的指针,再做再做“*”运算,取该指针所指变量,即运算,取该指针所指变量,即a0a0指针的关系运算指针的关系运算(续续2)2)+、-、取变量运算符取变量运算符*和取指针运算符和取指针运算符&的优先级相的优先级相同,按自右向左的方向结合。例如:同,按自右向左的方向结合。例如:p=&a0,b=*p+p=&a0,b=*p+:对于对于*p+p+,先做先做“+”,再做,再做“*”,因因“+”为后置运算,故等价于先取为后置运算,故等价于先取*p p,再使指针,再使指针p p加加1 1。结果:结果:b b为为1010,p p指向指向a1a1 p=&a0,b=*+pp=&
14、a0,b=*+p:对于对于*+*+p p,先做先做“+”,再做,再做“*”,因因“+”是前置运算,故先使指针是前置运算,故先使指针p p加加1 1,再取,再取*p p。结。结果:果:b b为为2020,p p指向指向a1a1 p=&a0,b=(*p)+p=&a0,b=(*p)+:对于对于(*(*p)+p)+,先做先做“*”,再做,再做“+”,即先取,即先取*p p,再使,再使*p p加加1 1。结果:。结果:b b为为1010,p p仍仍指向指向a0a0,a0a0的值改为的值改为1111*(*(p+)p+):*(p+)*(p+)等价于等价于*p+p+p=&a1,b=+*pp=&a1,b=+*p
15、:+*+*p p等价于等价于+(*+(*p)p)。结果:结果:b b为为2121,a1a1的值改为的值改为2121,p p仍指向仍指向a1a1指针的关系运算指针的关系运算(续续3)3)指针和字符串指针和字符串 字符串存于字符数组中,亦可用指针处理字符串存于字符数组中,亦可用指针处理 用指针处理字符串时,通常非常关心是否已处理到了字符串的用指针处理字符串时,通常非常关心是否已处理到了字符串的结束字符,而并不太关心存放字符串的数组的大小结束字符,而并不太关心存放字符串的数组的大小 用指针处理字符串,程序更加高效和简便用指针处理字符串,程序更加高效和简便 例例8.58.5用指针实现字符串的复制。用指
16、针实现字符串的复制。#includeinclude#include#include using namespace std;using namespace std;intint main(void)main(void)char s1=I am a student!;char s1=I am a student!;char*s2=You are a student!;char*s2=You are a student!;char s330,s430,s530,*p1,*p2;char s330,s430,s530,*p1,*p2;将字符串常量将字符串常量 You are a You are a
17、student!student!的首字符的指的首字符的指针赋值给指针变量针赋值给指针变量s2/逐个字符复制,直到逐个字符复制,直到 0 0复制完才结束!复制完才结束!for(p1=s3,p2=s1;for(p1=s3,p2=s1;*p1+=*p2+*p1+=*p2+;);/;);/用指针复制用指针复制for(unsigned i=0;for(unsigned i=0;i=i=strlenstrlen(s1)(s1);i+)/;i+)/用数组复制用数组复制s4i=s1is4i=s1i;strcpystrcpy(s5,s2)(s5,s2);/;/用库函数复制用库函数复制coutcouts3=s3s
18、3=s3 ns4=s4ns4=s4 ns5=s5ns5=s5 ns2=s2;ns2=s1;/s1;/正确正确cincinp;/p;/警告:警告:p p指向随机内存单元,潜存危险指向随机内存单元,潜存危险p=s2;p=s2;cincinp;/p;/正确,此时正确,此时p p指向已分配的内存单元指向已分配的内存单元 字符数组名是常量指针,不能改变;而字符指针变量的值字符数组名是常量指针,不能改变;而字符指针变量的值可变。例如:可变。例如:p=s1+5;/p=s1+5;/正确正确p=p+5;/p=p+5;/正确正确s1=s1+2;/s1=s1+2;/错误:数组名是常量指针,不能改变错误:数组名是常量指针,不能改变指针和字符串指针和字符串(续续3)3)