В программе на языке С можно использовать структурированные типы данных. К ним будем относить массивы, структуры и файлы.
Массив состоит из многих элементов одного и того же типа. Ко всему массиву целиком можно обращаться по имени. Кроме того, можно выбирать любой элемент массива. Для этого необходимо задать индекс, который указывает относительную позицию элемента в массиве. Число элементов массива назначается при его объявлении и в дальнейшем не меняется. Если массив объявлен, то к любому его элементу можно обратиться следующим образом : указать имя массива и индекс элемента в квадратных скобках. Массивы объявляются так же, как и переменные :
int a [100]; массив а из 100 элементов целого типа : а[0], a[1],.…, a[99] (индексация всегда начинается с нуля).
char b [30];
float c [42]; - элементы массива b имеют тип char, а с – float.
Двухмерный массив представляется как одномерный, элементы которого тоже массивы. Например, объявление char а[10][20]; задает двумерный массив символов. По аналогии можно установить и большее число измерений. Элементы двухмерного массива хранятся по строкам, т.е. если проходить по ним в порядке их расположения в памяти, то быстрее всего изменяется самый правый индекс. Например, обращение к девятому элементу пятой строки запишется так: а[5][9]. Пусть задано объявление: int a[2][3]; Тогда элементы массива а будут размещаться в памяти следующим образом: а[0][0], а[0][1] а[0][2], а[1][0], а[1][1], а[1][2]. Имя массива а – это указатель константы, которая содержит адрес его первого элемента ( для нашего примера – а[0][0] ). Предположим, что а=1000. Тогда адрес элемента а[0][1] будет равен 1002 (элемент типа int занимает в памяти 2 байта), адрес следующего элемента а[0] [2] – 1004 и т.п. Что же произойдет, если вы выберете элемент, для которого не выделена память. К сожалению, компилятор не следит за этим. В результате возникнет ошибка, и программа будет работать не верно.
В языке С существует сильная взаимосвязь между указателями и массивами. Любое действие, которое достигается индексированием массива, может быть выполнено и с помощью указателей, причем последний вариант будет быстрее. Объявление int а [5]; определяет массив из пяти элементов: а[0], а[1], а[2], а[3], а[4]. Если объект у объявлен как int *у; то оператор y=&a[0]; присваивает переменной у адрес элемента а[0]. Если переменная у указывает на текущий элемент массива а, то у+1 указывает на следующий элемент, причем здесь выполняется соответствующее масштабирование для приращения адреса с учетом длины объекта (для типа int – 2 байта, long – 4 байта, double – 8 байт и т.п.). Поскольку само имя массива есть адрес его нулевого элемента, то инструкцию у=&а[0]; можно записать и в другом виде: у=а;. Тогда элемент а[i] можно представить как *(а+i). С другой стороны, если у – указатель, то следующие две записи y[i] и *(y+i) эквивалентны. Между именем массива и соответствующим указателем есть одно важное различие. Указатель – это переменная и у=а; или у++; -допустимые операции. Имя же массива – константа, поэтому конструкции вида а=у; а++; использовать нельзя, так как значение константы постоянно и не может быть изменено.
Переменные с адресами могут образовывать некоторую иерархическую структуру (могут быть многоуровневыми), типа указатель на указатель ( то есть он содержит адрес другого указателя ), указатель на указатель на указатель и т.п. Их использование будет рассмотрено ниже на примере.
Если указатели адресуют элементы одного массива, то их можно сравнивать (отношения вида: <, >, = =, ! = и др. работают правильно).
В то же время нельзя сравнивать либо использовать в арифметических операциях указатели на разные массивы (соответствующие выражения не приводят к ошибкам при компиляции, но в большинстве случаев не имеют смысла). Как и выше, любой адрес можно проверять на равенство или неравенство со значением NULL. Указатели на элементы одного массива можно также вычитать. Тогда результатом будет число элементов массива, расположенных между уменьшаемым и вычитаемым объектами.
Язык С позволяет инициализировать массив при объявлении. Для этого используется такая форма:
тип имя_массива [ ] [ ] = { список значений };
Рассмотрим примеры:
int a[5] = {0,1,2,3,4};
char с[7] = { 'a','b','c','d','e','f','g'};
int b [2] [3]= {1,2,3,4,5,6};
В последнем случае: b[0][0] = 1, b[0][1] = 2, b[0][2] = 3, b[1][0] = 4,
b[1][1] = 5, b[1][2] = 6.
В языке допускаются массивы указателей, которые объявляются, например, следующим образом: char *m[5]; . Здесь [m] – массив, содержащий адреса элементов типа char.