如何遍历 std::vector<char> 并查找以 null 结尾的 c 字符串

How to iterate over std::vector<char> and find null-terminated c-strings

本文关键字:查找 null 字符串 结尾 gt lt 何遍历 遍历 vector std char      更新时间:2023-10-16

基于以下代码片段,我有三个问题
我有一个字符串列表。它只是碰巧是一个向量但也可以是任何来源

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,然后为零终止符
添加空间现在复制名称

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('');
}

问题:这是将元素从v1_name复制到v2_names的最有效方法吗?
主要问题:如何遍历v2_names并打印v2_names中包含的国家名称

使用简单连接,获利!

#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, "");
}

要估计存储空间,您可能应该测量字符串,而不是依赖于硬编码的常量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);

这并不一定是最有效的,因为在vector中有一定数量的可用空间的冗余检查,但它不应该太糟糕,而且它很简单。另一种方法是在开始时设置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,那么大的字符串仍然是非常罕见的。

计算所需存储空间的最佳方法是将v1_names中每个字符串的长度相加。

对于您的第二个问题,而不是使用For循环For,您可以在字符串上使用beginend的向量的iterator, iterator追加方法。

对于你的第三个问题:不要那样做。迭代v1_names的字符串。创建v2_names的唯一原因是将其传递到遗留的C API中,然后您不必担心迭代它。

如果您想要连接所有字符串,您可以只使用一次传递并依赖于平摊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,如果您认为这有帮助的话。这取决于你对弦的了解程度。但也许没有必要担心,因为从长远来看,插入次数是0(1)。