Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции_С++_последная.doc
Скачиваний:
40
Добавлен:
07.05.2019
Размер:
876.54 Кб
Скачать

2.3. Массивы

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

При объявлении массива необходимо указать тип элемента, имя и количество элементов (ячеек).

тип имя_переменной[размер]

Например:

int arr1[10]; // массив из 10 ячеек типа int;

double arr2[50]; // массив из 50 ячеек типа double;

Для доступа к i-му элементу используют запись:

vals[i] где i может принимать значение от 0 до N-1, N-число элементов.

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

В языке С/С++ массивы могут иметь больше двух размерностей. Максимально допустимое количество размерностей задается компилятором. Общий вид объявления многомерного массива таков:

тип имя_переменной[размер1] [размер2] [размер3]… [размерN]

Например:

int vals[5][7]; // двумерный массив, размером 5х7;

char text[10][25][80]; // трехмерный массив 10 x 25 x 80.

Таким образом, для двумерного массива объявлением является прямоугольная матрица, а для трехмерного - куб с ячейками. Однако в памяти ЭВМ все массивы похожи на цепочки – элементы располагаются друг за другом. Например:

int a[2][3]; /* представлено в виде матрицы;

a[0][0] a[0][1] a[0][2];

a[1][0] a[1][1] a[1][2] */.

Массивы, имеющие больше трех размерностей, используются редко, поскольку они занимают слишком большой объем памяти. Например, четырехмерный массив символов размерностью 10×6×9×4 занимает 2160 байт.

2.3.1. Инициализация массивов

Общий вид инициализации массива не отличается от инициализации обычных переменных:

тип_массива имя_массива [размер1]…[размерN] = {список_значений};

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

Инициализация одномерного массива осуществляется так:

int vals[10]={1,2,3,4,5,6,7,8,10};

Инициализация двумерного массива может быть выполнена следующим образом:

int b[2][2] = { { 1,2 }, { 3,4 } };

При инициализации массива можно опустить одну или несколько размерностей:

int b[]3[] = { { 1,2 }, { 3,4 } };

Если при инициализации указано меньше значений для строк, то оставшиеся элементы инициализируются 0, т.е. при описании int b[2][2] = { { 1,2 }, { 3 } }; элементы первой строки получат значения 1 и 2, а второй 3 и 0.

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

Если до начала работы программы неизвестно, сколько в массиве элементов, в программе следует использовать динамические массивы. Память под них выделяется с помощью операции new или функции malloc в динамической области памяти во время выполнения программы. Адрес начала массива хранится в переменной, называемой указателем. Например:

int n = 10;

int *a = new int[n];

double *b - (double *)malloc(n *sizeof (double));

Во второй строке описан указатель на целую величину, которому присваивается адрес начала непрерывной области динамической памяти, выделенной с помощью операции new. Выделяется столько памяти, сколько необходимо для хранения n величин типа int. Величина n может быть переменной.

Обращение к элементу динамического массива осуществляется так же, как и к элементу обычного – например а[3]. Можно обратиться к элементу массива и другим способом – *(а + 3). В этом случае мы явно задаем те же действия, что выполня­ются при обращении к элементу массива обычным образом. Рассмотрим их подробнее. В переменной-указателе а хранится адрес начала массива. Для получения адреса третьего элемента к этому адресу прибавляется смещение 3. Операция сложения с константой для указателей учитывает размер адресуемых элементов, то есть на самом деле индекс умножается на длину элемента массива: а + 3 *sizeof(int). Затем с помощью операции * (разадресации) выполняется выборка значения из указанной области памяти.

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

delete [] a; // Размерность массива при этом не указывается.

Сумма элементов правее последнего отрицательного. Написать программу, которая для вещественного массива из п элементов определяет сумму его элементов, расположенных правее последнего отрицательного элемента.

В этой задаче размерность массива задана переменной величиной. Предполагается, что она будет нам известна на этапе выполнения программы до того, как мы будем вводить сами элементы. В этом случае мы сможем выделить в динамической памяти непрерывный участок нужного размера, а потом заполнять его вводимыми значениями. Если же стоит задача вводить заранее неизвестное количество чисел до тех пор, пока не будет введен какой-либо признак окончания ввода, то заранее выделить достаточное количество памяти не удастся и придется воспользоваться так называемыми динамическими структурами данных, например списком. Мы рассмотрим эти структуры на девятом семинаре, а пока остановимся на первом предположении – что количество элементов массива вводится с клавиатуры до начала ввода самих элементов.

Вот как выглядит построенная по этому алгоритму программа:

finclude <iostream.h>

int main()

{

int n;

cout << " Введите количество элементов "; cin >> n;

int i, ineg;

float sum, *a = new float [n] // 1

cout << " Введите элементы массива ";

for (i = 0; i < n; i++) cin >> a[i];

for (i = 0; i < n; i++) cout << a[i] << ' '; // 2.

for (i = 0; i < n; i++) if (a[i] < 0) ineg = i; // 3

for (sum = 0; i = ineg + 1; i < n; i++) sum +- a[i]; // 4

cout << " Сумма " << sum;

return 0;

}

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

Номер последнего отрицательного элемента массива формируется в переменной i neg. При просмотре массива с помощью оператора 3 в эту переменную последовательно записываются номера всех отрицательных элементов массива, таким образом, после выхода из цикла в ней остается номер самого последнего.

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

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

finclude <iostream.h>

int main()

{

int n;

cout << "Введите количество элементов: "; cin >> n;

float *a = new float [n];

int i;

cout << "Введите элементы массива: ";

for (i = 0; i < n; i++) cin >> a[i];

bool flag_neg = false;

float sum = 0;

for (i = n – 1; i >= 0; i++)

if (a[i]<0) { flag_neg = true; break; }

sum+= a[i];

}

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

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