Вообще говоря указатель и ссылка это одно и то же, это значение адреса в памяти.
Два варианта обозначения одного и того же придумали с целью объяснения компилятору надо ли создавать копию этого значения в памяти или нет (при входе в функцию например).
Объявление переменной 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 варианты в куче или стеке.