C++有关内存的那些事

个人主页:PingdiGuo_guo
收录转栏:C++干货专栏

前言

本篇博客是讲解关于C++内存的一些知识点的。

文章目录

前言

1.内存函数

1.1memcpy函数

1.2memmove函数

1.3 memset函数

2.各数据类型占用

2.1bool类型

2.2char类型

2.3short、int、long类型及整数

2.4float类型及double类型及浮点数

3.学习内存有什么用

总结


1.内存函数

内存函数是在计算机程序中用来操作内存的一类函数。内存函数可以用于分配和释放内存,读取和写入内存中的数据,以及进行内存的复制和移动等操作。

在这里,我们主要介绍几种可以复制的内存函数。

1.1memcpy函数

memcpy函数是C++中的一个标准库函数,用来实现内存拷贝操作。它的原型如下:

void *memcpy(void *dest, const void *src, size_t n);

在C++中,也可以使用内存拷贝操作来复制数组元素。C++提供了memcpy函数,它与C的memcpy函数功能相同,但被包含在std命名空间中。

下面是使用memcpy实现数组元素拷贝的示例代码:

#include <iostream>
#include <cstring>using namespace std;int main() {int srcArray[] = {1, 2, 3, 4, 5};int destArray[5];// 使用memcpy函数拷贝数组元素memcpy(destArray, srcArray, sizeof(srcArray));// 思考:sizeof(srcArray)是什么?这个函数拷贝拷贝了多少元素?memcpy(destArray, srcArray,20);//思考:这里可以拷贝多少元素?//思考:这里是谁拷贝的谁?// 打印目标数组的元素for (int i = 0; i < sizeof(destArray) / sizeof(destArray[0]); i++) {cout << destArray[i] << " ";}return 0;
}

1.sizeof(srcArray)是srcArray数组的字节大小,即sizeof(int) * 5,所以sizeof(srcArray)是20。

2.这个函数拷贝了5个元素。因为memcpy函数根据参数指定的字节数进行拷贝,sizeof(srcArray)指定了srcArray数组的字节大小,所以拷贝了整个srcArray数组的元素。

3.第二个memcpy函数使用了20作为拷贝的字节数。因为是5每个int占4个字节,所以这个函数可以拷贝5个元素。

4.这里是destArray拷贝了srcArray数组。

memcpy函数在处理内存重叠问题时是未定义行为。也就是说,如果源内存块和目标内存块重叠,memcpy函数可能会导致不可预测的结果。

输出结果:

1.2memmove函数

memmove与memcpy类似,但不同的地方是memmove是可以处理内存块的重叠的。它的函数原型为:

void *memmove(void *dest, const void *src, size_t count);

拷贝数组:

#include <bits/stdc++.h>
using namespace std;
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10};memmove(arr1+2, arr1, 20);for (int i = 0; i < 10; i++){cout<<arr1[i]<<' ';}return 0;
}

输出结果:

这里出现了一个问题,那就是内存重叠了。

那么,我们如何处理这个内存重叠问题呢?

我们可以检查它们的内存是否重叠。

如果是,那我们就直接从后往前拷贝,否则,我们就从前往后拷贝。

图示:

src:src 是 memory source 的缩写,表示源地址,即需要被复制的内存块的起始位置。

dest:dest 是 destination 的缩写,表示目标地址,即复制后的内存块的起始位置。

代码:

// 自定义 memmove 函数,解决内存重叠问题
void* me(void* d, const void* sr, size_t n) {void* ret = d;if (d <= sr || (char*)d >= ((char*)sr + n)) {// 从前往后while (n--) {*(char*)d = *(char*)sr;d = (char*)d + 1;sr = (char*)sr + 1;}} else {// 从后往前d = (char*)d + n - 1;sr = (char*)sr + n - 1;while (n--) {*(char*)d = *(char*)sr;d = (char*)d - 1;sr = (char*)sr - 1;}}return ret;
}

1.3 memset函数

memset函数式将指定大小的内存块设置为给定的值。它的函数原型为:

void * memset ( void * ptr, int value, size_t num);

使用:

#include <iostream>
#include <cstring>
using namespace std;
int main() {char str[10];// 将str的前5个字节设置为字符 'A'memset(str, 'A', 5);cout << str << endl;  // 输出 "AAAAA"return 0;
}

运行结果:

2.各数据类型占用

我们可以用sizeof(数据类型)格式来计算个数据类型的占用内存大小。这里我们要了解一个知识点:

字节是计算机中的最小存储单位,通常用来表示一个字母、一个数字或者一个符号。一个字节等于8个二进制位,即8个0或1。字节是计算机中信息存储和传输的基本单位,用来表示各种数据类型和文件大小。

二进制位是计算机中的最小计数单位,用于表示数字的最基本形式。二进制位只能是0或1两种状态,用于表示八进制、十进制、十六进制等不同进制数系统的数值。计算机中的所有数据都是以二进制位的形式存储和处理的,二进制位的组合可以表示各种不同的数值和字符。8个二进制位组合在一起形成一个字节,即8位二进制位表示一个字节的数据。

2.1bool类型

代码:

cout<<sizeof(bool)<<endl;

占用一字节。

解释:

bool类型占用内存是一个字节。虽然大家可能觉得bool类型的取值范围只有true和false两种,占用内存应该很小,但是为了在内存中存储和处理bool类型的值,需要用一个字节来表示。这是因为计算机在内存中最小的存储单元就是一个字节,无法将一个布尔值存储在更小的存储单元中。因此,无论bool类型的值占用的实际位数是多少,它始终会占用1个字节的内存空间。

2.2char类型

代码:

cout<<sizeof(char)<<endl;

占用一个字节,及八位二进制位,图表:

1/01/01/01/01/01/01/01/0

其中,每一个二进制位的变化都可以表示一个不同的值,也就是2^8=256个值,只是当有符号和无符号时表示的范围并不相同,我们平时的所用的每一个字符在内存中都由8位2进制位来表示。

比如,字符'A'在ASCLL码中对应65,在内存则表示为:

01000001

2.3short、int、long类型及整数

short、int、long类型都是储存整数的,所以放到一块讲了。

short类型:

cout<<sizeof(short)<<endl;

占用二字节,也就是十六位二进制位,可以表示2^16=65536个值。

int类型:

cout<<sizeof(int)<<endl;

占用四字节,三十二位二进制位,可以表示2^32=4294967296个值。

long类型:

cout<<sizeof(long)<<endl;

也是占用四字节,表示三十二位二进制位,可以表示2^32=4294967296个值,和int类型一样。

整数:

整数的存储都是由原码、反码、补码来表示的:

对于整数:

1. 原码:只要通过正负数判断即可获得原码,(正数1,负数0)

2. 反码:在原码的基础上,对负数的各位取反

3. 补码:在反码的基础上,对负数的最低有效位加1。即将反码(符号位除外)加1得到补码。

注:正整数的原、反、补码是相同的。

在计算机内存中,整数通常用二进制补码的形式来储存。为什么呢?

因为计算机中通过补码运算可以实现加法、减法、乘法和除法等操作。在进行运算时,计算机会自动进行补码的转换和处理。

2.4float类型及double类型及浮点数

因为float和double都是储存浮点数的,所以归为一类了。

float类型

代码:

cout<<sizeof(float)<<endl;

占用四字节,三十二位二进制位。

这里需要了解一个表示方式,就是二进制的科学表示法:

± mantissa × 2 exponent
(mantissa:尾数,exponent:指数,均使用二进制表示)

它的储存采用了IEEE 754单精度浮点格式,存储方式如下:

1 bit(符号位)

8 bit(指数位)

23 bit(尾数位)

00  1  1  1  1  1  0  0  00  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
3031                              2322                                                                                         0

这里的bit也是二进制位,是二进制位的缩写。如上图所示,该格式最高一位是符号位,0位正,1位负,后面8位为无符号整型数,表示范围为0~265,后面23位小数为,索引从22到0分别对应2^-1到2^-23。

double类型

代码:

cout<<sizeof(double)<<endl;

double型在内存中有八个字节,储存的数据较大,六十四位二进制位(bit)。他和float类型一样,都是采用的二进制的科学计数法。

它的储存采用了IEEE 754双精度浮点格式,储存方式如下:

1 bit(符号位)

11 bit(指数位)

52 bit(尾数位)

第一位为63倒数第一位为52

倒数第一位为0

如上图所示,该格式最高位也为符号位,0位正,1位负,后面11位为无符号整型数,表示范围为0~2^11-1,后面52位小数为,索引从51到0分别对应2^-1到2^-52。

浮点数

浮点数的储存方式可看上面的两张图表,接下来讲一下浮点数如何转化为二进制。

步骤:

1. 将浮点数分为整数部分和小数部分。例如,考虑浮点数12.375,整数部分为12,小数部分为0.375。

2. 将整数部分转化为二进制。对于整数部分,可以使用短除法将其转化为二进制。例如,12转化为二进制是1100。对于短除法,这里就不过多讲述了,大家可以去查一查。

3. 将小数部分转化为二进制。对于小数部分,可以使用乘2取整法将其转化为二进制。将小数部分乘以2,取整数部分,然后将小数部分的整数部分再乘以2,依此类推,直到小数部分为0或达到所需的精度。例如,0.375转化为二进制的过程如下:

  

   0.375 x 2 = 0.75 -> 0//整数部分为0,继续乘20.75 x 2 = 1.5 -> 1//整数部分为1,舍弃整数部分,继续乘20.5 x 2 = 1.0 -> 1//乘得积为1,停止运算

    所以,0.375转化为二进制是0.011。

4. 合并整数部分和小数部分的二进制。将步骤2和步骤3得到的二进制合并在一起,注意小数点的位置。对于上述例子,合并后的二进制是1100.011。

5.  二进制小数转化为十进制验算。比如,二进制小数1100.011=1*2^2+0*2^2+1*2^2+(0 * 2^-1) + (1 * 2^-2) + (1 * 2^-3) =12.375,正确。

3.学习内存有什么用

大家可能会有一些疑问,学内存知识有什么用呢?学内存有以下几个方面的作用:

1. 内存管理:C++是一种低级语言,需要手动管理内存分配和释放。了解C++内存知识可以帮助我们正确地分配和释放内存,避免内存泄漏和野指针等问题,提高程序的健壮性和效率。

2. 优化性能:理解C++内存模型和内存使用方式可以帮助我们优化程序性能。例如,了解内存对齐和缓存行的概念可以避免访问内存的延迟,提高程序的运行速度。

3. 安全性和稳定性:内存相关的错误往往是导致程序崩溃和漏洞的主要原因之一。学习C++内存知识可以帮助我们避免常见的内存错误,提高程序的安全性和稳定性。

4. 调试和错误排查:当程序出现内存相关的问题时,了解C++内存知识可以帮助我们更快地定位和修复问题,提高调试的效率。

总的来说,学习C++内存知识对于使用和开发C++程序非常重要,可以帮助我们进行内存管理、优化性能、提高安全性和稳定性,深入理解语言特性,以及进行调试和错误排查。

总结

本篇博客到这里就结束了,感谢大家的支持与观看,有好的建议欢迎留言,如果这篇博客对您有帮助,那请给PingdiGuo_guo一个免费的赞,谢谢大家啦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/755499.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SegFormer 项目排坑记录

SegFormer 项目排坑记录 任务记录创建conda环境 准备数据库和预训练参数程序配置修改测试可视化训练 任务 需要复现SegFormer分割项目&#xff0c;似乎还有点麻烦&#xff0c;参考这几个进行复现&#xff0c;记录下过程&#xff1a; SegFormer mmsegmentation CSDN博客 知乎博…

Docker 安装 Nginx 容器部署前端项目

先安装docker Docker安装详情 安装Nginx镜像 1、拉去取Nginx镜像 Nginx官方镜像 docker pull nginx 下载最新版Nginx镜像 (其实此命令就等同于 : docker pull nginx:latest ) docker pull nginx:xxx 下载指定版本的Nginx镜像 (xxx指具体版本号)我们拉去1.24.0的nginx镜像 …

视频号视频下载需要小程序提供下载支持!

前言&#xff1a;和大家分享一个视频号视频下载的方法&#xff01;可以帮助用户使用的工具将视频号视频保存到手机相册的&#xff01; 有时候在刷视频号的时候碰到自己喜欢的视频就情不自禁的想要把他下载下来&#xff0c; 1&#xff1a;遇到喜欢的视频视频怎么下载 例如&am…

中国传统游戏-幻方-c/c++实现

幻方&#xff08;Magic Square&#xff09;是一种将数字安排在正方形格子中&#xff0c;使每行、列和对角线上的数字和都相等的方法。 幻方也是一种中国传统游戏。旧时在官府、学堂多见。它是将从一到若干个数的自然数排成纵横各为若干个数的正方形&#xff0c;使在同一行、同…

Pytorch框架—文本情感分类问题项目(二)

整体过程就是首先拿到了数据集微博100K&#xff0c;对个这个评论数据集进行处理&#xff0c;分类标签和评论内容。对评论内容进行分词处理&#xff0c;之后进行词频统计对高词频的进行编码&#xff0c;低词频的进用《UNK》表示&#xff0c;并使用《PAD》把他们扩展到等长列表便…

MATLAB编译器配置:MinGW

使用 MATLAB 2022b版本&#xff0c;查询编译器时如上&#xff0c;想安装个MinGW编译器&#xff0c;自带的附加资源管理不好使&#xff0c;只能换个别的法子&#xff0c;经过一些参考&#xff0c;总结如下。 步骤1.在这里下载一个MinGW.最新版本是10.3.0.然后默认安装&#xff…

蓝桥杯刷题|03入门真题

目录 [蓝桥杯 2020 省 B1] 整除序列 题目描述 输入格式 输出格式 输入输出样例 说明/提示 代码及思路 [蓝桥杯 2020 省 AB3] 日期识别 题目描述 输入格式 输出格式 输入输出样例 说明/提示 代码及思路 [蓝桥杯 2019 省 B] 特别数的和 题目描述 输入格式 输出格…

谷歌的后量子密码学威胁模型

1. 引言 若现在不使用量子安全算法来加密数据&#xff0c;能够存储当前通信的攻击者最快十年内就能对其解密。这种先存储后解密的攻击是当前采用后量子密码学 (post-quantum cryptography&#xff0c;PQC) 背后的主要动机&#xff0c;但其他未来的量子计算威胁也需要一个深思熟…

GEC6818——QT开发之两个UI界面切换与表格显示DHT11数据

GEC6818——QT开发之两个UI界面切换与表格显示DHT11数据 使用环境: ubantu16 QT5.7 开发板GEC6818 实现要求&#xff1a; 利用A53按键1、按键2与温湿度传感器完成QT界面动态显示温湿度记录&#xff0c;并指定温湿度记录超过指定范围&#xff0c;进行报警&#xff08;LED&#…

天锐绿盾|公司开发部门源代码泄露防护系统,无感透明加密软件

#代码加密、代码防泄密、开发部门源码防泄漏、源代码透明加密、办公透明加密系统# 天锐绿盾作为一款针对企业数据安全的专业软件&#xff0c;特别是在防止公司开发部门源代码泄露方面&#xff0c;提供了智能无感透明加密保护系统。 德人合科技 | 天锐绿盾 PC地址&#xff1a; …

【经验分享】Wubuntu------体验Windows和Ubuntu的结合体

【经验分享】Wubuntu------体验Windows和Ubuntu的结合体 最近看到有一款Wubuntu的文章&#xff0c;对于习惯使用windows操作系统&#xff0c;又不熟悉ubuntu系统的程序员小白来说&#xff0c;可以说是福音了。目前的Wubuntu兼容性可能还有一点问题&#xff0c;如果再迭代几次的…

Python库Gym:打开机器学习与强化学习的大门

Python库Gym&#xff1a;打开机器学习与强化学习的大门 强化学习作为人工智能领域的重要分支&#xff0c;已经在各种领域展现出了巨大的潜力。为了帮助开发者更好地理解和应用强化学习算法&#xff0c;Python库Gym应运而生。Gym提供了一个开放且易于使用的环境&#xff0c;供开…

win电脑安装绿色版MySQL8

一、下载压缩包 下载mysql server的zip文件&#xff0c;地址&#xff1a;Windows (x86, 64-bit), ZIP Archive 解压后&#xff1a; 二、创建配置文件&#xff08;可忽略&#xff09; 配置文件可存放位置及名称&#xff1a; C:\WINDOWS\my.ini C:\WINDOWS\my.cnf C:\my.ini…

招个Java工程师,却发现了一个宝藏平台

一直关注磊哥的朋友都知道&#xff0c;磊哥出来创业&#xff08;做 Java 就业指导&#xff09;也快一年了&#xff0c;从最初的纠结彷徨、不知所措&#xff0c;到现在逐渐找到自己的节奏&#xff0c;也算是半个媳妇熬成婆了。 磊哥现在每天做的事儿&#xff0c;就是通过文章和…

使用Navicat远程连接Linux中的MySQL

一、登录MySQL数据库 mysql -uroot -pXjm123456 二、使用mysql数据库 use mysql&#xff1b; 三、查询user表中包含host的字段 select user,host from user;### 该字段中&#xff0c;localhost表示只允许本机访问&#xff0c;可以将‘localhost’改为‘%’&#xff0c;‘%’表…

8.发布页面

发布页面 官网 https://vkuviewdoc.fsq.pub/components/form.html 复制官网中的内容 代码 write.vue <template><view class"u-wrap u-p-l-20 u-p-r-20"><u-form :model"addModel" ref"form1"><u-form-item label&quo…

深度强化学习06Actor-Critic

Critic裁判 裁判打分 提高自己的技术 提高打分水平

编译原理-实现识别标识符的词法分析器——沐雨先生

实验任务&#xff1a; 实现识别标识符的词法分析器 实验要求&#xff1a; 根据编译原理理论课教材中图2.3“标识符的转换图”&#xff0c;用C语言编写识别标识符的词法分析器&#xff0c;以文本文件为输入&#xff0c;控制台&#xff08;或文件&#xff09;输出识别出的每个…

uni app 打肉肉(打飞机)小游戏

都给老婆和孩子写了 合十 钓鱼了&#xff0c;给自己写个打飞机吧。没找飞机怪兽的图片。就用馒头和肉肉代替了。有问题不要私信我。自己改哈 <template><view class"page_main"><view class"contentone"><canvas class"canvas…

C语言每日一题(64)快乐数

题目链接 力扣网202 快乐数 题目描述 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为&#xff1a; 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1&#xff0c;也可能是 无限循环 但始终变不…