инструкция puts показывает это «на экране».
Это просто (плохая) удача, код вызывает неопределенное поведение, если компилятор не отказывается компилировать его вообще.
Эти предупреждения, полученные лязг (по умолчанию) для кода являются
$ clang badpoint.c
badpoint.c:6:18: warning: incompatible pointer types initializing 'char **' with an
expression of type 'char [5]' [-Wincompatible-pointer-types]
char **bs = {"this", "is", "a", "test"};
^~~~~~
badpoint.c:6:26: warning: excess elements in scalar initializer
char **bs = {"this", "is", "a", "test"};
^~~~
badpoint.c:8:10: warning: incompatible pointer types passing 'char **' to parameter of
type 'const char *'dereference with * [-Wincompatible-pointer-types]
puts(bs);
^~
*
/usr/include/stdio.h:688:32: note: passing argument to parameter '__s' here
extern int puts (__const char *__s);
^
3 warnings generated.
GCC генерирует предупреждение для каждого избыточного инициализатора, в то время как лязг дает только один для первого из трех, в противном случае предупреждения от ССЗ (также по умолчанию) являются немного менее информативными, но то же самое.
Так что же происходит?
Вы пытаетесь инициализировать скаляр (char**
), а также обеспечить {"this", "is", "a", "test"}
, скобу огороженного инициализатора-лист содержащих четыре инициализатор с. Per 6.7.9 (11)
Инициализатор для скаляра должен быть одним выражением, необязательно заключенным в фигурные скобки. Начальное значение объекта - это выражение (после преобразования); применяются те же ограничения типа и преобразования, что и для простого присваивания, при этом тип скаляра является неквалифицированной версией его объявленного типа.
, который нарушает требование «требуется» и, следовательно, вызывает неопределенное поведение.
Если компилятор не завершает перевод там, вероятно, просто игнорирует лишние инициализаторами - лязг и GCC как сделать - и обрабатывает декларацию, как это было
char **bs = "this";
который вызывает предупреждение об инициализации от несовместимый тип, поскольку он пытается инициализировать char**
с помощью char[5]
, но в соответствии с 6.5.16.1 тип инициализатора должен быть совместим с char**
.
Тем не менее, если компилятор успешно переводит программу, это может привести к bs
, содержащий адрес первого char
в строковый литерал (массив "this"
преобразуется в указатель на его первый элемент на правой стороне оператора присваивания).
Тогда вызов
puts(bs)
передает указатель неправильного типа (char**
) к puts
, что является нарушением ограничения и требует диагностического сообщения от компилятора (и делает программу недействительной).
Но указатель содержит правильный адрес, а неопределенное поведение проявляется как печать программы "this"
.
Как бы я идти о получении его, чтобы показать «есть» и так далее
Исправляя программу. Как есть, строки "is"
, "a"
и "test"
даже не отображаются в объектном файле, создаваемом gcc или clang.
Один из способов исправить это было бы изменением декларации
char *bs[] = {"this", "is", "a", "test"};
так что bs
является массивом из четырех char*
, указывая на (соответствующие первые элементы) четыре строк.
Затем вы должны настроить вызов puts
, разыменования или bs
индексации,
puts(bs[0]);
для печати "this"
;
for(int i = 0; i < 4; ++i) {
puts(bs[i]);
}
для печати всех четырех строк на отдельных строках.
Об этом ответили тысячи раз здесь, а также в многочисленных учебниках и текстах. Пожалуйста, сделайте некоторое исследование ... включая просто * попробуйте его *. –
это указывает на следующий адрес .... следующий адрес вычисляется как ... baseaddress + sizeofpointertype (1 для char, 2 для int и т. Д.) –
OTOH, я бы проигнорировал все данные о расчете адреса и размере , C, имеет этот инвариант: 'x [y] == * (x + y)'. Следовательно, 'x + y == & * (x + y) == & x [y]'. –