博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
正确使用memset
阅读量:4168 次
发布时间:2019-05-26

本文共 3112 字,大约阅读时间需要 10 分钟。

        前段项目中发现一个问题,程序总是在某个dynamic_cast进行动态转换时出异常,查了半天才发现问题原来是出在memset的使用上,虽然问题本身显而易见,但当处于几十万行代码量级中时,就变得不太那么容易定位了。

本文归纳了下使用memset几个需要注意的地方,虽然内容很简单,但也希望对大家有所帮助。
1. memset是以字节为单位,初始化内存块。
当初始化一个字节单位的数组时,可以用memset把每个数组单元初始化成任何你想要的值,比如,
[cpp] 
 
  1. char data[10];  
  2. memset(data, 1, sizeof(data));    // right  
  3. memset(data, 0, sizeof(data));    // right  
而在初始化其他基础类型时,则需要注意,比如,
[cpp] 
 
  1. int data[10];  
  2. memset(data, 0, sizeof(data));    // right  
  3. memset(data, -1, sizeof(data));    // right  
  4. memset(data, 1, sizeof(data));    // wrong, data[x] would be 0x0101 instead of 1  
2. 当结构体类型中包含指针时,在使用memset初始化时需要小心。
比如如下代码中,
[cpp] 
 
  1. struct Parameters {  
  2.           int x;  
  3.           int* p_x;  
  4. };  
  5. Parameters par;  
  6. par.p_x = new int[10];  
  7. memset(&par, 0, sizeof(par));  
当memset初始化时,并不会初始化p_x指向的int数组单元的值,而会把已经分配过内存的p_x指针本身设置为0,造成内存泄漏。同理,对std::vector等数据类型,显而易见也是不应该使用memset来初始化的。
3. 当结构体或类的本身或其基类中存在虚函数时,也需要谨慎使用memset。
这个问题就是在开头项目中发现的问题,如下代码中,
[cpp] 
 
  1. class BaseParameters  
  2. {  
  3. public:  
  4.     virtual void reset() {}  
  5. };  
  6.   
  7. class MyParameters : public BaseParameters  
  8. {  
  9. public:   
  10.     int data[3];  
  11.     int buf[3];  
  12. };  
  13.   
  14. MyParameters my_pars;  
  15. memset(&my_pars, 0, sizeof(my_pars));  
  16. BaseParameters* pars = &my_pars;  
  17.   
  18. //......  
  19.   
  20. MyParameters* my = dynamic_cast<MyParameters*>(pars);  
 
程序运行到dynamic_cast时发生异常。原因其实也很容易发现,我们的目的是为了初始化数据结构MyParameters里的data和buf,正常来说需要初始化的内存空间是sizeof(int) * 3 * 2 = 24字节,但是使用memset直接初始化MyParameters类型的数据结构时,sizeof(my_pars)却是28字节,因为为了实现多态机制,C++对有虚函数的对象会包含一个指向虚函数表(V-Table)的指针,当使用memset时,会把该虚函数表的指针也初始化为0,而dynamic_cast也使用RTTI技术,运行时会使用到V-Table,可此时由于与V-Table的链接已经被破坏,导致程序发生异常。

memset函数详细说明

  1。void *memset(void *s,int c,size_t n)

  总的作用:将已开辟内存空间 s 的首 n 个字节的值设为值 c。

  2。例子

  main(){

  char *s="Golden Global View";

  clrscr();

  memset(s,'G',6);//貌似这里有点问题//

  printf("%s",s);

  getchar();

  return 0;

  } 

  【这个问题相当大,程序根本就运行不下去了,你这里的S志向的是一段只读的内存,而你memset又试图修改它,所以运行时要出错,修改办法char *s修改为char s[]

函数原型

memset(dist , val,size);

char test[64];

memset(test, 0,sizeof(test))、或者memset(test,'A',sizeof(test))没有任何问题,可以完成数组的正确填充。

同比:

int test[64];

memset(test,0,sizeof(test))应该能够将test 数组的每个元素填充为0,经验证,同样可以;

memset(test,1,sizeof(test)),理论上能够test数组的每个元素填充为1,事实是,test数组中出现的是:0x01010101(十六进制)。

为什么填充失败了?

反过头来看memset函数说明,memset是采用将val逐字节填充到dist中去。

当数组为char类型时,sizeof(char)==1,没有问题;

数组为int类型时,sizeof(int)==4,memset 会将数组元素的四个字节均填充为val,对应数值1,就是00000001000000010000000100000001,当转化成二进制时,就不可能是1了。

所以,使用memset填充数组时,需要牢记其是逐个字节填充。

发现memset的这个问题是源于对指针数组和数组指针的理解,两者在c++可谓是相当强大,易于混淆,偶尔捡起来回顾一下,甚好!

鉴于网上诸多关于指针数组、数组指针的用法介绍,我就不再献丑赘述,仅贴上例子,简单明了(其实,网上资源稂莠不齐,错误的讲解很多,关键还需要靠自己验证,才能明白个中道理)

int _tmain(int argc, _TCHAR* argv[])

{
//指针数组
int *p[N];
memset(p,NULL,sizeof(p));
for (int i=0;i<N;i++)
{
p[i]=new int ;
*p[i]=i;
}
for (int i=0;i<N;i++)
{
delete p[i];
p[i]=NULL;
}
int array[8][8];
//数组指针
int (*arrayPointer)[N];
arrayPointer=array;
for (int i=0;i<N;i++)
{
memset(arrayPointer,i,sizeof(int)*N);
arrayPointer++;
}
//int p1[100]等价如下:
int *p1=new int [100];
printf("0x%p\n",p1);
for (int i=0;i<100;i++)
{
p1[i]=i;
printf("%-4d \n",p1[i]);
}

delete p1 [];

return 0;
}

所说的数组和int 类型指针等价,是我自己个人的理解,数组会由编译器自动分配内存,int类型的指针可以由我们控制内存的分配。

对指针数组深入透彻明白以后,利用指针数组管理类的设计模式也就云开雾明了;

对数组指针深入透彻明白以后,利用数组指针操纵矩阵便再无违和之感了。

鄙人不才、献丑。

 c++,openGL,cg  learning on my way 

转载地址:http://vghxi.baihongyu.com/

你可能感兴趣的文章
mongodb数据导入导出以及备份恢复(三)
查看>>
mongodb数据导入导出以及备份恢复
查看>>
python整理二十七——egg文件制作与安装【仅提供链接地址】
查看>>
十一新疆之旅中邂逅的一首诗《黄河,母亲之河》
查看>>
【MongoDB】The description of index(一)
查看>>
MongoDB索引学习笔记
查看>>
【MonogDB】The description of index(二) Embedded and document Index
查看>>
【MonogDB】The description of index(三) Compose and unique Index
查看>>
【MongoDB】The basic operation of Index in MongoDB
查看>>
【MongoDB】The connection between two tables
查看>>
【MongoDB】windows下搭建Mongo主(Master)/从(slave)数据库同步
查看>>
【MongoDB】以前学习mongodb知识的补充
查看>>
【MongoDB】The description of procedure in MongoDB
查看>>
【MongoDB】mongoimport and mongoexport of data (一)
查看>>
【MongoDB】mongoimport and mongoexport of data (二)
查看>>
【MongoDB】mongodump and mongorestore of mogodb
查看>>
【MongoDB】The Access control of mongodb
查看>>
【MongoDB】windows平台搭建Mongo数据库复制集(类似集群)(一)
查看>>
【MongoDB】深入了解MongoDB不可不知的十点
查看>>
【MongoDB】windows平台搭建Mongo数据库复制集(类似集群)(二)
查看>>