const char * в C ++ - PullRequest
       32

const char * в C ++

3 голосов
/ 04 января 2010

Как работают строковые выражения в C ++?

Рассмотрим:

#include <iostream>
using namespace std;

int main(int argc, char *argv[]){

    const char *tmp="hey";
    delete [] tmp;

    return 0;
}

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

Ответы [ 9 ]

18 голосов
/ 04 января 2010

Где он хранится, остается на усмотрение компилятора в этом (несколько особенном) случае. Однако для вас это не имеет значения - если вы не выделяете память с помощью new, не очень хорошо пытаться освободить ее с помощью delete. Вы не можете delete выделить память так, как вы ее выделили.

Если вы хотите контролировать освобождение этого ресурса, вы должны использовать std::string или выделить буфер с помощью malloc().

16 голосов
/ 04 января 2010

Когда вы присваиваете указатель const char * постоянной строке, такой как "hey" в примере, последовательность hey\0 сохраняется как статическая переменная внутри самого двоичного файла. Он не может быть удален и не должен манипулировать. В зависимости от архитектуры / операционной системы, может вызывать сбой при манипулировании .

Если вы сделаете const char[] tmp = "hey", тогда данные будут храниться в стеке, и ими можно манипулировать (но не удалять, так как они будут освобождены после очистки стека: когда функция вернется).

Не delete[] ничего, что не new[] 'd.

10 голосов
/ 04 января 2010

"hey" является строковым литералом и хранится в сегменте данных исполняемого файла , который отображается в памяти процесса во время загрузки. Конкретная часть, где живут литералы, отображается только для чтения . Вот фрагмент сборки, созданной из вашего кода с g++ -S:


...
    .section    .rodata
.LC0:
    .string "hey"
    .text
    .align 2
...

Таким образом, данные действительно только для чтения , и попытка манипулировать ими с помощью delete приводит к segfault.

5 голосов
/ 04 января 2010

const char *tmp="hey";

«эй» хранится в области только для чтения сегмента данных . Когда приложение запустится, «эй» будет отображено на странице памяти «только для чтения».

const char *tmp="hey";
delete [] tmp;

delete будет получать доступ и изменять некоторые метаданные выделения. , но "эй" на странице памяти ТОЛЬКО ДЛЯ ЧТЕНИЯ.

Изменение значения в READ-ONLY недопустимо, , поэтому произошла ошибка сегментации .

4 голосов
/ 04 января 2010

Что происходит, вот так.

"hey" означает поместить строку 'hey' в двоичное изображение где-нибудь и дать мне его адрес , который является значением выражения ("hey"). Он имеет тип char *. По этому адресу у вас есть 4 байта. 'h', 'e', ​​'y' и 0 (0 называется обычным нулевым терминатором. (ничего общего с терминатором фильма). Так работают строковые литералы в C.

Вы можете передать этот литерал как таковой: «адрес строки».

Вы не можете удалить его.

когда вы создаете std :: string ("hey"), он берет указанную строку и копирует ее в другое место - во вновь выделенную память.

4 голосов
/ 04 января 2010

Вы не можете удалить статические ресурсы: они доступны только для чтения.

1 голос
/ 04 января 2010

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

Надеюсь, это поможет, С наилучшими пожеланиями, Том.

1 голос
/ 04 января 2010

Вы не можете удалить постоянные данные. Вы бы позвонили delete[] tmp, только если вы ранее звонили new char[stringSize].

0 голосов
/ 04 января 2010

Строка "hey" имеет пространство, предварительно выделенное как часть программы, поэтому она появляется только при запуске программы и исчезает при ее завершении.

Если вы хотите увидеть программу, которая выделяет память, использует ее, затем удаляет, а затем посмотрите на это:

#include <iostream>
using namespace std;

int main(int argc, char *argv[]){

    const char *hey="hey";
    char* tmp=new char[4]; // NB allocate 4 chars for "hey" plus a null terminator
    strcpy(tmp,hey);  // copies the string and null terminator
    cout << tmp << endl;
    delete [] tmp;
    // must not use tmp now as it points to deallocated memory
    // must not delete hey

    return 0;
}

Обратите внимание, как мне удалось удалить new память, используя tmp. Я мог бы сделать это:

    cout << tmp << endl;
    hey = tmp;
    delete [] hey;

Неважно, в конце концов, мы указываем на new 'd память с hey или tmp, лишь бы мы удаляли ее правильно, чтобы избежать утечек памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...