Обработка массивов

Доступ к элементу массива

Работа с массивами

Примеры инициализации массивов

int a[3] = {0, 1, 2}; // Число инициализаторов равно числу элементов
double b[5] = {0.1, 0.2, 0.3}; // Число инициализаторов меньше числа элементов
int c[ ] = {1, 2, 4, 8, 16}; // Число элементов массива определяется по числу инициализаторов
int d[2][3] = {{0, 1, 2}, {3, 4, 5}}; // Инициализация двумерного массива. Массив состоит из двух строк, // в каждой из которых по 3 элемента. Элементы первой строки // получают значения 0, 1 и 2, а второй – значения 3, 4 и 5.
int e[3] = {0, 1, 2, 3}; // Ошибка – число инициализаторов больше числа элементов

Обратите внимание, что не существует присваивания массиву, соответствующего описанному выше способу инициализации.

int a[3] = {0, 1, 2}; // Объявление и инициализация
a = {0, 1, 2}; // Ошибка

Для доступа к конкретному элементу массива используются так называемые индексные выражения:
<имя массива>[<целочисленное выражение>]

Здесь квадратные скобки являются требованием синтаксисам языка, а не признаком необязательности конструкции.

Индекс массива может быть не только константой, но и выражением, которое имеет целочисленный тип, например, a[i + 1] (здесь a должно быть именем ранее объявленного массива, а i – переменной целого типа).

Объявление массива и индексное выражение, используемое для доступа к элементу массива, имеют схожий синтаксис. Различаются они по месту в программе. Это особенно важно, когда мы определяем индекс последнего элемента массива. Как было сказано ранее, индексы элементов массива в языке C начинаются с 0, и номер последнего элемента на 1 меньше количества элементов массива. Поэтому если Вы объявили массив x из 10 элементов, Вы не можете написать индексное выражение x[10], т.к. в этом случае Вы пытаетесь обратиться к элементу с индексом 10, которого нет в Вашем массиве. Компилятор не выдаст сообщения об ошибке, но результаты работы такой программы будут непредсказуемы.

Имя массива является адресом его начала! Оно имеет тип константный указатель на <тип элементов массива>. Конструкция a[i] эквивалентна *(a + i)

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

Для обработки элементов массива обычно используется оператор пошагового цикла for.

for (i = 0; // Присваиваем счетчику цикла значение индекса первого элемента
i < n; // Условие продолжения цикла – пока значение счетчика меньше количества элементов массива
i++) // Увеличиваем счетчик цикла на 1 для перехода к следующему элементу массива
<тело цикла> // В теле цикла происходит обработка одного элемента массива

Для обработки многомерного массива используется соответствующее количество циклов.

Массивы не самодостаточны в том смысле, что не гарантируется хранение информации о количестве элементов вместе с самим массивом. В большинстве реализаций С++ отсутствует проверка диапазона индексов для массивов. Таков традиционный низкоуровневый подход к массивам. Более совершенное понятие массива можно реализовать при помощи классов.

В С++ массивы тесно связаны с указателями. Имя массива можно использовать в качестве указателя на его первый элемент. Гарантируется осмысленность значения указателя на элемент, следующий за последним элементом массива. Это важно для многих алгоритмов. Но ввиду того, что такой указатель на самом деле не указывает ни на какой элемент массива, его нельзя использовать ни для чтения, ни для записи. Результат получения адреса элемента массива, предшествующего первому, не определён, и такой операции следует избегать.

Неявное преобразование имени массива в указатель на его первый элемент широко используется в вызовах функций.

int f(..., int x[], ...) { ... } int f(..., int *x, ...) { ... } void main() { int a[10]; ... // Можно использовать любой из двух вариантов
f(..., a, ...); ... } // Передаём в функцию f указатель на массив a

Неявное преобразование массива в указатель при вызове функции приводит к потере информации о размере массива. Вызываемая функция должна каким-либо образом определить этот размер, чтобы выполнять осмысленные действия.

При объявлении многомерного массива как параметра функции можно опустить только первую размерность.

int g(..., int x[][10], ...) { ... } // Вторая и последующие размерности обязательны

Это ограничение при желании можно обойти. Правда, при этом возникают другие проблемы

3.3. Ввод/вывод массивов

В языке C нет возможности вводить и выводить весь массив одним оператором ввода/вывода. Можно вводить и выводить только один элемент массива. Следовательно, для того чтобы ввести весь массив, надо использовать цикл.

int a[10], n; printf("Введите количество элементов массива (от 0 до 9): "); // Объявляем массив и переменную для количества элементов массива
scanf("%d", &n); // Ввод количества элементов массива
if (n < 0 || n > 9) { printf("Количество элементов массива должно быть от 0 до 9!\n"); return; } // Если входные данные неверны, // то печатаем соответствующее сообщение и выходим из программы
for (i = 0; i < n; i++) // Ввод массива по одному элементу
scanf("%d", &a[i]); // Можно использовать scanf("%d", a + i)

Вывод также осуществляется в цикле.

for (i = 0; i < n; i++) printf("a[%d] = %3d\n", i + 1, a[i]);  

В результате на экране мы увидим примерно следующий текст: a[1] = 4 a[2] = 15 a[3] = -2 ...

Единственным действием, которое возможно произвести с массивом целиком - присваивание. Для данного примера описания впоследствии допустима следующая запись:
S:=BB;

Однако, присваивать можно только массивы одинаковых типов. Даже массиву T присвоить массив S нельзя, хотя, казалось бы, их описания совпадают, произведены они в различных записях раздела описания.

Никаких других операций с массивами целиком произвести невозможно, но с элементами массивов можно работать точно также, как с простыми переменными соответствующего типа. Обращение к отдельному элементу массива производится при помощи указания имени всего массива и в квадратных скобках - индекса конкретного элемента. Например:
R[10] - элемент массива R с индексом 10.

Фундаментальное отличие компонента массива от простой переменной состоит в том, что для элемента массива в квадратных скобках может стоять не только непосредственное значение индекса, но и выражение, приводящее к значению индексного типа. Таким образом реализуется косвенная адресация:
BB[15] - прямая адресация;
BB[K] - косвенная адресация через переменную K, значение которой будет использовано в качестве индекса элемента массива BB.

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

Если вы помните, с такой формой организации данных мы встречались, когда изучали строковые переменные. Действительно, переменные типа String очень близки по своим свойствам массивам типа Char. Отличия в следующем: строковые переменные можно было вводить с клавиатуры и распечатывать на экране (с обычным массивом это не проходит); длина строковой переменной была ограничена 255 символами (255 B), а для размера массива критическим объемом информации является 64 KB.

Теперь рассмотрим несколько способов заполнения массивов и вывода их содержимого на экран. В основном мы будем пользоваться числовыми типами компонент, но приведенные примеры будут справедливы и для других типов (если они допускают указанные действия).

Program M1;
Var
A : Array [1..20] Of Integer;
Begin

A[1]:=7; {Заполняем массив значениями (отдельно каждый компонент)}
A[2]:=32;
A[3]:=-70;
.............. {Трудоемкая задача?}
A[20]:=56;
Writeln(A[1],A[2],A[3], ?,A[20])