В чём разница между этими объявлениями указателя?

155
22 февраля 2018, 14:49

Можете, пожалуйста, сказать, чем отличаются эти строки ptr1 и ptr2? Работают они, вроде бы, одинаково.

int mas[5] = {1, 2, 3, 8};    
const int *ptr1 = mas;
const int (&ptr2)[5] = mas;
Answer 1

Первое действительно объявляет указатель, второе - объявляет ссылку (так как ссылка на массив, оно может неявно преобразовываться в указатель, как и сам массив).

Answer 2

ptr1 - это указатель на const int, инициализированный адресом нулевого элемента массива mas. По сути, это будет равносильно записи вида:

ptr1 = &mas[0];

Такой указатель можно в дальнейшем переназначить, например:

ptr1 = &mas[1]; 

Или на любую другую переменную вовсе не связанную с массивом:

int i = 42;
ptr1 = &i;

Но менять данные через такой указатель нельзя из-за const в объявлении. Т.е. нельзя сделать так:

*ptr1 = 100500;

ptr2 - это ссылка на массив из пяти const int. По сути второе имя массива mas, но с наложенной на него константностью. Данные через такую ссылку так же нельзя менять. Но здесь ещё вступает в силу и само ограничение ссылок - их нельзя переназначать. Т.е. нельзя выполнить такое после инициализации:

ptr2 = mas;

В общем, вопрос отличия указателей от ссылок - это уже отдельный вопрос.

Answer 3

Ключевое отличие этих способов - вот в чем:

std::cout << sizeof ptr1 <<std::endl; // 4 или 8 - зависит от битности системы
std::cout << sizeof *ptr1 <<std::endl; // 4 (скорее всего)
std::cout << sizeof ptr2 <<std::endl; // 20

Когда вы объявляете указатель и присваиваете ему массив - вы теряете информацию о размере массива, остается лишь указатель на первый элемент.

Когда вы объявляете ссылку на массив - информация о размере сохраняется и может быть получена через sizeof.

Второе по важности отличие - указатель является изменяемым типом данных, без дополнительного const указателю можно присвоить какое-нибудь другое значение. Ссылка же связывается со своим начальным значением на всю жизнь.

Answer 4

В первом случае:

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
READ ALSO
Разница между указателем и ссылкой

Разница между указателем и ссылкой

Я не понимаю, почему выводит разные значения, разве ссылка не должна неявно преобразовываться в указатель на mas?

125
Асинхронное выполнение функции

Асинхронное выполнение функции

Функция, которая принимает параметры:

147
вектор классов - обращение

вектор классов - обращение

Есть класс, есть вектор векторов этого классаКак обратиться к элементу класса через вектор векторов?

152
Попытка отсортировать массив

Попытка отсортировать массив

Неиспользуемые переменные

126