В чем разница между указателем float и адресом int указателя?

Я попытался запустить этот код,

int *p; float q; q = 6.6; p = &q; 

Хотя это будет предупреждение, но я думаю, что &q и p имеют одинаковый размер, поэтому p может иметь адрес q . Но когда я печатаю &q и p я получаю разные результаты. Это мой вывод

 *p = 6.600000 q = 0.000000, p = 0x40d33333, &q = 0x7fffe2fa3c8c 

Что мне не хватает? И p и &q одинаковы, если оба типа указателя и переменной одинаковы.

Мой полный код

 #include void main() { int *p; float q; q = 6.6; p = &q; printf("*p = %f \nq = %f, p = %p, &q = %p \n",*p,q,p,&q); } 

Вы должны более серьезно относиться к предупреждениям компилятора.

C не требует от компиляторов отклонения недействительных программ, а просто требует «диагностики» для нарушения правил. Диагностика может быть либо фатальным сообщением об ошибке, либо предупреждением.

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

 void main() 

Это не верно; он должен быть int main(void) . Ваш компилятор может позволить вам уйти от него, и это может не вызвать никаких видимых проблем, но нет смысла не писать его правильно. (Это не совсем так просто, но это достаточно близко.)

 int *p; float q; q = 6.6; 

Это нормально.

 p = &q; 

p имеет тип int* ; &q имеет тип float* . Присвоение одного другому (без приведения) является нарушением ограничения . Самый простой способ взглянуть на это – это просто незаконно.

Если вы действительно хотите выполнить это задание, вы можете использовать бросок:

 p = (int*)&q; /* legal, but ugly */ 

но редко есть веские причины для этого. p – указатель на int ; он должен указывать на объект int если у вас нет веских оснований, чтобы он указывал на что-то другое. В некоторых случаях само преобразование может иметь неопределенное поведение.

 printf("*p = %f \nq = %f, p = %p, &q = %p \n",*p,q,p,&q); 

Формат %f требует double аргумента (аргумент float в этом контексте считается double поэтому float будет в порядке). Но *p имеет тип int . Вызов printf с аргументом неправильного типа приводит к тому, что поведение вашей программы не определено.

%p требует аргумент типа void* , а не только любого типа указателя. Если вы хотите напечатать значение указателя, вы должны наложить его на void* :

 printf("&q = %p\n", (void*)&q); 

Он, скорее всего, будет работать без приведения, но опять же, поведение не определено.

Если вы получаете какие-либо предупреждения при компиляции программы, даже не пытайтесь ее запустить. Сначала исправьте предупреждения.

Что касается вопроса в вашем названии, указатели типа int* и float* имеют разные типы. int* должен указывать на объект int ; float* должен указывать на объект float . Ваш компилятор может позволить вам их смешивать, но результат этого – либо определенный реализацией, либо неопределенный. Язык C, и особенно многие компиляторы C, позволят вам уйти со многими вещами, которые не имеют большого смысла.

Причина, по которой они являются разными типами, заключается в том, чтобы (пытаться) предотвратить или, по крайней мере, обнаружить ошибки в их использовании. Если вы объявляете объект типа int* , вы говорите, что намереваетесь указать его на объект int (если он не является нулевым указателем). Сохранение адреса объекта float объекте int* почти наверняка является ошибкой. Обеспечение безопасности типа позволяет обнаруживать такие ошибки как можно раньше (когда ваш компилятор печатает предупреждение, а не когда ваша программа вылетает во время демонстрации для важного клиента).

Вероятно (но не гарантировано), что int* и float* имеют одинаковый размер и имеют одинаковое внутреннее представление. Но значение объекта int* не является «набором из 32 (или 64) бит, содержащих виртуальный адрес», а «что-то, что указывает на объект int ».

Вы получаете неопределенное поведение, потому что вы передаете неправильные типы printf . Когда вы скажете ему ожидать поплавок, он на самом деле ожидает double но вы передаете int .

В результате он печатает неверную информацию, потому что printf полностью использует строку формата для доступа к аргументам, которые вы передаете.

В дополнение к тому, что сказано teppic,

Рассматривать,

 int a = 5; int *p = &a; 

В этом случае мы укажем компилятору, что p будет указывать на целое число. Таким образом, известно, что когда мы делаем что-то вроде *p , во время выполнения, нет. байтов, равных размеру int , будет считан.

Если вы назначаете адрес типа данных, занимающий x число байтов, указатель которого объявлен для хранения адреса типов данных с меньшим количеством байтов, чем x , вы читаете неправильное количество байтов при использовании оператора косвенности.