Несколько вопросов о указателях на символы - PullRequest
2 голосов
/ 02 июня 2010

1- Как это работает:

char *ptr = "hi";

Теперь компилятор поместит эту строку в память (я предполагаю стек) и создам указатель на нее? Это так работает?

2- Также, если она создается локально в функции, когда функция вернется, будет ли освобождена память, занятая строкой?

3- И последнее, но не менее важное: почему это не разрешено: ptr[0] = 'H';?

Ответы [ 4 ]

6 голосов
/ 02 июня 2010

1) Строка не (обычно) в стеке - обычно она находится в инициализированном сегменте данных, который читается непосредственно из исполняемого файла. Затем указатель инициализируется по адресу этой строки.

2) Нет.

3) Потому что стандарт говорит, что он дает неопределенное поведение. Подумайте, было ли у вас что-то вроде этого:

int a() { char *a = "a"; printf("%s\n", a); }
int b() { char *b = "a"; *b = 'b'; }

int main() { 
    b();
    a();
    return 0;
}

Теперь, когда вы печатаете a, ожидаете ли вы получить исходное значение (a) или обновленное значение (b)? Компиляторы могут, но не обязательно, совместно использовать такие статические строки; некоторые также помечают всю область только для чтения, поэтому попытка записи в нее приведет к исключению.

С точки зрения стандарта C единственным разумным ответом было назвать его неопределенным поведением.

2 голосов
/ 02 июня 2010
  1. Компилятор поместит строку "hi" где-нибудь в память (она не установлена ​​стандартом), и вы не знаете, где, но вы должны учитывать, что она может быть помещена в доступный только для чтения раздел памяти (хотя это должен решить компилятор). Затем будет создан указатель, указывающий на начало этого места в памяти.

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

  3. Это недопустимо, поскольку стандарт не гарантирует доступ на запись в такой автоматически выделенный блок памяти (см. 1.). Он может работать на некоторых системах / платформах / компиляторах, но это не гарантируется стандартом.

1 голос
/ 02 июня 2010
  1. Вы можете более точно и надежно выразить это как:

    const char *ptr = "hi";

    В вашем коде не только отображается фактическая информация, но и компилятор также будет перехватывать попытки записи в память, указанную ptr. Сама строка является «статической константой» (и поэтому не находится в стеке), указатель является переменной, инициализированной по адресу в строке.

  2. Нет, только один эпоинтер будет создан в стеке. Данные останутся в статической постоянной памяти (обычно как часть сегмента кода). Большинство цепочек инструментов компилятора / компоновщика будут соответствовать общим строкам, поэтому, если, например, у вас есть несколько экземпляров «hi» в вашем коде, они фактически ссылаются на один и тот же экземпляр.

  3. Это неопределенное поведение. В зависимости от того, как хранится текст, он может работать или не работать. Современные процессоры / ОС часто реализуют механизмы защиты для защиты сегмента кода как от модификации, так и от исполнения; поскольку такие строки также обычно находятся в сегменте кода, попытка изменить строку может привести к исключению во время выполнения. Гораздо лучше обнаружить эту ошибку во время компиляции, объявив указатель const.

    Если вы используете 16-разрядный DOS-компилятор или цель без защиты памяти, это может сработать; но поскольку общие строки могут быть сопоставлены, возможно, вы модифицируете строку, на которую ссылается более одного указателя. На встроенной цели строка может находиться в ПЗУ, и в этом случае, даже если доступ не заблокирован как незаконный, это не будет иметь никакого эффекта.

1 голос
/ 02 июня 2010
  1. Компилятор поместит указатель на строку в памяти и поместит адрес строки "hi" в указатель. Сама строка будет в образе кода программы.

  2. Память к указателю будет освобождена.

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

...