2014-01-11 1 views
1

Мне нужно реализовать простой динамический массив указателей для указателя typedef'ed.
Использование realloc каждый раз, когда пользователь запрашивает его, размер массива будет увеличиваться на sizeof (указатель).
Так что у меня есть это:Нужно ли инициализировать (установить в 0) память после вызова realloc?

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
typedef void* node; 

void printmem(node* a, int c) { 
    int i; 
    for (i = 0; i < c; ++i) 
    { 
     printf("%d\t\t%p\n", i, a[i]); 
    } 
} 

int main(void) { 
    node* nodes = NULL; 
    int i = 0, count = 20; 

    for (i = 0; i < count; ++i) 
    { 
     nodes = realloc(nodes, sizeof(node)); 
    } 
    printf("Done reallocating\n"); 
    printmem(nodes, i); 
    // free(a); 
    return 0; 
} 

Это дает следующий результат:

Done reallocating 
0  (nil) 
1  (nil) 
2  (nil) 
3  0x20fe1 
4  (nil) 
5  (nil) 
6  (nil) 
7  (nil) 
8  (nil) 
9  (nil) 
10  (nil) 
11  (nil) 
12  (nil) 
13  (nil) 
14  (nil) 
15  (nil) 
16  (nil) 
17  (nil) 
18  (nil) 
19  (nil) 

Я обеспокоен 3 элемента, и его содержание.
Вот почему я спрашиваю, должен ли я установить 0 память после нового realloc.

Edit:
Таким образом, как указано в стандарте С, по Н2СО3, новый вызов перераспределить, является:
nodes = realloc(nodes, (i+1)*sizeof(node));
И после этого для initiallization, я сделал это: nodes[i] = NULL
который также работал отлично.

Edit2:
У меня это сейчас:

int main(void) { 
    node* nodes = NULL; 
    int i = 0, count = 20; 

    for (i = 0; i < count; ++i) 
    { 
     nodes = realloc(nodes, (i+1)*sizeof(node)); 
     nodes[i] = NULL; 
     if (i == 1) { 
      nodes[i] = &count; 
     } 
    } 
    printf("Done reallocating\n"); 
    printmem(nodes, i); 
    printf("\t*nodes[1] == %d\n", *(int*)nodes[1]); 
    printf("\tAddress of count is %p\n", &count); 
    // free(a); 
    return 0; 
} 
+1

'realloc()' будет копировать все, что первоначально было в буфере. Если новый блок больше исходного, то элементы в конце (то есть те, которые отсутствовали в исходном массиве) будут неинициализированы. –

+0

@ H2CO3: Новый блок, безусловно, больше, чем старый, поэтому все предыдущие данные потеряны? – Chris

+0

Naw. Читайте мой комментарий еще раз. Элементы excess будут неинициализированы, исходное содержимое в начале блока памяти будет сохранено. –

ответ

5

Ну, это все зависит. Требуется ли вам , чтобы память была инициализирована на 0? Если нет, то нет, вам не нужно ничего делать. Как и в случае с malloc, realloc не выполняет никакой инициализации. Любая память из памяти, которая присутствовала в исходном блоке, остается неинициализированной.

+0

Так должен ли я, вызвать memset для этого конкретного нового элемента, который добавляется каждый раз? – Chris

+0

Ну, опять же, все зависит от того, нужна ли вам эта инициализация памяти. Если да, то да. Однако важно понимать, что C не гарантирует, что нулевой указатель представлен всеми нулевыми битами, только чтобы он сравнил *, равный '0'. Тонкая, но важная разница. –

1

Переход по определению перераспределить()

перераспределить (недействительными * р, size_t размера) изменяет размер объекта указывал на от p к size. Содержимое будет оставаться неизменным до минимума старых и новых размеров. Если новый размер больше, то новое пространство будет неинициализировано. (от Кернигана и Ричи)

Возможно, вам придется инициализировать новое пространство. Вы можете это сделать, когда будет решено, какие данные укажет адрес, на который указывает void *.

2

Помните, что нулевой указатель не обязательно должен быть равен буквалу 0 в C. Он просто гарантированно не будет равен любому действительному указателю. Кроме того, нулевые указатели технически разрешены для разных типов указателей (например, указатели функций против указателей символов).

Следовательно, просто инициализация памяти до нуля может вызвать неопределенное поведение.

Таким образом, инициализация до NULL будет правильной! Вот что я сделал! - Крис

Нет, что бы вы иметь сделать отливают нуль, как это: (недействительными *) NULL, и записать это в ячейку памяти.Но вы никогда не записываете в память вы malloc (через передачу NULL для realloc). В основном вы просто читаете неинициализированную память (это неопределенное поведение) в вашем printf.

+0

Так что инициализация до NULL была бы правильной! Вот что я сделал! – Chris

+0

Не могли бы вы объяснить разницу между (void *) NULL и NULL? Я использовал оба варианта и работал с программой valgrind и не получал ошибок. Кроме того, почему я не пишу в память, которую я выделил? Я разместил обновление в основном, если вы запустите его, вы увидите, что узлы [1] печатают адрес переменной 'c' и печатают' * (узлы [i]) 'Я получаю значение' c '. – Chris

+0

@Chris: Если в некоторой архитектуре nullptr! = Zero, компилятор должен знать, чтобы поместить соответствующее значение в память. Он должен знать, что бит памяти, на который ссылается, должен рассматриваться как указатель. Если разные типы указателей имеют разные значения nullptr, компилятор должен также знать, что * type * нулевого указателя, которое ему нужно записать в память. – EOF