精华内容
下载资源
问答
  • memset初始化std::string对象时,按字节顺序将std::string对象所在空间清零,破坏了std::string对象的成员结构,使Myroxy指针资源变为野指针,操作其迭代器会出现不可预知的异常,在存储字符串时可能分配了不必要的...
  • 段错误之 memset 对类对象的误用

    千次阅读 2015-12-21 23:03:17
    如果此时对类对象使用 memset 置空,那么虚函数表指针也会被置空,当使用 delete 释放对象的时候,就会根据虚函数表指针指向的空间去释放虚函数表,那么此时就发生了对内存空间的不正确操作,出现了段错误。...

    1.问题描述

    实际项目中,定义一个如下的基类和子类,均包含有虚函数。

    //基类
    class OriginalTask {
    public:
        OriginalTask() {};
        virtual ~OriginalTask() {};
        virtual bool readFromFileInit(TiXmlElement* const task_element) = 0;
        virtual string createResultFile(TiXmlElement* const task_element, Task* task){}
    };
    
    //子类
    class DICCUOriginalTask : public OriginalTask {
    public:
        bool readFromFileInit(TiXmlElement* const task_element){};
    	string createResultFile(TiXmlElement* const task_element, Task* task){};
        DICCUOriginalTask(){};
        ~DICCUOriginalTask(){};
      
    public:
    	uint8 algorithm;             			
    	uint8 encodeType;       
        uint32 cipher_num;      
        uint32 cipher_len;     
    };
    

    使用 new 定义一个DICCUOriginalTask的对象指针之后,使用memset将对象实体置为0之后,在使用delete析构该对象,就会出现莫名其妙的段错误。

    DICCUOriginalTask* dicOriTask=new DICCUOriginalTask;
    memset(dicOriTask,0,sizeof(DICCUOriginalTask));
    //对dicOriTask的各种处理均未出错
    delete dicOriTask;//Segmentation fault (core dumped)
    

    2.问题分析

    上面的错误,让我百思不得其解。段错误是指访问的内存超出了系统给这个程序所设定的内存空间,考虑到导致段错误的常见两种情况是:
    (1)访问系统保护的内存地址,如向地址0写入数据。
    (2)内存越界,如数组越界。

    当然还有其他的情况,如访问了不存在的内存地址。总而言之,段错误的出现是因为对内存空间的不正确操作。

    基于对段错误的理解,本以为是对 dicOriTask处理过程中有不正确的操作,但是几经周折排查后并未发现错误,莫名其妙,原来问题很简单。是memset对类对象的误用。

    memset 一般用于 C 语言中对结构体的对象进行置空操作,我却沿用到了 C++ 的类对象。如果类包含有虚函数,那么类对象就会包含有虚函数表指针。如果此时对类对象使用 memset 置空,那么虚函数表指针也会被置空,当使用 delete 释放类对象的时候,就会根据虚函数表指针指向的空间去释放虚函数表,那么此时就发生了对内存空间的不正确操作,出现了段错误。

    这就是使用 memset 对类对象的误用。即 delete 一个被 memset 为空的带有虚函数的类对象指针时,就会出现段错误。

    3.解决办法

    不用使用 memset 对类对象进行操作,使用类的构造函数对对象进行初始化。

    **心得:**对一个问题感到莫名其妙,那是因为我们知道的太少了。

    展开全文
  • memset

    2015-02-18 19:28:18
    memset 函数是内存赋值函数,用来给某一块内存空间进行赋值的。    其原型是:void*memset(void *_Dst, int _Val, size_t _Size);    使用时在文件头加上#include"stdlib.h" 。    _Dst是目标起始地址...

    memset 函数是内存赋值函数,用来给某一块内存空间进行赋值的。

     

      其原型是:void*memset(void *_Dst, int  _Val, size_t _Size);

     

      使用时在文件头加上#include"stdlib.h" 。

     

      _Dst是目标起始地址,_Val是要赋的值,_Size是要赋值的字节数 。



      例1:

           charstr[9];

           我们用memset给str初始化为“00000000”,用法如下

           memset(str,0,8);

             

      注意,memset是逐字节 拷贝的。



      下面再看一个例子:



        例2:

           intnum[8];

           我们用memset给str初始化为{1,1,1,1,1,1,1,1},

          memset(num,1,8);//这样是不对的



         一个int是4个字节的,8个int是32个字节,所以首先要赋值的长度就不应该为8而是32。

         因为memset是 逐字节 拷贝,以num为首地址的8字节空间都被赋值为1,

         即一个int变为0X0000000100000001 00000001 00000001,显然,把这个数化为十进制不会等于1的。

     memset函数常用来初始化内存的数据,比如memset(data,0x00,sizeof(date))等,我让一个同事写了一个函数接口,用来解码二进制文件,当我进入代码合入的时候,发现

    该接口函数执行到return 0语句之后就奔溃了,gdb之后发现没有多余的信息,只提示#0  0x0000000000000000 in ?? (),我百思不得其解,最重要的是,如果函数在单个进程里调用,不会发现该问题,执行成功,而我的程序是多线程,在多线程里就会崩溃。由于没有崩溃的具体位置,只能一个个排除用到内存的函数了,后来发现

    有个变量定义为,char ipadd[3][50];然后用memset(ipadd,0x00,500);进行初始化,500超出了ipadd的长度范围,导致内存要回收的时候,有部分的数据无法处理,导致崩溃。看来线程的内存管理还是更复杂严格。因为一个不经意的小错误,浪费了许多宝贵的时间。

        内存有多长就初始化为多长,如果超过规定的长度,那么超出的部分就没有安全的保证,很可能其他的线程刚好访问到这个,而导致崩溃!

    memset 函数是内存赋值函数,用来给某一块内存空间进行赋值的。

    其原型是:void* memset(void *_Dst, int _Val, size_t _Size);

    使用时在文件头加上#include "stdlib.h" 。

    _Dst是目标起始地址,_Val是要赋的值,_Size是要赋值的字节数 。


    例1:

           charstr[9];

           我们用memset给str初始化为“00000000”,用法如下

          memset(str,0,8);

             

    注意,memset是逐字节拷贝的。


    下面再看一个例子:


        例2:

           intnum[8];

           我们用memset给str初始化为{1,1,1,1,1,1,1,1},

          memset(num,1,8);//这样是不对的


         一个int是4个字节的,8个int是32个字节,所以首先要赋值的长度就不应该为8而是32。

         因为memset是 逐字节 拷贝,以num为首地址的8字节空间都被赋值为1,

         即一个int变为0X0000000100000001 00000001 00000001,显然,把这个数化为十进制不会等于1的。


         所以,在memset使用时要千万小心,在给char以外的数组赋值时,只能初始化为0或者-1。因为在计算机里,0的二进制都是0,-1的二进制都是1。


         最近才发现memset的这个问题,之所以要写这篇文章,是因为我在自己的DES算法里多处用到了memset,而我当时却不知memset有这个问题,特此记下,引以为鉴。

    ---------------------

    例如:

    #include "stdio.h"
    #include <string.h> 
    int main()

       char s[100]="Golden Global View";


       memset(s,'G',6); 
       printf("%s",s); 
       
       getchar(); 
       return 0; 
    }

    结果

    ----------

    函数原型:memset(void *buffer,int c,size_t n);
    1、size_t 是字节为单位
    内存中一个INT型4个字节,如下:
    int b ;
    memset ( &b, 1, 4);
    运行后:b = 0x01010101;
    2、深入体会以字节为单位
    如下代码:
    char chA[10];
    memset(chA, 1, 10 );
     注意对比memset函数第一个参数与上小节中的差异!一个带取地址符“&”,一个不带。为啥呢?因为memset函数是以字节为单位,若参数不是字节,则以地址进行操作。所以第一节中会出现那样的运行结果!所以,结构体等进行memset操作时,也要加取地址符。
    3、操作数个数
    memset最后一个参数是操作个数,数组或者非字节变量要注意,建议使用sizeof()进行操作. memset为内存填充函数,包含在<string.h>头文件中,可以用它对一片内存空间进行初始化,其原型为

     

    void *memset(void *s, int v, size_t n);

    英文释义如下:

    Copies the value v (converted to typeunsigned char) to the first n bytes pointed to by s; returns s.
     
    这里s可以是数组名,也可以是指向某一内在空间的指针;v为要填充的值;n为要填充的字节数,通常为sizeof(s);

    使用memset时要注意的是,memset是逐字节进行填充,所以s一般为char *型。对于其它类型的s,可以填充的值有两个,0和-1。这是因为计算机中用二进制补码表示数字,0和二进制补码为全0,-1的二进制补码为全1。如果要初始化为其它的值,可以用一个for循环,如下:

    for (int i=0; i<n; i++)
    {
        s[i] = v;
    }

    在使用memset()函数初始化内存空间是,代码如下:

    int main(void)

    {

             char*pBuf =0;

             if(!(pBuf=(char*)malloc(sizeof(char)*100+1)))

             {

                       //showerror information.

                       exit(1);

             };

             memset(pBuf,0, strlen(pBuf));

             free(pBuf);

             return0;

    }

    在vs2010下按F5启动调试,报错如下:

    Windows 已在 Test.exe 中触发一个断点。


    其原因可能是堆被损坏,这说明 Test.exe 中或它所加载的任何 DLL 中有 Bug。


    原因也可能是用户在 Test.exe 具有焦点时按下了 F12。


    输出窗口可能提供了更多诊断信息。

    运行报错,原因在于

    memset(pBuf, 0, strlen(pBuf));

    原本想通过strlen(pBuf);获取pBuf字符串的长度,但事与愿违,strlen(pBuf)=105,由此可知运行时报错是正常的。
    因此,strlen只关心存储的数据内容,不关心空间的大小和类型。事实上,strlen(pBuf)输出结果105实际上每次运行可能不一样,这取决于pBuf里面存了什么(从pBuf[0]开始直到遇到第一个'\0'结束);

    Strlen函数说明

    strlen(...)是函数,要在运行时才能计算。
    参数必须是字符型指针(char*), 且必须是以'\0'结尾的。当数组名作为参数传入时,实际上数组就退化成指针了。
    int ac[10];
    cout<<sizeof(ac)<<endl;
    cout<<strlen(ac)<<endl; (ac相当于一个指针,但是strlen只能接受char*类型,所以编译时出错)
    它的功能是:返回字符串的长度。该字符串可能是自己定义的,也可能是内存中随机的,该函数实际完成的功能是从代表该字符串的第一个地址开始遍历,直到遇到结束符'\0'。返回的长度大小不包括'\0'。

    另外,文章http://blog.pfan.cn/vfdff/33507.html详细说明了关于malloc和free函数的用法。原文如下:

    个人总结

    在C语言的学习中,对内存管理这部分的知识掌握尤其重要!之前对C中的malloc()和free()两个函数的了解甚少,只知道大概该怎么用——就是malloc然后free就一切OK了。当然现在对这两个函数的体会也不见得多,不过对于本文章第三部分的内容倒是有了转折性的认识,所以
    写下这篇文章作为一个对知识的总结。这篇文章之所以命名中有个“浅谈”的字眼,也就是这个意思了!希望对大家有一点帮助!

    如果不扯得太远的话(比如说操作系统中虚拟内存和物理内存如何运做如何管理之类的知识等),我感觉这篇文章应该是比较全面地谈了一下malloc()和free().这篇文章由浅入深(不见得有多深)分三个部分介绍主要内容。

    废话了那么多,下面立刻进入主题================》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》


    一、malloc()和free()的基本概念以及基本用法:

    1、函数原型及说明:

    void *malloc(long NumBytes):该函数分配了NumBytes个字节,并返回了指向这块内存的指针。如果分配失败,则返回一个空指针(NULL)。

    关于分配失败的原因,应该有多种,比如说空间不足就是一种。

    void free(void *FirstByte): 该函数是将之前用malloc分配的空间还给程序或者是操作系统,也就是释放了这块内存,让它重新得到自由。

    2、函数的用法:

    其实这两个函数用起来倒不是很难,也就是malloc()之后觉得用够了就甩了它把它给free()了,举个简单例子:

    // Code...

    char *Ptr = NULL;

    Ptr = (char *)malloc(100 * sizeof(char));

    if (NULL == Ptr)
    {
    exit (1);
    }

    gets(Ptr);

    // code...

    free(Ptr);

    Ptr = NULL;

    // code...

    就是这样!当然,具体情况要具体分析以及具体解决。比如说,你定义了一个指针,在一个函数里申请了一块内存然后通过函数返回传递给这个指针,那么也许释放这块内存这项工作就应该留给其他函数了。

    3、关于函数使用需要注意的一些地方:

    A、申请了内存空间后,必须检查是否分配成功。

    B、当不需要再使用申请的内存时,记得释放;释放后应该把指向这块内存的指针指向NULL,防止程序后面不小心使用了它。

    C、这两个函数应该是配对。如果申请后不释放就是内存泄露;如果无故释放那就是什么也没有做。释放只能一次,如果释放两次及两次以上会

    出现错误(释放空指针例外,释放空指针其实也等于啥也没做,所以释放空指针释放多少次都没有问题)。

    D、虽然malloc()函数的类型是(void*),任何类型的指针都可以转换成(void *),但是最好还是在前面进行强制类型转换,因为这样可以躲过一

    些编译器的检查。


    二、malloc()到底从哪里得来了内存空间:

    1、malloc()到底从哪里得到了内存空间?答案是从堆里面获得空间。也就是说函数返回的指针是指向堆里面的一块内存。操作系统中有一个记录空闲内存地址的链表。当操作系统收到程序的申请时,就会遍历该链表,然后就寻找第一个空间大于所申请空间的堆结点,然后就将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。就是这样!

    说到这里,不得不另外插入一个小话题,相信大家也知道是什么话题了。什么是堆?说到堆,又忍不住说到了栈!什么是栈?下面就另外开个小部分专门而又简单地说一下这个题外话:

    2、什么是堆:堆是大家共有的空间,分全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是用户分配的空间。堆在操作系统对进程初始化的时候分配,运行过程中也可以向系统要额外的堆,但是记得用完了要还给操作系统,要不然就是内存泄漏。

    什么是栈:栈是线程独有的,保存其运行状态和局部自动变量的。栈在线程开始的时候初始化,每个线程的栈互相独立。每个函数都有自己的栈,栈被用来在函数之间传递参数。操作系统在切换线程的时候会自动的切换栈,就是切换SS/ESP寄存器。栈空间不需要在高级语言里面显式的分配和释放。

    以上的概念描述是标准的描述,不过有个别语句被我删除,不知道因为这样而变得不标准了^_^.

    通过上面对概念的描述,可以知道:

    栈是由编译器自动分配释放,存放函数的参数值、局部变量的值等。操作方式类似于数据结构中的栈。

    堆一般由程序员分配释放,若不释放,程序结束时可能由OS回收。注意这里说是可能,并非一定。所以我想再强调一次,记得要释放!

    注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。(这点我上面稍微提过)


    所以,举个例子,如果你在函数上面定义了一个指针变量,然后在这个函数里申请了一块内存让指针指向它。实际上,这个指针的地址是在栈上,但是它所指向的内容却是在堆上面的!这一点要注意!所以,再想想,在一个函数里申请了空间后,比如说下面这个函数:

    // code...

    void Function(void)
    {
    char *p = (char *)malloc(100 * sizeof(char));
    }

    就这个例子,千万不要认为函数返回,函数所在的栈被销毁指针也跟着销毁,申请的内存也就一样跟着销毁了!这绝对是错误的!因为申请的内存在堆上,而函数所在的栈被销毁跟堆完全没有啥关系。所以,还是那句话:记得释放!

    3、free()到底释放了什么

    这个问题比较简单,其实我是想和第二大部分的题目相呼应而已!哈哈!free()释放的是指针指向的内存!注意!释放的是内存,不是指针!这点非常非常重要!指针是一个变量,只有程序结束时才被销毁。释放了内存空间后,原来指向这块空间的指针还是存在!只不过现在指针指向的内容的垃圾,是未定义的,所以说是垃圾。因此,前面我已经说过了,释放内存后把指针指向NULL,防止指针在后面不小心又被解引用了。非常重要啊这一点!

    好了!这个“题外话”终于说完了。就这么简单说一次,知道个大概就可以了!下面就进入第三个部分:

    三、malloc()以及free()的机制:

    这个部分我今天才有了新的认识!而且是转折性的认识!所以,这部分可能会有更多一些认识上的错误!不对的地方请大家帮忙指出!

    事实上,仔细看一下free()的函数原型,也许也会发现似乎很神奇,free()函数非常简单,只有一个参数,只要把指向申请空间的指针传递

    给free()中的参数就可以完成释放工作!这里要追踪到malloc()的申请问题了。申请的时候实际上占用的内存要比申请的大。因为超出的空间是用来记录对这块内存的管理信息。先看一下在《UNIX环境高级编程》中第七章的一段话:

    大多数实现所分配的存储空间比所要求的要稍大一些,额外的空间用来记录管理信息——分配块的长度,指向下一个分配块的指针等等。这就意味着如果写过一个已分配区的尾端,则会改写后一块的管理信息。这种类型的错误是灾难性的,但是因为这种错误不会很快就暴露出来,所以也就很难发现。将指向分配块的指针向后移动也可能会改写本块的管理信息。

    以上这段话已经给了我们一些信息了。malloc()申请的空间实际我觉得就是分了两个不同性质的空间。一个就是用来记录管理信息的空间,另外一个就是可用空间了。而用来记录管理信息的实际上是一个结构体。在C语言中,用结构体来记录同一个对象的不同信息是

    天经地义的事!下面看看这个结构体的原型:

    struct mem_control_block {

    int is_available; //这是一个标记?

    int size; //这是实际空间的大小

    };

    对于size,这个是实际空间大小。这里其实我有个疑问,is_available是否是一个标记?因为我看了free()的源代码之后对这个变量感觉有点纳闷(源代码在下面分析)。这里还请大家指出!

    所以,free()就是根据这个结构体的信息来释放malloc()申请的空间!而结构体的两个成员的大小我想应该是操作系统的事了。但是这里有一个问题,malloc()申请空间后返回一个指针应该是指向第二种空间,也就是可用空间!不然,如果指向管理信息空间的话,写入的内容和结构体的类型有可能不一致,或者会把管理信息屏蔽掉,那就没法释放内存空间了,所以会发生错误!(感觉自己这里说的是废话)

    好了!下面看看free()的源代码,我自己分析了一下,觉得比起malloc()的源代码倒是容易简单很多。只是有个疑问,下面指出!

    // code...


    void free(void *ptr)
    {

    struct mem_control_block *free;

    free = ptr - sizeof(structmem_control_block);

    free->is_available = 1;

    return;
    }

    看一下函数第二句,这句非常重要和关键。其实这句就是把指向可用空间的指针倒回去,让它指向管理信息的那块空间,因为这里是在值上减去了一个结构体的大小!后面那一句free->is_available = 1;我有点纳闷!我的想法是:这里is_available应该只是一个标记而已!因为从这个变量的名称上来看,is_available 翻译过来就是“是可以用”。不要说我土!我觉得变量名字可以反映一个变量的作用,特别是严谨的代码。这是源代码,所以我觉得绝对是严谨的!!这个变量的值是1,表明是可以用的空间!只是这里我想了想,如果把它改为0或者是其他值不知道会发生什么事?!但是有一点我可以肯定,就是释放绝对不会那么顺利进行!因为这是一个标记!

    当然,这里可能还是有人会有疑问,为什么这样就可以释放呢??我刚才也有这个疑问。后来我想到,释放是操作系统的事,那么就free()这个源代码来看,什么也没有释放,对吧?但是它确实是确定了管理信息的那块内存的内容。所以,free()只是记录了一些信息,然后告诉操作系统那块内存可以去释放,具体怎么告诉操作系统的我不清楚,但我觉得这个已经超出了我这篇文章的讨论范围了。

    那么,我之前有个错误的认识,就是认为指向那块内存的指针不管移到那块内存中的哪个位置都可以释放那块内存!但是,这是大错特错!释放是不可以释放一部分的!首先这点应该要明白。而且,从free()的源代码看,ptr只能指向可用空间的首地址,不然,减去结构体大小之后一定不是指向管理信息空间的首地址。所以,要确保指针指向可用空间的首地址!不信吗?自己可以写一个程序然后移动指向可用空间的指针,看程序会有会崩!

    最后可能想到malloc()的源代码看看malloc()到底是怎么分配空间的,这里面涉及到很多其他方面的知识!有兴趣的朋友可以自己去下载源
    代码去看看。


    四、关于其他:

    关于C中的malloc()和free()的讨论就写到这里吧!写了三个钟头,感觉有点累!希望对大家有所帮助!有不对的地方欢迎大家指出!最后
    ,谢谢参与这个帖子讨论的所有朋友,帖子:http://www.bc-cn.net/bbs/dispbbs.asp?boardID=5&ID=81781&page=1。也谈到版权问题,如果哪位想转载这篇文章(如果我有这个荣幸的话),最起码请标明“来自bc-cn C语言论坛”这几个字眼,我的ID可以不用写上!谢谢合作!


    五、参考文献:(只写书名)

    ——《UNIX环境高级编程》

    ——《计算机组成原理》

    ——《高质量C/C++编程指南》

    function

    <cstring>

    memset

    void * memset ( void * ptr, int value,size_t num );

    Fill block of memory

    Sets the first num bytesof the block of memory pointed by ptr to the specified value (interpretedas an unsigned char).


    Parameters

    ptr

    Pointer to the block of memory to fill.

    value

    Value to be set. The value is passed asan int, but the function fills the block of memory using the unsignedcharconversion of this value.

    num

    Number of bytes to be set to the value.
    size_t is anunsigned integral type.



    Return Value

    ptr isreturned.


    Example

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    /* memset example */

    #include <stdio.h>

    #include <string.h>

     

    int main ()

    {

      char str[] = "almost every programmer should know memset!";

      memset (str,'-',6);

      puts (str);

      return 0;

    }

    Edit & Run



    Output:

     

    ------ every programmer should know memset!

     

     

    展开全文
  • 对象使用 memset 应注意的问题

    千次阅读 2013-07-10 22:54:29
    在C++中,针对类对象除了用构造函数初始化对象外,也可以使用memset来进行初始化操作(确实有这种情况,不得已而为之,请大家不要把鸡蛋砸过来!)。但是一定要注意以下所说的这种情况:如果类包含虚拟函数,则不能...

    memset某个结构(或其它的数据类型)在C语言中是很常见的代码,其目的是对结构(或其它的数据类型)进行初始化,通常都是将变量置为NULL或者0。在C++中,针对类对象除了用构造函数初始化对象外,也可以使用memset来进行初始化操作(确实有这种情况,不得已而为之,请大家不要把鸡蛋砸过来!)。但是一定要注意以下所说的这种情况:如果类包含虚拟函数,则不能用 memset 来初始化类对象。下面是一个例子:

    class GraphicsObject{
    protected:
    char *m_pcName;
    int m_iId;
    //etc
    public:
    virtual void Draw() {}
    virtual int Area() {}
    char* Name() { return m_pcName;}
    };

    class Circle: public GraphicsObject{
    void Draw() { /*draw something*/ }
    int Area() { /*calculate Area*/ }
    };

    void main()
    {
    GraphicsObject *obj = new Circle; // 创建对象
    memset((void *)obj,NULL,sizeof(Circle)); // memset to 0
    obj->Name(); // 非虚函数调用没问题
    obj->Draw(); // 在这里死得很难看
    }

    结果我就不说了。因为每个包含虚函数的类对象都有一个指针指向虚函数表(vtbl)。这个指针被用于解决运行时以及动态类型强制转换时虚函数的调用问题。该指针是被隐藏的,对程序员来说,这个指针也是不可存取的。当进行memset操作时,这个指针的值也要被overwrite,这样一来,只要一调用虚函数,程序便崩溃。这在很多由C转向C++的程序员来说,很容易犯这个错误,而且这个错误很难查。
    为了避免这种情况,记住对于有虚拟函数的类对象,决不能使用 memset 来进行初始化操作。而是要用缺省的构造函数或其它的 init 例程来初始化成员变量。

     

    eg1:double array[10]={1,2,3,4};

    memset(array,0,sizeo(array));

    eg2:struct student

    {

         int Num;

        int Score;

    }stu{22,43};

    memset(&stu,0,sizeof(student));

     

    展开全文
  • 内存空间的动态申请new与动态释放delete的搭配使用 在下列三种情况下,析构函数被自动执行 Memset函数怎么用?它是干啥用的? 如何使用参数初始化表? 构造函数使用之如何根据输入变量的长度动态申请内存空间? ...

    目录

     

    构造函数使用之如何根据输入变量的长度动态申请内存空间?

    内存空间的动态申请new与动态释放delete的搭配使用

    在下列三种情况下,析构函数被自动执行

    Memset函数怎么用?它是干啥用的?

    如何使用参数初始化表?


    构造函数使用之如何根据输入变量的长度动态申请内存空间?

    如下示例:

    #include <iostream>  
    using namespace std;  
    #include<string>  
      
    class Cstudent  
    {  
    private:  
        int mark;  
        char *name;  
    public:  
        Cstudent(int mark, char *name) // 类类型内只能由一个析构函数但可以有多个构造函数  
        {  
            int i = sizeof(name);  
            this->name = new char[i];  
            memset(name, 0, i + 1); // 该函数直接对内存进行赋值操作,对于含有大量元素的数组来说极为有用  
            strcpy(this->name, name);  
      
            this->mark = mark; // this指针代表本对象的地址,this->成员变量代表对象的成员变量与函数的形参区分开来  
        }  
        ~Cstudent(); // 切记:析构函数只能有一个,它只在对象被释放的时候被调用,用来在对象被删除之前向外界传递消息  
    };  
      
    Cstudent::~Cstudent()  
    {  
        if (name) // 如果成员变量name指针不为空  
        {  
            delete[] name; // 自动判断动态申请内存大小并且释放  
        }  
        cout << "析构函数被调用,对象被释放" << endl;  
    }  
      
    int main()  
    {  
        char name[] = "超级无敌霸霸强";  
        Cstudent student(89, name);  
    }

     

     

    内存空间的动态申请new与动态释放delete的搭配使用

    这里就涉及到一个问题:在哪里用new动态申请,在哪里用delete动态释放:

    这里就引出了“构造函数”&“析构函数”:构造函数中我们可以动态申请变量,在析构函数中我们可以动态释放内存,他们两个就像一堆不可分割的兄弟,一个负责节目开始的筹备工作,一个负责节目的收尾工作,但是要注意的是析构函数是去执行内存释放前的收尾工作,并不是去操控内存删除对象,同理,构造函数不是去声明定义类对象而是在定义对象后去初始化类对象。

    如下所示:

    #include <iostream>  
    using namespace std;  
    #include<string>  
      
    class Cstudent  
    {  
    private:  
        int mark;  
        char *name;  
    public:  
        Cstudent(int mark, char *name) // 类类型内只能由一个析构函数但可以有多个构造函数  — 筹备工作show time
        {  
            int i = sizeof(name);  
            this->name = new char[i];  
            memset(name, 0, i + 1); // 该函数直接对内存进行赋值操作,对于含有大量元素的数组来说极为有用  
            strcpy(this->name, name);  
      
            this->mark = mark; // this指针代表本对象的地址,this->成员变量代表对象的成员变量与函数的形参区分开来  
        }  
        ~Cstudent(); // 切记:析构函数只能有一个,它只在对象被释放的时候被调用,用来在对象被删除之前向外界传递消息  
    };  
      
    Cstudent::~Cstudent()  // 收尾工作show time
    {  
        if (name) // 如果成员变量name指针不为空  
        {  
            delete[] name; // 自动判断动态申请内存大小并且释放  
        }  
        cout << "析构函数被调用,对象被释放" << endl;  
    }  
      
    int main()  
    {  
        char name[] = "超级无敌霸霸强";  
        Cstudent student(89, name);  
    }

     

    在下列三种情况下,析构函数被自动执行

    以下几种情况会自动调用析构函数:

    ①、如果在一个函数中定义了一个局部对象,那么当这个函数执行结束时也就是该类对象生命周期结束的时候,所以类的析构函数会被自动调用;

    ②、被声明成全局类类型或者static类类型的对象,他们的生命周期一般是在程序退出的时候,这时候该对象的析构函数才会被调用;

    ③、如果是用new操作符动态的动态创建了一个类对象,只有当用delete进行释放该对象的时候,析构函数才会被调用。

    总之,就是类对象的声明周期结束之时,就是析构函数调用之时。

    Memset函数怎么用?它是干啥用的?

    每种类型的变量都有各自的初始化方法,memset() 函数可以说是初始化内存的“万能函数”,通常为新申请的内存进行初始化工作。它是直接操作内存空间,mem即“内存”(memory)的意思。该函数的原型为:

    # include <string.h>  
    void *memset(void *s, int c, unsigned long n); 

     

    函数的功能是:将指针变量 s 所指向的前 n 字节的内存单元用一个“整数” c 替换,注意 c 是 int 型。s 是 void* 型的指针变量,所以它可以为任何类型的数据进行初始化。

    如下示例:

    # include <stdio.h>  
    # include <string.h>  
    int main(void)  
    {  
        int i;  //循环变量  
        char str[10];  
        char *p = str;  
        memset(str, 0, sizeof(str));  //只能写sizeof(str), 不能写sizeof(p)  
    }  
    // 结果:把str字符型数组初始化为{0,0,0,0,0,0,0,0,0,0}  
    

     

    如何使用参数初始化表?

    使用方式如下所示:

    class CStudent //  类类型声明原型  
    {  
    private:  
        int mark;  
        string name;  
        float height;  
    public:  
        CStudent(int Dmark, string Dname, float Dheight) :mark(Dmark), name(Dname), height(Dheight)  
        {} // 千万不要忘记大括号,即使里面为空也要写上  
        ~CStudent(){}  
    }; 

     

     

    展开全文
  • C语言 memset函数简单实现

    千次阅读 2017-01-02 15:36:23
    对于CString却是个坏方法,会释放掉CString内部分配的内存,并且导致其指针对象变成野指针。 下面贴上memset函数实现方法:void* MemSet(void* dst,int val,int size) { char *_dst = (char*)dst; assert ('\0' ...
  • 含义是把this指向的对象的所有字节的内容都置为0. 什么时候会出现问题? 如果基类A存在虚函数,类B是这个基类的子类,在类B的构造函数体内仅仅调用memset(this,0,sizeof(*this)); 那么此操作会将虚表指针的值...
  • C++ memset使用注意事项

    2020-07-08 23:22:12
    memset用于给某一块内存空间进行赋值,所以赋值的对象必须是定义的。 memset不能用于清空string、vector等类型。原因如下: string、vector类型内部除了数据还有其他东西,使用memset会破坏其内部结构。 ...
  • C++memset内存陷阱

    2019-01-15 03:19:36
    该程序在用户态24小时运行,整体架构使用C++的面向对象特性,使用多态实现多个子类各自独立的业务处理,采用多进程单线程的模式。近日刚好碰到一次程序处理变慢并重复处理数据的情况,对日志进行了详...
  • memset函数使用详解

    千次阅读 2014-03-07 14:27:27
    void *memset(void *s,int c,size_t n) 总的作用:将已开辟内存空间 s 的首 n 个字节的值设为值 c。 2。例子 #include void main(){ char *s="Golden Global View"; clrscr(); memset(s,'G',6); ...
  • 否则memset会破坏string本身的结构,导致在之后对string对象进行操作时,会引发内存分配的动作, 而这实际上是不应该发生的(应该直接使用string本身的内存而不是新申请内存块),分配的内存没有释放, 这样做的结果...
  • memset函数导致内存泄露的问题

    千次阅读 2015-06-03 10:02:53
    程序从堆中分配的内存使用完毕后必须显式释放,否则这块内存就不能被再次使用,即这块内存泄漏了。内存泄漏导致软件在运行过程中占用越来越多的内存,程序的效率会越来越低,从而影响用户的体验,失去市场竞争力。 ...
  • malloc,memset,new比较

    2015-05-18 09:58:24
    memset 原型 extern void *malloc(unsigned int num_bytes); 头文件 #include 功能 分配长度为num_bytes字节的内存块 返回值 如果分配成功则返回指向被分配内存的指针(此存储区中的初始值不确定),否则...
  • 在基于回调的模块边界,经常出现需要延迟释放一个对象以便回调者进行一定的操作的情况.如果用定时器又比较麻烦.用内存池也不是很方便. 下面给出一种最简洁的解决方法: template&lt;typenameT,...
  • 对象,如果直接memset会导致破坏类对象的数据结构,必然会导致内存访问异常,而且可能会仅仅释放了类对象的地址,其内部指向的内存空间应该没有释放,应该会导致内存泄漏,为此做了如下测试: 测试代码: #include...
  • memset(string) 是错误

    千次阅读 2015-01-15 09:30:50
    string和memset string类是C++中专门处理字符串的类,它的实际上是basic_string的一个typedef。它有四个跌代器: typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse...
  • strcpy、memcpy和memset之间的区别  转载链接: https://www.cnblogs.com/573177885qq/p/5302457.html  strcpy比较简单,就是拷贝字符串,遇到'\0'时结束拷贝。  memcpy用来做内存拷贝,可以拷贝任何数据类型...
  • void *memset(void *str, int c, size_t n) 复制字符 c(一个无符号字符)到参数 str 所指向的字符串的前 n 个字符。 str – 指向要填充的内存块。 c – 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时...
  • c函数之memcpy ,memset,malloc函数使用

    千次阅读 2020-07-30 22:56:09
    函数返回的指针一定要适当对齐,使其可以用于任何数据对象。 说明: 分配长度为num_bytes字节的内存块,malloc的全称是memory allocation,中文叫动态内存分配,当无法知道内存具体位置的时候,想要绑定真正的内存...
  • malloc和memset的理解

    千次阅读 2013-10-08 10:19:00
     memcpy用来做内存拷贝,你可以拿它拷贝任何数据类型的对象,可以指定拷贝的数据长度;例:  char a[100], b[50];  memcpy(b, a, sizeof(b)); //注意如用sizeof(a),会造成b的内存地址溢出。 ...
  • 对string进行memset操作

    2013-06-07 10:36:10
    导致在之后对string对象进行操作时, 即时字符串大小不大于15也会引发内存分配的动作, 而这实际上是不应该发生的(应该直接使用string本身的内存而不是新申请内存块), 于是就有了在字符串大小小于16字节时, 分配的内存...
  • 1、使用memset初始化: memset函数原型:void * memset(void *ptr,int value,size_t num); 作用:用于为地址ptr开始的num个字节赋值value typedef struct s1 { SOCKET m_Socket; SOCKADDR_IN m_ClientAddr; ...
  • C学习笔记--memset注意事项

    千次阅读 2014-07-04 21:05:15
    在C语言中,用结构体来记录同一个对象的不同信息是 天经地义的事!下面看看这个结构体的原型:  struct mem_control_block {  int is_available; //这是一个标记?  int size; //这是实际空间的...
  • 如果在类的构造函数体中仅仅调用memset(this,0,sizeof(*this)); 含义是把this指向的对象的所有字节的内容都置为0. 什么时候会出现问题? 第一种情况: 如果基类A存在虚函数,类B是这个基类的子类,在类B的构造...
  • 我们要知道,p向操作系统申请了10个int类型的空间,而pp只是指向这个空间,操作系统并没有为其再分配10个int类型的空间,所以当你用delete[]p释放这个空间后,再用delete[]pp释放就会发生错误。其实不管用哪个释放,...
  • 一、关键字explicit ...作用:防止类的对象参数类型进行不合时宜的转换。 #include <iostream> class CxString//没有使用explicit关键字的类声明,即默认为隐式声明 { public: char* _pstr; int _size; ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 17,711
精华内容 7,084
关键字:

memset对象释放