Перейти к содержимому

C-массивы (группы переменных)

  • Индексирование
  • Получение адреса первого элемента
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]{}?

Типа группы из 2 переменных (массив), по умолчанию равным нулю (благодаря {}).

Что такое массив?

Массив это как бы несколько переменных в одной. В данном случае, переменных как бы 2: arr[0] и arr[1].

Выражение “как бы” тут нарочно, потому что по факту arr[0] и arr[1] — это объекты, а не переменные, но это в другом уроке.

Ответ

arr[0] и arr[1] как бы эквивалентны именам переменных. То есть напечатается 1 и 2.

int arr1[2]{ 21, 32 };
std::cout << arr1[0];
std::cout << std::endl;
std::cout << arr1[1];
std::cout << std::endl;
Что значит этот синтаксис?

Здесь элементы массива заданы при создании, в том же порядке (0, 1).

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?

Это оператор, выполняющийся во время компиляции, который дает размер всего массива в байтах. В данном примере, в массиве arr1 3 инта, каждый по 4 байта, поэтому общий размер будет 12.

Какой размер у arr2?

У arr2 не задан размер, он определится автоматически из элементов.

Что значит []?

Это заменится во время компиляции на количество элементов справа (то есть 4, в этом примере) в качестве длины.

Ответ

3 инта по 4 байта — это 12.

4 инта по 4 байта — это 16.

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 вернёт размер указателя.

int arr[3]{ 1, 2, 3 };
size_t index { 2 };
int it { arr[index] };
std::cout << it;
std::cout << std::endl;
Ответ

Можно использовать “номер переменной” (индекс) из другой переменной или выражения.

Ответ будет 3.

int arr[3]{};
size_t index { 2 };
arr[index] = 5;
std::cout << arr[2];
std::cout << std::endl;
Ответ

Запись по индексу тоже можно делать исходя из индекса, произошедшего из выражения.

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.

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.
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 дважды.

int arr[3]{ 1, 2, 3 };
std::cout << arr;
std::cout << std::endl;
Ответ

Когда arr используется в качестве выражения (как аргумент <<), он деградирует в указатель на первый элемент, то есть эквивалентно &arr[0].

std::cout не умеет печатать C-массивы фиксированного размера — он видит лишь указатель, поэтому напечатается этот адрес, а не элементы 1, 2, 3. Чтобы напечатать элементы, нужно выводить каждый элемент по индексу, как в первых примерах.