C++快速入门 (四) 引用 和 指针

来源:互联网 发布:vidconvert mac注册机 编辑:程序博客网 时间:2024/05/22 03:53

一. 引用 

(1). 内存中变量的存储

前边说过 计算机管理内存时,会以字节为基本单位进行顺序线性格式化(x86保护模式下),这样每一字节的内存都会有一个独一无二的十六进制数字标识, 定义一个变量的过程 其底层就是将 变量的值写入某个数字标识符所代表的内存的过程。如

int a = 10;

变量名 a 实质上只是为了方便编程而由 编程语言机制 附加的功能,当代码编译为机器码时,变量名是不存在的, 只是用其地址值和其长度来表示。例如 变量 a 被存储在 地址 0x001efd1c (起始地址) , 而数据类型 int 编译时会被转换为其代表的变量长度4字节(32位处理器) ,
说了这么多,其实只是想说明 C++每个对象都有一个内存地址值, 地址值所指向的内存+加其长度所对应的内存块保存着对象的值, 比如上边的 a 的地址值是 0x001efd1c, (0x001efd1c+4)这块内存保存了 a 的值 10

(2). 引用

C++中 可以使用 符号 <&> 来声明引用

        int a = 10;
        int &ay = a;

这时 ay本身对应的内存空间 将保存 一个地址值 ,该地址值指向 变量 a内存空间 的 地址。既
  • ay -> ay的内存地址 -> a的变量值地址 -> a的值 10
在 C++ 中是无法获取引用本身的内存地址,而是返回其内存地址中存储的指向 a 的 变量值 的地址 .

(3). 引用的特性, 

  • 创建时必须要被初始化 
  • 一旦创建后指向一个对象地址就不能改变
  • 不能有 NULL 引用。

                int k=10,y=20;
                int &a = k;  
                cout << &a << endl;
                a = y;
                cout << &a << endl; // 引用地址相同
                cout << a << endl;

从上边的代码可以看出, 引用一旦定义,就不能改变其引用的对象地址, 只能改变引用对象本身, 


二. 指针

(1). 什么是指针

可以看到 引用的最大特性既  一旦定义就不能修改地址使其指向另一个对象,而指针 就没有这种限制,指针,则既可以改变指针指向的对象地址,也可以改变指针指向对象的本身
C++中 符号 <*> 来声明指针

int a = 10;
int *p = &a;

可以看到 , 必须要使用对象的地址为指针赋值, &a 就表示获取 a 的内存地址, 有些书上会把当前应用下的符号 <&> 叫 取地址操作符, 


(2). 指针的特性:

  • 指针是一种类型
  • 指针所指向的对象地址是可以更改的
  • 特殊指针void 可以指向任何类型

(3). 指针的使用

只定义一个指针显然是没有意义的,实用才是硬道理, 一般的对指针类型可以进行三种操作
  • 获取指针本身的地址
  • 获取指针所指向的对象地址
  • 获取指针所指向的对象

(4). 获取指针本身的地址

可以使用 使用 取地址符 <&>来获取 指针本身的地址

int a = 10;
int *p = &a;
cout << &p; //获取指针本身的地址


(5). 获取指针所指向的对象地址

指针本身保存的就是指向对象的地址,所以可以直接获得

int a = 10;
int *p = &a;
cout << p; //获取指针指向对象的地址


(6). 获取指针所指向的对象

对已定义的指针使用符号 <*>,就可以获取其指向的对象,在该应用场景下 符号 <*>通常被叫做解引用操作符

int a = 10;
int *p = &a;
cout << *p; //获取指针所指向的对象 输出 10


当需要访问指针所指向对象的内部类型或函数时,C++中 还有一种 解引用操作符 < -> > , 如下代码, 通过指针访问自定义类型 TT 的 共有变量 tem 

class TT
{
public :
    TT(int x =0):tem( x ){};
    int tem;
};

int _tmain (int argc, _TCHAR* argv [])
{
        TT *p = new TT(10);
        cout << (p->tem) << endl; // return 10
        return 0;

}


(7). 指针的指针

我们可以让一个指针指向另一个指针,听着就很蛋疼,但是的确可以这样做,

    int a = 10;
    int *p = &a;
    int **pv = &p; // **pv == *(*pv)
    cout << *pv << endl;
    cout << **pv << endl; // **pv == *(*pv)

传递给指针的指针 是 指针本身的地址,要输出指针的指针指向的对象,理所应当进行2次解引用操作

你可以按照该规则继续定义 指针的指针的指针,指针的指针的。。。


三 指针 和 const

(1). 使什么 const

通过前面我们知道,要改变指针的值 可以通过改变指针所指向的地址 或 改变指针所地址指向的对象 两种方式实现, 要将一个指针设置为常量,就得从这两个途径下手, 于是 C++ 为这两种方式都提供了 const 语法, 你也可以将这两种 const语法 同时使用在一个指针类型上, 使其成为真正的常量 (2). 三种 const 指针类型
下边这段有点绕~ 
  • 指向 常量( 指针指向的对象是常量 ) 的非常量指针(指针本身不是常量) , 不能通过该指针修改对象的值, 但可以修改该指针指向的地址

        int a = 10, b = 20;
        int const *p = &a; //  const int *p = &a; 两种写法是等价的
        p = &b;
        (*p) = 30; // error


  • 指向非常量( 指针指向的对象可更改 ) 的常量指针(指针本身不能更改), 这东东很像引用 -- 可以修改该指针指向对象的值,但不能修改指针指向地址 声明方式: 

        int a = 10, b = 20;
        int *const p = &a;
        p = &b; //error
        (*p) = 30; 


  • 指向常量的常量指针, 这个比较好理解,不能修改指针也不能通过该指针修改其指向对象的值, 声明方式:const int *const p3 = &a;

       int a = 10, b = 20;
       const int *const p = &a;
        p = &b; //error
        (*p) = 30;  //error



简单理解就是: 当const前有星号时, 表示指针地址不能修改, 当const前无星号时,则指针当前对象值不能修改,既  有星号锁地址 , 无星号锁对象,两个const真常量 示例如下

                int a = 10,b = 20;
                // 指向常量的 非常量指针
                int const *p1;// 不能通过 指针p1修改对象
                // *p1 = b; 错误的 不能通过该指针p1 来修改对象
                p1 = &b; // ok  但是可以改变当前指针指向的地址
                cout << *p1 << endl; // 20

                // 指向非常量的 常量指针
               // 很像引用 -- 可以修改指针指向的对象,但不能修改指针指向的地址
               int *const p2 = &a;  //初始化是必须定义对象
                // p2 = &b;  错误的 不能修改其指向的地址
                *p2 = b;   //ok  使用b的值 修改对象a的当前值
                cout << &a << " | " << p2 << endl; // 相等
                cout << *p2 << endl; // 20

               //指向常量数据的常量指针
                const int *const p3 = &a; //初始化时声明对象
                 // p3 = &b;  // 错误的
                 // *p3 = b   // 错误的
                a = 30;
                cout << *p3 << endl; // 30


(2). "不靠谱"的 引用/指针 常量

引用和指针声明为const,也只能表示通过自身不能更改对象,而不能保证对象一定不能被更改, 这是由于引用和指针都是保存对象的地址,当另一个指向该地址的变量非 const 并更改时, 很显然 只是保存该对象地址的 引用和指针的值也会更改

    int x = 10;
    const int &y = x;
    x = 30;
    cout << y << endl; // 30
    int a = 10;
    const int *const p = &a;
    a = 30;
    cout << *p << endl; // 30




四. 本质

(1). 引用和指针的本质

从语言级来说指针和引用差别还是很大的,上边都已经叙述过了,但从底层实现上来说不管是引用还是指针, 其实质都如下图



引用或指针本身都会占用4字节空间( 32位处理器 ) ,而自身的地址空间保存着指向某个对象的内存地址值。而不是对象本身,  举个例子来说,像使用手机打电话, 首先要在手机(指针)里输入电话号码(将对象地址存入指针地址), 然后接通(通过指针里存储的对象地址找到所指向的对象)。当我们要联系另外其他人时,只需换一个号码接通就可以,而不是换一个手机 , 不管指针还是引用 其底层实现都是这么个过程。





-

<原创文章 转载请注明出处 http://blog.csdn.net/meiwm 谢谢>


作者:meiwm
出处:http://blog.csdn.net/meiwm
本文为原创,本文版权归作者所有。欢迎转载,但请务必保留此段声明,且在文章页面明显位置给出原文连接,谢谢合作。

-



原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 用交易猫买完游戏账号被骗了怎么办 一个华为账号有两个游戏账号怎么办 加密u盘电脑上打开空怎么办 国网加密u盘电脑打开为空怎么办 足球竞彩软件下架后里面的钱怎么办 竞彩足球提现不到账怎么办 竞彩足球投注后输了怎么办 英雄联盟鼠标箭头右键点不了怎么办 上古卷轴5数值修改错了怎么办 小时候打针把屁股脂肪打扁了怎么办 大繁盛满腹市场2对话时闪退怎么办 月经来了一个月了还不停怎么办 对办公室的异性老师产生好感怎么办 上古卷轴5任务NPC老打我怎么办 1岁半宝宝走路内八字怎么办 最近几个月例假周期都25天怎么办 从pr导出的视频大小不一样怎么办 合作医疗收据丢了不给报销怎么办 沧州新生医院—老人腹胀了该怎么办 内痔疮术后一个月吃了点辣椒怎么办 肛周脓肿手术后大便干怎么办 月经半个月了还没干净怎么办 房东出租违建房不退房租怎么办 上海公租房住满5年后怎么办 监狱对死缓犯人延长转为无期怎么办 手机号码办理的宽带不想要了怎么办 朋友诈骗罪被关看守所了该怎么办 打架被拘留家里有孩子没人看怎么办 刑事拘留满37天给逮捕了怎么办 因打架被拘留十五天释放后会怎么办 犯罪人在拘留所生了小孩怎么办 我申请了进京证更换车辆怎么办 丈夫去世前想把财产留给妻子怎么办 假货中通代收货款发现是假货怎么办 注册志愿者时身份证被使用该怎么办 双眼皮贴贴的皮肤送了怎么办? 满60岁社保末满十五年怎么办 眼角膜少了一块怎么办应该吃什么 左右胸相差一个罩杯左右怎么办 穿一字肩的裙子没有无肩内衣怎么办 农业网柑橘被奄24小时怎么办