Segfault при разыменовании пользовательского адреса mem (C) - PullRequest
0 голосов
/ 16 сентября 2018

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

void main()
{
    char *ptr;
    ptr = (char *)0x123123; //the assignment works perfectly with a cast
    printf("%p\n", ptr); //and the pointer indeed holds the address it's supposed to
    *ptr = 'a'; //but this breaks
    puts("2");
}

Сначала я думал, что причина в том, что я пытаюсь разыменовать неинициализированную память.Но на самом деле я сомневаюсь, что это так, поскольку some_type *some_ptr = &some_variable; работает безупречно, поэтому сделка должна быть адресом, которому я ее назначаю.

Тогда я подумал, точно так же 3 или 'a' или "alpine" - это константы, (char *) 0x123123 тоже должна быть константой.И const -s нельзя редактировать в C, но это все равно не может быть, потому что попытка изменить значение const не скомпилируется.

3-е допущение состоит в том, что такой адрес должен быть недоступен, но это также не имеет смысла, поскольку строка 4 работает всегда, независимо от того, какой адрес я даю, или типа pointer. * 1016.*

Ответы [ 3 ]

0 голосов
/ 17 сентября 2018

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

например. используя malloc:

ptr = malloc(32); // now you can write to this memory block and it perfectly legal
*ptr = 'a';
0 голосов
/ 17 сентября 2018

ОП разъяснил в другом месте, что это на самом деле проблема XY.

Проблема X: чтение / запись в произвольные области памяти.

Проблема Y: реализация связанного списка, использующего последовательную память.

Конечно, ответ на этот вопрос: для достижения цели нужно внедрить свою собственную систему управления памятью.

Как в: во-первых, вы используете malloc(), чтобы получить большой блок последовательной памяти. Затем вы можете использовать произвольные указатели в пределах этого блока памяти. Но, конечно же, ваш код должен отслеживать, какие адреса уже используются. Или правильно "освободить", когда узлы списка будут удалены.

Сложная часть касается обработки угловых случаев, таких как: что происходит, когда ваш последний «указатель» израсходован? Вы используете malloc () большую область и перемещаете все данные в памяти?

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

0 голосов
/ 16 сентября 2018

3-е допущение: такой адрес должен быть недоступен,

Это правильно: в современных ОС (которые все имеют защиту памяти) вы не можете записать в произвольный адрес памяти.

Раньше было возможно получить доступ к любой памяти в ОС, которые не использовали виртуальную память (например, MS-DOS), но допускали, что это, как правило, очень плохая идея -она позволяла случайным программам повреждать состояние ОС и требовала очень частых перезагрузок.

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

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

Различие похоже на "Вы можете напечатать адрес?"(например, «123 Main Street, SomeTown, SomeCountry») и «Вы можете ввести дом по этому адресу?»(невозможно по вышеуказанному адресу, потому что на Земле нет "SomeCountry").Даже если адрес действителен, например, «1600 Pennsylvania Ave NW, Washington, DC 20500», вам все равно не разрешат его ввести.

...