基本数据类型之二:指针

来源:互联网 发布:matlab优化工具箱 编辑:程序博客网 时间:2024/04/26 14:02
一、指针:
指针都有一个数据类型,指针的类型可以指示编译器怎么解释特定地址上内存的内容,以及该内存区域应该跨越过多少内存单元。
ü         如果一个int 型的指针寻址到1000 内存处那么在32 位机器上跨越的地址空间是1000~1003
ü         如果一个double 型的指针寻址到1000 内存处那么在32 位机器上跨越的地址空间是1000~1007
1、定义:
通过在标志符前加一个解引用操作符(*)来定义指针,在逗号分隔的标志符列表中,每个将被用做指针的标志符前,都必须加上解引用操作符。如:
int *ip1, *ip2;//两个指针ip1和ip2标志符前都要有解引用操作符*
complex<double> *cp;
string *pstring;
vector<int> *pvec;
double *dp;
long *lp, lp2;//lp2是long型整数,不是long型指针
float fp, *fp2;//fp是float型整数,不是float型指针
一般,为了书写清楚起见,我们应该这样定义:
string *str;
而不应该定义成:
string* str;
当然,上面定义也是没有错误的,但是不容易理解。
int *i=0;
int *i=NULL;
上面两个定义作用是一样的,均表示整型指针i不指向任意内存单元。
2、举例:
int iVal=1024;
int *pi=0;
int *pi2=&iVal;//pi2初始化为变量iVal的地址
pi=pi2;//pi也指向iVal的地址
pi=iVal;//错误,指针被赋值为intiVal
 
3、指针不能被初始化为其他类型对象的地址:
double dval;
double *pd = &dval;//正确
// 下面两个定义都是编译时刻错误
// 无效的类型赋值: int* <== double*
pi = pd;
pi = &dval;
4、C++提供了一种特殊的指针类型void*,可以持有任意类型的地址值
// ok: void* 可以持有任何指针类型的地址值
void *pv = pi;
pv = pd;
上面,void*表明相关的值是个地址,但该地址的对象类型并不知道。我们不能够操作空类型指针所指向的对象,只能够传送该地址值或将它与其他地址值做比较。
5、用法
已知一个int型指针pi:
int *pi;
那么在使用时,pi表示包含在pi内部的int型数据的地址值;&pi表示内存中存储pi的地址值。
如果想获得pi所指向的int型数据值,应该使用:*pi,从而解除对指针的引用。
C++提供了解引用操作符以便间接访问指针所指向的具体数据,例如:
int ival = 1024, ival2 = 2048;
int *pi = &ival;
// 解除pi 的引用, 为它所指向的对象ival
// 赋以ival2 的值
*pi = ival2;
// 对于右边的实例, 读取pi 所指对象的值
// 对于左边的实例则把右边的表达式赋给对象
*pi = abs( *pi ); // ival = abs(ival);
*pi = *pi + 1; // ival = ival + 1;
6、特殊用法:指向指针的指针
int *pi = &ival;
//实际上*标志符左边的信息表示标志符指针存储的具体地址所指数据的类型,如下:
int **ppi = &pi;//ppi指针存储的地址是pi指针的地址
int *pi2 = *ppi;//对ppi解引用,获取ppi指向的内容即pi指针的内容,即iVal的地址,赋给指针pi2
                 
 
 
 
7、指针的加法操作:
char *ch;
int *pi;
double *pd;
ch+2;//表示前进两个字节的地址
pi+2;//表示前进8个字节的地址
pd+2;//表示前进16个字节的地址
指针类型不同,每加1所前进的字节数也是不同的。实际上,指针的加法操作主要用在数组上,例如:
int ia[ 10 ];
int *iter = &ia[0];
int *iter_end = &ia[10];
while ( iter != iter_end ) {
do_something_with_value( *iter );
++iter; // 现在iter 指向下一个元素
}
 
测试题:
1、已知下列定义
int ival = 1024, ival2 = 2048;
int *pi1 = &ival, *pi2 = &ival2, **pi3 = 0;
说明下列赋值将产生什么后果哪些是错误的
(a) ival = *pi3; (e) pi1 = *pi3;
(b) *pi2 = *pi3; (f) ival = *pi1;
(c) ival = pi2; (g) pi1 = ival;
(d) pi2 = *pi1; (h) pi3 = &pi2;
答:a错,*pi3表示指针pi3指向的内存单元的值,是一个整型地址值,而不是int。另外pi3是指针的指针,其值为0,解引用null指针会造成运行时错误。
       b错,同a
       c错,不能将指针赋值给整型变量
       d错,不能将整型数据赋值给整型指针
       e错,pi3是指针的指针,其值为0,解引用null指针会造成运行时错误。
       f正确
       g错,不能将整型数据赋值给整型指针
       h正确。
2、指针是C 和C++程序设计一个很重要的方面也是程序错误的常见起源例如
pi = &ival2;
pi = pi + 1024;
几乎可以保证pi 会指向内存的一个随机区域这个赋值在做什么什么时候它不是一个错误
答:如果pi指向一个不会越界的数组的话,这种操作还是有一定使用价值的。
3、类似地下面的小程序的行为是未定义的可能在运行时失败
int foobar( int *pi ) {
*pi = 1024;
return *pi;
}
int main() {
int *pi2 = 0;//定义时,指针pi2没有指向一块具体的内存,相当于没有初始化。
int ival = foobar( pi2 );
return 0;
}
答:问题在于我们指针pi2在定义时,并未指向一块已经分配的内存,那么在footbar函数中,执行*pi=1024操作时,试图将1024写入地址0的内存中,除非指针pi2定义时被赋予一个实际值,否则foobar函数中,对pi指向的内存写入1024时,就是错误的。改错方法,就是在foobar函数中加上一个if判断。
4、在前面两个练习中出现错误是因为缺少在运行时刻对指针使用的检查如果指针在C++
程序设计中起重要作用你认为为什么没有为指针的使用增加更多的安全性你能想到哪些
指导规则能使指针的使用更加安全
答:使用指针良好的习惯:总是将指针初始化,不要无视编译器发出的错误信息如“强制转换为指针变量”等。