Лекция № 4

Тема: «Обработка массивов на С++»

 

План

1. Описание одномерных массивов

2. Ввод/вывод одномерных массивов

3. Пример обработки одномерных массивов

4. Описание двумерных массивов

5. Ввод/вывод двумерных массивов

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

 

1. Описание одномерных массивов

Массив – это тип данных, который может содержать несколько значений одного типа. Для создания массива используется оператор объяв­ления. Объявление массива должно содержать три аргу­мента:

В C++ это реализуется путем изменения объявления простой переменной путем добавления скобок, которые содержат число элементов. Например, допустимы следующие объявления:

 

int mas[20]; //описан массив из 20 целых чисел

float mas1[10]; //описан массив из 10 вещественных чисел

 

Многие полезные свойства массива обусловлены тем фактом, что можно обращаться к элементам массива по отдельности. Для этого нужно использовать индекс для перечисления элементов. Массив в C++ нумеруется, начиная с 0. В C++ используется запись с индексом в квад­ратных скобках, чтобы определить элемент массива. Например, mas[0] – первый элемент массива mas, a mas[9] – десятый элемент. Обратите внимание, что индекс последнего элемента на единицу меньше, чем размер массива. Таким образом, объявление массива дает возможность создать множество перемен­ных одним объявлением, а затем можно использовать индекс, чтобы идентифицировать отдельные элементы.

Для обработки массива удобно использовать цикл for. Так как нумерация элементов в массиве начинается с 0, то конечное значение счетчика цикла должно быть на 1 меньше размера массива.

Например, пусть массив имеет описание:

float mas[10]; //массив из 10 вещественных чисел

 

Для обработки такого массива оператор цикла будет иметь вид:

//счетчик изменяется от 0 до 9 (всего 10 значений)

for (i=0; i<=9; i++)

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

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

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

Приведем пример описания такого макссива.

 

//описываем переменную-указатель на массив

float *mas;

//описываем переменную для ввода размера массива

int n;

//вводим размер массива

cout<<"Введите размер массива ";

cin>>n;

//описываем динамический массив указанного размера

mas=new float [n];

 

После описания такого массива обращаться к его элементам можно также, как и к элементам обычного массива: mas[0], mas[5], mas[i].

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

 

delete[] mas; (начало)

 

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

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

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

Инициализация массива при описании

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

Например, допустимо описание вида:

 

int mas[5]={2, 3, 5, -4, 0};

float mas1[4]={12.3, -0.15, 3.65, 2.458};

 

Если массив инициализируется частично, то транс­лятор устанавливает оставшиеся элементы равными нулю. Таким образом, можно присвоить всем элементам массива нуль – нужно только явно присвоить нуль пер­вому элементу и позволить компилятору инициализиро­вать нулем оставшиеся элементы:

 

float mas[1]={0};

 

Заполнение массива случайными числами

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

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

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

 

Замечания:

 

Пример. Массив из 10 вещественных чисел заполнить случайными числами.

//подключаем заголовочные файлы

#include <iostream.h>

#include <stdlib.h>

int main()

{

//отобраэаем русские символы

system("chcp 1251>nul");

//описываем концы отрезка и массив

float a,b,*mas;

//описываем счетчик цикла и количество элементов

int i,n;

//вводим количество элементов в массиве

cout<<"Введите размер массива: ";

cin>>n;

//описываем массив из n элементов

mas=new float [n];

//вводим концы отрезка

cout<<"Введите начало и конец отрезка: ";

cin>>a>>b;

//обнуляем базы для генерирования случайных чисел

srand(time(0));

//задаем точность для вывода массива на экран

cout.precision(4);

//организуем цикл для работы с массивом

for (i=0; i<=n-1; i++)

{

//записываем в очередной элемент массива случайное значение

mas[i]=(b-a)*rand()/32767+a;

//выводим элемент массива на экран

cout<<"mas["<<i+1<<"]="<<mas[i]<<"\n";

}

//удаляем массив из памяти

delete[] mas;

//делаем паузу для просмотра

system("pause");

//завершаем работу программы

return 0;

}

 

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

Ввод массива с клавиатуры

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

При этом ввод можно выполнить двумя способами:

 

В первом случае код может иметь вид:

//подключаем заголовочные файлы

#include <iostream.h>

int main()

{

//подключаем русский язык

system("chcp 1251>nul");

//описываем массив

float *mas;

//описываем счетчик цикла и размер массива

int i,n;

//вводим количество элементов в массиве

cout<<"Введите размер массива: ";

cin>>n;

//описываем массив из n элементов

mas=new float [n];

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

//организуем цикл для работы с массивом

for (i=0;i<=n-1;i++)

{

//вводим очередной элемент массива

cout<<"mas["<<i+1<<"]=";

cin>>mas[i];

}

//удаляем массив из памяти

delete[] mas;

//делаем паузу для просмотра

system("pause");

return 0;

}

 

Во втором случае код может иметь вид:

//подключаем заголовочные файлы

#include <iostream.h>

#include <conio.h>

int main()

{

//подключаем русский язык

system("chcp 1251>nul");

//описываем массив

float *mas;

//описываем счетчик цикла и размер массива

int i,n;

//вводим количество элементов в массиве

cout<<"Введите размер массива: ";

cin>>n;

//описываем массив из n элементов

mas=new float [n];

cout<<"Введите элементы массива через пробел: \n";

//организуем цикл для работы с массивом

for (i=0;i<=n-1;i++)

//вводим очередной элемент массива

cin>>mas[i];

//удаляем массив из памяти

delete[] mas;

//делаем паузу для просмотра

system("pause");

return 0;

}

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

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

В нашем примере для вывода массива в столбец фрагмент кода может иметь вид:

 

cout<<"Массив имеет вид:\n";

for (i=0; i<=n-1; i++)

cout<<"mas ["<<i+1<<"] = "<<mas[i]<<"\n";

 

Для вывода массива в строку фрагмент кода может иметь вид:

 

cout<<"Массив имеет вид:\n";

for (i=0; i<=n-1; i++)

cout<<"mas["<<i+1<<"]="<<mas[i]<<" "; (начало)

 

3. Пример обработки одномерных массивов

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

Приведем пример. Пусть имеется массив из целых чисел. Найти среднее значение четных чисел и произведение чисел, меньших найденного среднего. Массив заполнить случайными числами на отрезке [a,b].

 

//подключаем заголовочные файлы

#include <iostream.h>

#include <stdlib.h>

int main()

{

//подключаем русский язык

system("chcp 1251>nul");

//концы отрезка и переменные для результатов

float a, b, sum, pr;

//описываем массив

int *mas;

//описываем счетчик цикла, размер массива, количество четных чисел

int i,n, kol;

//вводим количество элементов в массиве

cout<<"Введите размер массива: ";

cin>>n;

//описываем массив из n элементов

mas=new int[n];

//вводим концы отрезка

cout<<"Введите начало и конец отрезка: ";

cin>>a>>b;

//обнуляем базы для генерирования случайных чисел

srand(time(0));

//выводим заголовок массива

cout<<"Массив имеет вид:\n";

//запускаем цикл для работы с массивом

for (i=0; i<=n-1; i++)

{

//заполняем очередной элемент случайным числом

mas[i]=(b-a)*rand()/32767+a;

//выводим элемент на экран

cout<<"mas["<<i+1<<"]="<<mas[i]<<"\n";

}

//запускаем цикл для подсчета среднего четных чисел

//в цикле инициализируем сумму и количество

for (sum=0, kol=0, i=0; i<=n-1; i++)

//проверка элемента массива на четность: если элемент делится на 2 без остатка

if (mas[i] % 2 ==0)

     {

//добавляем его к сумме четных чисел 

sum+=mas[i];

//увеличиваем количество четных чисел на 1    

kol++;

};

//выдаем результат

cout<<"Количество четных: "<<kol;

cout<<", их сумма: "<<sum;

cout<<", их среднее: "<<sum/kol<<"\n";

 

//находим произведение элементов, меньших найденного среднего

//инициализируем произведение в цикле

for (pr=1, i=0; i<=n-1; i++)

//если элемент меньше найденного среднего

if (mas[i]<(sum/kol))

//умножаем произведение на этот элемент

pr*=mas[i];

//выдаем результат

cout<<"Произведение по условию = "<<pr<<endl;

//удаляем массив из памяти

delete[] mas;

//делаем паузу для просмотра

system("pause");

return 0;

}

 

Замечания:

 

4. Описание двумерных массивов

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

int mas[4][3];         //описан двумерный массив целых чисел 4х3

float mas1[5][5]; //описан двумерный массив вещественных чисел 5х5

 

Для обращения к элементу такого массива указывают имя массива и в квадратных скобках номер строки и номер столбца. Например, mas[2][3] – элемент, стоящий на пересечении третьей строки и четвертого столбца.

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

Например, пусть массив имеет описание:

float mas[4][5]; //массив вещественных чисел 4x5

 

Для обработки такого массива оператор цикла будет иметь вид:

//счетчик строк изменяется от 0 до 3 (всего 4 значения)

for (i=0; i<=3; i++)

//счетчик столбцов изменяется от 0 до 4 (всего 5 значений)

for (j=0; j<=4; j++)

Динамические двумерные массивы

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

Для описания динамического двумерного массива использую код:

 

//описываем динамический массив

float **mas;

//описываем переменные для указания размера массива

//n – количество строк,  m – количество столбцов, i счетчик цикла

int n,m,i;

 

cout<<"Введите число строк и столбцов в массиве (n,m): ":

cin>>n>>m;

//выделяем память под двумерный массив

mas=new float *[n];

for (i=0;i<=n-1;i++)

    mas[i]=new float [m]

 

После создания такого массива к его элементам можно обращаться так же, как и к элементам обычного массива: mas[i][j]

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

 

for (i=0,i<=n-1,i++)

    delete[] mas[i];

delete[] mas; (начало)

 

5. Ввод/вывод двумерных массивов

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

Инициализация массива при описании

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

Например, допустима запись вида:

 

//описан и заполнен массив целых чисел 2х3

int mas[2][3]={{6,5,8},{0,-8,4}};

//описан и заполнен массив вещественных чисел 2х2

float mas1[2][2]={{2.3,12.6},{0.65,-56.87}};

 

Заполнение массива случайными числами

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

Например, заполним случайными числами массив вещественных чисел размером 4х3.

 

//подключаем заголовочные файлы

#include <iostream.h>

#include <stdlib.h>

int main()

{

//подключаем отображение русских символов

system("chcp 1251>nul");

//описываем переменные для концов отрезка заполнения массива

float a, b;

//счетчики цикла

int i,j;

   

//описываем двумерный динамический массив

float **mas;

//описываем переменные для указания размера массива

int n,m;

//вводим размер массива (n-строки, m-столбцы)

cout<<"Введите число строк и столбцов в массиве (n,m): ";

cin>>n>>m;

//выделяем память под динамический массив

mas=new float *[n];

for (i=0;i<=n-1;i++)

mas[i]=new float [m];

 

//вводим начало и конец отрезка

cout<<"Введите начало и конец отрезка: ";

cin>>a>>b;

 

//обнуляем базы для генерирования случайных чисел

srand(time(0));

 

//задаем точность вывода массива на экран

cout.precision(4);

//выдаем заголовок массива

cout<<"Массив имеет вид:\n";

//запускаем цикл по строкам массива

for (i=0; i<=n-1; i++)

{

//запускаем цикл по столбцам массива

for (j=0; j<=m-1; j++)

{

//в элемент массива записываем случайное число

mas[i][j]=(b-a)*rand()/32767+a;

//задаем ширину вывода элемента массива

cout.width(6);

//выдаем элемент массива на экран

cout<<mas[i][j]<<" ";

}

//переводим курсор на новую строку

cout<<"\n";

}

 

//удаляем массив из памяти

for (i=0; i<=n-1;i++)

     delete[] mas[i];

delete[] mas;

 

//делаем паузу для просмотра

system("pause");

return 0;

}

 

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

 

Ввод массива с клавиатуры

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

 

//подключаем заголовочные файлы

#include <iostream.h>

#include <stdlib.h>

int main()

{

//подключаем отображение русских символов

system("chcp 1251>nul");

//описываем переменные для концов отрезка заполнения массива

float a, b;

//счетчики цикла

int i,j;

   

//описываем двумерный динамический массив

float **mas;

//описываем переменные для указания размера массива

int n,m;

//вводим размер массива (n-строки, m-столбцы)

cout<<"Введите число строк и столбцов в массиве (n,m): ";

cin>>n>>m;

 

//выделяем память под динамический массив

mas=new float *[n];

for (i=0;i<=n-1;i++)

mas[i]=new float [m];

 

//выдаем заголовок массива

cout<<"Введите значения массива 5х5: \n";

//организовываем цикл по строкам массива

for (i=0; i<=n-1; i++)

//организовываем цикл по столбцам массива

for (j=0; j<=m-1; j++)

//вводим текущий элемент массива

cin>>mas[i][j];

 

 

//удаляем массив из памяти

for (i=0; i<=n-1;i++)

     delete[] mas[i];

delete[] mas;

 

//делаем паузу для просмотра

system("pause");

return 0;

}

 

Замечание: при вводе значения каждой строки вводят через пробел и в конце нажимают Enter.

 

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

Двумерный массив целесообразно выдавать в виде матрицы. Фрагмент такого вывода приведен в пример по случайному заполнению массива. Код вывода может иметь вид:

//запускаем цикл по строкам массива

for (i=0;i<=n-1;i++)

{

//запускаем цикл по столбцам массива

for (j=0;j<=m-1;j++)

{

    //задаем ширину вывода элемента массива

    cout.width(6);

    //выдаем элемент массива на экран

    cout<<mas[i][j]<<" ";

    }

//переводим курсор на новую строку

cout<<"\n";

} (начало)

 

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

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

 

//подключаем заголовочные файлы

#include <iostream.h>

#include <stdlib.h>

 

int main()

{

system("chcp 1251>nul");

//описываем концы отрезка, максимальное значение

float a, b, max;

//описываем счетчики циклов

int i,j;

 

 //описываем массив

float **mas;

//описываем переменные для указания размера массива

int n,m;

cout<<"Введите число строк и столбцов в массиве (n,m): ";

cin>>n>>m;

//выделяем память под динамический массив

mas=new float *[n];

for (i=0;i<=n-1;i++)

    mas[i]=new float [m];

 

//вводим концы отрезков

cout<<"Введите начало и конец отрезка: ";

cin>>a>>b;

//обнуляем базы для генерирования случайных чисел

srand(time(0));

//задаем точность вывода

cout.precision(3);

//выдаем заголовок массива

cout<<"\nИсходный массив имеет вид:\n";

//запускаем цикл по строкам массива

for (i=0;i<=n-1; i++)

{

//запускаем цикл по столбцам массива

for (j=0; j<=m-1; j++)

{

     //элементу массива присваиваем случайное число

     mas[i][j]=(b-a)*rand()/32767+a;

     //задаем ширину вывода элемента масcива

     cout.width(6);

     //выдаем элемент на экран

     cout<<mas[i][j]<<" ";

}

//переводим курсор на новую строку

cout<<"\n";

}

 

//максимуму присваиваем первое значение массива

max=mas[0][0];

//в цикле находим максимальный элемент в массиве

for (i=0; i<=n-1; i++)

for (j=0; j<=m-1; j++)

     if (mas[i][j]>=max)

         max=mas[i][j];

//выводим найденное максимальное значение на экран

cout<<"\nМаксимальный элемент="<<max<<"\n";

 

//организуем цикл по столбцам массива

for (j=0; j<=m-1; j++)

//к элементу третьей строки прибавляем

//максимальное значение

     mas[2][j]+=max;

 

//выдаем заголовок массива

cout<<"\nК элементам третьей строки прибавили максимальное значение:\n";

//организуем цикл по строкам массива

for (i=0; i<=n-1; i++)

{

//организуем цикл по столбцам массива

for (j=0; j<=m-1; j++)

{

    //задаем ширину вывода элемента массива

    cout.width(6);

    //выдаем элемент массива на экран

    cout<<mas[i][j]<<" ";

}

//переводим курсор на новую строку

cout<<"\n";

}

 

//удаляем массив из памяти

for (i=0; i<=n-1; i++)

     delete[] mas[i];

delete[] mas;

 

//делаем паузу для просмотра

system("pause");

return 0;

} (начало)