如何在C++中声明一个字符串数组?

92
我正在尝试以最佳方式迭代静态字符串数组中的所有元素。我想能够在一行中声明它,并轻松地添加/删除元素,而不必跟踪数量。听起来很简单,是吗?
可能的非解决方案:
vector<string> v;
v.push_back("abc");
b.push_back("xyz");

for(int i = 0; i < v.size(); i++)
    cout << v[i] << endl;

问题 - 没有办法用字符串列表在一行上创建向量

可能的非解决方案2:

string list[] = {"abc", "xyz"};

问题 - 没有自动获取字符串数量的方式(至少我不知道)。

一定有一种简单的方法来解决这个问题。


Boost assign library 似乎正是您要寻找的。它可以让常量分配到容器中变得更加简单。 - Craig H
12个回答

110

C++ 11增加了初始化列表,允许使用以下语法:

std::vector<std::string> v = {"Hello", "World"};

至少从GCC 4.4开始,支持这个C++11特性,但只有Visual Studio 2013才支持。


2018年。刚开始学习C++,并对灵活数组进行了相当多的研究。最终只使用了向量... - rmolinamir
你知道在对象定义中如何声明为static const吗? - undefined

37
你可以简洁地从一个静态创建的char*数组初始化vector:
char* strarray[] = {"hey", "sup", "dogg"};
vector<string> strvector(strarray, strarray + 3);

顺便提一下,这会复制所有字符串,因此您需要使用两倍的内存。 您可以使用Will Dean的建议,在此处用arraysize(str_array)替换魔数3--尽管我记得在其中某些特殊情况下,该特定版本的arraysize可能会出现某些问题(很抱歉我不能立即记住详情)。 但它通常正常工作。

另外,如果您真的非常热衷于一行代码实现,您可以定义变长宏,以便单个行中的内容,例如DEFINE_STR_VEC(strvector, "hi", "there", "everyone");起作用。


由于strarray在头文件中,这不会违反一个定义规则吗? - jww

22

问题 - 没有自动获取字符串数量的方法(就我所知道的情况而言)。

有一种常规的做法,许多人(包括微软)都会定义类似于arraysize的宏来解决:

#define arraysize(ar)  (sizeof(ar) / sizeof(ar[0]))

1
或者,您可以使用类似于以下内容的代码:template<typename T, size_t N> inline size_t arraysize(T (&ar)[N]) { return N; }(内联关键字不是必需的,但用于记录函数的意图。理论上,现代编译器应该能够返回整个函数。 - Justin Time - Reinstate Monica
1
这对指针无效。在C++中,计算数组元素的数量应以不同的方式进行。 - jww

8

在C++中声明一个字符串数组可以像这样:char array_of_strings[][]

例如:char array_of_strings[200][8192];

将会存储200个字符串,每个字符串的大小为8kb或8192字节。

使用strcpy(line[i],tempBuffer);将数据放入字符串数组中。


请注意,char array_of_strings[][] 无法接受 C++ 字符串,请确保先转换为 char*。http://www.cplusplus.com/reference/string/string/c_str/ - Luqmaan
由于array_of_strings在头文件中,它不会违反一个定义规则吗? - jww

7

一种可能的方式是使用 NULL 指针作为标志值:

const char *list[] = {"dog", "cat", NULL};
for (char **iList = list; *iList != NULL; ++iList)
{
    cout << *iList;
}

char ** 实际上是什么意思?在 Java 中,它是否表示字符串列表? - IAmGroot
1
@Doomsknight:在这种情况下,是的。在第一行中,我定义了一个char*数组。在内存中,它被布置为3个指针——一个指向“dog”,一个指向“cat”,另一个为空。我可以取得指向第一个指针的指针,得到一个char**——指向字符的指针。当我增加它时,我将char**移动到列表中的下一项——指向指向“cat”的指针,然后我再次增加,得到一个指向空指针的指针,我知道我完成了。 - Eclipse

4

您可以使用Boost Range库中的beginend函数轻松找到原始数组的末端,与宏解决方案不同的是,如果您意外地将其应用于指针,则会产生编译错误而不是无法正常运行。

const char* array[] = { "cat", "dog", "horse" };
vector<string> vec(begin(array), end(array));

3

这里有一个例子:

#include <iostream>
#include <string>
#include <vector>
#include <iterator>

int main() {
    const char* const list[] = {"zip", "zam", "bam"};
    const size_t len = sizeof(list) / sizeof(list[0]);

    for (size_t i = 0; i < len; ++i)
        std::cout << list[i] << "\n";

    const std::vector<string> v(list, list + len);
    std::copy(v.begin(), v.end(), std::ostream_iterator<string>(std::cout, "\n"));
}

3
您可以使用Will Dean的建议[#define arraysize(ar) (sizeof(ar) / sizeof(ar[0]))]来替换这里的魔数3,尽管我记得在特定情况下,这个版本的arraysize可能会出现一些问题(很抱歉我不能立即记起细节)。但它通常能正确地工作。
它不起作用的情况是当“数组”实际上只是一个指针而不是实际的数组时。此外,由于数组被传递给函数的方式(转换为指向第一个元素的指针),即使签名看起来像一个数组,也无法跨函数调用工作——some_function(string parameter[])实际上是some_function(string *parameter)

2
#include <boost/foreach.hpp>

const char* list[] = {"abc", "xyz"};
BOOST_FOREACH(const char* str, list)
{
    cout << str << endl;
}

2

不要使用那个宏,我建议使用这个宏:

template<typename T, int N>
inline size_t array_size(T(&)[N])
{
    return N;
}

#define ARRAY_SIZE(X)   (sizeof(array_size(X)) ? (sizeof(X) / sizeof((X)[0])) : -1)

1) 我们希望使用宏将其变为编译时常量;函数调用的结果不是编译时常量。

2) 但是,我们不想使用宏,因为宏可能会意外地用于指针。该函数只能用于编译时数组。

因此,我们使用函数的定义来使宏“安全”;如果函数存在(即具有非零大小),则像上面那样使用宏。如果函数不存在,则返回错误值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接