Окт
12
Опубликовано: 12 Окт 2009
Рубрика: Программирование | Автор: inst

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

Строй солдат

Чтобы досконально понять, что такое массив, достаточно провести аналогию со строем солдат. Командующий указывает: «по порядку рас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.: просто встречал подобное в текстах программ с соревнований по обфускации кода, мне показалось интересным.

Отзывы

Александр 13 Окт 2009 в 10:05 #

Плюсового реаллока несуществует. В плюсах для работы динамически выделяемой памятью есть операторы new и delete, а сишные функции для тех же целей берутся из стандартной библиотеки Си, соответсвенно, работают так же, как и в Си.


inst 13 Окт 2009 в 23:29 #

Именно наследие функций я и имел ввиду, когда употреблял словосочетание «плюсовый realloc()». Однако я считаю, что раз стандарт предполагает переименование всех Си’шных header’ов ( *.h → c* ), то и некоторые функции возможно, могут быть переписаны в связи с веяниями времени.

Просто, в примерах cURL видел функцию re_alloc(), реализующую описанную выше логику и над ней был какой-то двусмысленный комментарий =)


Комментировать
Имя:
Почта:
Сайт:
Сообщение:
В сообщении можно использовать такие теги:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Это не спам