Несколько замечаний:
Я не вижу, как вы используете realloc()
в своем коде, но если вы используете его таким образом, это неправильно:
variable = realloc(variable, amount);
Если не удается выделить больше памяти, realloc()
возвращает NULL
, но оставляет исходный указатель без изменений. В приведенной выше строке это означает, что variable
равно NULL
, и мы потеряли доступ к памяти, на которую оно указывало, но эта память не была освобождена. Правильная идиома такая:
void *tmp = realloc(variable, amount);
if(tmp)
{
// success! variable invalid, tmp has new allocated data
variable = tmp;
}
else
{
// failure! variable valid, but same size as before, handle error
}
Причина, по которой вы должны использовать второй, заключается в том, что при realloc()
неудача плохая, но вполне исправима во многих ситуациях, в отличие от malloc()
, где неудача обычно означает «останови все и умри».
Это более спорный вопрос, но сомнительно, должны ли вы приводить возвращаемое значение malloc()
и realloc()
, как вы. Рассмотрим:
// functionally identical in C
char *a = malloc(10);
char *b = (char *)malloc(10);
В C ++ приведение должно быть выполнено, потому что в C ++ void *
не может быть неявно преобразовано в другой тип указателя. (Я думаю, что это ошибка языка, но я не могу судить об этом.) Если ваш код на C ++, вы все равно должны использовать new
и delete
. Если ваш код на C, но должен компилироваться с помощью компиляторов C ++ (по какой-то глупой причине), у вас нет другого выбора, кроме как приводить. Если вам не нужно компилировать код C с помощью компиляторов C ++ (что похоже на необходимость запуска кода Ruby в интерпретаторе Python), перейдите к пунктам ниже, поэтому я думаю, что вам не следует приводить.
В C89, если функция используется без объявления, она будет неявно объявлена как возвращающая int
. Если, скажем, мы забыли #include <stdlib.h>
и вызвали malloc()
, версия без преобразования вызовет ошибку компилятора (неявные преобразования от int
до char *
не допускаются), в то время как версия с приведением (неправильно) сказал бы компилятору: «Я знаю, это звучит безумно, но все равно произнесу». Большинство компиляторов будут предупреждать вас о неявных (или несовместимых) объявлениях встроенных функций, таких как malloc()
, но приведение затрудняет поиск.
Скажем, у вас есть некоторые данные:
float *array = (float *)malloc(10 * sizeof(float));
Позже вы обнаружите, что вам нужна большая точность ваших данных, и вам нужно сделать этот массив double
. В приведенной выше строке вам необходимо поменять не более 3-х разных мест:
double *array = (double *)malloc(10 * sizeof(double));
Если, с другой стороны, вы написали:
float *array = malloc(10 * sizeof *array);
Вам нужно всего лишь изменить float
на double
в 1 месте. Кроме того, всегда использование sizeof *obj
вместо sizeof(type)
и никогда не использование приведений означает, что более поздний вызов realloc()
может работать без каких-либо изменений , тогда как использование приведений и явных имен типов потребует поиска в любом месте, куда вы звонили realloc
и измените приведение и sizeof
с. Также, если вы забудете и сделаете это:
double *array = (float *)malloc(10 * sizeof(float));
На большинстве платформ array
теперь будет представлять собой массив из 5 элементов, при условии, что выравнивание не отключено, и компилятор не будет жаловаться, что вы присваиваете float *
для double *
. Некоторые считают полезным предупреждение о проблемах компилятора, поскольку оно указывает на потенциально неправильные строки. Однако, если мы избегаем sizeof(type)
и избегаем приведения, мы можем видеть, что строки не будут некорректными, поэтому компилятор, обращающий на них внимание, тратит время, которое мы могли бы использовать для программирования.