Динамический массив в C. Является ли мое понимание malloc/realloc правильным?
Я изучаю, как создавать динамические массивы 1D в C. Приведенный ниже код пытается сделать это:
- Создайте динамический массив длиной 10, который содержит удвоения, используя
таНос.
- Задайте каждую запись массива
j/100
для j = 0,1,..., 9. Затем распечатайте
это.
- Добавьте дополнительную пустую запись в конец массива с помощью realloc.
- Установите новую запись в
j/100
и снова распечатайте каждую запись.
Тестирование
double* data = (double*)malloc(10*sizeof(double));
for (j=0;j<10;j++)
{
data[j]= ((double)j)/100;
printf("%g, ",data[j]);
}
printf("\n");
data = (double*)realloc(data,11*sizeof(double));
for (j=0;j<11;j++)
{
if (j == 10){ data[j]= ((double)j)/100; }
printf("%g, ",data[j]);
}
free((void*) data);
Вопросы
1) Я правильно кодирую это?
2) Учебники, которые я нашел, используют malloc
, не помещая (double*)
спереди. Например.
int *pointer;
pointer = malloc(2*sizeof(int));
Это не компилируется для меня на Visual Studio 2010, Windows 7. Ошибка: "значение типа void не может быть назначено сущности типа int".
Почему это работает для этих учебных пособий, а не для меня? Правильно ли я предполагаю, что это связано с тем, что компиляторы, которые они используют, автоматически заполняют (int*)
для них в моем примере?
Ответы
Ответ 1
Вы близко.
В C (по крайней мере, начиная с версии стандарта стандарта 1989 года) литье перед malloc
и realloc
не нужно, так как C может преобразовывать значения типа void *
в int *
без трансляции. Это не относится к С++, поэтому на основе ошибки, которую вы получаете, похоже, что вы компилируете этот код как С++, а не C. Проверьте документацию для VS2010, чтобы определить, как скомпилировать код как C.
Ниже приведен мой предпочтительный стиль написания вызова malloc
:
double *data = malloc(10 * sizeof *data);
Так как тип выражения *data
равен double
, sizeof *data
эквивалентен sizeof (double)
. Это также означает, что вам не нужно настраивать вызовы malloc
, если изменяется тип data
.
Что касается вызова realloc
, безопаснее назначать результат временному значению указателя. realloc
возвращает NULL, если он не может расширить буфер, поэтому безопаснее писать
double *tmp;
...
tmp = realloc(data, 11 * sizeof *data);
if (!tmp)
{
// could not resize data; handle as appropriate
}
else
{
data = tmp;
// process extended buffer
}
Помните, что поддержка Microsoft для C заканчивается версией языка 1989 года; с тех пор было два пересмотра языкового стандарта, которые внедрили некоторые новые функции и устарели старые. Поэтому, в то время как некоторые компиляторы C поддерживают функции C99, такие как смешанные объявления и код, массивы переменной длины и т.д., VS2010 не будет.
Ответ 2
1) Я правильно кодирую это?
В основном. Но data = (double*)realloc(data,11*sizeof(double));
теряет ссылку на выделенную память, если realloc
терпит неудачу, вы должны использовать временный указатель для хранения возвращаемого значения realloc
и проверить, не является ли оно NULL
(и вы также должны проверить возвращаемое значение malloc
).
2) Учебники, которые я нашел, используют malloc, не ставя перед собой (double *).
В C, malloc
возвращает a void*
, который может быть неявно преобразован в любой другой тип указателя, поэтому никакой приведение не требуется (и широко обескуражен, потому что кастинг может скрыть ошибки). Visual Studio, по-видимому, компилирует код как С++, где требуется выполнить актерский состав.
Ответ 3
В C вы не должны указывать возвращаемое значение malloc()
.
Кроме того, это плохая идея для кодирования типа в аргументе malloc()
. Это лучший способ:
double* data = malloc(10 * sizeof *data);