Как обнулить новую память после перевыделения

Что лучший способ состоит в том, чтобы обнулить новую память после называния перевыделения при сохранении первоначально выделенной памяти неповрежденной?

#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();
}
8
задан Nick Van Brunt 26 January 2010 в 19:33
поделиться

4 ответа

Нет сомнений, что я странный человек, но для настольных приложений (не веб-) вот что я делаю. Я считаю почти любое приложение просто прославленным редактором. То есть, он имеет структуру данных, которая должна быть постоянной, и пользовательский интерфейс, чтобы позволить пользователю поместить информацию в эту структуру данных и извлечь ее.

Структура данных должна быть простой, простой и простой. Я считаю, что это просто хранилище информации, с как можно меньшей избыточностью. Я не хочу строить структуру данных, которая существует для того, чтобы быть видимым проявлением базовых данных, таких как древовидные элементы управления и т.д., потому что тогда это должно быть согласовано с базовыми данными, и вы получите все вопросы о том, как сохранить избыточные данные согласованными. (Пример: для графики не строить его, рисовать .) Если я не могу избежать создания избыточной структуры данных, я остаюсь как можно дальше от программирования в стиле уведомлений, которое пытается поддерживать избыточную структуру данных в тесном согласии. Из этого вытекает большая часть проблем с буглистом и производительностью. Скорее я предпочитаю свободную связь, где определенная степень несогласованности может быть допустима и управляется процессами, которые выполняются один раз в раз для продвижения изменений.

Для пользовательского интерфейса я был большим верующим в кодирование пользовательского интерфейса в стиле ООП и 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 , необходимо использовать цикл.

4
ответ дан 5 December 2019 в 10:02
поделиться

Запишите свою собственную функцию, скажем reallocz, которая принимает текущий размер в качестве параметра и вызывает realloc и memset для вас. В конце концов, это не намного лучше, чем то, что у вас уже есть... это все-таки С.

1
ответ дан 5 December 2019 в 10:02
поделиться

Прежде всего, RealLoc может потерпеть неудачу, поэтому вам нужно проверить на нуле. Во-вторых, нет лучшего способа нуля памяти: просто MEMSET от конца старого буфера до конца большего буфера.

4
ответ дан 5 December 2019 в 10:02
поделиться

Нет никакого способа решить эту проблему как общую схему. Причина в том, что для того, чтобы узнать, какая часть буфера новая, вам нужно знать, какой длины был старый буфер.Это невозможно определить в 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;
}
8
ответ дан 5 December 2019 в 10:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: