• 内存分配与处理函数


    一:内存分配与释放

            1:man手册

    #include <stdlib.h>
    
    void *calloc(size_t nmemb, size_t size);
    void *malloc(size_t size);
    void free(void *ptr);
    void *realloc(void *ptr, size_t size);

            malloc申请size个字节的空间,并返回内存首地址。申请的内存空间没有初始化。如果size为0,则malloc要么返回NULL,要么返回一个特殊指针,该指针后续可以成功的传递给free。


            calloc申请一个数组空间,该数组的每个元素大小为size字节,共有nmemb个元素,所以该数组共占用nmemb*size个字节。该数组被初始化为0。calloc返回申请空间的首地址,如果nmemb或size为0,则calloc要么返回NULL,要么返回一个特殊指针,该指针后续可以成功的传递给free。        

     

            free释放ptr指向的内存空间,ptr必须是之前malloc、calloc或realloc的返回值。如果ptr不是这些函数的返回值,或者之前已经调用过free(ptr)了,则会发生未定义的行为。如果ptr为NULL,则不会执行任何动作。free没有返回值。

     

            realloc将ptr指向的内存块的大小改变为size个字节。从0到min(oldsize,newsize)内的空间内容是不变的,新分配的内存不会初始化。如果ptr为NULL,则realloc等价于malloc(size)。如果size为0,且ptr不是NULL,则等价于调用free(ptr),此时ptr要么是NULL,要么是之前malloc、calloc或realloc函数的返回值。

            realloc的返回地址有可能与ptr不同。如果内存地址改变了,则在内部会调用free(ptr)(已测)。如果realloc失败了,则原有的内存空间不会发生变化,既不会被释放,也不会被移走。

     

             malloc、calloc、realloc函数发生失败时,返回NULL。

     

            2:注意:

            a:In several allocation implementations, making a block smaller sometimes necessitates copying it, so it can fail if no other space is available.

            If the new size you specify is the same as the old size, realloc is guaranteed to change nothing and return the same address that you gave.

            使用realloc缩小内存空间时,如果空间不足也有可能会失败,因为realloc有可能会申请另外的空间。所以,当realloc缩小空间时,返回值不一定就是ptr。

            如果新旧内存大小一样,则可以保证realloc会返回与ptr相同的地址。

     

            b:使用realloc时,对于返回值一定要加以判断,不可简单的使用下面的语句:ptr = realloc(ptr,newsize),因为一旦realloc发生失败则会返回NULL,如果直接覆盖ptr的话,则原ptr指向的内存就丢失了。正确的用法应该是下面这样的:

    	int *newarray = (int *)realloc((void *)dynarray, 20 * sizeof(int));
    	if(newarray != NULL)
    		dynarray = newarray;
    	else 
    	{
    		fprintf(stderr, "Can't reallocate memory
    ");
    		/* dynarray remains allocated */
    	}

            c:使用realloc时,如果有其他指针依赖于原ptr指向地址,则该指针在realloc之后也需要做相应的调整。比如下面的例子,p2就是相对于p存在的,一旦p发生了变化,则p2也要做出相应的调整:

    char *p, *p2, *newp;
    int tmpoffset;
    
    p = malloc(10);
    strcpy(p, "Hello,");		/* p is a string */
    p2 = strchr(p, ',');		/* p2 points into that string */
    
    tmpoffset = p2 - p;
    newp = realloc(p, 20);
    if(newp != NULL) 
    {
    	p = newp;		/* p may have moved */
    	p2 = p + tmpoffset;	/* relocate p2 as well */
    	strcpy(p2, ", world!");
    }
    

            d:在对ptr进行free之后再次使用ptr是很危险的,即使不对其进行解引用,比如像比较这样看似无害的操作,都有可能造成意想不到结果(尽管大多数实现不会造成异常)。因此,最好的做法就是在free(ptr)之后,就将ptr置为NULL,已表明其无效。

     

            3:实例

            下面是libev中,实现的内存管理模块的代码:

    void *ev_realloc_emul (void *ptr, long size) EV_THROW
    {
        /* some systems, notably openbsd and darwin, fail to properly
        * implement realloc (x, 0) (as required by both ansi c-89 and
        * the single unix specification, so work around them here.
        * recently, also (at least) fedora and debian started breaking it,
        * despite documenting it otherwise.
        */
    
        if (size)
            return realloc (ptr, size);
    
        free (ptr);
        return 0;
    }
    
    void *(*alloc)(void *ptr, long size) = ev_realloc_emul;
    
    
    void *ev_realloc (void *ptr, long size)
    {
        ptr = alloc (ptr, size);
    
        if (!ptr && size)
        {
            fprintf (stderr, "(libev) cannot allocate %ld bytes, aborting.", size);
            abort ();
        }
        return ptr;
    }
    
    #define ev_malloc(size) ev_realloc (0, (size))
    #define ev_free(ptr)    ev_realloc ((ptr), 0)
    

    二:memmove

    #include <string.h>
    void *memmove(void *dest, const void *src, size_t n);

             memmove函数从src复制n个字节到dest。它与memcpy的区别就是,src和dest指向的内存区域可以重叠:复制过程就像是先将src复制到一个临时区域(其与src或dest都不重叠),然后复制该临时区域到dest。memmove的开销要比memcpy大一些。

     

             memmove的处理:

    当源内存的首地址等于目标内存的首地址时,不进行任何拷贝

    当源内存的首地址大于目标内存的首地址时,实行正向拷贝

    当源内存的首地址小于目标内存的首地址时,实行反向拷贝

     

             In standard C,this can be implemented as::

    #include <stddef.h> /* for size_t */
    void *memmove(void *dest, const void *src, size_t n)
    {
        unsigned char *pd = dest;
        const unsigned char *ps = src;
        if (__np_anyptrlt(ps, pd))
            for (pd += n, ps += n; n--;)
                *--pd = *--ps;
        else
            while(n--)
                *pd++ = *ps++;
        return dest;
    }
    

            __np_anyptrlt(p1,p2):A macro or function such that, for any two pointers p1 and p2,__np_anyptrlt(p1,p2) evaluates to:

            non-zero if p1 and p2 point within the same object and p1 is less than p2;

            zero if p1 and p2 point within the same object and p1 is greater than p2;

            an unspecified integer value if the pointers don't point within the same object or if they compare equal.

     

            参考:

    man手册

    http://www.c-faq.com/malloc/realloc.html

    http://www.c-faq.com/malloc/ptrafterfree.html

    http://www.gnu.org/software/libc/manual/html_node/Changing-Block-Size.html

    http://clc-wiki.net/wiki/memmove

  • 相关阅读:
    Java 多态
    HDFS读写原理
    HDFS详解
    Servlet基础
    Tomcat
    HTTP简介
    JDBC技术
    final、finally和finalize
    java 中的权限修饰符
    进程、线程、线程状态、多线程实现方法
  • 原文地址:https://www.cnblogs.com/gqtcgq/p/7247127.html
Copyright © 2020-2023  润新知