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,记录整数部分,小数部分继续乘2
   0.75 x 2 = 1.5 -> 1//整数部分为1,记录整数部分,小数部分继续乘2
   0.5 x 2 = 1.0 -> 1//整数部分为1,记录整数部分,小数部分为0,停止运算

所以,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一个免费的赞和关注,谢谢大家啦!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

计算机硕士,毕业直接后端开发岗,选择C++还是java?

我自己是一名工作多年的C程序员&#xff0c;大学学习的编程语言就是C/C&#xff0c;参加工作后自学了Python、Java、Golang等语言。 现在从事自动驾驶行业的工作&#xff0c;工作中主要使用的编程语言是C和Python。在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整…

canopen使用

CAN 总线协议 1&#xff09;、启动SDO 下载协议 ccs&#xff1a;客户端 指定命令 1&#xff1a;开始下载请求 •scs&#xff1a;服务器命令符 3&#xff1a;开始下载响应 •n&#xff1a;只有当e 1和s1&#xff0c;否则为0。如果有效则表示字节在d不这样做的数量有效包…

外包干了20天,技术退步明显.......

先说一下自己的情况&#xff0c;大专生&#xff0c;21年通过校招进入杭州某软件公司&#xff0c;干了接近2年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了2年的功能测试…

3个好用的WP免费主题

免费wordpress模板下载 高端大气上档次的免费wordpress主题&#xff0c;首页大图全屏显示经典风格的wordpress主题。 https://www.wpniu.com/themes/289.html 经典的红色免费wordpress主题 这是一款经典的免费wordpress主题&#xff0c;被广泛应用于多个行业的网站。 https…

SQL:窗口函数之OVER()

窗口函数 通用格式 “函数 OVER (PARTITION BY 分组 ORDER BY 排序依据 升降序)”。 这里记录下OVER() 以及搭配LEAD/LAG函数的使用方法&#xff08;执行平台Impala&#xff09; 目录 OVER函数1、不加条件的OVER函数——得到所有的汇总结果2、仅有排序的OVER函数——得到按顺序…

HAL库W25Q16+fatfs文件系统移植

配置时钟树 配置时钟树时钟频率为72 SPI1外挂SPIflash 其他不用改这里挂的是一个W25Q16 文件分类管理 生成原始代码 加入W25Q16的驱动代码 忘记配片选线了&#xff0c;这里加上 /*Configure GPIO pin : PtPin */GPIO_InitStruct.Pin GPIO_PIN_4;GPIO_InitStruct.Mode GPIO_…

《由浅入深学习SAP财务》:第2章 总账模块 - 2.5 科目余额查询理

SAP提供了强大的科目余额查询功能&#xff0c;可以查询科目的借贷方及余额&#xff0c;同时&#xff0c;也可以追溯到明细凭证。在凭证记账后&#xff0c;科目的余额就会同步得到更新。预制凭证是不更新科目余额的。 科目余额查询及追溯的操作步骤 路径&#xff1a;SAP菜单&g…

我的春招求职面经

智能指针在面试时经常被问到&#xff0c;最近自己也在写&#xff0c;有一点思考&#xff0c;于是找到了这样一个题目&#xff0c;可以看看&#xff0c;上面这个代码有什么问题&#xff1f;留言区说出你的答案吧&#xff01; 最后分享一下之前的实习->春招->秋招等文章汇总…

atomgit访问令牌就创建的时候显示一下

AtomGit 是开放原子开源基金会提供的代码托管平台&#xff0c;帮助团队更快、更安全地交付更好的软件。 在创建访问令牌的时候&#xff0c;发现创建之后点不出来令牌字段&#xff0c;不像其它网站会在令牌列表那里显示出来。在“我的令牌”页面只能看到令牌名字和权限&#xff…

设计模式—组合模式

定义: 组合模式&#xff08;Composite Pattern&#xff09;又称为合成模式、部分-整体模式&#xff08;Part-Whole&#xff09;&#xff0c;主要用来描述部分与整体的关系。 定义&#xff1a;将对象组合成树形结构以表示“部分-整体”的层次结构&#xff0c;使用户对单个对象和…

适用于vue3的vant4组件 没有日期时间选择器

项目中需要用到日期和时间一同选择的场景 本来想用 如下代码 van-datetime-picker 发现咋整也不好使 刚开始还以为是引入的问题 后来发现是vant4根本就没这玩应了… <van-datetime-pickerv-model"currentDate"type"datetime"title"选择完整时间&q…

数据结构之排序一

目录 1.排序 一.概念及其分类 二.排序的稳定性 2.插入排序 一.基本思想 二.插入排序的实现 复杂度 稳定性的分析 3.希尔排序 一.预排序代码的实现 二.希尔排序代码实现 复杂度分析 4.clock函数 1.排序 一.概念及其分类 说到排序&#xff0c;我们都不陌生&#x…

向上生长

&#xff08;1&#xff09; 我记得2010年&#xff0c;在中国的苹果应用商店里&#xff0c;充斥的App还有很多&#xff1a;日历App、天气App、电池省电App、记事本App…。但这已经过去了2007-2008-2009三年&#xff0c;这些应用仍然很欢。 我有一个朋友算是中国最早一批开发iOS …

vue.js+element-ui的基础表单

遇到原生的html小型单页应用时&#xff0c;是脱离了vue框架&#xff0c;而我们又想使用vue的语法和element的组件加快我们的开发速度&#xff0c;这个时候就需要引用他们的js了。技术栈即htmlvue.jselement-ui。而使用它们的方法也很简单&#xff0c;引入对应的js和css文件即可…

博世力士乐发布在线配置液压系统3D CAD目录

博世力士乐自1795从美因河畔洛尔的一个铸铁铸造厂到20世纪50年代进入液压市场&#xff0c;2001年&#xff0c;曼内斯曼力士乐与博世自动化的合并&#xff0c;推动了驱动与控制解决方案的所有相关技术无缝集成的新水平。如今博世力士乐独特的行业专业知识已成为量身定制解决方案…

手上积累了一些企业目录,但是没有电话,在企XX天X查也没找到咋办?如何快速精准批量查询其他平台上查不到的企业电话?

在B端业务场景中&#xff0c;长期需要进行拓客。有时候是企业提供客户的联系方式&#xff0c;有时候是销售利用自己的人脉资源&#xff0c;对于资源不多的销售就需要查找到目标客户的联系方式。长期来说&#xff0c;销售都需要进行拓客&#xff0c;自己通过社交&#xff0c;网络…

下载 macOS 系统安装程序的方法

阅读信息&#xff1a; 版本&#xff1a;0.4.20231021 难度&#xff1a;1/10 到 4/10 阅读时间&#xff1a;5 分钟 适合操作系统&#xff1a;10.13, 10.14, 10.15, 11.x, 12.x&#xff0c;13.x, 14 更新2023-10-21 添加Mist的介绍支持版本的更新&#xff0c;13.x&#xff0…

Xilinx FPGA 远程升级时bin和bit文件使用注意

以Spartan-6 ISE开发环境为例。 ISE开发环境支持生成bit和bin格式的程序文件&#xff0c;可以在生成选项进行配置&#xff1a; 把生成的bit文件和bin文件进行二进制比较&#xff0c;发现bit比bin文件头部多了一些内容&#xff08;头部信息&#xff09;&#xff0c;剩余部分完…

web前端笔记+表单练习题+五彩导航栏练习题

web前端笔记 1-骨架快捷方式!enter<!DOCTYPE html><html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>骨架部分</titl…

mysql 事务基本介绍

目录 命令小结 一 MySQL事务的概念 &#xff08;一&#xff09;事务介绍 &#xff08;二&#xff09;事务特点 &#xff08;三&#xff09;事务的ACID特点 1&#xff0c;原子性 1.1 原子性具体形容 1.2 原子性案例 2 &#xff0c;一致性 2.1一致性具体介绍 2.2…