4、c++指针与引用


在本章中,只讨论基本指针,不讨论智能指针
指针对于管理和操纵内存非常重要


指针

什么是指针

  • 指针本质:指针是一个整数,一种存储内存地址的数字

比如一个int类型的变量a,这个变量的内容是13 int a = 13;
int * p = &a;
把这个变量的地址保存在指针里,指针里面保存的不是这个变量本身,而是变量在内存中的地址

  • 如果我们给指针p一个类型,这个意思就是,我们假设p中存储这个地址的数据,被假设为我们所给的类型

一级指针的定义

int *p;//语法:类型 * 指针变量名;

  • &是取地址符,可以使用这个把地址存在指针变量中
    除了定义时,*代表逆向引用指针,*p可以把对应地址的变量取出来
  • 例如:假设manly是一个指针,则manly表示的是一个地址,而*manly表示存储在该地址处的值

二级指针的定义

与一级指针同理

  • 注:所有类型的二级指针,由于均指向一级指针类型,一级指针类型大小是 4,所以二级指针的步长也是 4,这个信息很重要。

指针所占内存大小

  • 在32位操作系统下,指针是占4个字节空间大小(不管是什么数据类型)

  • 在64位操作系统下,指针是占8个字节大小(不管是什么数据类型)

指针的危险

C++在创建指针时,计算机将分配用来存储地址的内存,但不会分配用来存储指针所指向的数据的内存。如下

long* fellow;    //create a pointer-to-long  
*fellow = 223323;

fellow确实是一个指针,但是它指向哪里呢?上述代码没有将地址赋给fellow。
由于fellow没有初始化,他可能有任何值,程序将它解释为存储223323的地址,如果fellow的值碰巧为1200,计算机将把数据放在地址1200上,即使这恰巧是程序代码的地址

所以,注:一定要在对指针应用解引用运算符(*)之前,将指针初始化为一个确定的、适当的地址。

new运算符

  • 指针的真正用武之地在于——在运行阶段分配未命名的内存以存储值。这种情况下,只能通过指针来访问内存。
  • 在C++中使用new运算符来分配堆内存
  • 程序员告诉new,需要为哪种数据类型分配内存;new将找到一个长度正确的内存块,并返回该内存块的地址。程序员的责任是将该地址赋给一个指针
int* pn = new int;

new int 告诉程序,需要适合存储int的内存。然后它找到这样的内存,并返回其地址。接下来将地址赋给pn,而*pn是存储在那里的值。

  • 将这种方法与将变量地址赋给指针进行比较
int higgens;
int* pt = &higgens;

在两种情况下,都是将一个int变量的地址赋值给了指针。只不过pn指向的内存没有名称,只是在pn里存储了地址。它使程序在管理内存方面有更大的控制权

  • 为一个数据对象(可以是结构,也可以是基本类型)获得并指定分配内存的通用格式:
    typeName* pointer_name = new tupeName;

使用new创建动态数组

  • 如果通过声明来创建数组,则在程序被编译时将为他分配内存空间。不管程序最终是否使用数组,数组都占用了内存。在编译时给数组分配内存被称为静态联编
  • 使用new时,如果在运行阶段需要数组,则创建他,否则不创建,还可以在程序运行时选择数组长度。被称为动态联编
  • 使用静态联编时,必须在编写程序时指定数组的长度
  • 使用动态联编时,程序将在运行时确定数组长度
	int x = 10;
	int* arr = new int[x];

new运算符返回第一个元素的地址

  • 为数组分配内存的通用格式
    type_name * pointer_name = new type_name[number_elements];

delete运算符

  • delete运算法使得在使用完内存后,能够将其归还给内存池。使用delete时,后面要加上指向内存块的指针(这些内存块最初是用new分配的)
int * ps = new int;
......
delete ps;

注:这将释放ps指向的内存,但不会删除指针ps本身。

  • 一定要配对的使用new 和 delete,否则将发生内存泄漏

使用delete删除动态数组

  • 对于使用new创建的数组,应使用另一种格式的delete来释放
delete [] arr;
  • 方括号告诉整个程序,应释放整个数组,而不仅仅是指针指向的元素。

使用new和delete时,应遵守以下规则:

  1. 不要使用delete来释放不是new分配的内存
  2. 不要使用delete释放同一内存块两次
  3. 如果使用new [ ]为数组分配内存,则使用delete[ ]来释放
  4. 如果使用new [ ]为一个实体分配内存,则使用delete来释放
  5. 对空指针使用delete是安全的

指针被free或者delete后,一定要置为null,没有置为null的指针常称为”野指针“。
下列两种情况也可以称为**”野指针“**:

1)未初始化指针

任何指针变量刚创建时,其内容是随机的,在内存中乱指一通。因此,使用指针前,一定要对其初始化。在声明的同时初始化或赋值,使其指向合法的内存。对于无处可指的指针变量,也要将其赋值/初始化为null,也就是空指针。

2)指向临时变量的指针

当前代码块执行完毕后,代码块中声明的临时变量(包括函数调用时的参数)都自动消亡,其占用的内存空间(栈内存)也被内存管理器收回。

指针、数组与指针算术

指针和数组基本等价的原因在于指针算术和C++内部处理数组的方式。

指针算术

首先来看一看算术

  • 将整数变量增加1后,其值将增加1.
  • 但将指针变量加1后,增加的量等于它指向的类型的字节数

比如将指向double的指针加1后,如果系统对double使用8个字节存储,则指针的数值增加8

sizeof()

对数组应用sizeof运算符得到的是数组的长度
对指针应用sizeof运算符得到的是指针的长度

引用

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。

  • 定义引用类型的格式:
    类型 & 引用变量名 = 引用实体;
    在生活中别名很好理解,比如 张三 有一个别名叫做 三儿 。那么这两个名称指的实际上就是同一个人,张三干嘛,三儿就在干嘛
  • 引用本身也是一个变量,但是这个变量又仅仅是另外一个变量一个别名,它不占用内存空间

引用的特点

  • 引用必须初始化
  • 引用不能为空
  • 引用不能更换目标
  • 一个变量可以有多个引用(就相当于一个变量有好几个别名,这是可以的)

引用与指针对比

必须初始化可以不初始化
不能为空可以为空
不能更换目标可以更换目标

引用的多种形式

  • 变引用——变量
int a = 10;//可读可写
int& ra = a;//可读可写
  • 变引用——常量
int const a = 100;//只读
int& ra = a;//编译不通过,因为本名是常量,别名就不可能是变量
  • 常引用——变量
int a = 10;//可读可写
int const& ra = a;//只读
  • 常引用——常量
int const a = 10;//只读
int const& ra = a;//只读

引用与函数

1、引用作为函数参数

  • 对形参修改了会体现到我们的外部实参上(因为形参就是实参的别名)
void swap(int& a1 , int& b1)
{
	int temp = a1;
	a1 = b1;
	b1 = temp;
}
int a = 10;
int b = 20;
swap(a,b)

由于引用仅仅是一个别名,对于形参的操作会影响到实参。
所以swap(a,b)过后,a = 20,b = 10;

  • 不过有时候使用函数不希望改变外部的实参时,可以用常引用
void function(int const& a)
{
	......
}
  • 一般我们使用const reference参数作为只读形参,这种情况下既可以避免参数拷贝还可以获得与传值参数一样的调用方式。
void test(const vector<int> &data)
{
    //...
}
int main()
{
    vector<int> data{1,2,3,4,5,6,7,8};
    test(data);
}

2、引用变量作为函数返回值

注:

  1. 引用作为函数的返回值时,必须在定义函数时在函数名前将&
  2. 用引用作函数的返回值的最大的好处是在内存中不产生返回值的副本
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木木彡、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值