Массив представляет нечто целое, что содержит целый набор однотипных элементов.
Мобильный телефон представляет из себя своеобразный массив, который содержит в себе набор контактов.
Спичечная коробка представляет из себя своеобразный массив, который содержит в себе набор спичек.
Квартирный дом представляет из себя своеобразный массив, который содержит в себе набор хозяев квартир.
Парк машин представляет из себя своеобразный массив, который содержит в себе коллекцию машин.
В общем, массив напоминает обычную коробку с хранимыми внутри вещами материального мира, например, продуктами.
Сам массив удобен для хранения, но ценны хранимые внутри него элементы, а не непосредственно массив. Конечно в мире материальном коробка может оказаться золотой, потому и дороже своих внутренностей, но в мире программирования массивы являются обычными контейнерами хранения.
Обрабатывая массивы, программист работает не с массивом, как с таковым, а с его внутренними данными. В отличие от материального мира, где хранимые объекты могут не обладать свойством самоидентификации, массивы мира программистов всегда сами нумеруют элементы своих колллекций (обычные массивы) или дают элементу коллекции признаки идентификации (ассоциативные массивы).
В массиве главную роль играют его элементы, а сам массив играет второстепенные роли.
Каждый элемент коллекции массива всегда имеет какой-то признак своей идентификации. Признаком идентификации элемента обычного массива всегда является число, которое есть номер ячейки массива. Называется число, номер ячейки, индексом массива. По этому номеру всегда можно идентифицировать и обработать некоторый элемент из массива.
Надеюсь, смысл понятен. Массив — это хранилище, контейнер. Обрабатываются его элементы, а не сам массив. Каждый элемент массива идентифицируется или номером, или каким-то задаваемым программистом ключом. В обычных массивах, а сейчас вы изучаете обычные массивы, идентификация происходит по номеру. Компилятор сам нумерует элементы массива, нумерация в С++ начинается с нуля.
Язык С++ является надмножеством языка С. В первых версиях языка С++ программистам приходилось работать с массивами так же, как программистам С. Самые обычные массивы относятся к фундаментальным типам данных и являются составными типами. Есть два способа работы с такими, обычными, массивами. Первый способ — выделение памяти под заранее известное число элементов, второй способ — выделение памяти в ходе работы программы под задаваемое количество элементов. Второй способ требует ручного управления памятью, что новичкам в большинстве случаев неудобно.
Бывает так, что известно количество элементов, которое будет хранится в массиве, известно, что это количество элементов не изменится за всю жизнь работы программы. В таких случаях используют обычные массивы. Для примера подобной необходимости несколько жизненных вариантов:
Воллейбольная площадка: больше шести игроков на ней не играет.
Квартира жилого дома: во всём доме может не быть квартир, с количеством комнат, превышающим 5.
Виды осадков: выпадающие на планете Земля виды осадков ограничены некоторым числом (дождь, снег, град)
Штат сотрудников: штат сотрудников может быть строго фиксирован
Именно для таких случаев и используется самый обычный массив. Количество элементов таким массивам задаётся непосредственно в исходном коде программы. Изменить количество элементов в ходе работы программы таким массивам невозможно. Такие массивы назывются статически-создаваемыми массивами, иногда называют статическими, но слово статические плохо подходит из-за существования ключевого слова static.
C++
1
2
3
4
5
//Массивы Листинг #1
intmain(){
intArr[100];//Статически-создаваемый массив получает имя Arr и возможность хранить
//внутри себя 100 элементов
}
Статический массив на самом деле немного другой:
C++
1
2
3
4
5
//Массивы Листинг #2
intmain(){
staticintArr[100];//Статически-создаваемый статический массив получает имя Arr и возможность хранить
//внутри себя 100 элементов
}
Имеется различие в работе первого и второго. Описание различий выходит за рамки статьи. Но имейте в виду, что есть такой дефект в терминологии. Вроде и принято называть обычный массив статическим, но оно неправильно как-то выходит в конечном итоге.
Не путайте статические массивы со статически-создаваемыми. Говорите правильно.
От нас требуется массиву сообщить, какие типы он должен хранить в себе и количество элементов. Зная эти составляющие, компилятор выделит необходимую память для всего массива.
C++
1
2
3
4
5
6
7
8
//Массивы Листинг #3
intmain(){
intArr1[35];//Статически-создаваемый массив получает имя Arr1 и возможность хранить
//внутри себя 35 элементов, тип которых int
charArr2[255];//Статически-создаваемый массив получает имя Arr2 и возможность хранить
//внутри себя 255 элементов, тип которых char
}
В квадратных скобках указывается число хранимых элементов.
В подавляющем большинстве случаев интересен не сам массив, а то, что он содержит. Почти всегда обработка массивов предполагает обработку его элементов, причём часто предпалагается обработка всех элементов из массива. Для обхода элементов массивов используют циклы. Одна и та же обработка на каждый отдельный элемент массива сама собой напрашивает использование циклов: повторение одних и тех же действий.
В языке С++ численный отсчёт начинается с нуля. В некоторых других языках программирования с единицы. Немного нестандартное для обычного человека начало отсчёта сбивает с толку многих начинающих программистов: трудно первое время ориентироваться, постоянно нарушаются некоторые границы.
C++
1
2
3
4
5
//Массивы Листинг #4
intmain(){
intArr[10]={1,2,3,4,5,6,7,8,9};
cout<<Arr[10]<<'\n';//Ошибка! Выход за границы массива
}
Эта ошибка не контроллируется компилятором. Программист, пишуший код, а не компилятор должен контроллировать возникновение такой ситуации и не допускать её. Из-за того, что отсчёт в С++ начинается с нуля, последним индексом массива, хранящего 10 элементов, будет индекс 9:
C++
1
2
3
4
5
//Массивы Листинг #5
intmain(){
intArr[10]={1,2,3,4,5,6,7,8,9};
cout<<Arr[9]<<'\n';//Вывод на экран последнего элемента массива
}
Для любого массива C++, хранящего N элементов, индекс последнего элемента всегда N-1, а индекс первого элемента 0
Можно подстроить отсчёт под себя, выделив массиву на 1 элемент больше, но делать такое не нужно. Пишущий на C++ должен писать, придерживаясь правил C++. Следование принципу использвания правил языка, на котором пишешь, поможет вам в будущем.
Каждый элемент массива представляет из себя переменную с указанным массиву типом. В отличие от обычной переменной, которой название даёт программист, элементы обычного массива подобны автонумерующимся переменным. Т. е. название массива вместе с индексом элемента = переменная. Работать с элементами массива можно абсолютно так же, как работаем с переменными. Единственное отличие — индексация.
Если нужно инициализировать массив нулями, то это можно делать следующим образом:
C++
1
2
3
4
5
//Borland C++ 3.1 Массивы Листинг #8.1
//Инициализация массива нулями в старых компиляторах
intmain(){
intArr[100]={0,};//Инициализация массива нулями
}
C++
1
2
3
4
5
//clang Массивы Листинг #8.2
//Инициализация массива нулями в современных компиляторах
intmain(){
intArr[100]={};//Инициализация массива нулями
}
В общем, не нужно каждый ноль прописывать вручную для инициализации нулями. Но не запутайтесь, нельзя инициализировать массив, например, одними единицами показанным в #8.1 способом. #8.1 подходит только для нолей.
Правилами языка С++ разрешено использовать пустые скобки при инициализации массивов. В случае использования пустых квадратных скобок компилятор сам определит, сколько памяти массиву нужно выделить.
C++
1
2
3
//Массивы Листинг #9
intA[]={0,};// Выделилось (1 байт * sizeof(int)) На 2 элемента
intA[]={0,0,0,};//Выделилось (3 байта * sizeof(int)) На 3 элемента
Узнать, сколько байт уходит на один элемент массива, можно так:
C++
1
sizeof(A[0]]);
Узнать, сколько элементов может поместиться в массив, можно так:
C++
1
sizeof(A)/sizeof(A[0]]);
Переходим к написанию простеньких примеров.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Borland C++ 3.1 Массивы Листинг #10
//Вывод массива на экран
#include <iostream.h>
intmain()
{
constintN=10;//Размер обычного массива можно определить константой
intA[N]={0,};//Массив в 10 элементов. Каждый из элементов стал равен нулю
A[5]=100;//Присвоили шестому элементу значение 100; (0,1,2,3,4,5) в скобках шесть чисел, а не 5 из-за отсчета с нуля так.
for(inti=0;i<N;i++){
cout<<A[i]<<" ";//Вывели массив на экран поэлементно
}
cin.get();
}
Количество элементов обычного массива задаётся только константным значением.
Количество элементов обычному массиву можно задать только неизменяемым значением. Задать такое значение возможно только в исходном коде программы. Хотя некоторые компиляторы могут компилировать коды, в которых количество указывается переменной, допускающей изменения, такие действия не приветствуются.
C++
1
2
3
4
5
//Массивы Листинг #11
intmain(){
intN=10;
Arr[N]={};//НЕПРАВЛЬНО! Хотя допускается некоторыми компиляторами
}
C++
1
2
3
4
5
//Массивы Листинг #12
intmain(){
constintN=10;
Arr[N]={};//ПРАВЛЬНО!
}
Если массив требует себе расширения или наоборот, сужения, то обычный статически-создаваемый массив не подходит. Изменять число элементов в нём невозможно. Хранит он только фиксированное число элементов. Хоть размер такому, как в листинге #11, и можно задать во время работы программы, задать его можно единожды и изменениям он не подлежит.
Массив из листинга #11 может обманывать. Возможно подумать, что он умеет изменять пространство для хранимых в себе элементов, но на самом дее это совсем не так. Изменять пространство под хранимые элементы можно только с помощью указателей на массивы, а умеют это делать самостоятельно массивы из библиотек: STL, BOOST и т. п.
В С++ нельзя применять операции к самому массиву как к его элементам. Он как коробка, а компилятор такой: "Зачем мне коробка?". Коробка отличается от хранимых внутри неё элементов.
Иногда массивы называют матрицами. Пока что вы поверхностно ознакомлены с самым простым типом массива. Можете встретить задачу сложения одномерных матриц/массивов. Чтобы решить такого вида задачу, нужно иметь представление о том, как складывать между собой две цепочки чисел. На самом деле ничего сложного нет: каждый элемент такой цепочки складывается с элементом другой цепочки, а связь складываемых элементов определяется номером элемента в цепочке.
1 2 3 4 5
+
7 5 3 2 0
=========
8 7 6 6 5
Таким образом, можно говорить о том, что {1 2 3 4 5} + {7 5 3 2 0} = {8 7 6 6 5}
В задачах на операции с массивами: сложение, вычитание, умножение и деление — вас именно об этом и просят. Точно помню, было время, когда мне сложно было понять, чего от меня требуется.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//Borland C++ 3.1 Сложение одномерных массивов Листинг №13
#include <iostream.h>
#include <conio.h>
intmain()
{
clrscr();
intA[]={10,23,44};//Инициализация двух массивов
intB[]={11,0,55};
intsumAB[3];//Количество элементов в складываемых массивах = 3 (по 3 элемента) и в результирующий помещаем 3
for(inti=0;i<3;i++)
{
sumAB[i]=A[i]+B[i];//Сложение двух элементов с одинаковыми индексами
cout<<sumAB[i]<<" ";//Вывод на экран результата
}
cin.get();
}
Немного объясню листинг #13. Сначала создаётся два одномерных массива, эти массивы именуются именами: A и B. Эти объявленные массивы инициализируются значениями, указываемыми в фигурных скобках. Получается два массива с конкретными значениями. Эти значения складываются между собой. Каждое слагаемое определяется номером, индексом массива. Первый элемент одного массива складывается с первым элементом другого, второй со вторым и т. д. Чтобы не складывать каждый элемент вручную, использован циклический обход по всем элементам массивов. Для того, чтобы сохранять результаты, был добавлен ещё один массив, названный sumAB. Элементы A[1] и B[1] сложились и сохранились в sumAB[1], A[2] и B[2] сложились и сохранились в sumAB[2]. Вот и вся премудрость. Сохранённое значение сразу выводится на экран.
Задача: Получить сумму всех элементов массива.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Borland C++ 3.1 Сумма всех элементов одномерного массива Листинг №14
#include <iostream.h>
#include <conio.h>
intmain()
{
clrscr();
constintN=5;
intA[N]={11,23,44,55,12};//Инициализация двух массивов
intsum=0;//Обязательно установить начальное значение 0!
for(inti=0;i<N;i++){
sum=sum+A[i];//или sum+=A[i]
}
cout<<"sum = "<<sum<<'\n';
cin.get();
}
//11 + 23 +44 +55 + 12 = 145
Чтобы правильно считать сумму, обязательно нужно переменную, сохраняющую промежуточные результаты, в самом начале инициализировать нулём. Без инициализации нулём результирующей переменной правильный результат может сложиться неизвестно с чем. Будьте внимательны.
Нужно различать задачи и понимать, что вам действительно нужно. Вот приведено две задачи, обе на сумму элементов, но одна требует сложить все элементы массивов поиндексно (листинг #13), а другая просто сложить все элементы массива между собой (листинг #14). Вроде бы условия так похожи, а результаты вон насколь разные.
Бывает необходимость задания значений в массив с клавиатуры. Пока что во всех примерах значения в массив записывались сразу из исходного кода. Запись значений с клавиатуры требует обхода всего массива с указанием на ячейки для записи. Любой обход — всегда цикл. Всё остальное ничем не отличается от работы с обычными переменными.
C++
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
//Borland C++ 3.1 Ввод значений в массив клавиатурой Листинг №15
#include <iostream.h>
#include <conio.h>
intmain()
{
clrscr();
constintN=5;
intA[N];//Объявление массива из N Элементов
for(inti=0;i<N;i++){
cout<<"input A["<<i+1<<"]:";
cin>>A[i];//Ввод значения в ячейку массива с клавиатуры
}
cout<<"\nOur Array:\n";//Форматирование вывода на экран
//ВЫВОД НА ЭКРАН
for(inti=0;i<N;i++){//Обход массива поэлементно
cout<<A[i]<<' ';//Вывод на экран текущего значения
}
cin.ignore();
cin.get();
}
Писал уже об этом, но напомню лишний раз:
Начинающим программистам и пришлым программистам (например, с Turbo Pascal) сложно контроллировать границы массивов. Одна из очень распространённых ошибок всех новичков — выход за пределы массива. Отсчёт в С++ ведётся с нуля!
В языке С++ массивы могут быть многомерными: двумерные, трехмерные, четырёхмерные и т. д. Мерность массивов определяется количеством квадратных скобок:
C++
1
2
3
4
5
6
7
8
9
10
//Мерность массивов Листинг #16
constintN=10;
constintM=20;
constintK=30;
intmain(){
intArr1[N];//Одномерный массив из N элементов, т. е. 10
intArr2[N][M];//Двумерный массив, подобен таблице NxM (N*M элементов, т. е. 200)
intArr2[N][M][K];//Трёхмерный массив, подобен кубу NxMxK (N*M*K элементов, т. е. 6000)
}
Мерность массивов ничем не ограничена. Но слишком глубокомерные массивы использовать невыгодно: вы задолбаетесь с вложенность циклов. Если нужен слишком глубокомерный массив, то присмотритесь к классам или структурам. Глубокомерный массив — это мой термин, я не знаю, как иначе назвать слишком мощную многомерность.
Мерность массивов определяет уровень вложенности обрабатываемых их циклов:
cout<<Arr[i][j]<<' ';// вывод на экран значения, взятого по индексу двумерного массива
}
cout<<'\n';//Разделение строкой
}
cin.ignore();
cin.get();
}
Иногда говорят, что имя массива это указатель на первый элемент массива. Чисто технически такое утверждение неправильное. Имейте это в виду.
Имя массива это только идентификатор. По стандарту массивы имеют право приводиться к типу "указатель", при этом получаемый указатель указывает на первый элемент массива.
Такие дела. Типы данных "указатель" и "массив" отличны друг от друга. Хотя часто имя массива используется как указатель на первый хранимый элемент, в некоторых случаях поведения у имени массива и переменной, тип которой указатель, будут отличаться.
Несмотря на то, что имя массива можно использовать как указатель, обработка указателей и обработка массивов может происходить по-разному. Компиляторы C++ различают массивы и указатели. Сходство очень большое, но некоторые отличия вы увидите прямо сейчас:
Операция sizeof, применённая к массиву, вернет сколько байт выделено массиву
Операция sizeof, применённая к указателю, вернет размер указателя
Адрес указателя поменять можно
Адрес массива поменять нельзя
Значением указателя, инициализированного с помощью выражения размещения, является адрес начала этой области. Сам указатель, как объект, обладает своим собственным адресом.
К сожалению, это не всё, что имеет смысл рассказать о массивах. Но тема уже получилась достаточно объёмной, надеюсь, что очень полезной. Цель этой статьи — дать вам понять природу массивов, научить их понимать и научить использовать массивы в ваших кодах. Статья ограничена описанием самого обыкновенного массива. Описание указателя на массивы выходит за рамки этой темы.
В С++11 был добавлен шаблонный класс array
Если вы сможете понять синтаксис этого шаблонного класса, то вместо обычных массивов лучше используйте array
C++
1
2
3
4
5
6
7
//clang C++11 или выше массивы array Листинг #18
#include <array>
intmain(){
array<int,10>Arr;//Объявлен массив Arr из 10 элементов типа int
}
Использование массивов, по листингу #18, вообще ничем не отличается от использования обычных массивов. Отличается только способ объявления.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//Borland C++ 3.1 Ввод значений в массив клавиатурой Листинг №13
#include <iostream>
#include <array>
usingnamespacestd;
intmain()
{
constintN=10;
array<int,N>Arr;//Объявление такое
//Используется как обычно
for(inti=0;i<N;i++){
Arr[i]=i+1;
}
for(inti=0;i<N;i++){
cout<<Arr[i]<<' ';
}
}
Хотя многомерные массивы array выглядит достаточно ужасно, но если вдруг кому надо:
C++
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
//Borland C++ 3.1 Ввод значений в массив клавиатурой Листинг №13
#include <iostream>
#include <array>
usingnamespacestd;
intmain()
{
constintN=10;
constintM=10;
array<array<int,N>,M>Arr;//Объявление такое
intindex=0;
//Используется как обычно
for(inti=0;i<N;i++){
for(intj=0;j<M;j++){
Arr[i][j]=index++;
}
}
for(inti=0;i<N;i++){
for(intj=0;j<M;j++){
cout.width(3);
cout<<Arr[i][j]<<' ';
}
cout<<'\n';
}
}
Любой многомерный массив — это массив, хранящий массивы. Это в любых массивах так. В случае объявления array это просто более очевидно.
Схема объявления шаблонного класса array на первое время может быть, например, такой:
Объявить тип array и прилепить к нему угловые скобки:
C++
1
array<>
Дать имя массиву:
C++
1
array<>Arr;
Указать тип и количество элементов внутри угловых скобок:
C++
1
array<int,10>Arr;
Чтобы создать двумерный массив, нужно массив заворачивать в массив. Чтобы трёхмерный: массив заворачивается в массив, всё это дело заворачивается в свой массив.
=====================
Небольшой набор задач, способных вызывать затруднения
Привет, нужна помощь.
Как найти сумму положительных чисел двух одномерных массивов, т.е. есть два массива, их надо объеденить в один, но при этом, отрицательные числа при сложении равны 0 ( если есть -2 и 3,то будет 0+3). Нужен код или структурная схема. Буду очень благодаен за помощь.
😥
Пажалуйста помогите нужно в однотипном массиве состоящего из 10ти элементов умножить первый и последний элементы но они оба равны нулю
0 * 0 == 0
Привет, нужна помощь.
Как найти сумму положительных чисел двух одномерных массивов, т.е. есть два массива, их надо объеденить в один, но при этом, отрицательные числа при сложении равны 0 ( если есть -2 и 3,то будет 0+3). Нужен код или структурная схема. Буду очень благодаен за помощь.