搜索
热搜: NOIP OIer 神牛
查看: 412|回复: 3

memset讲解

[复制链接]

35

主题

54

帖子

4536

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
4536
发表于 2022-10-17 10:15:47 | 显示全部楼层 |阅读模式
memset是一个极其方便的函数,其主要功能是初始化一段内存区域,来自于头文件<cstring>,但是这个函数也是一个相对而言很容易出错的函数,让我们先来看一下他的解释:

C++ Reference对于memset的定义为:
Fill block of memory
Sets the first num bytes of the block of memory pointed by ptr to the specified value (interpreted as an unsigned char).
void memset ( void ptr, int value, size_t num );
ptr: Pointer to the block of memory to fill.
value: Value to be set. The value is passed as an int, but the function fills the block of memory using the unsigned char conversion of this value.
num:Number of bytes to be set to the value.

解释一下其中的三个参数:
Ptr表示一个指针,其指向一段内存
Value表示填充这个区域内存的值
Num表示这段内存区间
这里可以注意一下,我们通常使用sizeof进行num段的表示,sizeof可以快速的获取到所需空间的字节大小,这通常是与类型所决定的。
比如说我们可以给一个数组初始化为0,测试代码如下:
  • #include<iostream>
  • #include<cstring>
  • using namespace std;
  • const int maxn=20;
  • int a[maxn];
  • int main(){
  •     cout<<"memset 使用前:"<<endl;
  •     for(int i=0;i<maxn;i++){
  •         cout<<a[i]<<' ';
  •     }
  •     cout<<endl<<"memset 使用后:"<<endl;
  •     memset(a,0,sizeof(a));
  •     for(int i=0;i<maxn;i++){
  •         cout<<a[i]<<' ';
  •     }
  •     cout<<endl;
  •     return 0;
  • }
结果为:
memset 使用前:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
memset 使用后:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
这样乍一看没什么问题,而且我们的数组在创建的同时自己就已经是一个赋值为0的情况下了,所以这样的操作没有任何问题,我们再拿字符数组进行一下测试,修改代码如下:
  • #include<iostream>
  • #include<cstring>
  • using namespace std;
  • const int maxn=20;
  • char a[maxn];
  • int main(){
  •     cout<<"memset 使用前:"<<endl;
  •     for(int i=0;i<maxn;i++){
  •         cout<<a[i]<<' ';
  •     }
  •     cout<<endl<<"memset 使用后:"<<endl;
  •     memset(a,'A',sizeof(a));
  •     for(int i=0;i<maxn;i++){
  •         cout<<a[i]<<' ';
  •     }
  •     cout<<endl;
  •     return 0;
  • }
结果为:
memset 使用前:
memset 使用后:
A A A A A A A A A A A A A A A A A A A A
因为我们的字符数组在空的情况下对于ASCII码表格的空,因此直接进行输出是没有任何东西的,但是我们在使用memset函数进行集体初始化之后他就变得有了值,如本样例他会变成全部是’A’的内容。
接下来就是问题所在了
如果我们想要将其全部初始化一个自定义的值呢?比如说全部初始化为1,又会怎么样呢?
我们修改测试代码如下:
  • #include<iostream>
  • #include<cstring>
  • using namespace std;
  • const int maxn=20;
  • int a[maxn];
  • int main(){
  •     cout<<"memset 使用前:"<<endl;
  •     for(int i=0;i<maxn;i++){
  •         cout<<a[i]<<' ';
  •     }
  •     cout<<endl<<"memset 使用后:"<<endl;
  •     memset(a,1,sizeof(a));
  •     for(int i=0;i<maxn;i++){
  •         cout<<a[i]<<' ';
  •     }
  •     cout<<endl;
  •     return 0;
  • }
其结果为:
memset 使用前:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
memset 使用后:
16843009 16843009 16843009 16843009 16843009 16843009 16843009 16843009 16843009 16843009 16843009 16843009 16843009 16843009 16843009 16843009 16843009 16843009 16843009 16843009
这与我们所求的结果大相径庭,我们所需要赋值的1去哪了?为什么是16843009这个完全不相干的数字在里面,难道我们的代码出错了么?为了测试,我们又将其内容赋值为了2,结果所有的数据变成了33686018这个值,同样与我们所需求的结果不相同。
这是为什么呢
其原因就是出在我们memset的底层设计上,memset是采用每一个字节每一个字节进行赋值的,也就是说,我们所给出的1,其因为int类型占用四个字节的原因被按照内存分为了四个部分,每一个部分存在一个1,因此经过memset函数初始化之后的数组的内容应该成了这个样子(使用二进制进行表示)
0000 0001 0000 0001 0000 0001 0000 0001 共4个字节,每一个字节占用8个二进制位
我们再来计算一下,
为了方便理解,这里不写直接的运算函数,而是使用C++的bitset函数进行测试,我们直接把数据放入bitset函数中,看一下他转换出来的二进制是否与我们之前的预期相同即可。
  • #include<bits/stdc++.h>
  • using namespace std;
  • int main(){
  •     bitset<32> s(16843009);
  •     cout<<s<<endl;
  •     return 0;
  • }
其结果为:
00000001 00000001 00000001 00000001
(为了方便而直观的表示我稍微用了一下空格做处理,8个二进制一组)
完全一致,因此我们根据这个结论,得出了一个经验:
  • 对于整形等精度在2字节以上的数据类型,除了赋值为0 (十六级进制0x00)与赋值为-1 (十六级进制0xff)之外的数据,不方便进行直接的初始化的结论。
  • 对于字符数组这样的单字节数据类型,可以方便的进行初始化
  • 此外,memset相当于一次从头到尾的遍历,其本身的时间复杂度是O(N)线性级别的,与for()循环遍历整个数组并且依次赋值并没有其他的区别,如果在极其苛刻的时间复杂度条件下这个函数需要慎用。


回复

使用道具 举报

主题

帖子

0

积分

新手上路

Rank: 1

积分
0
发表于 2022-10-17 20:23:09 | 显示全部楼层
怎么进阶管理员啊啊啊
回复

使用道具 举报

主题

帖子

0

积分

新手上路

Rank: 1

积分
0
发表于 2022-10-17 20:24:01 | 显示全部楼层
不是说
积分: 0 ( 总积分=发帖数+精华帖数X5+威望X2+金钱+贡献 )

回复

使用道具 举报

主题

帖子

0

积分

新手上路

Rank: 1

积分
0
发表于 2022-10-17 20:25:10 | 显示全部楼层
我的金钱都一堆了
还是不行
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

津ICP备19006949号-1 | 津公网安备12010102000465号

快速回复 返回顶部 返回列表