Вопрос по книге Числовые рецепты, 2-е изд.: распределение / освобождение памяти для векторов

Книга Числовые рецепты, 2-е издание ( http://numerical.recipes/) использует следующий код для выделения / освобождения памяти для вектора v с индексами [nl..nh]:

#define NR_END 1
#define FREE_ARG char*

float *vector(long nl, long nh)
/* allocate a float vector with subscript range v[nl..nh] */
{
  float *v;

  v=(float *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(float)));
  if (!v) nrerror("allocation failure in vector()");
  return v-nl+NR_END;
}

void free_vector(float *v, long nl, long nh)
/* free a float vector allocated with vector() */
{
  free((FREE_ARG) (v+nl-NR_END));
}

Вопрос 1: Какова цель сложения / вычитания NR_END элементы?

Вопрос 2: Какова цель преобразования float * в char * в free_vector?

Я это понимаю +1 в malloc происходит из-за включающей правой границы массива (который обычно не включается в C).

1 ответ

Решение
  1. Предположим, вы имели nl=1 а также NR_END=0, Тогда возвращаемый указатель будет выходить за пределы (он указывает перед выделенным блоком). Это неопределенное поведение и может привести к неправильным результатам, хотя вряд ли это вызовет проблемы на основных компиляторах, потому что указатель будет увеличен обратно до разыменования.

    Чтобы избежать этого неопределенного поведения, вы можете установить NR_END до максимального ожидаемого значения nl (который 1 в книге). Это гарантирует, что возвращаемый указатель действителен. Однако реализация, приведенная в вопросе, по-прежнему неверна, поскольку v-nl+NR_END уменьшение на nl перед увеличением на NR_END, Правильная реализация будет v+NR_END-nl,

    Обратите внимание, что если nl только когда-либо имеет неотрицательные значения, гораздо проще было бы просто выделить nh+1 значения, а затем вам не нужно никакой арифметики указателя после malloc или раньше free,

    Здесь вы можете увидеть цитату из книги, объясняющую это, на страницах 940-941 второго издания. Некоторые цитаты:

    в редких случаях (и, вероятно, только на сегментированной машине) может случиться, что выражение b-1 вообще не имеет представления. Если это происходит, то нет гарантии, что выполнено соотношение b=(b-1)+1.

    [....]

    параметр NR_END используется в качестве количества дополнительных мест хранения, выделенных в начале каждого вектора или матричного блока, просто для того, чтобы сделать ссылки на указатели смещения гарантированно представимыми.

  2. Актерский состав char* не требуется ни в одной стандартизированной версии C. Возможно, она была необходима в древних версиях. Приведение возвращаемого значения malloc тоже не нужно.

Другие вопросы по тегам