C/C++ 系统 内存分布图
屏幕快照 2019-08-13 上午11.07.25.png变量和内存地址的关系
计算机存储器位置具有地址并保存内容。地址是一个数字(通常用十六进制表示),这对程序员来说很难直接使用。通常,每个地址位置保持8位(即1字节)数据。程序员完全可以解释数据的含义,例如整数,实数,字符或字符串。
为了减轻使用数字表示的内存地址给程序员解释数据的编程负担,早期的编程语言(如C)引入了变量的概念。变量就是为存储特定类型值的内存地址命令了一个对人具有可读性的标识符。变量名(或标识符)附加到特定的地址中。tong此外,类型(例如int,double,char)与数据内容长度相关联,以便于解释数据。
每个地址位置通常保持8位(即1字节)数据。 4字节的int值占用4个内存位置。 32位系统通常使用32位地址。要存储32位地址,需要4个存储单元。
下图说明了计算机的内存地址,数据内容,变量的名称,类型和程序员使用的值之间的关系。
MemoryAddressContent.png
引用(reference)
C++ Primer这本书并没有对reference类型在内存管理方面给出一个明确的结论.因此以下从其他资料摘录了相关的定义
引用不是对象; 它们不一定占用存储空间,尽管如果有必要实现所需的语义,编译器可以分配存储空间(例如,引用类型的非静态数据成员通常会增加类的大小以存储存储器地址所需的数量)。
--摘录自https://en.cppreference.com/w/cpp/language/reference
根据Bjarne Stroustrup的说法,引用变量大多数时间都是优化的,并且没有为引用创建变量。 但是,在某些无法优化引用变量的情况下,它实现为指向原始对象的4字节指针。因此,在大多数情况下,编译器在涉及引用的语句中使用实际对象而不是引用变量。
--摘录自《The C++ Programming Language》
对引用的总结
- 在C++中所谓的引用"reference"就是左值引用,可以比喻为对象(变量)起一个别名。
- 初始化完成,引用将和它的初始值对象绑定在一起,无法重新绑定到另一个对象(变量)
- 引用不是对象,没有实际地址,所以“不存在引用的引用或指向某个引用的指针”。
- 引用只能绑定到对象,无法绑定到具体的字面量或某个表达式的计算结果
-
对引用变量取址(&)操作,大部份情况下引用变量所指向的对象的内存地址。特殊情况下,引用变量会被编译器识别为一个4字节长度的指针。
如图所示:0x????????表示引用不一定会产生内存分配
屏幕快照 2019-08-13 上午11.44.35.png
指针
《征服C指针》这本书对指针剖析十分透彻,以下对C指针的理解方法大部份源于该书。
#include <iostream>
int **pp=nullptr;
int main(int argc, char const *argv[])
{
int b=734;
int *p=&b;
pp=&p;
std::cout<<"variable b address:"<<p<<std::endl;
std::cout<<*"pointer p address:"<<pp<<std::endl;
std::cout<<*"pointer pp address:"<<&pp<<std::endl;
return 0;
}
如图所示所示指针关系
屏幕快照 2019-08-13 下午4.27.38.png
如何正确解读函数指针
用英文来解读指针,看如下几个经典的例子
int (*my_func)()
英文的阅读顺序:
- 首先着眼于标识符(变量名或者函数名)。
- 从距离标识符最近的地方开始,依照优先顺序解释派生类型(指针、数组和函数)。优先顺序说明如下,
1. 用于整理声明内容的括弧
2. 用于表示数组的[],用于表示函数的()
3. 用于表示指针的 * - 解释完成派生类型,使用“of”、“to”、“returning”将它们连接起来。
-
最后,追加数据类型修饰符(在左边,int、double 等)。
以下该图来自《征服c指针》的3.4章节
特殊的指针
- 空指针 c中为NULL,C++为nullptr
- void指针,也称为万能指针,任何类型的指针都可以赋值给void指针
- 指向常量的指针:不能用指向常量的指针改变其所指对象的值。
- 仅有指向常量的指针才能存放常量对象的地址。
- 指向常量的指针允许指向一个非常量的对象。
const double pi=3.14 //pi是个常量 //错误:&p的指针类型是【double *p】和 【const double *p】不匹配 double *p=π //正确:指针的类型与pi的指针类型【const double *p】匹配 const double *pt=π //错误:不能修改【指向常量的指针】所指向的对象 *pt=42.3; double dq=222.3; //正确:指向常量的指针允许指向一个非常量的对象。 pt=&dq;
- 常量指针
- 该指针存放其指向变量的地址值一经初始法,就不能再改变.
- 常量指针所指的变量不是常量.
示例1
示例2int a=123; int *const pr=&a; //后续一直指向变量a,无法修改.
const int c=777; //对应的指针类型【const int *p】 //错误:pr的指针类型【*const pr】和【const int *p】不匹配 int *const pr=&c;
5.指向常量的常量指针
- 该指针存放其指向变量的地址值一经初始法,就不能再改变.
- 无法通过指向常量的常量指针修改所指的变量值,即便指向的值是非常量对象.
const int c=77; int b=734; const int *const pr1=&c; const int *const pr2=&b; //错误:具体原因查看第二小点 *pr1=723; //但变量修改自身,和指向常量的常量指针没有关系 c=1024;
-
各种特殊指针的对比总结
知识点汇总
指向指针的引用
引用不是一个对象,因此不能定义指向引用的指针,但指针是一个对象,所以可以定义对指针的引用。
int i=42;
int *p; //p is pointer to int 或p是一个指向int类型的指针
int *&r=p;
//英文解读法:r is a reference **binding** pointer of int
//中文阅读法: "r是绑定int指针的引用"
r=&i
要理解r 的类型到底是千| 么,最简单的办法是从右向左阅读r 的定义。离变量名最近的符号( 此例中是&r 的符号&) 对变量的类型有最直接的影响,因此r 是一个引用。声明符的其余部分用以确定r 引用的类型是什么,此例中的符号* 说明E 引用的是一个指针。最后,声明的基本数据类型部分指出r 引用的是一个工nt 指针。 ---《摘录自c++ Primer 第五版》
网友评论