Указатели: чтение нарушения прав доступа при попытке разыменования указателя путем добавления большого числа

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

Это работает:

int *arth, art;
art = 100;
arth = &art;
printf("arth address is %p arth+1 value is %d", arth, *(arth + 1));

теперь, если я попытаюсь добавить большое число в арт, я получу нарушение доступа для чтения

Это не так:

printf("arth address is %p arth+1 value is %d", arth, *(arth + 1000));

Ошибка:

Возникло исключение: нарушение доступа для чтения. arth был 0xC9C5EFF964. произошел

СПРОСИТЕ:
кто-нибудь может объяснить, почему это работает при добавлении 1, а не при добавлении 1000


person TheGameiswar    schedule 05.09.2017    source источник
comment
Объяснять особо нечего? Разыменование вашего указателя bodged-a-lot вызывает аппаратное прерывание управления памятью и, следовательно, сообщение об ошибке.   -  person Martin James    schedule 05.09.2017
comment
Не вижу никакой проблемы. Вы ожидали какого-то другого результата? Что конкретно?   -  person n. 1.8e9-where's-my-share m.    schedule 05.09.2017
comment
Оба являются незаконным доступом и, следовательно, не определены, поэтому не имеет смысла спрашивать, почему один работал, а другой нет.   -  person Lee Daniel Crocker    schedule 05.09.2017


Ответы (5)


arth указывает на один экземпляр int. Добавление любого ненулевого значения к arth и последующее разыменование этого нового значения указателя считывает ячейку памяти за пределами исходного int. Это вызывает неопределенное поведение.

С неопределенным поведением может случиться что угодно. Ваша программа может дать сбой, она может выдавать странные результаты или может показаться, что она работает правильно. Тот факт, что вы не разбились на корпусе *(arth + 1)), но разбились на *(arth + 1000)), является тому примером.

То, что программа не дала сбой, не означает, что она не сделала что-то не так.

person dbush    schedule 05.09.2017
comment
With undefined behavior, anything can happen. Your program may crash, it may output strange results, or it may appear to work properly.Спасибо, кажется, я получаю неопределенное поведение - person TheGameiswar; 05.09.2017

Потому что это *(arth + 1) вызывает неопределенное поведение!

Неопределенное поведение — это когда программа может действовать неожиданно. В вашем случае это может работать как в первом фрагменте кода, так и во втором. Или сегодня это может вообще не сработать в обоих случаях. Завтра может. На вашей машине это может сработать, на моей... может и нет! Узнайте больше о UB.

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

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

Когда вы добавляете 1000, вы выходите за пределы сегмента программы, вызывая ошибку сегментации или нарушение прав доступа (вы называете это!).

Визуализация:

указатели

Вы действуете так, как будто arch указывает на массив, а когда array[i] допустимо, array[i + 1] тоже допустимо (при условии, что i + 1 не больше или равно размеру массива).

Однако arch просто указывает на одну переменную, ни больше, ни меньше!


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

person gsamaras    schedule 05.09.2017

Arth указывает на целое число, но arth+1 не указывает ни на что, что вы определили в своем коде, как и arth+1000.

C фактически позволяет вам увеличивать указатель на один элемент после выделения памяти, поэтому arth+1 технически разрешен, а arth+1000 — нет. Поведение для arth+1000 не определено, так что может случиться что угодно. В вашем случае это была ошибка.

person savram    schedule 05.09.2017
comment
so arth+1 is technically allowed Спасибо, я думаю, что даже арт+1 не определено, если я правильно понял - person TheGameiswar; 05.09.2017
comment
Arth+1 технически разрешен, но вы ничего не выделили в arth+1, поэтому попытка разыменовать его по-прежнему является неопределенным поведением, лол. - person savram; 05.09.2017

*(arth + 1000), аналогично arth[1000] и (arth+1) равно arth[1].(arth + 1000), для которого вы не выделили и не инициализировали пробел в памяти, и, следовательно, компилятор выдаст неопределенное поведение, и в этом месте нет таких выделенных данных.

person Vivek Singh    schedule 05.09.2017
comment
Я также не инициализировал arth+1, поэтому в итоге попытка уважать что-то, что не инициализировано, приводит к UB - person TheGameiswar; 05.09.2017

Оба недействительны, будь то * (arth + 1) или (arth +1000), поскольку вы обращаетесь к памяти, которая вообще не выделена. Это может работать из-за неопределенного поведения. Запустите с valgrind и проверьте журнал valgrind, он всегда будет сообщать недопустимое чтение, будь то * (arth +1) или * (arth +1000). Всегда запускайте valgrind при добавлении любого кода, связанного с указателем.

person Rohit    schedule 07.09.2017