С++ 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;
}
Ответы
Ответ 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, он включает в себя ограничитель строк.