tags:

views:

15115

answers:

13

I am trying to iterate over all the elements of a static array of strings in the best possible way. I want to be able to declare it on one line and easily add/remove elements from it without having to keep track of the number. Sounds really simple, doesn't it?

Possible non-solutions:

vector<string> v;
v.push_back("abc");
b.push_back("xyz");
for(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 ...

+18  A: 

The boost assign library seems to be exactly what you are looking for. It makes assigning constants to containers easier than ever.

Craig H
That is just straight up *fugly*.
Noah
+9  A: 

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
+2  A: 

Here's an example:


#include <iostream>
#include <string>
#include <vector>
#include <iterator>
using namespace std;

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) {
        cout << list[i] << "\n";
    }
    const vector<string> v(list, list + len);
    copy(v.begin(), v.end(), ostream_iterator<string>(cout, "\n"));
}
Shadow2531
+10  A: 

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
+2  A: 
Matthew Crumley
+9  A: 

C++ 0x is introducing initialization lists which will allow you to do:

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

Probably doesn't help you now. Although GCC 4.4 apparently supports this already.

Anthony Cramp
+1  A: 

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  A: 
#include <boost/foreach.hpp>

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

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
+2  A: 

Tried to upvote Craig H's answer that you should use boost::assign, but I have no rep :(

I encountered a similar technique in the first article I ever read by Andrei Alexandrescu in C/C++ Users Journal, Vol 16, No 9, September 1998, pp. 73-74 (have the full citation because it's in the comments of my implementation of his code I've been using ever since).

Templates are your friend.

mlbrock
Link to article: http://www.ddj.com/cpp/184403542
Daniel James
+1  A: 

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
A: 

SORRY FOR GOING off the topic..... i was trying to find how could i define string array i find it ..... but i don't know how could i compare them.. BEcause one is 2d string pointer and one is just a pointer

A: 
#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