C-массивы (группы переменных)
Концепты
Заголовок раздела «Концепты»- Индексирование
- Получение адреса первого элемента
Примеры на понимание
Заголовок раздела «Примеры на понимание»1. Массив
Заголовок раздела «1. Массив»int arr[2]{};arr[0] = 1;arr[1] = 2;
std::cout << arr[0];std::cout << std::endl;
std::cout << arr[1];std::cout << std::endl;
Что значит int arr[2]{}?
int arr[2]{}?Типа группы из 2 переменных (массив), по умолчанию равным нулю (благодаря {}).
Что такое массив?
Массив это как бы несколько переменных в одной.
В данном случае, переменных как бы 2: arr[0] и arr[1].
Выражение “как бы” тут нарочно, потому что по факту arr[0] и arr[1] — это объекты,
а не переменные, но это в другом уроке.
Ответ
arr[0] и arr[1] как бы эквивалентны именам переменных.
То есть напечатается 1 и 2.
2. Инициализация массива
Заголовок раздела «2. Инициализация массива»int arr1[2]{ 21, 32 };
std::cout << arr1[0];std::cout << std::endl;
std::cout << arr1[1];std::cout << std::endl;Что значит этот синтаксис?
Здесь элементы массива заданы при создании, в том же порядке (0, 1).
3. Массив с неуказанной длинной
Заголовок раздела «3. Массив с неуказанной длинной»int arr1[3]{ 1, 2, 3 };int arr2[]{ 1, 2, 3, 4 };
std::cout << sizeof(arr1);std::cout << std::endl;
std::cout << sizeof(arr2);std::cout << std::endl;
Что такое sizeof?
sizeof?Это оператор, выполняющийся во время компиляции, который дает размер всего массива в байтах.
В данном примере, в массиве arr1 3 инта, каждый по 4 байта, поэтому общий размер будет 12.
Какой размер у arr2?
arr2?У arr2 не задан размер, он определится автоматически из элементов.
Что значит []?
[]?Это заменится во время компиляции на количество элементов справа (то есть 4, в этом примере) в качестве длины.
Ответ
3 инта по 4 байта — это 12.
4 инта по 4 байта — это 16.
4. Размер массива с элементами типа size_t
Заголовок раздела «4. Размер массива с элементами типа size_t»size_t arr[3]{ 1, 2, 3 };
std::cout << sizeof(arr);std::cout << std::endl;Ответ
sizeof дает размер всего массива в байтах, а не количество элементов.
Здесь каждый элемент имеет тип size_t — это 8 байт на 64-битной системе,
поэтому 3 элемента по 8 байт — это 24.
5. Вычисление количества элементов через sizeof
Заголовок раздела «5. Вычисление количества элементов через sizeof»int arr[]{ 1, 2, 3, 4 };
std::cout << sizeof(arr);std::cout << std::endl;
std::cout << sizeof(arr[0]);std::cout << std::endl;
std::cout << sizeof(arr) / sizeof(arr[0]);std::cout << std::endl;Как вычислить количество элементов через sizeof?
Чтобы получить количество элементов, нужно поделить размер всего массива на размер одного элемента.
Ответ
Здесь sizeof(arr) — это 16 (4 инта по 4 байта),
sizeof(arr[0]) — это 4 (один int),
поэтому 16 / 4 даст 4 элемента.
Это работает, только пока arr остается массивом.
Как только он деградирует (decays) в указатель (см. ниже),
sizeof вернёт размер указателя.
6. Чтение по индексу
Заголовок раздела «6. Чтение по индексу»int arr[3]{ 1, 2, 3 };size_t index { 2 };int it { arr[index] };std::cout << it;std::cout << std::endl;Ответ
Можно использовать “номер переменной” (индекс) из другой переменной или выражения.
Ответ будет 3.
7. Вписывание по индексу
Заголовок раздела «7. Вписывание по индексу»int arr[3]{};size_t index { 2 };arr[index] = 5;std::cout << arr[2];std::cout << std::endl;Ответ
Запись по индексу тоже можно делать исходя из индекса, произошедшего из выражения.
8. Выражение как индекс
Заголовок раздела «8. Выражение как индекс»int arr[3]{};size_t index { 1 };arr[index + 1] = 5;std::cout << arr[2];std::cout << std::endl;Ответ
Здесь демонстрируется использование более сложного выражения для получения индекса.
9. Связь переменной и массива после перезаписи
Заголовок раздела «9. Связь переменной и массива после перезаписи»int arr[3]{ 0, 2, 1 };size_t index { 2 };int it { arr[index] };arr[index] = 5;std::cout << it;std::cout << std::endl;Ответ
В it на строчке int it { arr[index] } будет скопировано значение 1,
а не ссылка на элемент в массиве, поскольку тип it это int.
Так как это просто int, изменение переменной, из которой произошло его значение,
после присваивания, не воздействует на it.
Выведется 1.
10. Указатель как тип элемента
Заголовок раздела «10. Указатель как тип элемента»int a = 1;int b = 2;int* arr[]{ &a, &b };*arr[0] = 3;*arr[1] = *arr[0];
std::cout << arr[0] << std::endl;std::cout << arr[1] << std::endl;
std::cout << *arr[0] << std::endl;std::cout << *arr[1] << std::endl;Ответ
В массивах можно хранить данные, отличные от int.
В данном примере, в массиве были сохранены указатели на int (int*).
arr[0]содержит адрес переменнойa.arr[1]содержит адрес переменнойb.a, эквивалентно*arr[0], равно3.b, эквивалентно*arr[1], равно3.
11. Использование массива как адрес
Заголовок раздела «11. Использование массива как адрес»int arr[2]{};int* p = arr;*arr = 1;
std::cout << *p;std::cout << std::endl;
std::cout << arr[0];std::cout << std::endl;
std::cout << arr[1];std::cout << std::endl;Ответ
Когда arr используется в качестве выражения в int* p = arr,
он деградирует (decays) в указатель на первый элемент из массива.
arr тут эквивалентно &arr[0] или &(arr[0]).
И *p, и *arr, и arr[0] ссылаются на ту же переменную.
Выведется 1 дважды.
12. Печать массива
Заголовок раздела «12. Печать массива»int arr[3]{ 1, 2, 3 };std::cout << arr;std::cout << std::endl;Ответ
Когда arr используется в качестве выражения (как аргумент <<),
он деградирует в указатель на первый элемент, то есть эквивалентно &arr[0].
std::cout не умеет печатать C-массивы фиксированного размера —
он видит лишь указатель, поэтому напечатается этот адрес, а не элементы 1, 2, 3.
Чтобы напечатать элементы, нужно выводить каждый элемент по индексу, как в первых примерах.