Что такое массив. Обозначение элементов многомерного массива. Инициализация многомерных массивов

Если Вы хотите узнать о массивах деревьев, то эта статья не о том. Но не спешите закрывать статью, она поможет Вам стать еще более эрудированным, ведь помимо древесных массивов, Вы узнаете, что такое массив в программировании. Действительно, у слов, столько значений, что можно запутаться...

Массив в программировании

Чтобы добиться понимания, начнем с самого простого определения массива.

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

Для наглядности приведем пример из жизни. Так список студентов в журнале будет представлять собой массив. Порядковый номер каждого студента (обычно они идут по алфавиту, т.е. фамилии на "А" будут первыми) - это его индекс.

Каждое значение массива (студенты в примере) именуется компонентой (или элементом).

Массивы используют для решения различных задач программирования.

Виды массивов

Можно говорить о двух видах массивов:

  1. одномерные;
  2. многомерные.

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

  • Чтобы нагляднее представить, что такое одномерный массив, представим тетрадный листок в клетку. Так, любая линия по вертикали или горизонтали (а можно и по диагонали) - вот он, одномерный массив. А количество клеточек будет определять размерность данного одномерного массива. В каждый элемент (клеточку) можно записать значение (например, число), но только одно (!). Найти это значение можно, указав его порядковый номер (в квадратных скобочках).
  • Рассмотрим, что такое массив двумерный все на том же примере тетрадного листка в клеточку. Несколько клеток по горизонтали, несколько по вертикали - и у нас образуется некоторая прямоугольная табличка (о квадратной читайте ниже). Она и будет двумерным массивом. Здесь можно говорить о строках матрицы (клетки по вертикали) и столбцах (соответственно, горизонтальные клетки). Как и в массиве одномерном, в каждой клеточке хранится одно значение. Отличие - в поиске нужного значения. Здесь уже нужно указывать номер строчки и номер столбца, пересечение которых даст нужный нам элемент.

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

В квадратной матрице есть два вида диагоналей:

  1. главная - из верхнего левого уголка в нижний правый (т.е. где номер строки и столбца совпадает);
  2. побочная - идет из верхнего правого уголка в нижний левый.

Для закрепления приведем еще один пример из жизни, иллюстрирующий нам массивы.

Итак, жильцы подъезда, - пусть это будет массив под именем К.

Индекс здесь - номер квартиры. Этот элемент (квартира) представляет собой еще один массив - жильцы квартиры. Например, в 1-ой квартире живер 4 человека, во 2-ой - 3 человека, в 3-ей - 5 человек.

Так, одномерный массив - это перечисление в квадратных скобках (!) количества жильцов: 4, 3, 5.

Двумерный массив (вместо квадр. скобок у нас будет "*"): **1, 1, 1, 1*, *1,1,1*, *1, 1, 1, 1, 1**

Собственно и все. А о том, что такое raid-массив, Вы можете прочитать .

Описание многомерного массива позволяет использовать в программе любой из его элементов как индексированную переменную.

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

В массивах Си/Си++ индексы элементов на единицу меньше заданных математически. Это обстоятельство должно учитываться в программе, особенно при формировании условия повторения (выхода из) цикла.

Особенность работы с массивами в Си/Си++ – любой двумерный массив можно представить в виде одномерного при условии укрупнения единицы хранения (элемента).

Например, если в качестве элементов выбрать строки (столбцы), то двумерный массив превратится в одномерный массив строк (столбцов).

Хранение двумерного массива, например X(m n), реализуется схемой распределения оперативной памяти (рис. 9.4).

Для хранения трехмерного массива, например S(k m n), схема распределения оперативной памяти представлена на рис 9.5 (первая и последняя страницы).

x 00 x 01 . . . x 0j . . . x 0 n-1
s 0i0 s 0i1 . . . s 0ij . . . s 0i n-1

. . . . . . . . . . . . . . . . . . . . . . . . . . . .

s 0m-1 0 s 0 m-1 1 . . . s 0 m-1 j . . . s 0 m-1 n-1

. . . . . . . . . . . . . . . . . . . . . . . . . . . .

s k-100 s k-101 . . . s k-10j . . . s k-10 n-1

. . . . . . . . . . . . . . . . . . . . . . . . . . . .

s k-1i0 s k-1i1 . . . s k-1ij . . . s k-1i n-1

. . . . . . . . . . . . . . . . . . . . . . . . . . . .

s k-1m-10 s k-1 m-1 1 . . . s k-1 m-1 j . . . s k-1 m-1 n-1

Рис. 9.5. Хранение элементов трехмерного массива

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

Изменение индексов происходит последовательно – справа налево . Например, для трёхмерного массива вначале полностью перебирается крайний правый индекс (столбцов), затем средний (строк) и последним – левый (страниц).

Длина ячейки хранения каждого элемента определяется типом массива.

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

Следовательно, n-мерный массив в Си/Си++ интерпретируется как совокупность массивов (n-1) размерности, которые также могут быть представлены совокупностью массивов еще меньшей размерности.

Структура обозначения индексированной переменной многомерного массива:

где имя – идентификатор массива;

индекс_i – целая константа, задающая номер элемента по i-му измерению;

– ограничители индекса элемента по каждому измерению.

Так, в описанном ранее массиве D(20 30) элемент, расположенный в первом столбце первой строки, обозначается индексным выражением d, во втором столбце той же строки – d, в первом столбце второй строки – d, текущий – d[i][j], элемент последнего столбца, последней строки – d.

Рассмотренный пример идентификации элементов массива D применим к любому из двумерных массивов, указанных в соответствующем описателе.

Для трехмерных массивов обозначение элементов выполняется аналогично. Например, в массиве S(10 5 15) (описан ранее) элемент первой страницы на пересечении первой строки и первого столбца обозначается индексным выражением s, элемент второго столбца первой строки той же страницы – s, второго столбца второй строки первой страницы – s, текущий – s[k][i][j], а элемент последнего столбца, последней строки, последней страницы – s.

Индекс, при необходимости, может задаваться арифметическим выражением. Например, d, d[i], s, s[i].

ü Внимание! Индекс на момент использования переменной должен быть определен (рассчитан) и укладываться в заданный описателем диапазон.

Рассмотренные формы представления индексированных переменных позволяют осуществить программную реализацию элементов алгоритма с использованием многомерных массивов.

Непрерывное и последовательное расположение элементов многомерного массива в оперативной памяти позволяет адрес каждого элемента представить зависимостью:

а = а1 + смещение,

где а – адрес некоторого текущего элемента массива;

а1 – адрес первого элемента массива;

смещение – номер текущего элемента относительно первого.

Смещение рассчитывается для массивов различной размерности по аналогичным методикам.

Так для двумерного массива

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

Для трехмерного массива

смещение = индекс_1*(разм_2* разм_3) +

Первое слагаемое определяет число элементов в ранее расположенных страницах, второе – в предыдущих строках текущей страницы, третье – число элементов в текущей строке текущей страницы.

ü Внимание! Для любого массива размер первого измерения (разм_1) в расчете смещения не используется.

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

Описатели массивов определяют максимально возможные значения (размеры) каждого измерения. Это позволяет использовать зарезервированное пространство оперативной памяти полностью, либо частично, обеспечивая универсальность размеров в сторону уменьшения. Для двумерного массива это утверждение поясняется схемой (рис. 9.6):

Размер, заданный в описателе (максимальное число столбцов n max)
Размер, используемый в расчетах (n)
Размер, использу-емый в расчетах (m) Размер, заданный в описателе (максимальное число строк m max)

Рис. 9.6. Соответствие реальных размеров описанным

Размеры, указанные в описателе определяют количество зарезервированных в оперативной памяти ячеек. При этом ячейки создаваемого двумерного массива располагаются последовательно и линейно (построчно). Если в расчетах зарезервированное пространство используется частично (с меньшим числом строк и/или столбцов), то участки с хранимыми значениями будут чередоваться с неиспользуемыми, количество которых должно быть учтено при указании длины каждой строки в индексном выражении. Суммарное количество элементов каждой строки задано в описателе массива. Поэтому адреса любой ячейки определяется индексным выражением, использующим в качестве одного из параметров указанный в описателе размер.

Так, если двумерный массив z описан как z, а в задаче используется с размерами m=7, n=12, то адрес текущего элемента &z[i][j] = z + i * 20 + j, а не &z[i][j] = z + i * n + j.

Исходя из изложенного, адрес i-го, j-го элемента массива D(20х30) вычисляется по формуле

&(d[i][j]) = d + i * 30 + j,

а адрес k-го, i-го, j-го элемента массива S(10х5х15) вычисляется как

&(s[k][i][j]) = s + k * (5 * 15) + i * 15 + j

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

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

Таблица 9.1

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

Классический вариант программирования задачи

#include /* директивы */

#include /* препроцессора */

#include

#define M 10 /* увеличенные */

#define N 12 /* размеры массивов */

main() /* заголовок головной функции */

char buf; /*описание символьного массива*/

CharToOem(" Введите m (m<= ",buf); /* запрос */

printf("\n %s %d):",buf,M); /* и */

scanf("%d", &m); /* ввод */

CharToOem(" Введите n (n<= ",buf); /* фактических */

printf("\n %s %d):",buf,N); /* размеров */

scanf("%d", &n); /* массивов */

printf("\n n=%d m=%d ", n, m); /*вывод размеров массивов*/

for(i = 0; i < m; i++) /*заголовок внешнего цикла ввода x[i][j]*/

for(j = 0; j < n; j++) /*заголовок внутр. цикла ввода x[i][j]*/

CharToOem(" Введите значение ",buf); /* ввод */

printf("\n %s x[%d][%d]:",buf,i+1, j+1); /* элементов */

scanf("%f", & x[i][j]); /*массива Х*/

CharToOem(" Массив X",buf); /* вывод */

for(i = 0; i < m; i++)/* заголовок внешн. цикла вывода x[i][j]*/

for(j=0; j < n; j++)/*заголовок внутр. цикла вывода x[i][j]*/

printf(" %5.2f", x[i][j]);

for(i = 0; i < m ; i++ /*заголовок внешн. цикла расчета y[i][j]*/

for(j = 0; j < n; j++)/*заголовок внутр. цикла расчета y[i][j]*/

CharToOem(" Массив Y",buf); /* вывод */

printf("\n %s \n",buf); /*заголовка*/

for(i = 0 ; i < m ; i++)/*заголовок внешн. цикла вывода y[i][j]*/

for(j = 0; j < n; j++) /*заголовок внутр. цикла вывода y[i][j]*/

printf(" %5.2f", y[i][j]);

2 3 – размеры массива;

Результаты решения представлены в приложении 9.1.

Программирование задачи с графическим интерфейсом

Программирование задачи при использовании графического интерфейса предварим его разработкой.

ListBoxХi
ListBoxYi

Для ввода количества столбцов и строк массива планируем однострочные поля редактирования (EditN, EditМ). Для ввода элементов массива Х – многострочное поле редактирования (EditХ). Вывод элементов массивов X и Y реализуем в поля-списки (ListBoxXi, ListBoxYi).

Управление процессом решения реализуем двумя командными кнопками, расположенными в нижней части окна. Назначение каждой определяется ее названием.

Использование графического интерфейса для вывода числовых элементов двумерных массивов в виде таблицы требует:

· представления каждого числового данного соответствующей символьной строкой;

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

· размещение сформированной общей символьной строки в окне вывода.

Представление числовых данных символьными строками комментариев не требует.

Формирование элементов выводимой строки в единое целое выполняется функцией «склеивания» строк strcat.

Функция «склеивания» символьных строк strcat()

Функция предназначена для получения результирующей строки из двух исходных строк. Структура функции:

strcat(buf1, buf2)

где strcat – обозначение функции;

buf1 – имя исходной (результирующей) символьной строки;

buf2 – имя добавляемой символьной строки;

() – ограничители аргумента.

Функция располагается в библиотеке string.h.

Правила записи и использования

1. Операнды buf1 и buf2 – символьные строки. Строка buf1 увеличивает свое значение после выполнения функции на величину buf2.

2. Обязательное условие формирования строк buf1 и buf2 – окончание каждой символом «\0».

3. Пробелы, при необходимости, формируются структурой соответствующей строки (включением в нее).

4. Однократное использование функции – чтение строки buf1, добавление к ней строки buf2 и занесение результата в buf1. Поэтому размер buf1 в описателе создается увеличенным (на величину добавляемых компонентов).

5. Многократное использование функции – последовательное добавление второго операнда (buf2) к предварительно полученной строке buf1.

6. Повторное использование функции для создания новой результирующей строки требует предварительной очистки первого аргумента функции. Один из вариантов – присваивание строке buf1 пустой строки: sprintf(buf1,"%s","");

7. Проверка результирующей строки на переполнение не выполняется.

8. Функция используется как операнд арифметического выражения (присваивания) или самостоятельный оператор.

Общий вид фрагмента программы «склеивания» символьных строк str и buf:

#include /* директива препроцессора*/

char str, buf; /*описатель символьных строк*/

EditStr->

EditBuf->GetText(buf, 10); /*ввод buf из поля EditBuf*/

Описатель типа определяет массивы str и buf как символьные максимальной длины 25 и 10 символов. Пятая и шестая строки предписывает ввод строк str и buf из полей EditStr и EditBuf соответственно. Оператор strcat(str, buf); формирует «склеенную» строку и хранит ее под именем str .

Многократное использование функции позволяет создать результирующую строку с любым количеством компонентов в пределах, предусмотренных размером buf1.

Вариант 1: последовательное соединение нескольких строк

#include /* директива препроцессора*/

char str, buf1, buf2;/*описатель символьных строк*/

EditStr->GetText(str, 10); /*ввод строки str из поля EditStr*/

EditBuf1->GetText(buf1, 10); /*ввод buf1 из поля EditBuf1*/

EditBuf2->GetText(buf2, 10); /*ввод buf2 из поля EditBuf2*/

strcat(str, buf1); /*формирование результирующей строки str «склеиванием» исходных строк str и buf1*/

strcat(str, buf2); /*формирование результирующей строки str «склеиванием» полученных str и buf2*/

Описатель типа определяет массивы str, buf1 и buf2 как символьные, максимальной длины 25, 10 и 5 символов, соответственно. Пятая, шестая и седьмая строки предписывает ввод str, buf1 и buf2 из полей EditStr, EditBuf1 и EditBuf2 соответственно. Операторы strcat(str, buf1); и strcat(str, buf2); последовательно формируют «склеенную» строку из str, buf1 и buf2. Полученная строка имеет имя str .

Вариант 2: использование функции в теле цикла.

#include /* директива препроцессора*/

char str = “ ”, buf;/*описание и инициализация

символьных строк*/

for(j = 0 ; j < 5 ; j++) /* заголовок цикла ввода buf и формирования str*/

EditBuf->GetLine(buf, 10, j); /* ввод buf */

strcat(str, buf); /*формирование результирующей строки str «склеиванием» исходных строк str и buf*/

Описатель типа определяет массивы str и buf как символьные максимальной длины 50 и 10 символов соответственно и инициализирует str пустой строкой. Оператор EditBuf->GetLine (buf, 10, j); предписывает ввод buf из j-й строки многострочного поля EditBuf. Оператор strcat(str, buf); формирует в теле цикла, из последовательно вводимых строк buf, «склеенную» строку и хранит ее под именем str .

С учетом планируемого интерфейса выполним программирование задачи.

#include

#include

#include

void TSumprDlgClient::Ok()

// INSERT>> Your code here.

float x[M][N], y[M][N]; /* описатели массивов */

char buf,buf1=" "; /*описание символьного массива*/

ListBoxYi->

ListBoxXi->ClearList(); /*очистка поля вывода*/

EditN->

n = atoi(buf); /* столбцов массива*/

EditM->GetText(buf, 10); /*ввод количества*/

m = atoi(buf); /* строк массива*/

for(i = 0 ; i < m ; i++) /* заголовок внешн. цикла ввода x[i][j] */

for(j = 0 ; j < n ; j++) /* заголовок внутр. цикла ввода x[i][j] */

EditX->GetLine(buf, 30, i*n+j); /* ввод элементов */

x[i][j]=atof(buf); /* массива Х*/

for(i = 0; i < m; i++) /*заголовок внешн. цикла вывода x[i][j]*/

for(j = 0; j < n; j++)/*заголовок внутр. цикла вывода x[i][j]*/

sprintf(buf,"%11.3f",x[i][j]); /* вывод текущих*/

ListBoxXi->AddString(buf1); /*значений xi*/

sprintf(buf1,"%s","");

for(i = 0; i < m; i++)/*заголовок внешн. цикла расчета y[i][j]*/

for(j = 0; j < n; j++) /*заголовок внутр. цикла расчета y[i][j]*/

y[ i ][ j ] = x[ i ][ j ] / 2.;

for(i = 0 ; i < m ; i++)/*заголовок внешн. цикла вывода y[i][j]*/

for(j = 0; j < n; j++)/*заголовок внутр. цикла вывода y[i][j]*/

sprintf(buf,"%11.6f",y[i][j]); /* вывод текущих*/

strcat(buf1, buf); /*склеенных*/

ListBoxYi->AddString(buf1); /*значений yi*/

sprintf(buf1,"%s","");

3 2 – размеры массива;

10. 20. 30. – элементы первой строки;

100. 200. 300. – элементы второй строки.

Под закрывающей скобкой приведены исходные данные для решения задачи.

Результаты решения представлены в приложении 9.2.


Похожая информация.


Массив (программирование)

Индексный массив (в некоторых языках программирования также таблица , ряд ) - именованный набор однотипных переменных, расположенных в памяти непосредственно друг за другом (в отличие от списка), доступ к которым осуществляется по индексу.

Индекс массива - целое число, либо значение типа, приводимого к целому, указывающее на конкретный элемент массива.

Общее описание

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

Количество используемых индексов массива может быть различным. Массивы с одним индексом называют одномерными , с двумя - двумерными и т. д. Одномерный массив нестрого соответствует вектору в математике, двумерный - матрице. Чаще всего применяются массивы с одним или двумя индексами, реже - с тремя, ещё большее количество индексов встречается крайне редко.

Пример статического массива на Паскале -

WordArray: array [ Word ] of Integer ; // Статический, размер = High(Word) + 1 multiArray: array [ Byte , 1 ..5 ] of Char ; // Статический массив, 2 измерения rangeArray: array [ 5 ..20 ] of String ; // Статический массив, размер = 16

Пример статического массива на Си -

Int Array[ 10 ] ; // Статический, размер 10, базовый тип данных - целое число (int) double Array[ 12 ] [ 15 ] ; // Статический массив, 2 измерения, базовый тип данных - число // с дробной частью (double)

Поддержка индексных массивов (свой синтаксис объявления, функции для работы с элементами и т. д.) есть в большинстве высокоуровневых языков программирования . Максимально допустимая размерность массива, типы и диапазоны значений индексов, ограничения на типы элементов определяются языком программирования и/или конкретным транслятором.

В языках программирования, допускающих объявления программистом собственных типов , как правило, существует возможность создания типа «массив». В определении такого типа может указываться размер, тип элемента, диапазон значений и типы индексов. В дальнейшем возможно определение переменных созданного типа. Все такие переменные-массивы имеют одну структуру. Некоторые языки поддерживают для переменных-массивов операции присваивания (когда одной операцией всем элементам массива присваиваются значения соответствующих элементов другого массива).

Объявление типа «массив» в Паскале -

Type TArrayType = array [ 0 ..9 ] of Integer ; (* Объявления типа "массив" *) var arr1, arr2, arr3: TArrayType; (* Объявление трёх переменных-массивов одного типа *)

Специфические типы массивов

Динамические массивы

Динамическим называется массив, размер которого может меняться во время исполнения программы. Для изменения размера динамического массива язык программирования , поддерживающий такие массивы, должен предоставлять встроенную функцию или оператор. Динамические массивы дают возможность более гибкой работы с данными, так как позволяют не прогнозировать хранимые объёмы данных, а регулировать размер массива в соответствии с реально необходимыми объёмами. Обычные, не динамические массивы называют ещё статическими .

Пример динамического массива на Delphi

ByteArray: Array of Byte ; // Одномерный массив multiArray: Array of Array of string ; // Многомерный массив

Пример динамического массива на Си

Float *array1; // Одномерный массив int **array2; // Многомерный массив array1=(float *) malloc (10 *sizeof (float ) ) ; // выделение 10 блоков по sizeof(float)байт каждый array2=(int **) malloc (16 *sizeof (int ) ) ; // выделение 16*8 блоков по sizeof(int) байт каждый for (i=0 ;i<16 ;i++) array2[ i] =(int *) malloc (8 *sizeof (int ) ) ;

Гетерогенные массивы

Гетерогенным называется массив, в разные элементы которого могут быть непосредственно записаны значения, относящиеся к различным типам данных . Массив, хранящий указатели на значения различных типов, не является гетерогенным, так как собственно хранящиеся в массиве данные относятся к единственному типу - типу «указатель». Гетерогенные массивы удобны как универсальная структура для хранения наборов данных произвольных типов. Отсутствие их поддержки в языке программирования приводит к необходимости реализации более сложных схем хранения данных. С другой стороны, реализация гетерогенности требует усложнения механизма поддержки массивов в трансляторе языка.

Массивы массивов

Многомерные массивы, как правило реализованные как одномерные массивы, каждый элемент которых, является ссылкой на другой одномерный массив.

Реализация

Стандартным способом реализации статических массивов с одним типом элементов является следующий:

  1. Под массив выделяется непрерывный блок памяти объёмом S*m 1 *m 2 *m 3 …m n , где S - размер одного элемента, а m 1 …m n - размеры диапазонов индексов (то есть количество значений, которые может принимать соответствующий индекс).
  2. При обращении к элементу массива A адрес соответствующего элемента вычисляется как B+S*(i 1p *m 1 +i 2p *m 2 +…+i (n-1)p *m n-1 +i np), где B - база (адрес начала блока памяти массива), i kp -значение k-го индекса, приведённое к целому с нулевым начальным смещением.

Таким образом, адрес элемента с заданным набором индексов вычисляется, так что время доступа ко всем элементам массива одинаково.

Первый элемент массива, в зависимости от языка программирования , может иметь различный индекс. Различают три основных разновидности массивов: с отсчетом от нуля (zero-based), с отсчетом от единицы (one-based), и с отсчетом от специфического значения заданного программистом (n-based). Отсчет индекса элемента массивов с нуля более характерен для низкоуровневых ЯП, однако этот метод был популяризирован в языках более высокого уровня языком программирорования С.

Более сложные типы массивов - динамические и гетерогенные - реализуются сложнее.

Достоинства

  • легкость вычисления адреса элемента по его индексу (поскольку элементы массива располагаются один за другим)
  • одинаковое время доступа ко всем элементам
  • малый размер элементов: они состоят только из информационного поля

Недостатки

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

При решении задач с большим количеством данных одинакового типа использование переменных с различными именами, не упорядоченных по адресам памяти, затрудняет программирование. В подобных случаях в языке Си используют объекты, называемые массивами.

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

Массив характеризуется следующими основными понятиями:

Элемент массива (значение элемента массива) – значение, хранящееся в определенной ячейке памяти, расположенной в пределах массива, а также адрес этой ячейки памяти.
Каждый элемент массива характеризуется тремя величинами:

  • адресом элемента — адресом начальной ячейки памяти, в которой расположен этот элемент;
  • индексом элемента (порядковым номером элемента в массиве);
  • значением элемента.

Адрес массива – адрес начального элемента массива.

Имя массива – идентификатор, используемый для обращения к элементам массива.

Размер массива – количество элементов массива

Размер элемента – количество байт, занимаемых одним элементом массива.

Графически расположение массива в памяти компьютера можно представить в виде непрерывной ленты адресов.

Представленный на рисунке массив содержит q элементов с индексами от 0 до q-1 . Каждый элемент занимает в памяти компьютера k байт, причем расположение элементов в памяти последовательное.

Адреса i -го элемента массива имеет значение

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

Длина массива – количество байт, отводимое в памяти для хранения всех элементов массива.

ДлинаМассива = РазмерЭлемента * КоличествоЭлементов

Для определения размера элемента массива может использоваться функция

int sizeof (тип);

Например,

sizeof (char ) = 1;
sizeof (int ) = 4;
sizeof (float ) = 4;
sizeof (double ) = 8;

Объявление и инициализация массивов

Для объявления массива в языке Си используется следующий синтаксис:

тип имя[размерность]={инициализация};

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

int a = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // массив a из 10 целых чисел

Если количество инициализирующих значений, указанных в фигурных скобках, меньше, чем количество элементов массива, указанное в квадратных скобках, то все оставшиеся элементы в массиве (для которых не хватило инициализирующих значений) будут равны нулю. Это свойство удобно использовать для задания нулевых значений всем элементам массива.

int b = {0}; // массив b из 10 элементов, инициализированных 0


Если массив проинициализирован при объявлении, то константные начальные значения его элементов указываются через запятую в фигурных скобках. В этом случае количество элементов в квадратных скобках может быть опущено.

int a = {1, 2, 3, 4, 5, 6, 7, 8, 9};

При обращении к элементам массива индекс требуемого элемента указывается в квадратных скобках .

Пример на Си

1
2
3
4
5
6
7
8

#include
int main()
{
int a = { 5, 4, 3, 2, 1 }; // массив a содержит 5 элементов
printf("%d %d %d %d %d\n" , a, a, a, a, a);
getchar();
return 0;
}

Результат выполнения программы:

Однако часто требуется задавать значения элементов массива в процессе выполнения программы. При этом используется объявление массива без инициализации. В таком случае указание количества элементов в квадратных скобках обязательно.

int a;

Для задания начальных значений элементов массива очень часто используется параметрический цикл:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18


#include
int main()
{
int a;
int i;
// Ввод элементов массива
for (i = 0; i<5; i++)
{
printf("a[%d] = " , i);
scanf("%d" , &a[i]);
}
// Вывод элементов массива
for (i = 0; i<5; i++)
printf("%d " , a[i]); // пробел в формате печати обязателен
getchar(); getchar();
return 0;
}

Результат выполнения программы

Многомерные массивы

В языке Си могут быть также объявлены многомерные массивы. Отличие многомерного массива от одномерного состоит в том, что в одномерном массиве положение элемента определяется одним индексом, а в многомерном - несколькими. Примером многомерного массива является матрица.

Общая форма объявления многомерного массива

тип имя[размерность1][размерность2]...[размерностьm];

Элементы многомерного массива располагаются в последовательных ячейках оперативной памяти по возрастанию адресов. В памяти компьютера элементы многомерного массива располагаются подряд, например массив, имеющий 2 строки и 3 столбца,

int a;


будет расположен в памяти следующим образом

Общее количество элементов в приведенном двумерном массиве определится как

КоличествоСтрок * КоличествоСтолбцов = 2 * 3 = 6.

Количество байт памяти, требуемых для размещения массива, определится как

КоличествоЭлементов * РазмерЭлемента = 6 * 4 = 24 байта.

Инициализация многомерных массивов

Значения элементов многомерного массива, как и в одномерном случае, могут быть заданы константными значениями при объявлении, заключенными в фигурные скобки {} . Однако в этом случае указание количества элементов в строках и столбцах должно быть обязательно указано в квадратных скобках .

Пример на Си

1
2
3
4
5
6
7
8
9

#include
int main()
{
int a = { 1, 2, 3, 4, 5, 6 };
printf("%d %d %d\n" , a, a, a);
getchar();
return 0;
}



Однако чаще требуется вводить значения элементов многомерного массива в процессе выполнения программы. С этой целью удобно использовать вложенный параметрический цикл .

Пример на Си

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

#define _CRT_SECURE_NO_WARNINGS
#include
int main()
{
int a; // массив из 2 строк и 3 столбцов
int i, j;
// Ввод элементов массива
for (i = 0; i<2; i++) // цикл по строкам
{
for (j = 0; j<3; j++) // цикл по столбцам
{
printf("a[%d][%d] = " , i, j);
scanf("%d" , &a[i][j]);
}
}
// Вывод элементов массива
for (i = 0; i<2; i++) // цикл по строкам
{
for (j = 0; j<3; j++) // цикл по столбцам
{
printf("%d " , a[i][j]);
}
printf("\n" ); // перевод на новую строку
}
getchar(); getchar();
return 0;
}



Передача массива в функцию

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

  • адрес массива,
  • размер массива.

Исключение составляют функции обработки строк, в которые достаточно передать только адрес.

При передаче переменные в качестве аргументов функции данные передаются как копии. Это означает, что если внутри функции произойдет изменение значения параметра, то это никак не повлияет на его значение внутри вызывающей функции.

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

Пример на Си Дан массив из 10 элементов. Поменять местами наибольший и начальный элементы массива. Для операций поиска максимального элемента и обмена использовать функцию.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

#define _CRT_SECURE_NO_WARNINGS
#include
// Функция обмена
void change(int *x, int n)
{
// x - указатель на массив (адрес массива)
// n - размер массива
int i;
int max, index;
max = x;
index = 0;
// Поиск максимального элемента
for (i = 1; i {
if (x[i]>max)
{
max = x[i];
index = i;
}
}
// Обмен
x = x;
x = max;
}
// Главная функция
int main()
{
int a;
int i;
for (i = 0; i<10; i++)
{
printf("a[%d] = " , i);
scanf("%d" , &a[i]);
}
change(a, 10); // вызов функции обмена
// Вывод элементов массива
for (i = 0; i<10; i++)
printf("%d " , a[i]);
getchar();
getchar();
return
p = p * x[i];
}
return p;
}
// Главная функция
int main()
{
int a; // объявлен массив a из 5 элементов
int i;
int pr;
// Ввод элементов массива
for (i = 0; i<5; i++)
{
printf("a[%d] = " , i);
scanf("%d" , &a[i]); // &a[i] - адрес i-го элемента массива
}
pr = func(a, 5); // вычисление произведения
printf("\n pr = %d" , pr); // вывод произведения четных элементов
getchar(); getchar();
return 0;
}



>> Статьи

Что такое массивы в программировании?

Массив – это переменная, которая является совокупностью компонентов одного типа. Чтобы использовать массивы в программировании, потребуется предварительное описание определенного типа и указание доступа к элементам. Элементы массива в программировании объединены общим именем. Если требуется обратиться к определенному элементу массива, то достаточно указать имя и индекс. В математике есть понятный пример массива – это векторы и последовательности чисел, в которых группа чисел может обозначаться одним именем. Обратившись к конкретному числу, используют разные индексы.

Виды массивов: одномерные и двухмерные

Если для обращения к элементам использован единственный порядковый номер , то массив называется одномерный или линейный. Выглядит как таблица с одной строкой. Размерность массива определяется посредством количества индексов элементов.

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

Как заполнить массив?

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

Какие действия производятся с элементами массива?

Сортировка элементов в определенном порядке – убывание или возрастание

Поиск значений

Подсчет количества элементов в массиве, соответствующих определенному условию

Когда два массива эквивалентны, то возможно присвоение одному массиву имени другого. Все компоненты копируются в тот массив, которому и присваивается значение.

Как объявить массив

Чтобы объявить массив и выделить в памяти ячейку для хранения элементов, следует указать размерность и имя. Ключевое слово – массив. К примеру, А 20 означает, что одномерный массив состоит из двадцати элементов. К 6,5 означает, что это двухмерный массив , который представлен в виде таблицы из шести строк и пяти ячеек. Если говорить об ограничениях одномерного массива в программировании, то оно составляет тысячу элементов. Для двухмерных массивов максимально допустимым значением станет таблица из тысячи строк и тысячи ячеек.

Массивы в программировании: работа с ними

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

Типы имени, элементов, индексов

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

Что касается типа элементов в массиве, то это может быть ранее введенный или стандартный. Для создания индексов используются целые числа, а типом станет диапазон. Допустим, тип 1…20 говорит о том, что массив состоит из двадцати элементов, каждый из которых соответствует целому числу от одного до двадцати.