const char ** a = {“string1”, “string2”} и указательный арифметический

main() { const char **a = {"string1","string2"}; printf("%c", *a); /* prints s */ printf("%s", a); /* prints string1 */ printf("%s", a+1);/* prints ng1 */ } 

GCC v4.8.3 печатает «% s» для последнего printf, где в качестве http://codepad.org/ печатает «ng1».

Я думал, что код создаст массив указателей на две строки и базовый адрес, назначенный на a, что позволяет использовать обычную арифметику указателя. но, похоже, что-то не так с предположением. Первый printf предполагает, что мое предположение неверно. может ли кто-нибудь объяснить, почему такое поведение наблюдается? (обратите внимание, что VS 2012 выложил ошибку, в которой говорилось слишком много инициаторов, где GCC выдает предупреждение о несовместимом назначении указателя). Я знаю предупреждение из-за несовместимого назначения указателя.

const char **a не является массивом указателей на две строки. Он объявляет a указателем на указатель на const char .

 const char **a = {"string1","string2"}; //No memory is allocated to store string literals 

будет вызывать неопределенное поведение, и вы можете получить либо ожидаемые, либо неожиданные результаты.
Чтобы объявить как массив из двух указателей, вам нужно изменить объявление как

 const char *a[] = {"string1","string2"}; 

Диапазон памяти в стеке вашей программы выглядит следующим образом: (обратите внимание, что он не назначен перед назначением, что является неправильным)

 char** a = {s, t, r, i, n ,g, 1, \0, s, t, r, i, n, g, 2, \0} 

Поэтому, когда вы печатаете команду:

 printf("%c", *a); 

Вы разыскиваете первый символ строки, которая является ‘s’.

С другой стороны, когда вы печатаете команду:

  printf("%s", a); 

вы печатаете строку, которая начинается с указателя a и заканчивается на ‘\ 0’. Вот почему вы видите вывод ‘string1’.

Наконец, когда вы набираете «a + 1», вы увеличиваете указатель за один шаг (пример здесь: как увеличить адрес указателя и значение указателя? ). в этом случае, поскольку char ** является указателем, и каждый указатель имеет 4 байта, «+1» перескакивает 4 символа вперед. Поэтому, когда вы печатаете команду:

 printf("%s", a+1); 

Printf начинается с указателя ‘a’ + 4 байта и заканчивается на ‘\ 0’. Вот почему вывод «ng1».

Надеюсь, это было достаточно ясно.

Это связано со следующей специфической инициализацией, выполняемой GCC. см. int q = {1,2}; уникальный список инициализации . оператор const char ** a = {“string1”, “string2”}; приводит к тому, что объект обрабатывается так, как будто const char ** a = “string1”. это решает загадку как * a print ‘s’, a будет печатать строку1.