Как раз для того, чтобы получить техническую поддержку, ваша вторая версия:
printf("%s" , &s);
имеет неопределенное поведение и работает только случайно. Явно беря адрес, вы получаете адрес массива (что нормально), но результат имеет тип «указатель на массив из 12 символов», а не тип «указатель на символ», как требуется для printf
% s конверсия. Поскольку типы не совпадают, результатом является неопределенное поведение.
В действительности, однако, это чисто техническая составляющая - код будет отлично работать на каждой реализации C, о которой я знаю.
Если вы хотите продемонстрировать, что разница существует, вы можете сделать это довольно легко. Например:
char string[] = "hello world";
printf("without &: %p, %p\n", (void *)string, (void *)(string+1));
printf("with &: %p, %p\n", (void *)&string, (void *)(&string+1));
В первом случае string
распадается на указатель на символ, поэтому в первой строке второй указатель будет ровно на единицу больше первого. Во второй строке мы добавляем единицу к указателю на массив символов, поэтому, когда мы добавим единицу, он фактически добавит размер массива. Запустив это на моей машине, я получаю следующие результаты:
without &: 0038F96C, 0038F96D
with &: 0038F96C, 0038F978