我的编程空间,编程开发者的网络收藏夹
学习永远不晚

实例详解C++中指针与引用的区别

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

实例详解C++中指针与引用的区别

前言

在计算机存储数据时必须要知道三个基本要素:信息存储在何处?存储的值为多少?存储的值是什么类型?因此指针是表示信息在内存中存储地址的一类特殊变量,指针和其所指向的变量就像是一个硬币的两面。指针一直都是学习C语言的难点,在C++中又多了一个引用的概念。初学时很容易把这两个概念弄混,下面就来通过一些例子来说明二者之间的差别。

1、指针的声明

上文中提到,指针和其所指向的变量就像硬币的两面,因此通过取址符号"&"我们可以找到变量的地址,通过解引用符号"*"可以找到地址内存放的变量值。


int data = 10; //声明了一个变量data,并赋初始值10,存储的值是int类型
int* p_data = &data; //找到 data 在内存中存放的位置,即p_data
cout << "地址为:" << int(p_data) << "\t 存放的值为:" << data << endl;

输出结果为:

地址为:8191436  存放的值为:10

地址默认是16进制,我们在输出时将其转换成了int 类型,因此以十进制输出。输出结果翻译过来就是:在地址编码为8191436的位置存放了值为10的变量data,再进一步地说,data与*p_data 表示同一个东西。为了更有助于理解,我们绘制了下图:

因此从本质上看,指针与普通的变量并没有什么太大的区别,只是指针变量可以通过解引用的方式找到指针所对应的地址中存放的数值。假如定义如下:


int data = 10;
int* p_data = &data;  //定义指向 int 类型的指针 p_data, 存储的是 int 类型的变量 data的地址,其
int** p_p_data = &p_data; //定义指向 int* 类型的指针 p_p_data, 存储的是 int* 类型的变量 p_data的地址

cout << "p_data:" << p_data << "\t 存放的值为:" << *p_data << endl;
cout << "p_p_data:" << p_p_data << "\t 存放的值为:" << *p_p_data << endl;

输出结果为:

p_data:00EFF96C         存放的值为:10
p_p_data:00EFF960       存放的值为:00EFF96C

从输出结果可以看出,p_p_data中存储的值就是p_data,而p_data中存储的值就是data,很像”我爱她,她爱他“的这种桥段。下面我们就重点分析一下变量与指针之间的关系:我们在上述例子中把指针初始化为变量的地址,而变量是在编译时分配的有名称的内存,指针只是为可以通过名称直接访问的内存提供了一个别名。还拿上面这个例子:对程序员来说,变量10的名字就是data;而对于计算机来说,变量10就是存在 8191436 地址的数据;实现程序员与计算机沟通的方式就是指针,通过对data取址让程序员能够明白计算机的存储结构,同样,通过对地址解引用,也能轻松地找到该地址中存储的数据。在上述情况下,指针的出现显得有些多余,然而指针的真正用武之地在于,在运行阶段分配未命名的内存以存储值,在这种情况下,只能通过指针来访问内存。

最后关于指针声明的一点建议:在声明一个指针变量时,必须要指定一个确定的地址,否则声明的指针变量不知道指向哪里,因此容易造成系统崩溃。

2、使用new来分配内存

内存四区之代码区,全局区,栈区和堆区中提到过,new 会在堆区创建一个内存空间,其返回值就是该内存空间的地址,因此程序员的责任就是将该地址赋给一个指针。下面是一个示例:


int* p_data = new int; //在堆区开辟一个空间,并返回该内存空间的地址
*p_data = 10; //将向该内存中存储数值10
cout << "p_data:\t" << p_data << "\t *p_data: " << *p_data << endl;

通过比较会发现,new 后面指定了数据类型 int,同样地,p_data 也被声明为指向 int 的指针。这是因为,计算机的内存是以字节为存储单位,不同类型的变量会占用不同的字节,因此使用 new 时必须要告诉编译器分配多少字节的存储空间,并且接收的指针也必须与声明的类型一致。输出结果为:

p_data: 00D0D9A0         *p_data: 10

当处理大型数据,比如数组时,通常会使用的一种方法是定义一个数组类型的数据,在定义的时候分配足够大的空间。但是这种做法太过于死板,但是当使用 new 时,如果在运行阶段需要数组,那么则创建它,如果不需要则不创建,最重要的是可以在程序运行时选择数组的长度。 下面就看一下如何使用 new 来创建动态数组。在C++中,数组名被解释为数组地址,即数组第一个元素的地址。下面是一个实例:


int Arr[10]; // 定义一个包含10个int类型元素的数组
cout << "Arr:" << Arr << "\t&Arr[0]:" << &Arr[0] <<endl;

输出结果为:

Arr:008FFAB4    &Arr[0]:008FFAB4

这种声明方式只能在刚开始就声明固定的数组长度,在C++中创建动态数组时,只需要将数组的元素类型和元素数目告诉给 new 即可,new 的返回值同样是数组的首地址。


int ele_num = 10; //临时指定数组内元素的个数
int* p_arr = new int [ele_num]; //根据临时指定的元素个数创建数组

通过 new 在堆区开辟空间,由程序员管理释放,因此当 new 的内存不用后,需要通过 delete 进行变量,使用 delete [] 来释放开辟的数组空间。代码如下:


int* p_data = new int;
*p_data = 10;
cout << "p_data: " << p_data << "\t*p_data:" << *p_data << endl;

int ele_num = 10;
int* p_arr = new int [ele_num];

for(int i = 0; i<9; i++)
 *(p_arr+i) = i+2;

cout << "p_arr:" << p_arr << "\t\t*(p_array):";
for(int i = 0; i<9; i++)
 cout << *(p_arr + i) << " ";
cout << endl;

delete p_data;
delete [] p_arr;

cout << "\n******使用delete释放内存后......*******" << endl;
cout << "p_data: " << p_data << "\t*p_data:" << *p_data << endl;
cout << "p_arr:" << p_arr << "\t\t*(p_array):";
for(int i = 0; i<9; i++)
cout << *(p_arr + i) << " ";
cout << endl;

输出结果如下:

p_data: 0082B1C8        *p_data:10
p_arr:0082BB58          *(p_array):2 3 4 5 6 7 8 9 10

******使用delete释放内存后......*******
p_data: 0082B1C8        *p_data:-572662307
p_arr:0082BB58          *(p_array):-572662307 -572662307 -572662307 -572662307 -572662307 -572662307 -572662307 -572662307 -572662307

3、malloc 与 new 的区别

学过C语言的朋友都知道,在C语言中通过malloc函数开辟一块内存空间,malloc的函数原型如下:


void* malloc(unsigned int numbytes);

从函数原型的参数可以看出,malloc 函数以字节数为参数,开辟固定字节的内存空间。这与 new 就有了第一点不同:new 不需要自己计算字节数,只需要给定内存中存储的数据类型与元数个数即可。

从函数原型的返回类型可以看出,malloc 函数返回 void* 类型,需要我们在使用时自己指定指针类型。比如:


int* p_malloc = nullptr; // 创建一个指向int的指针
p_malloc = (int*) malloc(10); //将 malloc 的返回值强制转换为 int* 类型

而 new 在使用时则不需要。总结看来,malloc 在使用时需要自己根据内存中的数据类型以及内存长度计算处所需要的字节数,然后返回 void* 类型,需要使用对应类型的指针进行接收。而 new 在使用时只需要给定内存的长度与内存中数据的类型,编译器会自动计算所需要的字节数。

4、引用的声明与本质

C++中新增了引用作为已定义的变量的别名。引用的最主要用途是作为函数形参,这样函数就可以使用原始数据而不是数据副本,这样听起来似乎与指针没什么区别,我们还是从引用的声明说起。


int data = 10;
int& p_data = data; //创建一个引用变量 p_data
cout << "data:" << data << "\tp_data:" << p_data << endl; //p_data 与 data 相当于一个变量的两个名字

输出结果为:

data:10  p_data:10

从输出结果来看,p_data 与 data 就是一个变量的两个不同叫法而已。引用必须在声明时就为其指定初始值,而不能像指针一样可以先声明,再赋值。下面将引用作为函数的参数来进一步说明引用与指针的区别:


template <typename T> //定义一个模板函数
void swap(T a, T b){
 int temp;
 temp = a;
 a = b;
 b = temp;
}
int main(void){
 int a = 10, b = 20; 
 swap_value<int>(a,b); //首先进行值传递
 cout << "a:" << a << "\t\tb:" << b << endl;
 swap_value<int&>(a,b); //然后进行引用传递
 cout << "\na:" << a << "\t\tb:" << b << endl;
}

从上述代码中可以看到,值传递和引用传递的形参都是一样的,不同的是引用传递时,实参被声明为引用,引用的用法与使用值一模一样,输出结果如下:

a:10            b:20
a:20            b:10

惊奇的发现,引用传递改变了原始数据的值,这点与指针的用法一致,但是指针在书写 swap 函数时应该这样写:


void swap(int* a, int* b){
 int temp;
 temp = *a;
 *a = *b;
 *b = temp;
}
swap(&a, &b); //调用格式

综上发现,引用其实就是变量的另一个名称,它的用法与变量一模一样,但是能在作为形参传递时,改变原始数据的值。除了这些用法上的区别,引用的本质其实就是一个指针常量,意味着指针指向的位置不可变,但是指针指向位置的值可变。即:


// 这两者的语句是等效的,因此引用被当作指针常量来处理
int& p_a = a;  
int* const p_a=&a;

再补充一点小知识,关于 const 修饰符的问题,有些新手朋友来说很容易弄不清楚 const 修饰下什么是可变的,什么是不可变的。具体实例如下:


int data = 10, data2 = 20;
const int* p_data = &data; //修饰的是int,即 p_data 所指向的值不可变,而p_data可变
p_data = &data2;

int* const p_data2 = &data; //修饰的是int*,即 p_data 所指向的值可变,而p_data不可变
*p_data2 = data2;

引用即是第二种用法。

总结

到此这篇关于C++中指针与引用的区别的文章就介绍到这了,更多相关C++指针与引用内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

实例详解C++中指针与引用的区别

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

c++中引用与指针的区别

引用和指针都是用于处理内存地址的机制。引用在编译时绑定,始终指向同一内存地址,与对象共享相同内存空间。指针在运行时绑定,可以指向不同的内存地址,不与对象共享相同内存空间。引用用于不修改对象的情况下操作对象,而指针用于处理动态分配的内存或修改
c++中引用与指针的区别
2024-05-06

java中的引用与c++中的指针的区别

Java的引用和C++的指针都是指向一块内存地址的,通过引用或指针来完成对内存数据的操作,但是它们在实现,原理作用等方面却有区别。(1)类型:引用其值为地址的数据元素,Java封装了的地址,可以转换成字符串查看,长度也可以不必担心。C++指针是一个装地址的变量
java中的引用与c++中的指针的区别
2014-09-04

C++中指针与引用的区别有哪些

这篇文章主要介绍C++中指针与引用的区别有哪些,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!1、指针的声明上文中提到,指针和其所指向的变量就像硬币的两面,因此通过取址符号"&"我们可以找到变量的地址,通过解引用符号"
2023-06-20

C++中指针与引用的区别是什么

这篇文章主要介绍了C++中指针与引用的区别是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C++中指针与引用的区别是什么文章都会有所收获,下面我们一起来看看吧。1、指针的声明上文中提到,指针和其所指向的变量
2023-06-19

C++指针与引用有什么区别

这篇文章将为大家详细讲解有关C++指针与引用有什么区别,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1、引用与指针的区别指针和引用的原理非常的相似,所以很多时候尤其是面试的时候经常会拿来比较。本文来梳理一
2023-06-25

Java引用与C指针的区别是什么

Java引用与C指针的区别如下:1、现象指针在运行时可以改变其所指向的值(地址)即指向其它变量,而引用一旦和某个对象绑定后就不能再改变,总是指向最初的对象。2、编译程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变量名以及变量所对应的地址。(相关视
Java引用与C指针的区别是什么
2022-03-17

C++引用的特点及与指针的区别是什么

这篇文章主要讲解了“C++引用的特点及与指针的区别是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++引用的特点及与指针的区别是什么”吧!一.引入在生活中,我们可能也会给一些同学起外号
2023-06-30

C++的引用和指针有哪些区别

本篇内容主要讲解“C++的引用和指针有哪些区别”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++的引用和指针有哪些区别”吧!引用和指针有如下三种区别:1 引用必须在声明时初始化,而指针不用;2
2023-06-17

C++中指针常量与常量指针的区别是什么

在C++中,指针常量和常量指针是不同的概念。1. 指针常量(Pointer to constant):指针本身是一个常量,即指针的值不能被修改,但是它所指向的值可以被修改。声明一个指针常量时,要在指针类型前加上const关键字。示例:```
2023-08-16

简单总结C++中指针常量与常量指针的区别

C++中指针常量与常量指针有以下区别:1. 指针常量(Pointer to constant):指针常量是一个指针,它的值是一个常量,即指针指向的地址不可变。可以修改指针存储的地址,但不能通过指针修改所指向的值。声明指针常量时,常量修饰符c
2023-08-15

C++中的指针与引用的定义

本篇内容主要讲解“C++中的指针与引用的定义”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++中的指针与引用的定义”吧!1、指针和引用的定义 在深入介绍之前我们首先来看一下指针和引用的定义、指
2023-06-17

C++ 函数中引用参数和指针参数的区别

在 c++++ 函数中,引用参数传递变量地址,对参数的修改影响原始变量,而指针参数传递指向地址的指针,对参数的修改不影响原始变量。C++ 函数中引用参数和指针参数的区别在 C++ 中,函数可以接受引用参数或指针参数。虽然两者都用于传递一个
C++ 函数中引用参数和指针参数的区别
2024-04-20

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录