Почему я получаю ошибку сегментации, если я печатаю содержимое этой ячейки памяти

#c #memory #pointers

#c #память #указатели

Вопрос:

Предположим, я делаю следующее

 int *p = 1;
printf("%d", *p);
 


Я получаю ошибку сегментации. Теперь, насколько я понимаю, эта ячейка памяти 1 находится в адресном пространстве моей программы. Почему должна быть проблема при чтении этой ячейки памяти?

Ответ №1:

Ваш указатель не указывает ни на что действительное. Все, что вы делаете, это присваиваете значение 1 указателю на int, но 1 это недопустимая ячейка памяти.

Единственный допустимый способ получить значение указателя - это либо взять адрес переменной, либо вызвать функцию распределения:

 int a;
int * p1 = amp;a; // OK
int * p2 = malloc(sizeof(int));  // also OK

*p1 = 2;
*p2 = 3;
 

Что касается "почему должна быть проблема": что касается языка, если вы разыменовываете недопустимый указатель, у вас неопределенное поведение, поэтому может случиться все, что угодно - это действительно единственный разумный способ указать язык, если вы не хотите вводить какие-либо произвольные ограничения, и Cвсе дело в простоте реализации.

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

Ответ №2:

Правильный ответ на этот вопрос действительно будет зависеть от ряда факторов. Однако вполне вероятно, что адрес 0x00000001 (страница 0) не сопоставлен и / или не защищен от чтения.

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

РЕДАКТИРОВАТЬ: Другая возможная причина заключается в том, что это может быть нарушение сегментации, поскольку доступ к целому числу не выровнен.

Комментарии:

1. 1 за упоминание о том, что сопоставление страницы 0 запрещено даже в защищенных операционных системах (это может привести к эксплойтам против ядра).

Ответ №3:

Ваша операционная система не позволит вам получить доступ к ячейкам памяти, которые не принадлежат вашей программе. Однако это будет работать в режиме ядра...

Комментарии:

1. Я думал, что у каждого процесса есть свое собственное виртуальное адресное пространство. Итак, начиная с 0x0, все пространство принадлежит моему процессу, и я должен иметь к нему доступ?

2. @AnkurVj: все виртуальное пространство принадлежит вам, но вам все равно нужно сначала выделить его, чтобы оно было допустимым местоположением.

3. Предположим, я объявляю целое число и печатаю его адрес. Является ли это местоположение реальной физической ячейкой памяти?

4. @AnkurVj: Это логический адрес, который был выделен системой.

Ответ №4:

Нет, адрес 1 отсутствует в адресном пространстве вашей программы. Вы пытаетесь получить доступ к сегменту, который вам не принадлежит, и получаете ошибку сегментации.

Ответ №5:

Вы пытаетесь напечатать 1, а не ячейку памяти. 1 не является допустимой ячейкой памяти. Чтобы распечатать фактическую ячейку памяти, выполните:

 printf("%p", p);
 

Обратите внимание на %p, как указал icktoofay.

Комментарии:

1. Я считаю, что правильная спецификация форматирования для указателя %p - нет %d .

2. Нет. Я не пытаюсь распечатать ячейку памяти. Я действительно пытаюсь распечатать то, что хранится в этой ячейке памяти

3.Я думаю, что он на самом деле пытается вывести int адрес at 1.