#c #указатели
Почему так работает? #includeint main(){ int *p1[1] = {2018}; char *p2[1] = {"abcd"}; p1[0] = p2[0]; printf("%s\n\n", p1[0]); /* выводит abcd */ return 0; } Мы же создаем массив из одного элемента, который является указателем на int. Если происходит приведение к типу char*, то почему оно происходит без потери информации?
Ответы
Ответ 1
Сразу стоит заметить, что абсолютно ничего в вашем коде не имеет какой-то принципиальной связи с массивами. Массивы тут совершено ни к чему и ни на что не влияют. Почему вы использовали массивы размера 1 вместо обычных переменных - не ясно. Далее: ваш код не "работает". Его поведение не определено, ибо он не является корректной программой на языке С. int *p1[1] = {2018}; Это попытка инициализации указателя типа int * целочисленным значением 2018. Это constraint violation, т.е. ошибка. Стандартным языком С это не поддерживается. Такое преобразование типов требует явного приведения типа (каста). p1[0] = p2[0]; Это попытка присваивания указателя типа char * в переменную типа int *. Это constraint violation, т.е. ошибка. Стандартным языком С это не поддерживается. Такое преобразование типов требует явного приведения типа (каста). printf("%s\n\n", p1[0]); Спецификатор формата %s требует аргумента типа char *. Вы передали int *. Поведение не определено. Ваш компилятор сообщил вам об этих нарушениях, но вы, очевидно, проигнорировали диагностические сообщения компилятора. Независимо от того, согласился ли ваш компилятор "скомпилировать" этот код, программа написана не на языке С и ее поведение никак не оговаривается языком С. Возьмите в привычку первым делом проверять свой код в online компиляторе GCC с флагом -pedantic-errors и многие бессмысленные вопросы отпадут сами собой http://coliru.stacked-crooked.com/a/823471ccc0b42efaОтвет 2
В дополнение к предыдущим ответам хочу сказать, что когда вы пишите код: printf("%s\n\n", p1[0]); то printf выводит значения всех встреченных байт от текущей позиции (адреса p1[0]) и пока не встетит \0. Спецификатор %s не проверяет что находится по указанному адресу, он означает что выводится все до нулевого байты. Так если вы поменяете присваивание, то все также будет работать, но выведет уже не abcd, а какю-то билеберду в которой первые 4 символа будут всегда одинаковы (это число 2018 - выведет, конечно, не число, а значения его байт), а остальные - их может быть разное количество и содержать они могут что угодно.Ответ 3
В присваивании p1[0] = p2[0]; не происходит преобразования типов, поэтому и не происходит потери информации. Просто один указатель скопирован в другой. Так как оба указателя по 4 (или 8 байт, если платформа 64бита), то никаких проблем. В строке вывода мы говорим printf - возьми значение по указателю и трактуй как строку (потому что %s) и выведи. И ничего странного. Просто си это язык, который допускает достаточного много "вольностей". "правильный компилятор" должен был в двух (а точнее - в четырех) местах настучать по пальцам.
Комментариев нет:
Отправить комментарий