2015-02-08 2 views
2
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".Const символ ** а = { "string1", "строка2"} и указатель arithametic

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

+4

'const char ** a = {" string1 "," string2 "};' неверно. Ваш 'main()' не возвращает 'int', что также неверно. Пожалуйста, прочитайте о указателях и массивах, прежде чем предполагать, что вы должны писать. –

+3

Вопрос не в абсолютной правильности моей программы, обратите внимание, что это юридическая программа, составленная GCC v4.8.3 с предупреждением. вопросы касаются того, почему поведение странно. –

+1

@bare_metal это не юридическая программа. Обработка gcc этим не меняет этот факт –

ответ

2

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

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

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

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

Я знаю об этом, но не могли бы вы помочь мне понять, почему программа ведет себя так, как она есть. если я создаю массив указателей, а затем верну их обратно в char **, тогда все будет работать как ожидается –

+0

@bare_metal; Обновлен ответ. – haccks

+0

Как мы можем сказать, что память не выделена, в char * a = "string1", где строка хранится в .rodata? –

2

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

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); 

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

И наконец, когда вы набираете «a + 1», вы увеличиваете указатель за один шаг (пример здесь: How to increment a pointer address and pointer's value?). в этом случае, поскольку char ** является указателем, и каждый указатель имеет 4 байта, «+1» перескакивает 4 символа вперед. Поэтому при печати команды:

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

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

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

+0

Спасибо за попытку, но объяснение кажется неправильным –

+1

Просьба уточнить. Что, по-вашему, неправильно? Я был бы рад изменить мой ответ, если понадобится. – nerez

+0

const char ** a = {"string1", "string2"}; и const char ** a = {s, t, r, i, n, g, 1, \ 0, s, t, r, i, n, g, 2, \ 0} не являются одинаковыми ('' опущены), когда я пытаюсь printf («% s», a); я получаю ошибку seg. –

1

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

 Смежные вопросы

  • Нет связанных вопросов^_^