C++中的指针与引用以及动态内存分配
对于C语言和C++来说,最重要的一个内容就是指针。使用指针能够让我们实现对内存的高效利用,提高程序的效率,但是很多埋藏的很深的Bug都和指针有关,因此如果想要很好的使用指针首先需要对指针具有深入的了解
同时在C语言中,我们通常结合stdlib.h头文件中的malloc和calloc函数来实现指针的高效存取。但是在C++中,我们可以直接使用关键字new和delete来实现动态内存的分配而不需要使用上面的两个函数。
此外,C++中还具有C语言所不具有引用特性,因此本章讲解的内容如下
- C++中的指针
- C++中的动态内存分配
- C++中的引用
由于本笔记是作为C++基础语法学习,补充C语言中所不具有的语言特性的内容,因此主要讲解各个部分中的C++的新特新
C++中的指针
由于C++中许多内容都是从C语言中继承而来,因此关于指针的基础知识实际上和C语言一模一样,因此这里不在赘述,如果不懂指针的基础知识去看我的C语言基础语法专栏,里面有详细的讲解
这里主要讲解C语言中不具有的const关键字和指针间的结合
将关键字const用于指针
在前面讲解C++的基础变量和常量时候,我们曾今讲过我们可以将变量声明为const,这样可以确保在整个变量的声明周期内值都是固定的初始值,无法被改变
实际上,由于指针也是一种类型的变量,其指向的地址中的内容也是变量,因此我们具有如下三种声明const关键字的方法
固定指针指向的变量
我们使用如下方式来声明指针,就可以来让指针指向一个固定的变量,而不能被重新赋值指向其他变量
数据类型 * const 指针变量名 = 被指向的变量名
通过这种方式,我们其实可以通过修改被指向的变量的值来修改取指针时候得到的值
固定指针指向的变量的值
我们通过如下方式来声明指针,从而实现让指针指向的变量为常量
数据类型 * 指针变量名 = const 被指向的变量名
这种方式声明的指针变量我们可以改变其指向来修改取指针时得到的值
固定指针指向的变量以及变量的值
我们通过如下的方式声明指针,从而使得指针和被指向的变量都是常量
数据类型 * const 指针变量名 = const 被指向的变量名
通过这种方式我们声明的指针既无法改变其指向,也无法改变其指向的变量的值
C++中的动态内存分配
使用new来分配新内存
我们可以使用关键字new来分配新内存,通常情况下,如果成功分配,将会返回一个指针,如果未能成功分配将会引发异常
数据类型 * 变量名 = new 数据类型
我们也可以划分内存来创建一个新数组,只需要指定数组大小即可
数据类型 * 变量名 = new 数据类型[数组大小]
使用delete来释放内存
我们使用关键字new分配的新内存一定要用delete来释放,否则将会造成系统资源占用,此外我们也只能用delete来释放用new分配的内存
对于使用new分配的单个数据,我们直接使用delete即可
delete 变量名
对于用new划分的数组,我们需要使用下面的语句来释放
delete [] 变量名
需要注意的是,我们使用delete来释放使用new开辟的数组时,需要为其传入开辟的数组的首地址,因为delete [] 会将给定的指针后的与数组大小相同个数的地址进行释放,所以我们只有传入开辟的数组首地址时候,才能够将所有的使用new开辟的地址释放,而不会释放无关的内存
最后,我们将在后面讲解的C++处理异常中讲解如何处理分配指针失败时的后果
下面我们将举个动态内存分配的例子
#include <iostream>
//导入命名空间
using namespace std;
int main(){
char * charPointer = new char;
int * intPointer = new int[10];
cout << "请输入一个字符:";
cin >> * charPointer;
for (int i = 0; i <10; i++)
{
cout << "请输入第"<< i+1<<"个整数:";
cin >> *intPointer;
intPointer++;
}
cout << endl << *charPointer<< endl;
intPointer-=10;
for (int i = 0; i < 10; i++)
{
cout << * intPointer;
cout << '\t';
intPointer++;
}
cout <<endl;
delete charPointer;
delete [] (intPointer-10);
return 0;
}
C++中的引用
引用是C++的新语言特性,其本质上是变量的一个别名
声明引用
类似于C++中指针的声明中使用*
来告诉编译器我们将要声明一个指针变量而非对地址取值的*
取值,我们申明一个引用的时候需要使用&
符号,和在非声明语句中的取地址符号&
不同,我们在声明语句中使用&
将会创建一个引用
数据类型 & 新变量名 = 原变量名
详解引用
就像前面所讲的,我们使用创建的新变量名只是原变量名的一个别名,我们可以通过下面的程序来看看
#include <iostream>
//导入命名空间
using namespace std;
int main(){
int num=10;
int * numPointer = #
int & numReference = num;
cout << "变量num的值是 :" << num << endl;
cout << "指向num的指针变量numPointer的值是:" << *numPointer << endl;
cout << "变量num的引用numReference的值是:" << numReference << endl<<endl;
cout << "变量num的地址是:" << &num << endl;
cout << "变量num的引用numReference的地址是:" << &numReference <<endl;
cout << "指向num的指针变量numPointer的地址是:" << &numPointer <<endl;
return 0;
}
编译成功后运行的得到的结果是
jackwang@jackwang-ThinkPad-X390-Yoga:~/桌面/TryC++$ ./Try
>>>
变量num的值是 :10
指向num的指针变量numPointer的值是:10
变量num的引用numReference的值是:10
变量num的地址是:0x7ffca90cef84
变量num的引用numReference的地址是:0x7ffca90cef84
指向num的指针变量numPointer的地址是:0x7ffca90cef88
我们其实可以发现,指定使用应用创建的变量的存储地址和原变量的存储地址其实是一样的,这就意味着编译器在将源文件编译为可执行文件的时候将num
和numReference
翻译为同一个地址,因此引用实际上只是为变量取了一个别名
将关键字const用于引用,禁止修改指向的变量的值
和指针一样,我们同样可以将关键字const用于引用,但是和将const关键字用于指针不同,将const关键字用于引用只有一种功能,即禁止通过引用来修改变量的值
#include <iostream>
//导入命名空间
using namespace std;
int main(){
int num = 10;
int & numReferenceVariable = num;
const int & numReferenceConst = num;
cout << num<<endl ;
numReferenceVariable=1;
cout << num <<endl;
numReferenceConst=2;
cout <<num <<endl;
return 0;
}
编译会报错,报错信息如下
jackwang@jwang:~/桌面/TryC++$ g++ trypointer.cpp -o trypointer
>>>
trypointer.cpp: In function ‘int main()’:
trypointer.cpp:14:23: error: assignment of read-only reference ‘numReferenceConst’
numReferenceConst=2;
^
注释掉14,15行后重新编译
jackwang@jwang:~/桌面/TryC++$ ./trypointer
>>>
10
1
为什么需要使用引用
引用能够让我们以另外一个变量名来访问变量所在的内存单元,这个处理过程发生在编译阶段。
因此引用操作通常使用在编写函数阶段,因为编写函数的时候我们进行的都是值传递,所以会包括复制参数和复制返回值两步,针对于大型的数组作为参数或者返回值的时候,我们这种值传递就会造成内存的浪费,因此为了避免在程序运行的时候造成空间的开销,我们可以直接使用应用来对同一个内存单元进行方位。
这和C语言中将指针作为参数和返回值具有异曲同工之妙
下面我们将编写一个将引用作为参数的函数来避免复制造成的开销
#include <iostream>
//导入命名空间
using namespace std;
int Square( int & numSquare){
cout << "函数Square中变量numSquare的地址是:" << &numSquare << endl;
numSquare *=numSquare;
}
int main(){
int num_1 = 10;
cout << "主函数中变量num_1的地址是:" << &num_1 << endl;
Square(num_1);
cout << num_1<<endl;
return 0;
}
编译成功之后运行得到的结果如下
jackwang@jackwang-ThinkPad-X390-Yoga:~/桌面/TryC++$ ./Try
>>>
主函数中变量num_1的地址是:0x7ffd11e04a54
函数Square中变量numSquare的地址是:0x7ffd11e04a54
100