一、Pointers

  Pointer是指针,可以用来指向任何一个objects,包括一般变量:

1 int  i = 3;
2 int * pi = &i;
3 cout << pi << endl; // 0x0064FDF0
4 cout << *pi << endl; // 3

  此时pi本身内含i的地址,要取出pi所指向的object,可以使用*运算符(dereference operator).Pointer也可以用来指向任何一个class type objects。由于下面的pPoint指向一整个大结构(一个object),如果要取用其中的members(data members 或member functions都可以,只要他们的封装等级是public),必须使用—>运算符(arrow operator),例如:

1 class CPoint { public: float _x, _y, _z; };
2 CPoint * pPoint = new CPoint;
3 cout << pPoint << endl; // 0x00770560
4 pPoint->_x = 9.28;
5 cout << pPoint->_x << endl; // 9.28

  Pointer 甚至可以指向一个不明对象(void):

1 void * pv;
2 pv = malloc(1024); // 配置 1024 bytes(来自 heap)
3 cout << pv << endl; // 0x00760A14

  此时如果要提取 pv 所指的对象,不可以,会出现编译出错:

1 cout << *pv << endl; // error C2100: illegal indirection

  也说是说,pointer本身没有意义,它的意义来自于它的类型,因此,将pointer前进一个单位,究竟是前进多少个bytes呢?那要看pointer的类型,如果将int *pi和CPoint *pPoint各加1,得到:

1 cout << ++pi << endl; // 0x0064FDF4,比原先增加 4
2 cout << ++pPoint << endl; // 0x0077056C,比原先增加 12

  这是因为在32位的系统中int为4 bytes,而我们设计的CPoint里面有一个float数据,大小为12bytes,所以各指针累加1时,分别前进4bytes和12bytes。如果把一个指向不明对象的指针加1,会得到什么结果呢?不会有结果,只会编译出错:

1 cout << ++pv << endl; // error C2036: 'void *' : unknown size

  当然,如果你做了强转型(cast)动作,就可以解决“不明对象”的问题,因为你赋予了该指针一个明确的类型,例如:

1 double * pd = (double*)pv; // 强转型。double is 8 bytes.
2 cout << pd << endl; // 0x00760A14
3 cout << ++pd << endl; // 0x00760A1C,比原先增加 8

  下表是上述验证结果的一个整理:

  当我们开始设计classes继承体系,有许多时候需要把一个pointer指向一个类型不符的object(但彼此类型又有继承的关系存在,这其实正是polymorphism的一个精髓),这时候类型的转换就非常重要。强制转型太过粗暴,在不够安全的时候仍然强转换,存在风险。C++有其它更精致的转型工具,我们后续再谈。

  Pointer不但可以指向object,还可以指向class的data members或member functions。它们的形式有点怪,结果也可能出人意外,这些问题我们后续再谈。

二、References

  与pointer常常相提并论,并且常常被混淆不清的是所谓的reference。Reference(&)像是一个常数指针,可以被自动提取(dereference)。下面这个例子就是使r成为x的一个reference:

1 int x;
2 int& r = x; // r is a reference of x

  当一个refernce产生,它必须被初始化为某个原已存在的object,像上面那样,如查我写:

1 int& q = 12;

  那么编译器会先配置一块int内存空间,将内容设为12,然后把q这个reference“捆绑”到该空间上。重点是,任何reference都必须被“捆绑”到某一个空间,成为一个"化身“。当你处理该reference,你就是在处理那个被捆绑的空间。如果:

1 int x = 0;
2 int& r = x; // r is a reference of x
3 int* p = &x; // p is a pointer to x
4 r++; // 请注意:sizeof(r) == sizeof(x)

  那么r和x的现值都为1,因为增加r的值就是增加x 的值。

  面对reference,最简单的想像就是,把它幻想为一个形式漂亮的pointer。这个形式漂亮的pointer好处是,我们不需要担心它是否被初始化(编译器会强迫做),也需要担心何提取(dereference)它(同样的,编译器会负责)。Refernce虽然在本质上是一个指针,在形式却是个object。也就是因为其形式漂亮,而本质实用(用于call by refernce),所以refernce常被用于函数的参数列表(arguments list)和回传值(return value)。下面就是个例子:

  

 1 int* funcl(int* x)
2 {
3 (*x)++;
4 return x;
5 }
6
7 int& func2(int& x)
8 {
9 x++;
10 return x;
11 }
12
13 int main()
14 {
15 int a=0;
16 //ugly but explictit,你可以你可以清楚看到传給 func1() 的是个指针。
17 //传回值的形式也很「难看」。
18 cout<<*funcl(&a)<<endl;
19 // clean but hidden。传給 func2() 的其实是个指针(借助 reference)。
20 // 但你看不出來。传回的也是指针(借助 reference),你也看不出來。
21 cout<<func2(a)<<endl;
22 23 return 0;
24 }

C++指针与引用(Pointers OR References)的更多相关文章

  1. golang 中Pointers Vs References

    原文: https://spf13.com/post/go-pointers-vs-references/ Pointers Vs References Some languages includin ...

  2. C++指针与引用

    1.指针与引用的区别: (1)非空区别.引用不能指向空值. (2)合法性区别.由于指针可能为空,所以需要测试它以防止它为空. (3)可修改区别.引用初始化后不可再被修改. (4)内容区别.指针的内容是 ...

  3. C/C++中指针和引用之相关问题研究

    一.基本知识 指针和引用的声明方式: 声明指针: char* pc; 声明引用: char c = 'A'                   char& rc = c; 它们的区别: ①从现 ...

  4. [速记]关于指针,引用和递归和解递归——C++

    在写基于二叉排序树的查找时,分为三个过程 1.二叉排序树的插入 2.二叉排序树的建立 3.基于二叉排序树的查找 其中第三部可以递归方式实现,也可以用while循环解递归,于是我想也解解第一步的递归,看 ...

  5. C++指针参数引用

    粘个代码占位置,以后有时间把指针函数,函数指针都补上 #include <iostream> using namespace std; void freePtr1(int* p1){ /* ...

  6. C/C++:提升_指针的指针和指针的引用

    C/C++:提升_指针的指针和指针的引用 写在前面 今天在使用指针的时候我发现了一个自己的错误.

  7. C++_系列自学课程_第_8_课_指针和引用_《C++ Primer 第四版》

    C语言最富有迷幻色彩的部分当属指针部分,无论是指针的定义还是指针的意义都可算是C语言中最复杂的内容.指针不但提供给了程序员直接操作硬件部分的操作接口,还提供给了程序员更多灵活的用法.C++继承这一高效 ...

  8. C++学习笔记 指针与引用

    指针与引用  1. 指针 (1) 指针是一个变量(实体),存储的是一个地址,指向内存的一个存储单元,指针可以为空 (2) 指针可以为空,在声明定义时可以不初始化 (3) 指针在初始化之后可以重新指向其 ...

  9. 数组类型与sizeof与指针的引用

    以char类型为例: char a[100];     //a类型为char[100]    &a类型为 char (*)[100]    *a类型为char char *p = a;     ...

  10. c++指针与引用问题

    本来是回答问题的,到这里做个笔记 *&L是指针的引用,实参是个指针.所以L是实参指针的别名,对别名L的修改,等于对实参的修改.*L是传值,你无法改变传过来的实参指针变量的值程序代码: #inc ...

随机推荐

  1. C#中字典集合的两种遍历

    记录一下 Dictionary<string, string> dictionary = new Dictionary<string,string>(); foreach (s ...

  2. vue三种插槽

    1. 作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 父组件 ===> 子组件 . 2. 分类:默认插槽.具名插槽.作用域插槽 3. 使用方式: a.默认插 ...

  3. 攻防世界 gametime 使用IDA pro+OD动调

    自学犟种琢磨动调的一个记录,算是第一次动调的新手向,大佬请飘过 题目 准备工作--IDA pro(32X) 下载得到一个exe文件,首先丢到PE里面--无壳,32bit 丢到IDA pro(x32)里 ...

  4. 基于vivado中AXI的模型分析

    基于vivado中AXI的模型分析 1.底层代码 `timescale 1 ns / 1 ps module myip_v1_0_S00_AXI # ( // Users to add paramet ...

  5. arch linux安装并简单配置zsh

    1.安装zsh sudo pacman -S zsh 2.设置默认zsh 列出所有已安装shell chsh -l 要为您的用户设置一个默认值 chsh -s /full/path/to/shell ...

  6. #费马小定理,BSGS#BZOJ 3285 离散对数解指数方程

    题目 求最小的正整数 \(x\) 满足 \(g^{ax+b}\equiv c\pmod p\) 其中 \(p\) 是一个质数, \(g,a,b,c\leq 10^{1000000},p\leq 2^{ ...

  7. #差分约束系统,最长路,线段树优化建边#洛谷 3588 [POI2015] PUS

    题目 给定一个长度为\(n\)的正整数序列 \(a\) ,每个数都在 \(1\) 到 \(10^9\) 范围内, 告诉你其中 \(s\) 个数,并给出 \(m\) 条信息,每条信息包含三个数 \(l, ...

  8. #构造#B 连通子图

    题目 给定正整数\(k\),构造一棵树,使得包含了\(1\)号点的连通子图个数恰好为\(k\). 连通子图就是点集的一个子集(可以为全集),使得该点集中任意两个点均可以经过该点集中的点相互到达. 分析 ...

  9. #Tarjan#洛谷 1407 [国家集训队]稳定婚姻

    题目 分析 如果婚姻安全那么两个点不在同一个强连通分量, 考虑强制定方向,夫妻女向男连边,情侣男向女连边, 这样就直接用Tarjan有向图缩点就可以了 代码 #include <iostream ...

  10. JDK9的新特性:String压缩和字符编码

    目录 简介 底层实现 总结 简介 String的底层存储是什么?相信大部分人都会说是数组.如果要是再问一句,那么是以什么数组来存储呢?相信不同的人有不同的答案. 在JDK9之前,String的底层存储 ...