当前位置: 首页 > article >正文

C++—14、C++ 中的指针最基础的原理

       这里的指针是指原始指针,并非智能指针。计算机跟内存打交道,内存是计算机的一切,编程中最重要的东西可能就是内存。当你编写一个应用程序并启动它时,整个程序被载入内存,在你写的代码中,所有指令告诉计算机要做什么,所有这些被加载到内存中,这就是cpu如何访问你的程序并执行指令的。当你创建一个变量时,当你从硬盘中载入数据时,所有东西都会被存储到内存中,如果没有内存,你将什么也做不了。而指针对管理和操纵内存很重要。所以什么是指针?

一、指针的定义

指针是一个无符号整数(unsigned int),其值表示一个内存地址(其存储一个内存地址)。

因为我们代码所做的每一件事都是从内存中读取或者写入内存。内存可能是你拥有的至关重要的东西,你的电脑所能提供的重要的资源,所有的东西都依赖它,所以能够对这些内存有更多的控制至关重要。指针的类型与指针的值没有任何关系,类型只是我们虚构出来的,好让我们感觉轻松些,别管你有什么类型的指针,里面存放的都是个整数,都是个地址。

二、实例应用

新建项目,里面只有一个main.cpp文件。

这里新建个指针,void类型的,把变量var的地址存里面了。

再次强调,指针是没有什么类型的,里面存储的只是一个地址,一个整数,如果要是说有类型,只是指它所存储的地址所指的里面是存放什么类型的数据而已。

指针如果是空的话,我们可以这样写:

void*ptr=nullptr;

我们如上图所示F9来设置断点,按F5来调试程序。

当我们把鼠标悬停在ptr上时,显示一个地址0X0034FA58.我们把内存视图调出来

我们输入这个地址来看一看,这个地址中存放的是什么?

发现这个地址中正好存放的是8,变量var的值。

从这个实例中我们更加理解了,指针是个变量,是个存储地址的变量。

三、*指针

假设我想读取我的数据,我有指向那个数据的指针,现在我想写入或者读取这块数据,或者我想更改他,任何更改呢?

这时候逆向引用,就派上用场了,可以通过在指针前面加上个星号来实现。

*ptr,我实际上在逆向引用那个指针,也就是我现在在访问那块数据,我可以读取或者写入那块数据。例如我将值10写入。

如果这样做可能会产生错误,因为这里的类型指的是指针所指的地址的数据类型,为void。

测试下:

计算机如何从能把值写道一个void类型上去?这里的10,有可能是短整型2个字节,int是4个字节,long int是8个字节,它不知道该写入多少个字节的数据。其实这时应该用到类型了。程序修改如下:

我们来告诉编译器他就是个int类型,4个字节。记住是我们告诉编译器的,并不是编译器自己思考的。

我们来把这个值输出一下看看对不?

可以看到值已经被修改。

我们可以通过调试来观察内存的变化。

通过上面实例我们可以看出,通过星指针就是在访问那块数据,就可以写入那块内存。

现在对于指针的工作,大家应该很清楚了吧!

总结一下:指针就是指向内存中的一个位置。有些人说它指向一块内存,虽然不是很准确,因为我们不知道那块内存有多大。在上面这种情况下,我们知道,因为是int类型,是4个字节。

在实际的指针中并没有说内存有多大,当我们创建数组的时候,它有记录大小。确切的说它没有保存数据,我们不应该知道它有多大。

指针只是一个整数,也就是一个内存地址。

四、堆上内存分配

char是一个字节,这里我问他要的是8个字节的内存,并返回了指向这个内存开始地址的指针。然后我们可以使用memset的函数来填充这块内存,函数参数为指向这块地址开始地址的指针,然后是值,然后是大小就是需要填充多少字节。

调试运行

输入查询内存,发现

由于这里使用了new关键字,所以该数据是分配在heap上的

五、堆和栈

Heap 和 Stack 是计算机科学中两个基本的概念,它们在内存管理和数据结构方面扮演着重要的角色。以下是关于 Heap 和 Stack 的详细解释和比较。

堆(Heap)

定义:堆是一种内存区域,通常由程序员手动分配和释放内存。如果程序员不释放内存,程序结束时操作系统可能会回收这部分内存4。

特点

  • 手动管理:程序员需要显式地使用 malloc 或 new 等函数来分配内存,使用 free 或 delete 来释放内存21。
  • 动态大小:堆的大小在程序运行期间可以动态变化,没有固定的大小限制,但受到系统可用内存的限制2。
  • 内存碎片:频繁的内存分配和释放可能导致内存碎片,影响性能2。
  • 生长方向:堆的增长方向通常是向上的,即向内存地址增加的方向扩展2。

栈(Stack)

定义:栈是一种内存区域,由编译器自动分配和释放内存,通常用于存储函数的局部变量和参数4。

特点

  • 自动管理:编译器自动管理栈内存的分配和释放,不需要程序员显式地进行内存管理21。
  • 固定大小:栈的大小在程序开始时就已经确定,通常较小,受限于系统资源2。
  • 无内存碎片:由于栈采用先进后出(LIFO)的结构,不会产生内存碎片问题2。
  • 生长方向:栈的增长方向通常是向下的,即向内存地址减小的方向扩展2。

主要区别

特性Heap(堆)Stack(栈)
内存管理手动分配和释放自动分配和释放
内存大小动态大小,较大但有限固定大小,相对较小
内存碎片可能产生内存碎片不会产生内存碎片
生长方向向上,内存地址增加向下,内存地址减小
分配效率较低,涉及复杂算法较高,由硬件直接支持

 C++ 中,声明一个对象并在堆上分配内存的示例如下:

bject* p = new Object();

而在栈上分配内存的示例如下

Object obj;

六、指针的指针

如下:

注意这里说了需要手动释放,所以应该为:

设置断点在第8行,我们来调试一下:

我们在ptr的值输入内存:

这个值006fe648正好是buff的值,

而buff变量的值作为地址,里面放的是0.也就是这个指针变量放的是另一个指针的地址,另一个指针的地址指向一个内存空间的开始地址。


http://www.kler.cn/a/488804.html

相关文章:

  • SQLite 命令
  • (五)ROS通信编程——参数服务器
  • G-Star Landscape 2.0 重磅发布,助力开源生态再升级
  • 计算机网络之---数据链路层的功能与作用
  • GPU算力平台|在GPU算力平台部署Qwen-2通义千问大模型的教程
  • 代码随想录算法训练营day23
  • React 元素渲染
  • 苍穹外卖的微信支付和接单和催单提醒
  • 青少年编程与数学 02-006 前端开发框架VUE 16课题、组件基础
  • 初学stm32 --- ADC多通道采集
  • 鸿蒙原生应用如何才能拉起系统浏览器?
  • Linux 命令与日志查看实用指南
  • 详解Sonar与Jenkins 的集成使用!
  • 【C++】Muduo库
  • vivado 时钟指南
  • .gitignore记录
  • 前端全局水印, 拖拉拽图片 ,拽入等比压缩,上传服务器后,java 转base64 加水印,然后前端http预览,确认保存,拽出删除。
  • VS Code 可视化查看 C 调用链插件 C Relation
  • 腾讯云AI代码助手编程挑战赛-知识百科AI
  • Unity3D Huatuo热更环境安装与示例项目详解
  • MYSQL------MySQL 复制MySQL Cluster 架构
  • Xsens惯性动捕技术优化人型机器人AI训练流程
  • 搭建docker私有化仓库Harbor
  • flask-admin 在modelview 默认视图下重写create_model_actions来实现列表数据的批量处理actions
  • (长期更新)《零基础入门 ArcGIS(ArcMap) 》实验六----流域综合处理(超超超详细!!!)
  • 2025年第三届“华数杯”国际赛A题解题思路与代码(Matlab版)