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.