如何在realloc之后将新内存清零

时间:2010-01-26 17:33:52

标签: c null memory-management

在保持最初分配的内存完好无损的同时调用realloc后将新内存清零的最佳方法是什么?

#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>

size_t COLORCOUNT = 4;

typedef struct rgb_t {
    int r;
    int g;
    int b;
} rgb_t;

rgb_t** colors;

void addColor(size_t i, int r, int g, int b) {
    rgb_t* color;
    if (i >= COLORCOUNT) {
        // new memory wont be NULL
        colors = realloc(colors, sizeof(rgb_t*) * i);
       //something messy like this...
        //memset(colors[COLORCOUNT-1],0 ,sizeof(rgb_t*) * (i - COLORCOUNT - 1));

         // ...or just do this (EDIT)
        for (j=COLORCOUNT; j<i; j++) {
            colors[j] = NULL;
        }

        COLORCOUNT = i;
    }

    color = malloc(sizeof(rgb_t));
    color->r = r;
    color->g = g;
    color->b = b;

    colors[i] = color;
}

void freeColors() {
    size_t i;
    for (i=0; i<COLORCOUNT; i++) {
        printf("%x\n", colors[i]);
        // can't do this if memory isn't NULL
       // if (colors[i])
         //   free(colors[i]);

    }
}


int main() {
    colors = malloc(sizeof(rgb_t*) * COLORCOUNT);
    memset(colors,0,sizeof(rgb_t*) * COLORCOUNT);
    addColor(0, 255, 0, 0);
    addColor(3, 255, 255, 0);
    addColor(7, 0, 255, 0);


    freeColors();
    getchar();
}

4 个答案:

答案 0 :(得分:7)

没有办法解决这个问题作为一般模式。原因是为了知道缓冲区的哪个部分是新的,你需要知道旧缓冲区有多长。在C中无法确定这一点,因此阻止了一般解决方案。

但是你可以写一个像这样的包装器

void* realloc_zero(void* pBuffer, size_t oldSize, size_t newSize) {
  void* pNew = realloc(pBuffer, newSize);
  if ( newSize > oldSize && pNew ) {
    size_t diff = newSize - oldSize;
    void* pStart = ((char*)pNew) + oldSize;
    memset(pStart, 0, diff);
  }
  return pNew;
}

答案 1 :(得分:4)

首先,realloc可能会失败,因此您需要检查NULL。其次,没有更好的方法可以将内存清零:只需从旧缓冲区的末尾到较大缓冲区的末尾进行memset。

答案 2 :(得分:4)

可能没有必要执行memset:您可能在使用colors[k]之前使用colors[i]之前使用了有效的内容。例如,您的代码将color设置为新分配的colors[i]指针,因此您无需将NULL设置为NULL

但是,即使你想“把它归零所以一切都很好”,或者真的需要新的指针为NULL:C标准并不保证所有位零都是null指针常量(即memset()),所以NULL无论如何都不是正确的解决方案。

您可以做的唯一便携式事情是在循环中将每个指针设置为size_t k; for (k=COLORCOUNT; k < i+1; ++k) /* see below for why i+1 */ colors[k] = NULL;

realloc()

您的主要问题是您的realloc()电话是错误的。 /* i+1 because you later assign to colors[i] */ rgb_t **tmp = realloc(colors, (i+1) * sizeof *tmp); if (tmp != NULL) { /* realloc succeeded, can't use colors anymore */ colors = tmp; } else { /* realloc failed, colors is still valid */ } 返回指向已调整大小的内存的指针,它不会(必然)就地调整它的大小。

所以,你应该这样做:

memset()

如果您真的想知道colors+COLORCOUNT调用应该是什么,则需要将内存设置为零,从i+1-COLORCOUNT开始,并将memset(colors+COLORCOUNT, 0, (i+1-COLORCOUNT) * sizeof *colors); 成员设置为零:

NULL

但正如我上面所说,所有字节零都不能保证是memset()指针,所以你的NULL无论如何都是无用的。如果你想要{{1}}指针,你必须使用一个循环。

答案 3 :(得分:1)

编写您自己的函数,例如reallocz,将当前大小作为参数接受,并为您调用reallocmemset。它真的不会比你已经拥有的好多了......毕竟它是C。