Intereting Posts
Как мы можем проверить, является ли входная строка допустимым двойным? Микроcontrollerы PIC: входы сканирования на клавиатуре 4×4, используя только порт C RC0-RC3 в C Найти IP-адрес шлюза по умолчанию, а не parsing файловой системы proc API для создания нового модема Какова цель ungetc (или ungetch от K & R)? Как конвертировать 64-битный длинный тип данных в 16-битный тип данных getrusage возвращает нули в ru_utime.tv_usec и ru_utime.tv_sec Правило Misra 19.7: функция вроде макроса Можно ли сначала объявить массив и дать его значение позже? Коммуникация сокетов / сервера (AF_UNIX) возвращающий массив строки из функции, не работающей как ожидалось C строк malloc (выход) Арифметический оператор присваивания – левая сторона оценивается только один раз Добавление 2d-массива C индексированное значение не является ни массивом, ни указателем, ни вектором при назначении значения элемента массива

Инициализация указателя дает ошибку сегментации

Я написал программу C следующим образом:

СЛУЧАЙ 1

int *a; /* pointer variable declaration */ int b; /* actual variable declaration */ *a=11; a=&b;/* store address of b in pointer variable*/ 

При выполнении программы возникает segmentation fault.

Я изменил код следующим образом:

CASE 2

 int *a; /* pointer variable declaration */ int b; /* actual variable declaration */ a=&b;/* store address of b in pointer variable*/ *a=11; 

Теперь он работает нормально.

Если кто-нибудь знает, пожалуйста, объясните, почему он дает ошибку сегментации в CASE 1.

 CASE .1 int *a; /* pointer variable declaration */ int b; /* actual variable declaration */ *a=11;//Not valid means you are not owner of the address where a now pointing it is unknown and accessing this will segfault/ a=&b;/* store address of b in pointer variable*/ 

Это будет segmentation fault, потому что адрес, который вы используете, не является действительным адресом и там вы храните 11, что является незаконным.

  b +-------+ +--------+ | + | 11 | |Unknown| | | +---+---+ +---+----+ | | | | + + aa CASE .2 int *a; /* pointer variable declaration */ int b; /* actual variable declaration */ a=&b;/* store address of b in pointer variable*/ *a=11; 

Теперь он работает нормально, потому что адрес b действителен, там вы храните 11, что является законным.

Кроме того, вышеприведенные случаи являются неправильным способом объявления указателя

  int *a = NUll; a = malloc(sizeof(int)); *a=5; free(a);//must 

или же

  int *a = NUll; int b; a = &b; *a=5; 

Это позволит устранить ошибку сегментации много раз, что трудно найти.

 int *a; // a pointer variable that can hold a memory address of a integer value. 

В случае 1,

  *a = 10; // here you have asigned 10 to unknown memory address; 

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

В случае 2,

 a=&b; // assigning a proper memory address to a. *a=11;// assigning value to that address 

Рассмотрим этот пример:

 #include int main() { int *a,b=10; printf("\n%d",b); a=&b; *a=100; printf("-->%d",b); } Output: 10-->100 

Вот как это работает.

  b // name ---------- + 10 + // value ---------- 4000 // address 

Сохранение памяти в памяти b равно 4000.

 a=&b => a=4000; *a=100 => *(4000)=100 => valueat(4000) => 100 

После манипуляции это выглядит так.

  b // name ---------- + 100 + // value ---------- 4000 // address 

Одна строка: первый код вы разыгрываете неинициализированный указатель, который показывает неопределенное поведение, а во втором коде вы разыскиваете инициализированный указатель, который даст доступ к значению по адресу.

Немного объяснения:

Сначала вам нужно понять, что указатель – это не что иное, как целое число, а с *var мы сообщим компилятору, что будем использовать содержимое переменной var (целое число в ней) в качестве адреса для извлечения значения в этом адресе , Если существует **var аналогично, мы сообщаем компилятору, что сначала будем использовать сохраненное значение переменной var для извлечения значения по адресу и снова использовать это извлеченное значение в качестве адреса и получить значение, хранящееся в нем.

Поэтому в вашей первой декларации это:

  +----------+ +----------+ | garbage | | garbage | +----------+ +----------+ | a | | b | +----------+ +----------+ | addr1 | | addr2 | +----------+ +----------+ 

Затем вы пытаетесь использовать значение, сохраненное в качестве адреса. a содержит мусор, это может быть любая ценность, но у вас нет доступа к любому адресу. Поэтому в следующий момент, когда вы сделаете *a он будет использовать сохраненное значение в качестве адреса. Поскольку хранимое значение может быть чем угодно, все может случиться.

Если у вас есть разрешение на доступ к местоположению, код будет продолжать выполняться без сбоев сегментации. Если адрес является адресом из структуры хранения кучи или другой областью памяти, которую ваш код выделяет из кучи или стека, тогда, когда вы делаете *a = 10 он просто уничтожит существующее значение с 10 в этом месте. Это может привести к неопределенному поведению, поскольку теперь вы что-то изменили, не зная контекста, имеющего фактическую власть памяти. Если у вас нет прав на память, вы просто получаете ошибку сегментации. Это называется разыменованием неинициализированного указателя.

Следующий оператор вы делаете a = &b который просто присваивает адрес b в a . Это не помогает, потому что предыдущая строка разыменовывает неинициализированный указатель.

Следующий код у вас есть что-то вроде этого после третьего заявления:

  +----------+ +----------+ | addr2 |---+ | garbage | +----------+ | +----------+ | a | +--> | b | +----------+ +----------+ | addr1 | | addr2 | +----------+ +----------+ 

Третий оператор присваивает адрес b в a . До этого a не разыменовывается, поэтому значение мусора, хранящееся в a до инициализации, никогда не используется в качестве адреса. Теперь, когда вы назначаете действительный адрес своих знаний в a , разыменование a теперь даст вам доступ к значению, на которое указывает a .

Расширяя ответ, вам нужно следить за тем, чтобы даже если вы назначили действительный адрес указателю, вы должны убедиться, что во время разыменования указателя время жизни указателя, на которое указывает указатель, не истекло. Например, возвращающая локальная переменная.

 int foo (void) { int a = 50; return &a; //Address is valid }//After this `a' is destroyed (lifetime finishes), accessing this address //results in undefined behaviour int main (void) { int *v = foo (); *v = 50; //Incorrect, contents of `v' has expired lifetime. return 0; } 

То же самое в случае доступа к свободной памяти из кучи.

 int main (void) { char *a = malloc (1); *a = 'A'; //Works fine, because we have allocated memory free (a); //Freeing allocated memory *a = 'B'; //Undefined behaviour, we have already freed //memory, it's not for us now. return 0; } 

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

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

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