在保持最初分配的内存完好无损的同时调用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();
}
答案 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
,将当前大小作为参数接受,并为您调用realloc
和memset
。它真的不会比你已经拥有的好多了......毕竟它是C。