目录
引用(Reference)
引用是C++中的一种复合类型,它是某个已存在变量的别名,也就是说引用不是独立的实体,它只是为已存在的变量取了一个新名字。一旦引用被初始化为某个变量,就不能改变引用到另一个变量。引用的主要用途包括函数参数传递、操作符重载等,它可以避免复制大对象的开销,并且使得代码更加直观易读。
new 和 delete
new
和delete
是C++中的动态内存管理操作符,用于在运行时分配和释放内存。
一、引用
【1】定义
引用和目标公用一片空间
对一片取别名
数据类型 &引用名 = 目标名;
引用的底层实现:类型 * const p; ------>常指针
int const *p; ----->修饰*p
const int *p; ----->修饰*p
int *const p; ----->修饰p
const int *const p; ----->修饰*p和p
【2】&的使用
- 取变量的地址
- 位运算符
- &&逻辑与
- 定义引用,---->如果&前面有数据类型,就说明是在定义引用
【3】引用的性质
- 引用必须初始化
- 访问引用相当于访问目标
- 引用的目标一旦指定,不能修改
- 引用和目标占用同一片空间(引用不会额外开辟空间)
示例:
#include <iostream>
using namespace std;
int main()
{
int num1=30,num2=90;
//int &ref2; 引用必须初始化
int &ref1 = num1; //定义了一个引用refn1,目标是num1
//在后面,访问ref1和访问num1是同一个效果
//尝试修改ref1的目标
ref1 = num2; //<===>num1 = num2;
cout << ref1 << endl;
cout << &num1 << endl;
cout << &ref1 << endl;
}
【4】引用作为函数的形参
好处:
- 不需要额外开辟空间
- 不涉及到值传递和地址传递的问题,传到函数内部的就是实参本身
#include <iostream>
using namespace std;
//可以实现两数交换,但是需要额外开辟两个指针的空间
void my_swap(int &x,int &y) //my_swap(num1,num2); int &x = num1;
{
//由于形参是引用变量,所以函数内对形参的修改也是对实参的修改
int temp;
temp = x;
x = y;
y = temp;
}
int main()
{
int num1=30,num2=90;
//int &ref2; 引用必须初始化
int &ref1 = num1; //定义了一个引用refn1,目标是num1
//在后面,访问ref1和访问num1是同一个效果
//尝试修改ref1的目标
ref1 = num2; //<===>num1 = num2;
cout << ref1 << endl;
cout << &num1 << endl;
cout << &ref1 << endl;
my_swap(num1,num2);
cout << "函数调用后" << endl;
cout << "num1 = " << num1 << endl;
cout << "num2 = " << num2 << endl;
return 0;
}
【5】数组引用和指针的引用
#include <iostream>
using namespace std;
int main()
{
int arr[5]={89,12,34,0,5};
int *p = arr;
int *(&r3) = p; //定义了一个指针p的引用r3
//定义一个指向整个一维数组的指针
//int (*p)[5];
//定义一个数组arr的引用
int a = 90;
int &r1 = a;
//定义了一个r2是arr数组的引用
int (&r2)[5] = arr; //arr的数据类型int [5]
return 0;
}
【6】引用作为函数的返回值
复习:指针作为函数的返回值 ---->指针函数
- 全局变量
- static修饰的局部变量
- 堆区申请的空间
- 常量区的空间
- 实参传递过去的地址 ------>返回的是生命周期长的变量的地址
引用作为函数的返回值,和指针函数一样,需要返回生命周期长的变量的引用
引用作为函数的返回值,是一个左值,(因为返回引用就是返回变量本身),可以被赋值和自增自减运算
#include <iostream>
#include <cstdlib>
using namespace std;
int num1 = 12;
int &fun(int *p1) //fun(&a); <==>int *p = &a; p指向a
{
//return num1; // <==>返回num1的引用
cout << p1 << endl;
return *p1; //p1是一个4Byte的指针,需要返回4Byte的int
}
int &fun1()
{
return num1;
}
int main()
{
int a = 90;
int *p1 = (int *)malloc(4);
cout << num1 << endl; //12
fun1()++ ; // <==>num1++;
cout << num1 << endl;
*p1 = 90;
return 0;
}
【7】引用和指针的区别*
- 引用定义必须初始化,指针定义可以不初始化(野指针)
- 指针可以指向NULL,引用不可以
- 可以改变指针的指向,不能改变引用的目标
- 有指针数组但是没有引用数组
- 指针会额外开辟空间,引用不会额外开辟空间
- 有多级指针,没有多级引用
- 动态内存分配
C中的动态内存分配:malloc和free ----->C++中可以继续使用
C++中动态内存分配的关键字:new、delete
【1】new
i)单个内存空间的申请
回忆malloc:
int *p = (int *)malloc(4);
只申请单个空间的操作
数据类型 *指针名 = new 数据类型; //new会按照数据类型申请空间
申请并初始化操作
数据类型 *指针名 = new 数据类型(初始值); //申请到空间中的初始值就是()内的内容
ii)多个空间的申请
数据类型 *指针名 = new 数据类型[size]{初始值};
//使用new申请多个空间,仍然可以使用不完全初始化的方式,未初始化的部分默认为0
【2】delete
单个空间的释放:
delete 指针名;
多个空间的释放:
delete []指针名;
#include <iostream>
using namespace std;
int main()
{
int *p = new int(3); //指针p指向堆区申请的一个int的空间
cout << *p << endl;
string *ps = new string;
int *ptr = new int[5]{2,3,5,6}; //申请了5个int的空间
int i;
for (i=0;i<5;i++)
{
cout << *(ptr+i) << endl;
}
delete p; //释放单个的堆空间
p = NULL; //NULL的ASCII是0,可能会满足整形0的情况,
//C++中提供的nullptr,只表示指针为空的情况
delete [] ptr; //释放多个堆空间,需要使用[],[]内不需要写任何内容
ptr = nullptr;
return 0;
}
C++中不推荐使用malloc和free的原因:
malloc和free时不会自动调用构造函数和析构函数
new和delete会自动调用构造函数和析构函数