<--
如果你觉得我写的分享对你有帮助,请点个赞
<--
如果你觉得我写得有错误,请点个踩并在评论区指出!
<--
如果你想在之后再次看这篇分享,请点下这个星星!
memset的坑人之处
WHY MEMSET IS KENGDIE
不知道你有没有遇到过这种情况:
明明用 memset
初始化了数组,为什么之后的程序里,数组里的数好像并没被初始化呢?
目录
第一章 memset定义
- 1.1 memset的定义
- 1.2 memset常见用法1
- 1.3 memset常见用法2
第二章 memset易错点
- 2.1 小明的疑惑
- 2.2 memset的坑点
- 2.3 memset特性利用
本文中的 int
类型变量均占用 4 个字节,且数组类型默认为 int
。
本文中的 char
类型变量均占用 1 个字节。
第一章 memset定义
1.1 memset的定义
memset
定义:
memset
是计算机中 C/C++ 语言初始化函数。作用是将某一块内存中的内容全部设置为指定的值, 这个函数通常为新申请的内存做初始化工作。
memset
在头文件string.h
或cstring
中作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法。
memset
函数按字节对内存块进行初始化。
1.2 memset常见用法1
memset
可用于给数组赋值。
比如 memset(a, 0, sizeof(a));
,就是先找到 a
的首地址,向后 sizeof(a)
个字节,将范围内的区域赋值。
结果就是,a 数组的每一项都被赋值成了 0。
其他用法:
memset(a, 0, sizeof(int) * n);
就是将数组 a
的前 n 个元素赋值成 0。
memset(a + m, 0, sizeof(int) * n);
就是从数组 a[m]
开始,将后面 n 个元素赋值成 0。注意不要写成 memset(a + sizeof(int) * m, 0, sizeof(int) * n);
。
单变量初始化:
memset(&a, 0x3f, sizeof(a));
1.3 memset常见用法2
memset
可用于给字符串赋值。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int main(){
char s[12] = "HelloWorld\n";
cout << s;
cout << "发现脏话“Hello”,即将屏蔽\n";
memset(s, '*', sizeof(char) * 5);
cout << s;
return 0;
}
输出:
HelloWorld
发现脏话“Hello”,即将屏蔽
*****World
Hello什么时候是脏话了。。。
memset(s, '*', sizeof(char) * 5);
意思就是将 s
的前 5 个字符修改成 '*'
。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int main(){
char s[12] = "HelloWorld\n";
cout << s;
cout << "发现脏话“World”,即将屏蔽\n";
memset(s + 5, '*', sizeof(char) * 5);
cout << s;
return 0;
}
输出:
HelloWorld
发现脏话“World”,即将屏蔽
Hello*****
这里也类似,从 s[5]
开始,给后面 5 个字符赋值。
那么这样就能总结出规律:memset(s + i, (数值), sizeof((类型)) * j);
代表将 s
里第 i
个值开始,连续将后面 j
个值赋值。
第二章 memset易错点
2.1 小明的疑惑
小明(万能工具人小明)最近写了一个程序,程序中有这样一个函数,函数的目的是初始化数组,将数组 a
的每一项更新成 1。
#include <iostream>
#include <cstring>
using namespace std;
int a[100005];
void init(){
memset(a, 1, sizeof(a));
}
小明写完后兴高采烈地提交了程序,喜提WA。
小明十分不解,他的代码的其余部分和题解完全一样,为什么答案会错呢?(抄题解的屑小明)
输出一下 a
数组,发现 a
的每一项没有被赋值成 1,而是 16843009。
#include <iostream>
#include <cstring>
using namespace std;
int a[100005];
void init(){
memset(a, 1, sizeof(a));
}
int main(){
init();
for(int i = 0; i < 100005; i++) printf("%d ", a[i]);
return 0;
}
2.2 memset的坑点
memset
函数按字节对内存块进行初始化。
意思是说,memset(s, i, sizeof(s));
其中 i 的范围应在二进制的 00000000~11111111 间,因为该函数只能取 i 的后八位赋值给你所输入的范围的每个字节。
就举小明的例子来说,他的数组每一项被初始化为了 16843009,在二进制里是:
00000001 00000001 00000001 00000001
再看看 1 的二进制:
00000000 00000000 00000000 00000001
memset
只保留了 1 最后一字节,
00000000 00000000 00000000 00000001
然后填入数组内,使得数组内元素的值被赋值成了:
00000001 00000001 00000001 00000001
这就是为什么会初始化错误了。
那么,memset(a, 54321, sizeof(a));
会使 a
数组的每一项变成多少呢?
54321 的二进制:
00000000 00000000 11010100 00110001
保留最后一字节:
00000000 00000000 11010100 00110001
赋值:
00110001 00110001 00110001 00110001
也就是 825307441。
2.3 memset特性利用
以下是堆优化Dijkstra模板:
int dijkstra(){
memset(dist, 0x3f, sizeof(dist));
dist[1] = 0;
priority_queue<PII, vector<PII>, greater<PII>> heap;
heap.push({0, 1});
while(heap.size()){
auto t = heap.top();
heap.pop();
int ver = t.second, distance = t.first;
if(st[ver]) continue;
st[ver] = true;
for(int i = h[ver]; i != -1; i = ne[i]){
int j = e[i];
if(dist[j] > dist[ver] + w[i]){
dist[j] = dist[ver] + w[i];
heap.push({dist[j], j});
}
}
}
if(dist[n] == 0x3f3f3f3f) return -1;
return dist[n];
}
这里,memset(dist, 0x3f, sizeof(dist));
会将 dist
的每一项变为 0x3f3f3f3f,和 if(dist[n] == 0x3f3f3f3f) return -1;
匹配。
备注
本分享为作者原创,如有雷同,纯属巧合。
#include <iostream> #include <cstring> #include <algorithm> using namespace std; int main(){ char s[9] = "yxcyyds\n"; cout << s; cout << "发现脏话“yxc”,即将屏蔽\n"; memset(s, '*', sizeof(char) * 3); cout << s; return 0; }
#
龟速逃az
如果你觉得yxc是脏话,请点个赞;如果你觉得yxc不是脏话,请点个踩#栈
addd
栈:我干了什么
赞:我被遗忘了吗
学以致用,给个赞
那我只能点踩了咯~(逃)被这玩意坑到现在了QAQ
LaTeX 炸了:)
?我这边还行啊
《如有雷同,纯属巧合。》
qwq