В приведенном примере:
char *a = "c";
char *p = a;
void *k = a;
printf( "\n%c\n" , *p );
printf( "\n%s\n" , k );
Что происходит, в первом printf значение 'c' передается из разыменования указателя char
, printf
знает только то, что вы его далиchar
из-за тега формата %c
.
Теперь void*
- это просто необработанный указатель с неизвестным типом, вы не можете разыменовать его, потому что компилятор не знает, какой типчитать из него, если вы не приведете его к чему-то другому.
Во втором printf указатель void*
передается внутрь. printf
просто видит его как простое число и не знает, что это такоепока он не прочитает данный тег форматирования.Используя %s
, вы сообщаете функции printf, которую вы фактически передали в char*
, поэтому она соответственно преобразует ее и правильно читает в виде строки, т.е. она разыменовывает указатель char*
, а не void*
указатель.
Это допустимый код, если указатель void*
указывает на массив char
с нулевым символом в конце.Если указатель void*
указывает на что-то другое, функция printf
все равно с радостью попытается прочитать его как указатель char*
(если вы укажете %s
) и вызовет неопределенное поведение.
AДругой плохой пример:
char *a = "ce";
int b = (int)a;
printf( "\n%s\n" , b );
Вы также не можете разыменовать целое число, но я сказал printf
, что это char*
, поэтому оно работает.