Nic*_*unt 8 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();
}
Run Code Online (Sandbox Code Playgroud)
作为一般模式,没有办法解决这个问题.原因是为了知道缓冲区的哪个部分是新的,你需要知道旧缓冲区有多长.在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;
}
Run Code Online (Sandbox Code Playgroud)
可能不需要执行以下操作:在使用稍后有效的内容设置它之前,memset您可能不会使用它。colors[k]例如,您的代码设置colors[i]为新分配的color指针,因此您不需要设置colors[i]为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;
Run Code Online (Sandbox Code Playgroud)
您的主要问题是您的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 */
}
Run Code Online (Sandbox Code Playgroud)
如果您确实想知道调用memset()应该是什么,则需要将从 开始的内存设置为零colors+COLORCOUNT,并将i+1-COLORCOUNT成员设置为零:
memset(colors+COLORCOUNT, 0, (i+1-COLORCOUNT) * sizeof *colors);
Run Code Online (Sandbox Code Playgroud)
但正如我上面所说,所有字节为零并不能保证都是指针NULL,所以你的memset()无论如何都是无用的。如果你想要指针,你必须使用循环NULL。