С++ new/delete и char * - программирование
Подтвердить что ты не робот

С++ new/delete и char *

Может кто-нибудь мне помочь, почему я получаю сообщение об ошибке при попытке освободить выделенную память: обнаружено обнаружение кучи. CTR обнаружил, что приложение записало память после завершения буфера кучи.

char *ff (char *s){
    char *s1 = new char [strlen(s)];
    strcpy(s1, s);
    return s1;
}

int _tmain(int argc, _TCHAR* argv[])
{
    char *s = new char [5];

    strcpy(s, "hello");
    char *s2 = ff(s);

    delete []s;     // This works normal
    delete []s2;    // But I get an error on that line
    return 0;
}
4b9b3361

Ответ 1

char *s = new char [5];
strcpy(s, "hello");

Вызывает поведение Undefined (UB).
Вы пишете за пределы выделенной памяти. Вы выделили достаточно памяти для символов 5, но ваша строка имеет 6 символы, включая \0.

Как только ваша программа вызвала этот UB, все ставки отключены и любое поведение возможно.

Вам нужно:

char *s = new char [strlen("hello") + 1];

На самом деле идеальным решением является использование std::string, а не char *. Это ошибки, которые избегают std::string. И нет реальной необходимости использовать char * вместо std::string в вашем примере.
С помощью std::string:

  • Вам не нужно new ничего
  • Вам не нужно delete ничего и
  • Вы можете сделать все с помощью std::string, что вы делаете с char *.

Ответ 2

new char [strlen(s)]; не учитывает закрывающий символ \0, поэтому ваш буфер слишком короткий одним символом.

Ответ 3

strcpy включает нулевой ограничитель; strlen нет. Запись:

char *s1 = new char [strlen(s) + 1];

Ответ 4

От человека strcpy (3):

Функция strcpy() копирует строку, на которую указывает src, , включая завершающий нулевой байт ('\ 0'), в буфер, на который указывает по dest.

Поэтому вам нужно зарезервировать 6 bytes 5 для строки и 1 для NULL байт

char *s = new char [6];
strcpy(s, "hello");

Ответ 5

Все ответы до сих пор касались либо первого, либо второго распределения. Подводя итог, вы должны сделать два изменения:

char *s1 = new char [strlen(s) + 1];
...
char *s = new char [5 + 1];

В обоих случаях вы должны выделить достаточно места для строки плюс один байт для завершения "\ 0" .

Как уже указывалось другими, с С++ проще и безопаснее использовать std::string. Нет проблем с распределением и выпуском памяти или обращением к байтам '\ 0':

std::string ff (const std::string &s){
    std::string s1(s);
    // do something else with s1
    return s1;
}

int main(int argc, char* argv[])
{
    std::string s("hello");
    std::string s2 = ff(s);
    return 0;
}

и если он просто копирует строку:

std::string s("hello");
std::string s2(s);

Ответ 6

Вам нужно указать char *s1 = new char [strlen(s) + 1];, чтобы освободить место для '\0', которая завершает строку.

Ответ 7

Ваша начальная строка s имеет длину всего пять символов, поэтому не может быть завершена нуль. "hello" будет скопирован с помощью strcpy, включая нуль-терминатор, но вы будете перекрывать буфер. strlen требует, чтобы оно было завершено нулем, поэтому, если нуль не существует, у вас будут проблемы. Попробуйте изменить эту строку:

char * s = новый char [6];

Еще лучше, предпочитайте std::string для строковых функций стиля C - они так же эффективны и намного безопаснее и проще в использовании. Также старайтесь избегать new и delete, если вам действительно не нужно их использовать. Проблемы, которые вы получаете, очень распространены и их можно легко избежать.

Ответ 8

У вас поврежден указатель s2 на

strcpy(s, "hello");

Поскольку s имеет размер 5, в то время как вы пропустили этот strcpy, он включает в себя ограничитель строк.