memset详解 设置无穷大INF
memest原型 (please type "man memset" in your shell)
void *memset(void *s, int c, size_t n);
memset:作用是在一段内存块中填充某个给定的值,它对较大的结构体或数组进行清零操作的一种最快方法。
常见的三种错误
第一: 搞反了c 和 n的位置.
一定要记住 如果要把一个char a[20]清零, 一定是 memset(a, 0, 20)
而不是 memset(a, 20, 0) ;
第二: 过度使用memset
我想这些程序员可能有某种心理阴影, 他们惧怕未经初始化的内存, 所以他们会写出这样的代码:
char buffer[20];
memset(buffer, 0, sizeof((char)*20));
strcpy(buffer, "123");
这里的memset是多余的. 因为这块内存马上就被覆盖了, 清零没有意义.
第三: 其实这个错误严格来讲不能算用错memset, 但是它经常在使用memset的场合出现
int some_func(struct something *a){
…
…
memset(a, 0, sizeof(a));
…
}
问:为何要用memset置零?memset( &Address, 0, sizeof(Address));经常看到这样的用法,其实不用的话,分配数据的时候,剩余的空间也会置零的。
答: 1.如果不清空,可能会在测试当中出现野值。 你做下面的试验看看结果()
char buf[5];
CString str,str1;
//memset(buf,0,sizeof(buf)); for(int i = 0;i<5;i++)
{ str.Format(“%d “,buf[i]); str1 +=str ; } TRACE(“%s\r\n“,str1)
2.其实不然!特别是对于字符指针类型的,剩余的部分通常是不会为0的,不妨作一个试验,定义一个字符数组,并输入一串字符,如果不用memset实现清零,使用MessageBox显示出来就会有乱码(0表示NULL,如果有,就默认字符结束,不会输出后面的乱码)
问:
如下demo是可以的,能把数组中的元素值都设置成字符1,
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char a[5];
memset(a,'1',5);
for(int i = 0;i < 5;i++)
cout<<a[i]<<" ";
system("pause");
return 0;
}
而,如下程序想吧数组中的元素值设置成1,却是不可行的
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
int a[5];
memset(a,1,5);//这里改成memset(a,1,5 *sizeof(int))也是不可以的
for(int i = 0;i < 5;i++)
cout<<a[i]<<" ";
system("pause");
return 0;
}
问题是:
1,第一个程序为什么可以,而第二个不行,
2,不想要用for,或是while循环来初始化int a[5];能做到吗?(有没有一个像memset()这样的函数初始化)
答:
1.因为第一个程序的数组a是字符型的,字符型占据内存大小是1Byte,而memset函数也是以字节为单位进行赋值的,所以你输出没有问题。而第二个程序a是整型的,使用memset还是按字节赋值,这样赋值完以后,每个数组元素的值实际上是0x01010101即十进制的16843009。你看看你输出结果是否这样?
2.如果用memset(a,1,20);
就是对a指向的内存的20个字节进行赋值,每个都用ASCII为1的字符去填充,转为二进制后,1就是00000001,占一个字节。一个INT元素是4字节,合一起就是1000000010000000100000001,就等于16843009,就完成了对一个INT元素的赋值了。
总结:
因为char是1字节,memset是按照字节赋值的,相当于把每个字节都设为那个数,所以char型的数组可赋任意值,int是4个字节,当memset(,1,sizeof()); 1相当于ASSCII码的1,1转为二进制00000001,当做一字节,一字节8位,int为4字节,所以初始化完每个数为00000001000000010000000100000001 = 16843009 .
memset(,0xff,sizeof()),0xff转为二进制11111111,int为4字节所以最后为11111111111111111111111111111111为-1。(化为二进制补位,然后再赋值)。可以全赋值为0,0的二进制位000000000000000000000000000000000,还可以是-1,-1的二进制就是11111111111111111111111111111111,所以memset可以直接初始化(0,-1);
例如:0xff转为二进制位11111111,正好是一位,0x1f小于0xff,而0x59也小于0xff,所以这些都可以用来初始化,只要能填满8位的二进制,就可以了。
如果你想初始最大化,第一位为符号位,不能为1,剩下全是1,也就是7个1,1111111化为十六进制正好为0x7f,所以memset(,0x7f,sizeof());就可以了
Memset中无穷大常量的设定技巧
如果问题中各数据的范围明确,那么无穷大的设定不是问题,在不明确的情况下,很多程序员都取0x7fffffff作为无穷大,因为这是32-bit int的最大值。如果这个无穷大只用于一般的比较(比如求最小值时min变量的初值),那么0x7fffffff确实是一个完美的选择,但是在更多的情况下,0x7fffffff并不是一个好的选择。
很多时候我们并不只是单纯拿无穷大来作比较,而是会运算后再做比较,例如在大部分最短路径算法中都会使用的松弛操作:
if (d[u]+w[u][v]<d[v]) d[v]=d[u]+w[u][v];
我们知道如果u,v之间没有边,那么w[u][v]=INF,如果我们的INF取0x7fffffff,那么d[u]+w[u][v]会溢出而变成负数,我们的松弛操作便出错了,更一般的说,0x7fffffff不能满足“无穷大加一个有穷的数依然是无穷大”,它变成了一个很小的负数。
除了要满足加上一个常数依然是无穷大之外,我们的常量还应该满足“无穷大加无穷大依然是无穷大”,至少两个无穷大相加不应该出现灾难性的错误,这一点上0x7fffffff依然不能满足我们。
所以我们需要一个更好的家伙来顶替0x7fffffff,最严谨的办法当然是对无穷大进行特别处理而不是找一个很大很大的常量来代替它(或者说模拟它),但是这样会让我们的编程过程变得很麻烦。在我读过的代码中,最精巧的无穷大常量取值是0x3f3f3f3f,我不知道是谁最先开始使用这个精妙的常量来做无穷大,不过我的确是从一位不认识的ACMer(ID:Staginner)的博客上学到的,他/她的很多代码中都使用了这个常量,于是我自己也尝试了一下,发现非常好用,而当我对这个常量做更深入的分析时,就发现它真的是非常精巧了。
0x3f3f3f3f的十进制是1061109567,也就是10^9级别的(和0x7fffffff一个数量级),而一般场合下的数据都是小于10^9的,所以它可以作为无穷大使用而不致出现数据大于无穷大的情形。
另一方面,由于一般的数据都不会大于10^9,所以当我们把无穷大加上一个数据时,它并不会溢出(这就满足了“无穷大加一个有穷的数依然是无穷大”),事实上0x3f3f3f3f+0x3f3f3f3f=2122219134,这非常大但却没有超过32-bit int的表示范围,所以0x3f3f3f3f还满足了我们“无穷大加无穷大还是无穷大”的需求。
最后,0x3f3f3f3f还能给我们带来一个意想不到的额外好处:如果我们想要将某个数组清零,我们通常会使用memset(a,0,sizeof(a))这样的代码来实现(方便而高效),但是当我们想将某个数组全部赋值为无穷大时(例如解决图论问题时邻接矩阵的初始化),就不能使用memset函数而得自己写循环了(写这些不重要的代码真的很痛苦),我们知道这是因为memset是按字节操作的,它能够对数组清零是因为0的每个字节都是0,现在好了,如果我们将无穷大设为0x3f3f3f3f,那么奇迹就发生了,0x3f3f3f3f的每个字节都是0x3f!所以要把一段内存全部置为无穷大,我们只需要memset(a,0x3f,sizeof(a))。
所以在通常的场合下,0x3f3f3f3f真的是一个非常棒的选择。
memset详解 设置无穷大INF的更多相关文章
- c语言memset详解
void *memset(void *s, int ch, size_t n);(int ch可以是char或int) 将s所指向的某一块内存中的每个字节的内容全部设置为ch指定的ASCII值, 块的 ...
- 微信小程序上拉加载:onReachBottom详解+设置触发距离
前端经常遇到上拉加载更多的需求,一般还涉及到翻页.小程序里已经给了下拉到底的触发方法onReachBottom(),这里记录下怎样使用这个方法实现下拉加载更多,有需要的直接看代码,有详细注释: 1.首 ...
- 【转】Eclipse Java注释模板设置详解
Eclipse Java注释模板设置详解 设置注释模板的入口: Window->Preference->Java->Code Style->Code Template 然后 ...
- UITextView的使用详解
//初始化并定义大小 UITextView *textview = [[UITextView alloc] initWithFrame:CGRectMake(20, 10, 280, 30)]; te ...
- 【转】UITextView的使用详解
//初始化并定义大小 UITextView *textview = [[UITextView alloc] initWithFrame:CGRectMake(20, 10, 280, 30)]; te ...
- Vue1.0用法详解
Vue.js 不支持 IE8 及其以下版本,因为 Vue.js 使用了 IE8 不能实现的 ECMAScript 5 特性. 开发环境部署 可参考使用 vue+webpack. 基本用法 1 2 3 ...
- Mysql资料 用户权限详解
目录 一.MySQL权限详解 设置MySQL用户资源限制 用户资源限制执行操作 二.MySQL权限级别介绍 MySQL权限级别 MySQL创建权限 MySQL删除与插入权限 MySQL修改与触发器权限 ...
- memset函数详解
语言中memset函数详解(2011-11-16 21:11:02)转载▼标签: 杂谈 分类: 工具相关 功 能: 将s所指向的某一块内存中的每个字节的内容全部设置为ch指定的ASCII值, 块的大 ...
- V4L2 API详解 <二> Camera详细设置【转】
转自:http://blog.sina.com.cn/s/blog_602f87700101bf36.html 作者: Sam (甄峰) sam_code@hotmail.com Camera的 ...
随机推荐
- Spring 拦截器实现+后台原理(MethodInterceptor)
MethodInterceptor MethodInterceptor是AOP项目中的拦截器(注:不是动态代理拦截器),区别与HandlerInterceptor拦截目标时请求,它拦截的目标是方法. ...
- Bayesian generalized linear model (GLM) | 贝叶斯广义线性回归实例
一些问题: 1. 什么时候我的问题可以用GLM,什么时候我的问题不能用GLM? 2. GLM到底能给我们带来什么好处? 3. 如何评价GLM模型的好坏? 广义线性回归啊,虐了我快几个月了,还是没有彻底 ...
- mismatch详解
mismatch到底只是一个碱基替换,还是也包括了插入缺失? If two sequences in an alignment share a common ancestor, mismatches ...
- H3C S6800交换机 BCM shell命令
H3C S6800交换机 BCM shell命令 http://wgli978.blog.163.com/blog/static/13592877220172315858831/ <H3C> ...
- Confluence 6 创建一个空间
在 Confluence 中并不限制你可以创建多少空间.你可以选择为你每一个小组,项目都创建一个空间,或者你也可以将这 2 者混合在一起.所有的这些都基于你的需求来决定的. 每一个 Confluenc ...
- hdu5992 kdt
题意:n个旅馆,每个有花费,m个查询,查询在某个点在c花费范围内的距离最小的旅馆 题解:kdt,建成四维,坐标两维,花费一维,id一维,实际上建树只用前两维,正常的查询,如果满足条件在更新答案即可 / ...
- P2756 飞行员配对方案问题
题目背景 第二次世界大战时期.. 题目描述 英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2 名飞行员,其中1 名是英国飞行员,另1名是外 ...
- ArrayList详细
(IList值的集合 索引访问 ArrayList类IDictionary:键/值对 HashTable类 可变的集合 长度自动增长) ICollection-----IEnumerable--- I ...
- 从零搭建和配置OSX开发环境
对于每一名开发者来说,更换系统或者更换电脑的时候,都免不了花上不短的时间去折腾开 发环境的问题.我本人也是三番两次,深知这个过程的繁琐.所有,根据我自己以往的经验, 以及参考一下他人的意见,整理一下关 ...
- NOI1995石子合并&多种石子合并
题目描述 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分. 试设计出1个算法,计算出将N堆石子合并成1 ...