Что лучший способ состоит в том, чтобы обнулить новую память после называния перевыделения при сохранении первоначально выделенной памяти неповрежденной?
#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();
}
Нет сомнений, что я странный человек, но для настольных приложений (не веб-) вот что я делаю. Я считаю почти любое приложение просто прославленным редактором. То есть, он имеет структуру данных, которая должна быть постоянной, и пользовательский интерфейс, чтобы позволить пользователю поместить информацию в эту структуру данных и извлечь ее.
Структура данных должна быть простой, простой и простой. Я считаю, что это просто хранилище информации, с как можно меньшей избыточностью. Я не хочу строить структуру данных, которая существует для того, чтобы быть видимым проявлением базовых данных, таких как древовидные элементы управления и т.д., потому что тогда это должно быть согласовано с базовыми данными, и вы получите все вопросы о том, как сохранить избыточные данные согласованными. (Пример: для графики не строить его, рисовать .) Если я не могу избежать создания избыточной структуры данных, я остаюсь как можно дальше от программирования в стиле уведомлений, которое пытается поддерживать избыточную структуру данных в тесном согласии. Из этого вытекает большая часть проблем с буглистом и производительностью. Скорее я предпочитаю свободную связь, где определенная степень несогласованности может быть допустима и управляется процессами, которые выполняются один раз в раз для продвижения изменений.
Для пользовательского интерфейса я был большим верующим в кодирование пользовательского интерфейса в стиле ООП и MVC, пока не обнаружил это в 1986. Теперь я испорчен, и я могу получить сложные пользовательские интерфейсы, закодированные за часть времени, которое возможно обычным стилем обработки событий управления, и они тривиальны, чтобы изменить по мере изменения требований. Но пока я в компании, может быть, только 3 человек в мире, которые его используют, потому что это точно не мейнстрим.
-121--2291550-Вы можете попробовать Решарпер .
Другой вариант - вы можете попробовать Just Code компании Telerik.
-121--2291547- Вероятно, нет необходимости использовать 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;
Основная проблема заключается в том, что вызов 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
, необходимо использовать цикл.
Запишите свою собственную функцию, скажем reallocz
, которая принимает текущий размер в качестве параметра и вызывает realloc
и memset
для вас. В конце концов, это не намного лучше, чем то, что у вас уже есть... это все-таки С.
Прежде всего, RealLoc может потерпеть неудачу, поэтому вам нужно проверить на нуле. Во-вторых, нет лучшего способа нуля памяти: просто MEMSET от конца старого буфера до конца большего буфера.
Нет никакого способа решить эту проблему как общую схему. Причина в том, что для того, чтобы узнать, какая часть буфера новая, вам нужно знать, какой длины был старый буфер.Это невозможно определить в 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;
}