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.rhkb.cn/news/279688.html

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

相关文章

京东商品信息采集API商品价格商品详情图主图抓取接口key(提供测试入口)

item_get 获得JD商品详情item_search 按关键字搜索商品item_search_img 按图搜索京东商品&#xff08;拍立淘&#xff09;item_search_shop 获得店铺的所有商品item_history_price 获取商品历史价格信息item_recommend 获取推荐商品列表buyer_order_list 获取购买到的商品订单列…

CMake笔记之GLOB和GLOB_RECURSE的使用方法

CMake笔记之GLOB和GLOB_RECURSE的使用方法 —— 杭州 2024-03-19 夜 文章目录 CMake笔记之GLOB和GLOB_RECURSE的使用方法1.GLOB使用方法2.GLOB对比GLOB_RECURSE 1.GLOB使用方法 在 CMake 中&#xff0c;file(GLOB ...) 命令用于将匹配特定模式的文件列表赋值给变量。这可以用…

MySQL中replace into详解、批量更新、不存在插入存在则更新、replace into的坑

文章目录 一、replace into原理二、replace into的三种形式三、replace into 使用案例3.1、replace into values3.1.1、只有主键且主键冲突3.1.2、有主键有唯一索引且主键冲突3.1.3、有主键有唯一索引且唯一索引冲突(有坑)3.1.4、有主键有唯一索引且与一条主键冲突与另一条唯一…

瑞_Redis_短信登录_基于Session实现登录流程

文章目录 项目介绍1 短信登录1.1 项目准备1.2 基于Session实现登录流程1.2.1 功能流程介绍1.2.1.1 发送短信验证码1.2.1.2 短信验证码登录、注册1.2.1.3 校验登录状态 1.2.2 实现发送短信验证码功能1.2.2.1 页面流程1.2.2.2 代码实现1.2.2.3 测试 1.2.3 实现短信验证码登录、注…

2024年蓝牙耳机哪个好?真人实测告诉你如何选购,避免后悔!

在繁忙的通勤途中&#xff0c;无线蓝牙耳机已成为我们摆脱线缆束缚、享受音乐的理想选择。面对众多品牌和型号&#xff0c;选择合适的耳机似乎并不简单。因此&#xff0c;我精心挑选了几款表现不错的蓝牙耳机&#xff0c;希望我的分享能为你提供有价值的参考。 一、如何挑选蓝牙…

搭建EMQX MQTT服务器(超详细)

MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;服务器是一种实现 MQTT 协议的服务器软件。MQTT 是一种轻量级的、发布/订阅模式的消息传输协议&#xff0c;通常用于物联网&#xff08;IoT&#xff09;应用中的设备通信。MQTT 服务器负责接收来自客户端的消息…

Java_13 反转字符串中的单词 III(方法一将String改为StringBuilder)

一、反转字符串中的单词 III 给定一个字符串 s &#xff0c;你需要反转字符串中每个单词的字符顺序&#xff0c;同时仍保留空格和单词的初始顺序。 示例 1&#xff1a; 输入&#xff1a;s "Lets take LeetCode contest" 输出&#xff1a;"steL ekat edoCteeL …

数据之谜:解读Facebook的用户行为

在当今数字化时代&#xff0c;社交媒体平台已经成为人们生活中不可或缺的一部分&#xff0c;而Facebook作为全球最大的社交网络之一&#xff0c;其背后隐藏着许多数据之谜。本文将深入探讨Facebook的用户行为&#xff0c;并试图解读其中的奥秘。 用户行为数据的收集 Facebook作…

在Arm 虚拟硬件(AVH)部署深度学习OCR算法

AI算法的嵌入式部署 AI算法在独立的设备上运行其实就是行业内的嵌入式AI的概念, 大致过程如下: 开发AI模型, 2.对数据集进行处理, 3.训练AI模型并验证效果, 4.转成ONNX格式(ONNX:万金油中间格式,给模型优化和部署带来了更多可能性)或者借助libtorch或者TensorFlow来部署C++版…

CSS学习(3)-浮动和定位

一、浮动 1. 元素浮动后的特点 脱离文档流。不管浮动前是什么元素&#xff0c;浮动后&#xff1a;默认宽与高都是被内容撑开&#xff08;尽可能小&#xff09;&#xff0c;而且可以设置宽 高。不会独占一行&#xff0c;可以与其他元素共用一行。不会 margin 合并&#xff0c;…

json字符串的数据提取

json的数据提取 学习目标 掌握 json相关的方法(load loads dump dumps)了解 jsonpath的使用(提取 json中的数据) 2 复习什么是json JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式&#xff0c;它使得人们很容易的进行阅读和编写。同时也方便了机器进行解析和…

【LeetCode: 173. 二叉搜索树迭代器 + dfs + 二叉搜索树】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

docker入门(五)—— 小练习,docker安装nginx、elasticsearch

练习 docker 安装 nginx # 搜素镜像 [rootiZbp15293q8kgzhur7n6kvZ home]# docker search nginx NAME DESCRIPTION STARS OFFICIAL nginx …

SpringBoot中使用验证码easy-captcha

easy-captcha使用的大概逻辑: 当一个请求发送到后端服务器请求验证,服务器使用easy-captcha生成一个验证码图片,并通过session将验证信息保存在服务器,当用户登录校验时候,会从ession中取出对比是否一致 但是前后端分离之后 由于跨域问题 以上就无法实现了 下面这种情况没…

SpringBoot打造企业级进销存储系统 第五讲

package com.java1234.repository;import com.java1234.entity.Menu; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query;import java.util.List;/*** 菜单Repository接口*/ public interface MenuReposit…

【机器学习-05】模型的评估与选择

在前面【机器学习-01】机器学习基本概念与建模流程的文章中我们已经知道了机器学习的一些基本概念和模型构建的流程&#xff0c;本章我们将介绍模型训练出来后如何对模型进行评估和选择等 1、 误差与过拟合 学习器对样本的实际预测结果与真实值之间的差异&#xff0c;我们称之…

小米手机官方解锁

1、官方说要申请&#xff0c;还要等几天&#xff0c;反正现在2024-03-20是不需要的&#xff0c;直接下载解锁工具 2、解锁工具下载 3、工具登录后按钮一直灰色&#xff0c;我跑去下载了个驱动根本没用。正确方法是按照上面说的操作后&#xff0c;进入那个有个兔子戴帽子的状态…

Mock.js了解(Mock就是模拟一个后端,Postman模拟前端)

Mock.js 基于 数据模板 生成模拟数据。基于 HTML模板 生成模拟数据。拦截并模拟 ajax 请求。 基本语法 DTD&#xff08;数据模板定义规范&#xff09; 数据模板的每个属性由3部分构成&#xff1a;属性名、生成规则、属性值&#xff08;‘name|rule’: value&#xff09; 属性名…

pytorch 实现线性回归(Pytorch 03)

一 从零实现线性回归 1.1 生成训练数据 原始 计算公式&#xff0c; 我们先使用该公式生成一批数据&#xff0c;然后使用 结果数据去计算 计算 w1, w2 和 b。 %matplotlib inline import random import torch from d2l import torch as d2ldef synthetic_data(w, b, num_ex…

[蓝桥杯 2015 省 B] 生命之树

水一水的入门树形DP #include<iostream> #include<algorithm> #include<vector> using namespace std; using ll long long; #define int long long const int N 2e610; const int inf 0x3f3f3f3f; const int mod 1e97;int n; int w[N]; vector<vecto…