IK
Size: a a a
IK
IK
b
b
AZ
ШН
ШН
V
V
b
b
IK
Для примера, в 11: *((int*)p) = 20;
В памяти компьютера все представлено целыми числами. В лучшем случае, точно, в худшем - приближенно. Эти числа хранятся в памяти/регистрах процессора. Регистры имеют размер (зависит от архитектуры), например 32 или 64 бита. Нельзя сослаться (указать) на "середину"ячейки памяти или регистра, только на начало (указатель указывает на самый первый байт ячейки).
Чем больше размер регистра, тем большее число в него можно записать: в 64 бита больше, чем в 32, в 128 - больше, чем в 64.
Маленькое целое число, например, 20 можно записать в любой регистр, начиная с размера 8 бит. И установить оставшиеся неиспользованные биты в 0.
Проблема в том, что при записи в оперативную память, неизвестно, как именно она была распределена: был выделен под переменную 1 байт (тип char) или, например, 4 (тип long). Аналогично, при чтении из памяти, необходимо знать сколько байт следует прочесть. Этот размер необходимо задать компилятору явно - через тип указателя.
Указатель на char означает, что переменная, которую адресует указатель, занимает один байт, указатель на long - 4 байта (на 32-битной машине), указатель на пользовательский тип (struct MY_STRUCT) будет использовать размер sizeof(struct MY_STRUCT).
Таким образом, единственное назначение типа указателя - дать компилятору информацию о том, как понимать то, что адресует этот укатель.
Если имеется ввиду void (с маленькой буквы), то он используется всюду, где нужно сказать "указатель на область памяти, заранее неизвестного размера". В этом случае размер, при необходимости, должен быть задан отдельно. Иными словами, void* - это псевдоним для "какой-то указатель".
Например, библиотечная функция memcpy(), копирующая область памяти, не может знать заранее, тип/размер копируемого объекта, поэтому ее прототип void* memcpy(void* destination,const void* source,size_t num);
b
T
b