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

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

Два варианта обозначения одного и того же придумали с целью объяснения компилятору надо ли создавать копию этого значения в памяти или нет (при входе в функцию например).

Объявление переменной 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 )

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


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 варианты в куче или стеке.