C++ 删除字符串时堆损坏

C++ 删除字符串时堆损坏,c++,string,stl,heap,cstring,C++,String,Stl,Heap,Cstring,这是我的密码: std::string readString() { int strLen = Read<int>(); char* rawString = new char[strLen]; Read(rawString, strLen); rawString[strLen] = '\0'; std::string retVal(rawString); delete [] rawString; return re

这是我的密码:

std::string readString()
{
     int strLen = Read<int>();
     char* rawString = new char[strLen];
     Read(rawString, strLen);
     rawString[strLen] = '\0';
     std::string retVal(rawString);
     delete [] rawString;
     return retVal;
 }
std::string readString()
{
int strLen=Read();
char*rawString=新字符[strLen];
读取(原始字符串,strLen);
原始字符串[strLen]='\0';
std::string retVal(rawString);
删除[]原始字符串;
返回返回;
}
第一行读取字符串的长度。
第二行创建一个字符串长度为
第三行读取字符串(从文件中读取)
第四行在末尾添加一个空值。
第5行从c字符串中创建一个std::字符串。
第6行删除c字符串(此处发生堆损坏)
第7行返回字符串,但由于错误,它从未到达这一点

在第6行,我得到一个堆损坏错误: CRT检测到应用程序在堆缓冲区结束后写入内存

我的问题可能很明显,但为什么我会得到一堆腐败?当我创建一个std::string时,它应该复制这个字符串,我应该可以安全地删除这个c字符串

目前,我怀疑std::string在删除c字符串后试图访问它

有什么想法吗

int strLen=Read()
可能只返回以非空结尾的字符串的长度,当您尝试将
\0
字节写入字符串时,会遇到缓冲区溢出问题

您应该检查strLen是什么,很可能您必须这样分配:

char *rawString = new char[strlen+1];
std::string retVal(rawString, strlen);
或者像这样使用
std::string(const char*,size\t n)
的重载构造函数:

char *rawString = new char[strlen+1];
std::string retVal(rawString, strlen);

您正在访问字符串的保留字节。您保留了
strLen
字符,但在字符
strLen
处放置了一个
\0
。从0开始作为C数组计数,字符
strLen
位于位置
strLen+1
,因此将一个值放在字符串的保留空间之外。您应该在
main
的第二行中保留
strLen+1
,以便代码正常工作。

更改:

char* rawString = new char[strLen];
致:


由于数组在C++中是0索引的,当你创建一个大小为<代码> StLLUN <代码>的数组,然后在位置<代码> StLLUN < /> >中放置一个0,在你所分配的数组的末尾,你就写了0个。

 rawString[strLen] = '\0';
将NUL从已分配空间的末尾写入

 rawString[strLen] = '\0';

如果strLen为10,则为10个字符分配空间,读取10个字符,然后将该NUL写入位置11。Ooops

到目前为止有很多建议,但没有一个能解决异常安全问题:如何消除潜在的内存泄漏

有两种方法可以避免使用
new
进行分配(从而避免内存泄漏)。第一种方法非常简单,使用了一种称为VLA的编译器扩展,用于可变长度数组:

std::string readString()
{
  int strLen = Read<int>();
  char rawString[strLen+1]; // VLA: the length is determined at runtime
                            // but the array is nonetheless on the stack
  Read(rawString, strLen);
  rawString[strLen] = '\0';

  std::string retVal(rawString);
  return retVal;
}

我相信最后一个版本要好得多。不再涉及任何复制:)

您的代码中有
delete[]
,因此您的代码是错误的。使用
std::vector
或其他什么,甚至直接读入字符串。@GMan:在我发布之前,我甚至没有看到你的评论:p它还简化了代码,真是不可思议……谢谢。真不敢相信我竟然忽略了那样的事情。我用C++已经有一段时间了:谢谢所有在这上面发布帮助的人!前者是非标准C++,实际上是非标准C++。第二个只允许const访问:要读入
向量
或保留字符串并读入
&retVal[0]
,这会产生一个连续的缓冲区。哦,你说的“非常简单”。)@GMan:废话,我以为有两种版本的
数据。我确实认为前者是非标准的,但我确实认为它是一个编译器扩展(而且是一个很好的扩展…)