3

I want to mimic a structure:

char [][40] = { "Stack", "Overflow", "Exchange", "Network" };

using a std::vector, so I can populate it at runtime and dynamically change the size of the vector, but keeping the member elements located inside fixed size blocks.

Static initialization is not my question - I can do that using boost::assign or other tricks.

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
karim
  • 33
  • 4
  • possible duplicate of [C++: Easiest way to initialize an STL vector with hardcoded elements](http://stackoverflow.com/questions/2236197/c-easiest-way-to-initialize-an-stl-vector-with-hardcoded-elements) – Frerich Raabe Aug 17 '11 at 21:39
  • @Kerrek SB No I do not have C++11 – karim Aug 17 '11 at 21:48

4 Answers4

2

I'd use something like Boost.Array:

typedef boost::array<char, 40> arr_t;
std::vector<arr_t> vec;
{
    arr_t arr = { "Stack" };
    vec.push_back(arr);
}
{
    arr_t arr = { "Overflow" };
    vec.push_back(arr);
}
{
    arr_t arr = { "Exchange" };
    vec.push_back(arr);
}
{
    arr_t arr = { "Network" };
    vec.push_back(arr);
}

If you're using a reasonably recent compiler, instead of Boost you can probably use std::array<> (C++11; #include <array>) or std::tr1::array<> (C++03 with TR1; #include <array> or #include <tr1/array>, depending on platform).

ildjarn
  • 62,044
  • 9
  • 127
  • 211
  • This looks interesting. Do you know if vec would be contiguous. i.e can I pass &vec[0] to a C function? – karim Aug 17 '11 at 22:06
  • @karim : Yes, each contained `array<>` is stored contiguously in memory. E.g., a `vector<>` with 2 elements will have a contiguous 80 byte buffer. – ildjarn Aug 17 '11 at 22:08
  • @karim What kind of weird C function takes n*40 bytes of char data with null separators in between? – pmr Aug 17 '11 at 22:09
  • @pmr : I don't know about the OP's requirements, but offhand I know of a few Windows API functions that work with null-delimited, double-null-terminated lists of strings. – ildjarn Aug 17 '11 at 22:15
  • @pmr Think of a database api function that accepts data as an array i.e. many rows to be loaded in one roundtrip. – karim Aug 17 '11 at 22:17
  • @ildjarn That makes more sense. But in this case there is the waste of memory and the need to pass the size of the array etc. Maybe OP misunderstands the requirements of the function he is going to call? – pmr Aug 17 '11 at 22:19
  • @karim You need a new database. – pmr Aug 17 '11 at 22:21
  • @ildjarn is this supposed to work? char* cv = (char*)&vec[0]; cout << cv << endl; It prints the first element only – karim Aug 18 '11 at 02:27
  • @karim : `std::ostream& operator<<(std::ostream&, char const*)` stops printing as soon as a null character is encountered. If you want to print past the first element, then the first element cannot contain any null characters. This is C++ 101 ;-] – ildjarn Aug 18 '11 at 02:33
  • @ildjarn And this too? printf("%s\n",&vec[0])? I am still trying to convince myself that &vec[0] as constructed above ( nested ) truly gives me contiguous memory – karim Aug 18 '11 at 02:37
  • @karim : All C-string functions operate on a null-termination basis -- how else would it know when the C-string ends? If you want to verify that the elements are stored in contiguous memory (which they are, and have to be, according to basic C++ rules regarding `operator new[]`), then open a debugger and look at the memory directly. – ildjarn Aug 18 '11 at 02:39
1
struct fixed_string { 
    char data[40];

    fixed_string(char const *init);
};

std::vector<fixed_string> whatever;

If you have C++11 (or at least TR1), you probably want to use std::array instead of fixed_string. I think Boost has an equivalent as well.

In case anybody's wondering why I put it in a struct, instead of creating a vector of array directly: because items in a vector need to be copyable and assignable, and a bare array is neither.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
0

May be vector in vector helps. Here size is fixed, strings could be used in pure C.

vector< vector<char> > vector_of_strings;

// Add new string
vector_of_strings.push_back( vector<char>(40) );
// use the string
strcpy( &vector_of_strings[0][0], "text" );
Naszta
  • 7,560
  • 2
  • 33
  • 49
  • Do you think this will have contiguous memory like the C array in the question? – karim Aug 17 '11 at 21:50
  • 2
    If you're willing to go for nested containers, then why not a `std::vector>`? – Kerrek SB Aug 17 '11 at 21:51
  • @All: [Check this out!](http://stackoverflow.com/questions/849168/are-stdvector-elements-guaranteed-to-be-contiguous) – Naszta Aug 17 '11 at 21:53
  • @Kerrek SB: tr1 is not supported by all of the compilers. – Naszta Aug 17 '11 at 21:55
  • @Naszta : This doesn't have contiguous memory -- the nested `vector` objects are stored in contiguous memory, but the actual data buffers are not (nor are they fixed-size as was specifically requested in the question). – ildjarn Aug 17 '11 at 22:01
  • @Naszta I didn't think nested vectors would be contiguous but I may be wrong. – karim Aug 17 '11 at 22:02
  • 1
    @Naszta: If you *really* can't dig up a TR1 (how old is your compiler?) you can write an `array` yourself pretty quickly and easily, and as a bonus you could be sure that your `std::vector>` is actually contiguous. – Kerrek SB Aug 17 '11 at 22:05
0

Parapura's answer is correct, but you will be storing the pointers to the strings. If the original character array falls out of scope you will lose the information posted. If this vector is used elsewhere, it should allocate (and deallocate!) it's own memory. This can be done when the input is taken.

Here's a sample program that does that.

#include <vector>
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
using std::vector;

int main()
{
    int numEntries = 4;
    const int strlen = 40;

    // Parapura's correct answer, but let's expand this further
    vector<char*> strvec;
    char* input = 0;
    int i;

    cout << "Enter four names." << endl;
    for (i=0; i<numEntries; i++)
    {
        // Allocate some memory to store in the vector
        input = new char[strlen];
        cout << "Name: ";
        cin.get(input, strlen);
        cin.ignore(strlen, '\n');

        // Push the populated memory into the vector.
        // Now we can let 'input' fall out of scope.
        strvec.push_back(input);
    }
    cout << endl;

    /* -- cool code here! -- */

    cout << "List of names." << endl;
    for (i=0; i<numEntries; i++)
    {
        cout << strvec[i] << endl;
    }

    /* -- more cool code! -- */

    // don't forget to clean up!
    for (i=0; i<numEntries; i++)
    {
        delete[] strvec[i];
    }

    return 0;
}