#c #pointers
#c #указатели
Вопрос:
У меня есть эти две программы только для понимания того, как работают указатели. Первый из них назван test.c
, и вот код.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *mem = malloc(sizeof(int) * 1);
*mem = 90;
//free(mem);
printf("%p", mem);
return (0);
}
итак, в основном у меня есть программа, которая выделяет место для одного целого числа, а затем выводит этот адрес на стандартный вывод. В разделе с комментариями я освобождаю выделенную память после присвоения значения. Я расскажу о том, почему я прокомментировал это позже. Вот мой второй код. Она находится в файле с именем test1.c
. И вот код,
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
int num = (int)strtol(argv[1], NULL, 16);
int *mem = (void *)(long)num;
printf("at test1 string> %s, changed to pointer-->%p, after being dereferenced-->%in",argv[1], mem, *mem);
return (0);
}
В этой второй программе ввод берется из командной строки, а затем он изменяется на указатель (адрес). Предполагается, что передается шестнадцатеричная строка. Что он делает, это просто напечатать переданный адрес памяти, а затем попытаться получить значение по этому адресу.
Что я сделал дальше, так это скомпилировал каждый файл в test
и test1
, соответственно, используя gcc (я использую Linux) и выполнил следующую команду ./test | xargs ./test1
, и это выдает следующую ошибку xargs: ./test1: terminated by signal 11
. Я понял, что это из-за ошибки сегментации, вызванной test1, потому что, если я не пытаюсь разыменовать указатель, я не получаю эту ошибку. Но я не понимаю, почему я получаю ошибку seg. даже после освобождения памяти (раскомментируйте комментарий в первой программе) Я все еще получаю ошибку сегментации. Я ожидал получить какое-то значение мусора, а не ошибку seg.Я начинаю работу со всем этим процессом и указателем, поэтому наверняка мне чего-то не хватает, я надеюсь, что кто-нибудь объяснит или направит меня к ресурсу.
Чтобы просто перефразировать мой вопрос, как программа может получить доступ к определенной памяти, не выделяя ее?
Комментарии:
1. <хакер>: О, смотрите, мое веб-приложение только что просканировало всю память, потому что все программы могут видеть всю память в ОС 70-х годов, и нашли часть, принадлежащую суперсекретному приложению. Давайте повеселимся…
2. На ПК существует только определенный диапазон адресов, к которым может обращаться ваша программа, и в любом случае это не физические адреса, и диапазон может меняться от одного запуска к следующему. Если вы должны получить адрес из одной программы и попытаться поместить его в другую, это совершенно бесполезно (по замыслу).
3. @MichaelDorgan жаль, что я не родился в 70-х годах
4. Я работал над оригинальными играми GameBoy. Это была система, в которой все вышеперечисленное работало бы…
5. @MichaelDorgan круто, что это очень проницательно. Мало ли что я знал, после изучения указателей я хотел создать программу, которая считывала бы то, что находится в каждом бит памяти. 🙂
Ответ №1:
Вы не можете.
Адреса памяти разделены на страницы (обычно 4096 байт). Когда вы обращаетесь к адресу, центральный процессор ищет страницу с этим адресом в «таблице страниц» процесса. В этой таблице указано, где в физической памяти (т.Е. «Какой чип ОЗУ») находится этот адрес.
Таким образом, вы не можете получить доступ к адресам, которых нет в таблице страниц вашего процесса. Полная остановка.
Как вы добавляете страницы в свою таблицу страниц? Вы спрашиваете ОС. В Windows вызывается функция VirtualAlloc
. В Linux это называется mmap
. Или вы используете функцию, подобную malloc
, которая позволяет вам выделять только небольшую часть страницы (путем разделения страниц, которые она получает из ОС).
Кроме того, у каждого процесса своя таблица страниц. Таким образом, адреса означают разные вещи в разных процессах. Возможно test
, процесс мог бы иметь запись таблицы страниц для страницы 0x12345000, но test1
процесс этого не делает, потому что это совершенно разные таблицы. Вот почему не имеет смысла отправлять указатели от одного процесса к другому.
В старые времена вычислений не было таблиц страниц, а указатели были фактическими адресами оперативной памяти, но те времена давно прошли.
Редактировать: вы также можете попросить ОС поместить одну и ту же страницу в таблицы страниц двух разных процессов одновременно — это называется общей памятью.
Ответ №2:
Итак, если я понимаю, что вы делаете, вы печатаете адрес динамически выделяемого блока памяти из одной программы, вырезаете и вставляете его в качестве входных данных во вторую программу, которая затем пытается получить доступ к этому адресу.
Есть несколько причин, по которым это не сработает.
Первое, на что указывает user253751 — адреса не отображаются в разных процессах. 0x1234
в процессе A сопоставляется с другой ячейкой физической памяти, чем 0x1234
в процессе B. Существуют способы настройки общей памяти между запущенными процессами, но это немного сложнее, чем это.
Во-вторых, вы используете неправильные типы. int
Недостаточно большой, чтобы хранить значение указателя — после приведения и присвоения результата strtol
to num
вы, безусловно, потеряли некоторые цифры, поэтому приведение их обратно к указателю не даст вам правильного адреса.
Типы intptr_t
и uintptr_t
in stddef.h
являются целочисленными типами, достаточно большими для хранения значений указателей, но их реализация необязательна, и все еще нет уверенности в том, что strtol
можно точно преобразовать входное значение.
Комментарии:
1. Хорошо, спасибо. Спасибо за все уроки, я буду читать больше о том, что вы упомянули.
Ответ №3:
Хотя пользователь253751 дал хорошее техническое объяснение, я хочу изложить его более понятным для начинающих: ваша ОС гарантирует, что один процесс не сможет получить доступ к памяти другого, поскольку это означало бы, что вы можете манипулировать или уничтожать другие программы или красть их данные (пароли, например). Язык C не проверяет указатели, поэтому вы можете установить для них все, что захотите, но если вы хотите получить доступ к этому адресу, ОС останавливает вас, потому что у нее есть функции безопасности.
Комментарии:
1. Хорошо, спасибо. Я узнал о виртуальном распределении, задав этот вопрос, спасибо вам всем.