Можете, пожалуйста, сказать, чем отличаются эти строки ptr1
и ptr2
? Работают они, вроде бы, одинаково.
int mas[5] = {1, 2, 3, 8};
const int *ptr1 = mas;
const int (&ptr2)[5] = mas;
Первое действительно объявляет указатель, второе - объявляет ссылку (так как ссылка на массив, оно может неявно преобразовываться в указатель, как и сам массив).
ptr1
- это указатель на const int
, инициализированный адресом нулевого элемента массива mas
. По сути, это будет равносильно записи вида:
ptr1 = &mas[0];
Такой указатель можно в дальнейшем переназначить, например:
ptr1 = &mas[1];
Или на любую другую переменную вовсе не связанную с массивом:
int i = 42;
ptr1 = &i;
Но менять данные через такой указатель нельзя из-за const
в объявлении. Т.е. нельзя сделать так:
*ptr1 = 100500;
ptr2
- это ссылка на массив из пяти const int
. По сути второе имя массива mas
, но с наложенной на него константностью. Данные через такую ссылку так же нельзя менять. Но здесь ещё вступает в силу и само ограничение ссылок - их нельзя переназначать. Т.е. нельзя выполнить такое после инициализации:
ptr2 = mas;
В общем, вопрос отличия указателей от ссылок - это уже отдельный вопрос.
Ключевое отличие этих способов - вот в чем:
std::cout << sizeof ptr1 <<std::endl; // 4 или 8 - зависит от битности системы
std::cout << sizeof *ptr1 <<std::endl; // 4 (скорее всего)
std::cout << sizeof ptr2 <<std::endl; // 20
Когда вы объявляете указатель и присваиваете ему массив - вы теряете информацию о размере массива, остается лишь указатель на первый элемент.
Когда вы объявляете ссылку на массив - информация о размере сохраняется и может быть получена через sizeof.
Второе по важности отличие - указатель является изменяемым типом данных, без дополнительного const
указателю можно присвоить какое-нибудь другое значение. Ссылка же связывается со своим начальным значением на всю жизнь.
В первом случае:
const int *ptr = mas;
ptr
— это указатель на const int
, который вы инициализируете массивом. Однако, массив mas
неявно преобразуется к указателю на свой первый элемент и, следовательно, ptr
указывает на первый элемент массива mas
.
Если бы вы написали так:
const int (*ptr2)[5] = &mas;
то ptr2
был бы указателем на массив из пяти элементов типа const int
. Указатель на массив — это не тоже самое, что указатель на первый элемент массива.
Например, обратиться к элементу массива mas
с индексом 1
можно так ptr[1]
, или так (*ptr2)[1]
.
Однако, запись ptr2[1]
— это попытка обращения к объекту, первый байт которого начинается с байта, следующего непосредственно за последним байтом массива mass
. А запись (*ptr)[1]
и вовсе является некорректной.
Теперь касательно ссылок. Ссылка — это что-то вроде альтернативного имени для некоторого объекта (На строгость и полное соответствие стандарту языка C++ не претендую :) ). По аналогии с указателями, вы можете объявить ссылку как на некоторый элемент массива mas
:
const int &r = mas[1]; //Ссылка на второй элемент массива mas;
так и на весь массив:
const int (&r2)[5] = mas;
Небольшой пример, демонстрирующий некоторые свойства ссылок и указателей:
int mas[5] = {1, 2, 3, 8};
const int *ptr = mas;
int (*ptr2)[5] = &mas;
const int &r = mas[1];
const int (&r2)[5] = mas;
cout << uintptr_t(ptr + 1) - uintptr_t(ptr) << " " << sizeof(int) << " " << sizeof(r) << endl;
cout << uintptr_t(ptr2 + 1) - uintptr_t(ptr2) << " " << sizeof(mas) << " " << sizeof(r2) << endl;
cout << sizeof(ptr) << " " << sizeof(*ptr) << " " << sizeof(ptr2) << " " << sizeof(*ptr2) << endl;
mas[1] = 42; (*ptr2)[2] = 24;
cout << r << " " << r2[2] << endl;
ptr = &mas[3];
cout << *ptr << endl;
Возможный вывод этой программы будет таким:
4 4 4
20 20 20
8 4 8 20
42 24
8
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Я не понимаю, почему выводит разные значения, разве ссылка не должна неявно преобразовываться в указатель на mas?
Есть класс, есть вектор векторов этого классаКак обратиться к элементу класса через вектор векторов?