2011-09-16 25 views
0

我有三個問題基於以下代碼片段
我有一個字符串列表。這恰好是一個矢量但也可能是任何來源如何遍歷std :: vector <char>並找到以空字符結尾的c字符串

vector<string> v1_names = boost::assign::list_of("Antigua and Barbuda")("Brasil")("Papua New Guinea")("Togo"); 

以下是存儲每個名字的長度

vector<int> name_len; 

下面是我想要的存儲串

std::vector<char> v2_names; 

估計從v1_names複製名稱所需的內存

v2_names.reserve(v1_names.size()*20 + 4); 

問題:這是估計存儲的最好方法嗎?我固定在20這是確定爲LEN的最大值,然後添加空間空treminator
現在複製名稱

for(std::vector<std::string>::size_type i = 0; i < v1_names.size(); ++i) 
{ 
    std::string val(v1_names[i]); 
    name_len.push_back(val.length()); 
    for(std::string::iterator it = val.begin(); it != val.end(); ++it) 
    { 
     v2_names.push_back(*it); 
    } 
    v2_names.push_back('\0'); 
} 

問題:這是元素從v1_name複製到v2_names最有效的方法是什麼?
主要問題:我如何遍歷v2_names和打印包含在v2_names

+0

爲什麼要這樣做?存儲「矢量」的問題是什麼?你可能最終會使解決方案非常複雜,無緣無故... –

回答

1

要估計存儲,你應該測量的字符串,而不是依賴於硬編碼的常數20例如:

size_t total = 0; 
for (std::vector<std::string>::iterator it = v1_names.begin(); it != v1_names.end(); ++it) { 
    total += it->size() + 1; 
} 

在循環的主要效率低下可能是你需要一個額外副本每個字符串依次:std::string val(v1_names[i]);可以改爲const std::string &val = v1_names[i];

要追加的每個字符串,你可以使用insert功能:

v2_names.insert(v2_names.end(), val.begin(), val.end()); 
v2_names.push_back(0); 

這未必是最有效的,因爲有一定量的矢量可用空間的冗餘校驗,但它不該不會太糟糕,而且很簡單。另一種方法是在開始時設置v2_names的大小而不是預留空間,然後複製數據(使用std::copy)而不是附加數據。但是他們中的任何一個可能會更快,並且它不應該有很大的不同。

對於主要的問題,如果你已經是v2_names,你要打印的字符串,你可以做這樣的事情:

const char *p = &v2_names.front(); 
while (p <= &v2_names.back()) { 
    std::cout << p << "\n"; 
    p += strlen(p) + 1; 
} 

如果你也有name_len

size_t offset = 0; 
for (std::vector<int>::iterator it = name_len.begin(); it != name_len.end(); ++it) { 
    std::cout << &v2_names[offset] << "\n"; 
    offset += *it + 1; 
} 

請注意,name_len的類型在技術上是錯誤的 - 不能保證您可以將字符串長度存儲在int中。也就是說,即使在特定實現中int小於size_t,那麼大的字符串仍然非常少見。

+0

我希望你可以使用'name_len'中存儲的信息來計算偏移量,但是找不到可行的方法來做到這一點 – samra

+0

@samra:啊,所以你需要'name_len'和'v2_names'。好的,我會編輯。 –

+0

只有你似乎已經閱讀(並理解)了整個問題並回答了所有問題。謝謝 – samra

0

,最好的辦法是國家的名字來計算所需的存儲是總結每個字符串的長度v1_names

對於你的第二個問題,而不是使用for循環,你可以使用向量的iterator, iterator追加方法beginend上的字符串。

對於你的第三個問題:只是不這樣做。改爲使用v1_names的字符串代替。 有史以來唯一的原因創建這樣的事情v2_names是將它傳遞到一個傳統的C API,然後你不必擔心迭代它。

+0

我真的想迭代v2_names。事實上這是主要問題。 v1_names只是我的字符串的一個來源的例子。目標是v2_names。 – samra

0

如果你想連接的所有字符串,你可以只使用一個單一的傳球,並依靠攤銷O(1)插入:

name_len.reserve(v1_names.size()); 

// v2_names.reserve(???); // only if you have a good heuristic or 
          // if you can determine this efficiently 

for (auto it = v1_names.cbegin(); it != v1_names.cend(); ++it) 
{ 
    name_len.push_back(it->size()); 
    v2_names.insert(v2_names.end(), it->c_str(), it->c_str() + it->size() + 1); 
} 

可以另一個循環預先計算的總長度在此之前如果您認爲這會有所幫助,請致電reserve。這取決於你對字符串的瞭解程度。但也許沒有必要擔心,因爲從長遠來看,插入是O(1)。

2

使用簡單連接,獲利!

#include <boost/algorithm/string/join.hpp> 
#include <vector> 
#include <iostream> 

int main(int, char **) 
{ 
    vector<string> v1_names = boost::assign::list_of("Antigua and Barbuda")("Brasil")("Papua New Guinea")("Togo"); 

    std::string joined = boost::algorithm::join(v1_names, "\0"); 
}