Разыменование указателя char в C/C++?

Я работаю в программе, используя информацию DWARF и ELF. Я подключен к другой программе с помощью инструмента под названием Pin. У меня есть адреса из глобальных переменных, объявленных в программе «Y», и я подключаю их к своему модулю Pin, который я буду называть «X».

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

char * limit, * address1;

for(address1 = (char *) 0x804A040, limit = address1 + bytesize; address1 < limit; address1++)
      cout <<  *(address1) << "\n";

Я должен получить переменную, хранящуюся по этому адресу, который представляет собой char * к слову. Должен ли я разыменовывать два указателя в этом случае? Адрес, а затем char * хранится в этом адресе?

Это отлично работает, когда я хочу разыменовать переменную int, но всякий раз, когда я пытаюсь разыменовать указатель или переменную char, я получаю значения non-ASCII...


person attis    schedule 25.09.2012    source источник
comment
Ваш оператор for имеет только два аргумента, разделенных точкой с запятой, но для корректности требуется три.   -  person mrb    schedule 26.09.2012
comment
Вы ожидаете напечатать адрес строки или саму строку?   -  person Pete Fordham    schedule 26.09.2012
comment
Вы пытаетесь считать данные из текущего процесса или из отдельного процесса?   -  person Adam Rosenfield    schedule 26.09.2012
comment
@PeteFordham Я ожидаю получить саму строку. Я получаю буквально следующее: @@�   -  person attis    schedule 26.09.2012
comment
Я пытаюсь прочитать данные из процесса, к которому подключен Pin, поэтому это будет текущий процесс, управляемый моим модулем Pin @AdamRosenfield.   -  person attis    schedule 26.09.2012
comment
Какова структура данных по адресу? Похоже, он должен содержать int (сколько байтов, 2, 4 или 8?) вместе с указателем на строку. И что int содержит длину строки. Однако меня немного смущает фрагмент кода.   -  person Richard Chambers    schedule 26.09.2012
comment
@RichardChambers Я использую таблицу символов ELF, чтобы получить размер байта и адреса каждой из переменных. Но сейчас я просто экспериментирую с адресами и смотрю, смогу ли я разыменовать их без каких-либо проблем... Структура данных - это char *, точнее слово "0xDEADBEEF", которое является char array из size 10, по крайней мере, из моего понимание размеров шрифта   -  person attis    schedule 26.09.2012
comment
Если это массив символов, а не указатель на массив символов (строка), то вы должны обращаться к нему как char *addr = (char *)0x804A040; printf("%s\n", addr). Если это указатель на массив символов, вам следует проверить мой ответ.   -  person Toribio    schedule 26.09.2012
comment
Попробуйте address1 = *((char **)0x804a040), чтобы посмотреть, исправит ли это проблему.   -  person Benny Smith    schedule 12.06.2013


Ответы (2)


Думайте так: если вы хотите разыменовать int, вы используете int *:

int *addr = (int *)0x12345678;
printf("%d\n", *addr);

Но строка уже является указателем, поэтому, если вы сделаете это:

char *addr = (char *)0x12345678;

Вам не нужно разыменовывать его, чтобы распечатать, поэтому вы получите его следующим образом:

printf("%s\n", addr);

Кроме того, предположим, что у вас есть эта память:

00000001:  0x12345678
...
12345678:  'A'
12345679:  'B'
1234567A:  '\0'
...

Давайте получим доступ к адресу 0x00000001 и посмотрим, что мы можем сделать:

unsigned int *addr = (unsigned int *)0x00000001;

Теперь *addr содержит целое число, которое является адресом первого символа нашей строки. Функции, принимающие строковый аргумент, обычно запрашивают строковый адрес, то есть указатель на него, поэтому *addr также является строкой, которую мы должны напечатать, например, на cout или printf.

// This should print "AB"
printf("%s\n", (char *)(*addr));

Теперь, если вы разыменуете наше значение (0x12345678), мы получим первый символ строки и только его как char. Поэтому, если вы неправильно используете его и разыменовываете его до char *, printf попытается найти в памяти «A», то есть 0x00000041, и, вероятно, получит ошибку сегментации.

Итак, правильный способ разыменовать его значение, чтобы получить первый символ, будет таким:

// This should print "A"
printf("%c\n", (char)(**addr));

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

person Toribio    schedule 25.09.2012
comment
Я думал об этом, но при этом у меня возникает ошибка сегментации. У меня есть доступ к этому виртуальному пространству памяти, поэтому я не знаю, почему я его получаю. - person attis; 26.09.2012
comment
это действительно полезно, большое спасибо, чувак! Я попробую и дам вам знать, что получится! Спасибо, чувак @flaviotoribio РЕДАКТИРОВАТЬ: Ты уверен, что это правильный синтаксис? Компилятор продолжает жаловаться на недопустимый аргумент типа унарного * из-за указателя на указатель - person attis; 26.09.2012
comment
Возможно, попробуйте (char)(*(char *)*addr). Это потому, что я использовал промежуточную переменную другого типа для разыменования. - person Toribio; 26.09.2012
comment
Мне удалось заставить его работать, приведя указатель к char *. (char *) *(address1) Большое спасибо! - person attis; 26.09.2012

Да, вам нужно разыменовать два указателя. Сначала получить адрес переменной, содержащей char*, а затем разыменовать char*.

person sdkljhdf hda    schedule 25.09.2012