отличие указателей от ссылок

Вообще говоря указатель и ссылка это одно и то же, но как говорится есть нюансы.

Ссылка это просто ещё один псевдоним для указания на существующий об'ект. То есть об'ект обязательно уже существует в памяти и ссылка - это адрес об'екта в памяти.

Указатель это отдельная область в памяти (размером например int), в которой находится значение, которое является адресом, который указывает на какой-то другой об'ект в памяти.

Таким образом указатель может и не указывать ни на что, иметь значение 0 например.Также указатель может указывать на не существующий адрес в памяти, что влечет проблемы при обращении к об'екту, находящемуся по этому  адресу в памяти.

Объявление переменной i, создание ссылки на нее и указателя на нее :

int i=0x12;
int &ri=i;
int *pi=&i;
printf("i=%x       \n",i);
printf("pi=%x   %p   \n",pi,pi);
printf("*pi=%x   %p   \n",*pi,*pi);
printf("ri=%x   %p \n",ri,ri);
printf("&ri=%x   %p \n",&ri,&ri);
printf("&pi=%x   %p \n",&pi,&pi); 
// адрес самого указателя

выведет :

i=12       
pi=28ff20     0028FF20   
*pi=12           00000012   
ri=12              00000012 
&ri=28ff20   0028FF20 
&pi=28ff1c  0028FF1C  
 // адрес самого указателя

1. Сразу отметим важный момент - синтаксическое отличие указателя от ссылки:

для указателя :
int *pi=&i; *pi - это само значение , pi  - это адрес значения
у ссылки наоборот :
int &ri=i;   ri - это само значение , &ri - это адрес значения
Далее надо тупо это понимать!
*xxx - значение, xxx - адрес
&xxx - адрес , xxx - значение

2. Создание указателя - это новая ячейка в памяти, а ссылка ничего не создает нового в памяти

int *pi=&i;
// итак pi - - это адрес указателя
printf("&pi=%x   %p \n",&pi,&pi);  так можно делать и вы увидите адрес самой ссылки 
&ri - адрес "ссылки", но ri по сути это просто псевдоним i, 
просто нам хочется i обозвать еще также ri. 
Но это все равно останется только одна ячейка памяти с одним и тем же адресом.
а как вывести адрес ссылки &ri & - правильно никак - так нельзя делать ( &&ri Очень полезнпя

Другими словами можно создать указатель на указатель и т.д. Но нельзя создавать ссылку на ссылку!

const QString &ref

Очень полезная фича это применения спецификатора const при передаче параметра типа ссылка в функцию. Как результат копии передаваемого об'екта компилятор создавать не будет и как это актуально для большого по их  размеру типов данных (разных структур, классов и т.д.)

const Data * dat

Константный указатель тоже полезная вещь, если вы не меняете сам указатель на об'ект, то почему бы при передаче в функцию не передать его со спецификатора const.

Data * const dat

Кстати если надо запретить изменять сами данные об'екта (а не указатель на него), то похоже есть возможность указать спецификатор const справа от звёздочки.

Устаревшая информация

Далее можно не читать, т.к. ниже идет старая информация, собранная  при разработке контроллеров.

volatile

Применяйте иногда директиву volatile , если не хотите , чтобы компилятор оптимизировал размещение в памяти ваших переменных (данных), а вы потом ломали голову почему оттуда такие странные значения читаются.

"Это как его волюнтаризм..."

Маленький , но принципиальный пример на с

Разрабатывая микроконтроллер STM32 пришлось юникодить , делать таблицы точек для каждого символа , чтобы выводить на термопринтер текст.

В очередной раз завис с указателями на элементы этих таблиц, как их использовать . Допустим есть двухмерный массив :

volatile uint8_t lat00[256][5]={
		{ 0 , 0 , 0 , 0 , 0 },
		{ 0 , 0 , 0 , 0 , 0 },
.............................................................
		{ 0x3E, 0x51, 0x49, 0x45, 0x3E }, 	// 0x30 '0'
		{ 0x00, 0x42, 0x7F, 0x40, 0x00 },	// 0x31 '1'
		{ 0x42, 0x61, 0x51, 0x49, 0x46 },	// 0x32
};

В [5] байтах лежит растровое представление символа 5*8. Но не об этом.

Хотим получить указатель на какой-то байт массива, пожалуйста :

volatile uint8_t *b8 = &lat00[b1][0];

А как дальше добраться до остальных 1,2,3,4 байт - вот тут меня подзаклинило, но не надолго. Вот так надо:

uint8_t b1 = (uint8_t)*(b8 k);  // k=1,2....

Еще задачка и непонятого

Поимел проблемы вот с такими вариантами одного и того же массива:


volatile uint8_t lat00[][5]={

uint8_t lat00[][5]={

const uint8_t lat00[][5]={ 

Только третий вариант размещает байты в памяти последовательно подряд.

const кстати размещает массив в .rodata это flash контроллера. А 1,2 варианты в куче или стеке.