关于指针及 * 运算符的一些使用方法
2015-09-17 08:17
393 查看
对于* 运算符,熟悉C的程序员一定对它不陌生,他表示的是指针, 指向内存中的某一个变量或者对象。因为指针本身是一个内存的地址, 所以指针本身的大小与计算机的内存有关(在编译器位数与计算机相匹配时), 如4GB内存(可使用的内存)的计算机指针大小为4byte即32位 , 8GB内存的计算机指针大小为8byte即64位 (可以使用sizeof 运算符查看某台计算机上的指针大小)。 不管指向什么类型(或类) , 指针本身大小是固定的(这也是为什么一个类在声明后可以定义一个指向它的指针而不能初始化对象)。
对于 * 的用法 , 一种是定义(声明)指向某个类型的指针 , 使用方法位在类型名称后面加上 * 运算符 , 注意这个变量是一个指针 , 所以赋给它的值必须是一个地址 。 还有一种用法是解除引用 , 但我们想访问这个指针指向的对象是 , 在指针变量前面加上 * 即(未初始化、 未赋值的指针行为是未定义的)。
因为pi指向i , 所以最后i 的值为1 ,这就是通过指针间接改变变量的值。
可能很多C程序员习惯把指针当成实参传入函数并改变它指向的对象的值 , 这里多说一句:
空指针的概念是不指向任何对象的指针 , 对于这种指针不能解除引用 。 制造空指针的方法最简单的是直接赋予指针0这个值 , 也可以用NULL(c++11可以用nullptr)
当把指针转为布尔值时 , 只要指针不是空指针就返回true , 否则返回false。举个例子:
还有一项常见的操作是对指针加减某一个整数 , 该操作通常用于数组转指针 , 但从机器层面来看 , 实际上是对指针的指向进行移位 , 即下移或上移一个数据单元 , 至于移动的大小则根据指向的类型而定 。 即 type * pt ,则移动的大小为type所占大小字节数的整数倍。 当type 为int 时 , 每加1移动2(4)个byte , 为char时 , 移动1个byte 。但对于非数组的指向单值的指针进行移动 , 指向的对象会是未定义的 , 所以不能解除引用。同样基于上述原因 , 不能用某一个类型的指针指向另个类型的对象
, 这样做编译器会报错 , 因为它无法判定对象到底占用几个byte 。
因为指针中的值是地址 , 所以比较两个指针就相当于比较两个地址 , 这样做是毫无意义的(特殊情况除外 , 比如比较相等==和不等!=) , 应该要比较指针指向的值。
有一种非常特殊的指针 void* , 这种指针可以指向任何对象的地址 , 它的意义只是表示一个内存地址而已 , 也不能确定指向的对象是什么。可以把其他指针赋给void* , 但不能将其赋给其它指针。该指针可以作为地址与其他指针比较 , 也可以输出来查看地址 。
对于指向指针的指针 , 可以把它想象成把一个变量放在一个袋子里, 再在外面再套一层袋子 , 如果要拿到里面的东西 , 就必须拆掉两层袋子。
对于指针来说,如果指向的是一个类的对象 , 还可以间接访问类成员。
这是指针最基本的用法 , 还有一些跟其他内容组合在一起的下次更新 。(智能指针 , 动态内存分配 , 函数指针以后介绍)
对于 * 的用法 , 一种是定义(声明)指向某个类型的指针 , 使用方法位在类型名称后面加上 * 运算符 , 注意这个变量是一个指针 , 所以赋给它的值必须是一个地址 。 还有一种用法是解除引用 , 但我们想访问这个指针指向的对象是 , 在指针变量前面加上 * 即(未初始化、 未赋值的指针行为是未定义的)。
int * pi; //声明一个指针 int i = 0; //定义一个变量 pi = &i; //使指针指向变量 *pi = 1; //解除引用使i的值变为1
因为pi指向i , 所以最后i 的值为1 ,这就是通过指针间接改变变量的值。
可能很多C程序员习惯把指针当成实参传入函数并改变它指向的对象的值 , 这里多说一句:
void change(int * pi){ //把指向整型的指针当成形参传入函数 *pi = 0; //把pi指向的对象的值改成0 , 离开该函数后该对象的值为0 pi = 0; //把pi设为空指针, 在该函数作用域内有效 , 离开该函数后作为实参的指针本身的值不变 }上述函数的例子告诉我们 , 传入指针能改变指向对象的值是因为函数把指针复制了 , 也就是拷贝了一份与该指针一样的地址 , 这样就可以根据地址改变指向的值 , 但改变指针的值实际上是改变了那个复制而来的值 , 对原指针没有任何影响。
空指针的概念是不指向任何对象的指针 , 对于这种指针不能解除引用 。 制造空指针的方法最简单的是直接赋予指针0这个值 , 也可以用NULL(c++11可以用nullptr)
当把指针转为布尔值时 , 只要指针不是空指针就返回true , 否则返回false。举个例子:
//pi是一个指向int型的指针 if(pi); //当pi不是空指针时结果为true if(*pi); //当pi指向的值不为0时结果为true
还有一项常见的操作是对指针加减某一个整数 , 该操作通常用于数组转指针 , 但从机器层面来看 , 实际上是对指针的指向进行移位 , 即下移或上移一个数据单元 , 至于移动的大小则根据指向的类型而定 。 即 type * pt ,则移动的大小为type所占大小字节数的整数倍。 当type 为int 时 , 每加1移动2(4)个byte , 为char时 , 移动1个byte 。但对于非数组的指向单值的指针进行移动 , 指向的对象会是未定义的 , 所以不能解除引用。同样基于上述原因 , 不能用某一个类型的指针指向另个类型的对象
, 这样做编译器会报错 , 因为它无法判定对象到底占用几个byte 。
因为指针中的值是地址 , 所以比较两个指针就相当于比较两个地址 , 这样做是毫无意义的(特殊情况除外 , 比如比较相等==和不等!=) , 应该要比较指针指向的值。
//pi_1与pi_2为两个指向int型的指针 pi_1 > pi_2; //比较两个地址 *pi_1 > *pi_2; //比较两个指针指向的值
有一种非常特殊的指针 void* , 这种指针可以指向任何对象的地址 , 它的意义只是表示一个内存地址而已 , 也不能确定指向的对象是什么。可以把其他指针赋给void* , 但不能将其赋给其它指针。该指针可以作为地址与其他指针比较 , 也可以输出来查看地址 。
int i = 1 , *pi = &i; void * pv = &i; //合法 , 可赋予任何对象给void * pv = pi; //合法 , 可赋予任何指针给void * if(pv == pi); //比较两个地址 //pi = pv; //非法 , 不能把void *付给其他类型的指针 cout << pv; //合法 , 输出一个地址
对于指向指针的指针 , 可以把它想象成把一个变量放在一个袋子里, 再在外面再套一层袋子 , 如果要拿到里面的东西 , 就必须拆掉两层袋子。
int i = 1 , *pi = &i; int ** p_pi = &pi //指向pi的指针 //p_pi = pi; //错误 , 因为pi和p_pi级别不同 , 不能赋值 **p_pi = 0; //解除两层引用 , 改变i的值
对于指针来说,如果指向的是一个类的对象 , 还可以间接访问类成员。
string s = "Hello,World" , *ps = &s; cout << ps->size(); //与(*ps).size()等价
这是指针最基本的用法 , 还有一些跟其他内容组合在一起的下次更新 。(智能指针 , 动态内存分配 , 函数指针以后介绍)
相关文章推荐
- android apk --- Active的生命周期
- 用NetBeNetBeans
- Unity粒子系统参数解析(二)(发射器)
- 编译安装zabbix 3.0及分开部署配置详解
- CodeForces 545B Equidistant String (模拟)
- 黑客专用屏保
- HDU 4415 贪心
- 整数的所有因子
- 小球落地
- 级数之和
- 【1】基于ATmega 8A -PU 的蓝牙遥控电源插座设计——【1、总体方案设计】
- 乘法表
- 一元兑换问题
- log4j:WARN No appenders could be found for logger
- 打印机正在打印出错
- allegro中Autosilk top, Silkscreen top 和Assembly top三个什么区别(转)
- Valid Palindrome 解答
- CodeForces 545C Woodcutters (贪心orDP)
- Database Primary key and Foreign key [From Internet]
- SendAnywhere 跨平台传输文件(推荐)