Массивы существуют в любом современном языке программирования. Массив — это упорядоченная совокупность элементов одного типа, а значит и размера, объединённая одним общим именем. Каждый такой элемент снаружи массива представлен порядковым числом, называемым индексом и доступ к нему осуществляется именно при помощи этого индекса.

Чтобы досконально понять, что такое массив, достаточно провести аналогию со строем солдат. Командующий указывает: «по порядку расcчитайсь!», происходит расчёт и у каждого солдата появляется свой номер (читай, «индекс»), по которому командир может к нему обратится.
Пример: arr[-1] — неверно, arr[10.1] — тоже неверно, arr[11] — верно.
Индексы должны быть представлены целым беззнаковым числом. Любой массив в Си начинается с нулевого элемента.
Внимание! Если мы резервируем память для 12-ти элементов массива, то индекс последнего — 11! Наиболее часто встречающаяся ошибка в программах новичков по моему мнению.
В Си есть жёсткое требование к организации массива: все элементы должны располагаться в памяти по порядку друг возле друга, а имя массива указывает на начало блока памяти, где эти элементы расположены. Любое обращение к элементам массива компилятор в итоге преобразовывает в указатель, т.е. x[i] будет растолковано им как указатель на область x плюс i шагов нужного размера.
Пример: arr[0] == *arr, arr[11] == *(arr + 11 * sizeof(arr)).
Однако, прежде чем начать использовать массив, следует выделить под него нужный объём памяти.
В чистом Си у программиста есть бо́льшая свобода по отношению к выбору целевой памяти. Т.е. можно использовать память с произвольными данными (например, ранее использовавшуюся, но освободившуюся) либо сразу при выделении проинициализировать все выделенные ячейки значением нуль.
Соответственно, для первого случая используется функция malloc():
double *x = (double*)malloc(n * sizeof(double));
где double нужно заменить на название нужного типа памяти (например, int или название новоопределённой структуры), а запись в скобках дословно означает — n элементов по 8 байтов.
Второй случай — функция calloc():
Единственным отличием в данном случае является то, что функция принимает 2 аргумента. Впрочем, это всего лишь означает, что надо * из примера malloc заменить на ,:
double *x = (double*)calloc(n, sizeof(double));
Обратите внимание, что результаты обеих функций следует явно преобразовывать в указатель на нужный тип данных. В приведённых примерах это делать было необязательно, но правила хорошего тона требуют именно такой записи, чтобы не возникло путаницы при построении более сложных приложений.
Сразу после того, как в коде нам перестал требоваться этот выделенный участок памяти, его следует освободить, т.е. отметить, как неиспользуемый. Для этого используют очень простую функцию free():
free(x);
Тут вроде всё ясно. Однако бывают также случаи, когда выделенной ранее памяти становится недостаточно для продолжения вычислений. В таком случае мы имеем возможность расширить используемую область памяти при помощи функции realloc(). Она принимает два аргумента: указатель на ранее размеченную область памяти и размер итоговой области памяти в таком же виде, как и для функции malloc(), т.е.:
x = (double*)realloc(x, n * sizeof(double));
Тип данных опять-таки рекомендуется преобразовывать. Сто́ит также обратить особое внимание на то, что в стандарте Си описана функция realloc(), которая в случае, если ей передан указатель равный NULL, вернёт его же. Если не ошибаюсь, плюсовый realloc() при таких условиях работает как malloc().
И на последок небольшой трюк: x[i] в коде как на Си так и на плюсах всегда равно i[x]. Изложенного выше материала вполне достаточно, чтобы это понять и доказать ;)
P.S.: просто встречал подобное в текстах программ с соревнований по обфускации кода, мне показалось интересным.
Плюсового реаллока несуществует. В плюсах для работы динамически выделяемой памятью есть операторы new и delete, а сишные функции для тех же целей берутся из стандартной библиотеки Си, соответсвенно, работают так же, как и в Си.
Именно наследие функций я и имел ввиду, когда употреблял словосочетание «плюсовый realloc()». Однако я считаю, что раз стандарт предполагает переименование всех Си’шных header’ов ( *.h → c* ), то и некоторые функции возможно, могут быть переписаны в связи с веяниями времени.
Просто, в примерах cURL видел функцию re_alloc(), реализующую описанную выше логику и над ней был какой-то двусмысленный комментарий =)