Как объявить массив строк в C ++?

89

Я пытаюсь перебрать все элементы статического массива строк наилучшим образом. Я хочу иметь возможность объявлять его в одной строке и легко добавлять / удалять из него элементы без необходимости отслеживать номер. Звучит очень просто, не правда ли?

Возможные нерешения:

vector<string> v;
v.push_back("abc");
b.push_back("xyz");

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

Problems - no way to create the vector on one line with a list of strings

Possible non-solution 2:

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

Problems - no way to get the number of strings automatically (that I know of).

There must be an easy way of doing this.

naumcho
источник
The boost assign library seems to be exactly what you are looking for. It makes assigning constants to containers easier than ever.
Craig H

Ответы:

108

C++ 11 added initialization lists to allow the following syntax:

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

Support for this C++ 11 feature was added in at least GCC 4.4 and only in Visual Studio 2013.

Anthony Cramp
источник
2018. Just starting C++ and did quite some research regarding flexible arrays. Ended up just using vectors...
Robert Molina
37

You can concisely initialize a vector<string> from a statically-created char* array:

char* strarray[] = {"hey", "sup", "dogg"};
vector<string> strvector(strarray, strarray + 3);

This copies all the strings, by the way, so you use twice the memory. You can use Will Dean's suggestion to replace the magic number 3 here with arraysize(str_array) -- although I remember there being some special case in which that particular version of arraysize might do Something Bad (sorry I can't remember the details immediately). But it very often works correctly.

Also, if you're really gung-ho about the one line thingy, you can define a variadic macro so that a single line such as DEFINE_STR_VEC(strvector, "hi", "there", "everyone"); works.

Tyler
источник
Since strarray is in a header, won't it violate the one definition rule?
jww
22

Problems - no way to get the number of strings automatically (that i know of).

There is a bog-standard way of doing this, which lots of people (including MS) define macros like arraysize for:

#define arraysize(ar)  (sizeof(ar) / sizeof(ar[0]))
Will Dean
источник
1
Alternatively, one could use something like this: template<typename T, size_t N> inline size_t arraysize(T (&ar)[N]) { return N; } (Inline keyword not necessary, but used to document the function's intent. A modern compiler should theoretically be able to return the entire function, I believe.
Justin Time - Reinstate Monica
1
This fails for pointers. Counting array elements should be done a different way in C++.
jww
8

Declare an array of strings in C++ like this : char array_of_strings[][]

For example : char array_of_strings[200][8192];

will hold 200 strings, each string having the size 8kb or 8192 bytes.

use strcpy(line[i],tempBuffer); to put data in the array of strings.


источник
FYI, char array_of_strings[][] can't accept C++ strings, be sure to convert to char* first. cplusplus.com/reference/string/string/c_str
Luqmaan
Since array_of_strings is in a header, won't it violate the one definition rule?
jww
7

One possiblity is to use a NULL pointer as a flag value:

const char *list[] = {"dog", "cat", NULL};
for (char **iList = list; *iList != NULL; ++iList)
{
    cout << *iList;
}
Eclipse
источник
What does char ** actually mean? In java, would it be a list of strings?
IAmGroot
1
@Doomsknight: In this case, yes. In the first line I define an array of char*. In memory, this gets laid out as 3 pointers - one points to "dog", one points to "cat" and one is left NULL. I can take a pointer to that first pointer, and get a char** - a pointer to pointer to char. When I increment that, I move the char** to point to the next item in the list - a pointer to the pointer that points to "cat", then I increment again, and get a pointer that points to the NULL pointer, and I know I'm done. (
Eclipse
4

You can use the begin and end functions from the Boost range library to easily find the ends of a primitive array, and unlike the macro solution, this will give a compile error instead of broken behaviour if you accidentally apply it to a pointer.

const char* array[] = { "cat", "dog", "horse" };
vector<string> vec(begin(array), end(array));
Ross Smith
источник
3

You can use Will Dean's suggestion [#define arraysize(ar) (sizeof(ar) / sizeof(ar[0]))] to replace the magic number 3 here with arraysize(str_array) -- although I remember there being some special case in which that particular version of arraysize might do Something Bad (sorry I can't remember the details immediately). But it very often works correctly.

The case where it doesn't work is when the "array" is really just a pointer, not an actual array. Also, because of the way arrays are passed to functions (converted to a pointer to the first element), it doesn't work across function calls even if the signature looks like an array — some_function(string parameter[]) is really some_function(string *parameter).

Matthew Crumley
источник
3

Here's an example:

#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"));
}
Shadow2531
источник
2

Instead of that macro, might I suggest this one:

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) We want to use a macro to make it a compile-time constant; the function call's result is not a compile-time constant.

2) However, we don't want to use a macro because the macro could be accidentally used on a pointer. The function can only be used on compile-time arrays.

So, we use the defined-ness of the function to make the macro "safe"; if the function exists (i.e. it has non-zero size) then we use the macro as above. If the function does not exist we return a bad value.

DrPizza
источник
2
#include <boost/foreach.hpp>

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

источник
1
#include <iostream>
#include <string>
#include <vector>
#include <boost/assign/list_of.hpp>

int main()
{
    const std::vector< std::string > v = boost::assign::list_of( "abc" )( "xyz" );
    std::copy(
        v.begin(),
        v.end(),
        std::ostream_iterator< std::string >( std::cout, "\n" ) );
}
Dominic.wig
источник
1

You can directly declare an array of strings like string s[100];. Then if you want to access specific elements, you can get it directly like s[2][90]. For iteration purposes, take the size of string using the s[i].size() function.

kajol jain
источник