2010-11-18 90 views
2

這裏堆損壞時是我的代碼:刪除字符串

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; 
} 

第一行讀取字符串的長度。
第二行創建一個字符串長度爲
的新字符數組(字符串)第三行讀取字符串(從文件中讀取它)
第4行將NULL添加到最後。
第5行創建一個std ::字符串出c字符串。
第6行刪除c字符串(HEAP CORRUPTION HAPPENS HERE)
第7行返回字符串,但由於錯誤,它永遠不會到達這一點。

在第6行,我得到一個堆損壞錯誤: CRT檢測到應用程序在堆緩衝區結束後寫入內存。

我的問題可能很明顯,但爲什麼我得到堆腐敗?當我創建一個std :: string時,它應該複製該字符串,並且我應該安全地刪除該c字符串。

目前,我懷疑std :: string在刪除它後試圖訪問c字符串。

任何想法?

+0

您在代碼中有'delete []',因此您的代碼很糟糕。使用'std :: vector'或其他東西,甚至直接讀入字符串。 – GManNickG 2010-11-18 21:30:42

+0

@GMan:在我發佈之前甚至沒有看到您的評論:p它太簡單了,它也簡化了代碼... – 2010-11-19 07:44:16

回答

4

變化:

char* rawString = new char[strLen]; 

到:

char* rawString = new char[strLen + 1]; 
+0

謝謝。我無法相信我忽略了這樣的事情。我一直在使用C++一段時間:)。感謝所有在此提供幫助的人! – Brad 2010-11-18 21:54:34

2

int strLen = Read<int>()可能只返回一個非空值終止字符串的長度,而當你嘗試寫\0字節的字符串,您遇到緩衝區溢出問題。

你應該檢查什麼strLen是的,很有可能你要麼必須分配是這樣的:

char *rawString = new char[strlen+1]; 

或使用std::string(const char *, size_t n)這樣的重載的構造函數:

std::string retVal(rawString, strlen); 
8

你所訪問超過字符串的保留字節。您保留了strLen個字符,但在strLen處輸入了\0。從0開始計數爲C數組,字符strLen位於strLen + 1,因此您要爲該字符串的保留空間外放置一個值。您應在main的第二行中保留strLen + 1,以便您的代碼正常工作。

1

由於陣列在C++ 0索引,在創建大小strLen的陣列,然後將一個0在strLen位置,你是在你分配的數組結束後寫入一個零。

0
rawString[strLen] = '\0'; 

將NUL寫入已分配空間的末尾。

如果strLen爲10,則爲10個字符分配空間,讀取10個字符,然後將此NUL寫入位置11。Ooops

1

到目前爲止的許多建議,但沒有一個解決異常安全問題:你如何擺脫潛在的內存泄漏?

有兩種方法可以避免與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; 
} 

另一種是符合標準:string具有可以訪問(感謝GMAN內部緩衝器,data是不正確的訪問方法)

std::string readString() 
{ 
    int strLen = Read<int>(); 

    std::string retVal(strLen, '\0'); // no need to allocate extra space 

    Read(&retVal[0], strLen);  // &retVal[0] gives access to the buffer 

    return retVal; 
} 

我相信最後的版本更好。不再涉及任何複製:)

+0

實際上,前者是非標準的C++。第二個只給const訪問。 :S你想要讀入一個'vector'或者保留這個字符串並讀入'&retVal [0]',這會吐出一個連續的緩衝區。哦,你有「非常簡單」。 :) – GManNickG 2010-11-19 07:55:01

+0

@GMan:廢話,我以爲有兩個版本的'data'。我做了精確的前者是非標準的,但我確實是一個編譯器擴展(和一個很好的...) – 2010-11-20 14:47:58