2015-05-22 29 views
1

爲什麼這段代碼錯了?我是否錯過了deletedelete[]的行爲?刪除和刪除[]的確切行爲是什麼?

void remove_stopwords(char** strings, int* length) 
{ 
    char** strings_new = new char*[*length]; 
    int length_new = 0; 

    for(int i=0; i<*length; i++) { 
     if(is_common_keyword(strings[i]) == 0) { 
      strings_new[length_new] = strings[i]; 
      length_new++; 
     } 
     else { 
      delete strings[i]; 
      strings[i] = nullptr; 
     } 
    } 
    delete[] strings; 

    strings = new char*[length_new]; 
    for(int i=0; i<length_new; i++) { 
     strings[i] = strings_new[i]; 
    } 
    delete[] strings_new; 
    *length = length_new; 
} 

說明:這段代碼應該包含一個C風格的字符串數組,並刪除它們中的某些特定字符串; C風格的字符串數組是使用new []創建的,每個C風格的字符串都是使用new創建的。代碼的結果是沒有單詞被取消,但數組僅被切片。

+0

爲什麼會有'c'標籤? –

+7

只是...不要這樣做。使用'std :: vector >'。 –

+1

for'delete' vs'delete []':https://stackoverflow.com/questions/2425728/delete-vs-delete-operators-in-c –

回答

6

我在使用new[]delete[]顯示的代碼中看不到任何問題。

不,等等。

我看到一個很多¹的問題,但你的意圖是明確的,代碼似乎正在做你想做的事情。

我注意到的唯一合乎邏輯的問題是您通過值strings(它是一個char**並重新分配它在函數中不會影響包含指針的調用方變量)。簽名更改爲

void remove_stopwords(char**& strings, int* length) 

所以參考,而是隻傳遞應該修復它。

(1)如果可能的話,使用std::vector<const char *>似乎更合乎邏輯,甚至更好std::vector<std::string>,這將負責所有分配和釋放。

2

每個C風格的字符串都是使用new創建的。

我懷疑這是你的問題 - 空調風格字符串char陣列,所以你不能很容易與new創建它們,你需要使用new[]。這意味着你需要使用delete[]

1

As @ 6502指出,你的基本問題很簡單:你傳遞一個char **,並試圖修改它(而不是它指向的)在函數中。

您正在使用它作爲動態分配的字符串數組,因此您要修改的只是傳入該函數的指針副本。既然你(顯然)想要函數修改傳入的函數,你需要通過一個char ***(ugh!)或char **&(仍然相當糟糕)。

您確實應該使用vector<std::string>作爲數據。至少在我看來,去除停止詞的代碼應該寫成一個通用的算法,這個一般順序的東西:

template <typename InIt, typename OutIt> 
void remove_stop_words(InIt b, InIt e, OutIt d) { 
    std::remove_copy_if(b, e, d, 
     [](std:string const &s) { is_stop_word(s); }); 
} 

這樣,調用代碼會是這個樣子:

// read input 
std::vector<std::string> raw_input { std::istream_iterator<std::string>(infile), 
            std::istream_iterator<std::string>() }; 

// Filter out stop words: 
std::vector<std::string> filtered_words; 

remove_stop_words(raw_input.begin(), raw_input.end(), 
        std::back_inserter(filtered_words)); 

然而,在這樣的情況下,您根本不需要將原始輸入詞存儲在向量中。您可以直接傳遞一個istream_iterator到remove_stop_words,並有它只是產生期望的結果:

std::ifstream in("raw_input.txt"); 

std::vector<std::string> filtered_words; 

remove_stop_words(std::istream_iterator<std::string>(in), 
        std::istream_iterator<std::string>(), 
        std::back_inserter(filtered_words)); 

順便說一句,你也可以考慮使用升壓filter_iterator代替。這將允許您在讀取數據時在迭代器中執行過濾,而不是在應用於迭代器的算法中進行過濾。