2015-03-25 31 views
2

我的問題來自我的一個C++練習(來自C++編程抽象,2012版,練習12.2)。那就是:C++:動態分配的新操作符是否檢查內存安全性?

void strcpy(char *dst, char *src) { 
    while (*dst++ = *src++); 
} 

的strcpy的定義是危險的。危險源於事實 strcpy無法檢查 字符數組中是否有足夠的空間接收副本,從而增加了發生緩衝區溢出錯誤的機會 。但是,可以通過使用動態分配爲複製的字符串創建內存空間來消除很多危險。寫一個函數

char *copyCString(char *str); 

,對於C風格的字符串str分配足夠的內存,並終止空字符到 新分配的內存中,然後 複製的字符,沿。

這是我的問題: 這種新方法真的很安全嗎?爲什麼它是安全的? 我的意思是,要有點激進,如果堆中沒有足夠的空間呢? 如果空間不足,new運營商是否能夠檢查空間可用性並以優雅的方式降落? 會導致其他類型的「東西溢出」?

回答

2

如果new未能分配請求的內存,它應該拋出一個std::bad_alloc異常(但請參閱下面的更多內容)。之後,堆棧將被解開到匹配的異常處理程序,並由您的代碼決定要從那裏執行什麼操作。

如果您確實需要確保不會拋出異常,您可以使用new版本的new,該版本將返回一個空指針以指示信號失敗 - 但這幾乎專門用於C兼容性,並且不經常使用(或有用)。

對於問題中引用的情況類型,您通常希望使用std::string,而不是根據自己的空間分配空間。

另請注意,在許多現代系統中,new在發生故障時拋出或返回空指針的概念確實相當陌生。實際上,Windows通常會嘗試擴展分頁文件以滿足您的請求。 Linux有一個「OOMKiller」進程,它會嘗試查找「壞」進程並殺死它們以釋放內存(如果用完的話)。因此,即使C++標準(和C標準)規定如果分配失敗,應該發生什麼1010,這在現實生活中很少發生。

+0

感謝您的回答!我想我明白了。但是這個問題是故意設計的,以便讓讀者分配空間。所以他們可以獲得動態分配的感覺。它位於名爲動態內存管理的章節之下。 – 2015-03-25 00:25:08

+0

@宗耀進:是的,這很好,而且是一個完全合理的學習。然而不幸的是,大多數書籍似乎並沒有對動態內存管理進行足夠詳細的介紹,因此非常有用。 – 2015-03-25 00:26:40

+0

再次感謝您的補充!我懂了。我知道它幾乎不會發生,尤其是像我這樣的新程序員。這只是關於安全問題,並沒有提到爲什麼「新」是一個更好的策略。所以,我對此很好奇。無論如何,非常感謝你! – 2015-03-25 00:28:30

1

如果新運算符無法分配內存,則會拋出bad_alloc異常,除非未指定。如果你指定常量不動,如果它不能分配內存,你會得到NULL指針。

0

strcpy的代碼是不安全的,因爲它會嘗試複製分配的內存以外的指針。例如:

int main() 
{ 
    const char* s1 = "hello"; // allocated space for 6 characters 
    char* s2 = new char[ 2 ]; // allocated space for 2 characters. 
    strcpy(s2, s1); 
    cout << s2 << endl; 

    char c; cin >> c; 
    return 0; 
} 

此打印正確的價值「你好」,但請記住,指針S2被分配到只有2個字符空間。所以我們可以假設其他字符被寫入隨後的內存插槽,這是不安全的,因爲我們可能覆蓋數據或訪問無效內存。

考慮這樣的解決方案:

char* e4_strdup(const char*& c) 
{ 
    // holds the number of space required for the c-string 
    unsigned int sz{ 0 }; 

    // since c-style strings are terminated by the '\0' character, 
    // increase the required space until we've found a '\0' character. 
    for (const char* p_to_c = c; *p_to_c != '\0'; ++p_to_c) 
     ++sz; 

    // allocate correct amount of space for copy. 
    // we do ++sz during allocation because we must provide enough space for the '\0' character. 
    char* c_copy{ new char[ ++sz ] }; // extra space for '\0' character. 
    for (unsigned int i{ 0 }; i < sz; ++i) 
     c_copy[ i ] = c[ i ]; // copy every character onto allocated memory 

    return c_copy; 
} 

運營商仍然會返回一個std :: bad_alloc異常,如果你耗盡內存。

+0

在你的第一個例子中,大小分別是'6'和'2' – 2015-03-25 00:38:12

+0

你是對的,我忽略了'\ 0'字符,另一個是我編輯帖子時發生的錯誤。謝謝。固定。 – 2015-03-25 01:11:36