29

I am trying to write a program that has a vector of char arrays and am have some problems.

char test [] = { 'a', 'b', 'c', 'd', 'e' };

vector<char[]> v;

v.push_back(test);

Sorry this has to be a char array because I need to be able to generate lists of chars as I am trying to get an output something like.

a a a b a c a d a e b a b c

Can anyone point me in the right direction?

Thanks

aHunter
  • 3,490
  • 11
  • 39
  • 46
  • Forget the vector and just use std::string. Then you can use += to add more characters to it. – Tronic Mar 06 '10 at 11:50
  • 1
    I do not need to just add characters I need to change the characters before as well to the next one in the array. – aHunter Mar 15 '10 at 21:28

9 Answers9

83

You cannot store arrays in vectors (or in any other standard library container). The things that standard library containers store must be copyable and assignable, and arrays are neither of these.

If you really need to put an array in a vector (and you probably don't - using a vector of vectors or a vector of strings is more likely what you need), then you can wrap the array in a struct:

struct S {
  char a[10];
};

and then create a vector of structs:

vector <S> v;
S s;
s.a[0] = 'x';
v.push_back( s );
  • 2
    How are arrays not copyable or assignable? – quantum231 Jun 23 '16 at 23:39
  • 4
    C-style arrays (as opposed to std::array) have no information available at compile or run-time that allows one to know the size of the array, or the size of the object contained in an array element. Without that size information, the compiler can't copy or assign one array to another. memcpy(array2,array1,some_size) isn't "copying" in the sense of the verb used in the answer. – user1329482 Apr 05 '18 at 19:29
16

You need

char test[] = "abcde";  // This will add a terminating \0 character to the array
std::vector<std::string> v;
v.push_back(test);

Of if you meant to make a vector of character instead of a vector of strings,

std::vector<char> v(test, test + sizeof(test)/sizeof(*test));

The expression sizeof(test)/sizeof(*test) is for calculating the number of elements in the array test.

Tronic
  • 10,250
  • 2
  • 41
  • 53
  • using this how would I push_back another instance of test adding it to the existing vector? – aHunter Mar 06 '10 at 11:38
  • About ```sizeof(test)/sizeof(*test)```, the STL library provides std::size, so you can use ```size(test)``` instead. It is not just shorter, it is more correct. – armagedescu Jul 10 '21 at 10:55
2

Use std::string instead of char-arrays

std::string k ="abcde";
std::vector<std::string> v;
v.push_back(k);
Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
  • 3
    While this may work perfectly for this implementation, to my understanding std::string implementation does not guarantee to have contiguous memory storage. If someone was to use this to receive streams and use this solution it *may be* a problem. Moreover, if you have 'NULL' character in stream you will encounter issues with std::string. – enthusiasticgeek Feb 24 '14 at 13:34
  • @enthusiasticgeek C++98 did not guarantee contiguous storage. However all known implementations provided it, and it was such a useful guarantee that they added it. You may safely assume that both vector and string are contiguous. – Martin Bonner supports Monica Sep 25 '19 at 16:10
2

You can use boost::array to do that:

boost::array<char, 5> test = {'a', 'b', 'c', 'd', 'e'};
std::vector<boost::array<char, 5> > v;
v.push_back(test);

Edit:

Or you can use a vector of vectors as shown below:

char test[] = {'a', 'b', 'c', 'd', 'e'};
std::vector<std::vector<char> > v;
v.push_back(std::vector<char>(test, test + sizeof(test)/ sizeof(test[0])));
missingfaktor
  • 90,905
  • 62
  • 285
  • 365
1

You can directly define a char type vector as below.

vector<char> c = {'a', 'b', 'c'};
vector < vector<char> > t = {{'a','a'}, 'b','b'};
MAOXU
  • 329
  • 2
  • 3
1

In fact technically you can store C++ arrays in a vector Not directly, but with a simple workaround. And it makes a lot of sense. Question is already answered by anon, but some explanations still needed. Wrapping the array in a class will make the vector data to meet the requirements of a multidimensional array. STL in C++ 11 and upper already provides such a wrapper std::array.
The vector of vectors fits many purposes, but is not the answer and in some cases it is just wrong. Is an unpleasant experience to fall in the trap of fixing errors caused by not understanding clearly the difference between arrays and pointers, or between multidimensional arrays and arrays of arrays. Vectors of vectors contains vectors as elements: each contains a copy of size, capacity, pointer to data pointing to random segments of data in memory. These segments will not be placed one after another like in a multidimensional array. That will cause problems to interoperability with other programming languages or libraries that are not C++ vector aware.
But a vector of arrays will point always to a contiguous segment of memory, containing all segments of a multidimensional array in correct order in a single place. Technically the data pointer will point to something identical to multidimensional array. There is no good reason to keep the size of each array element while it is known to be the same for all elements. At least it is redundant, but it is not that a big problem. The bigger problem, it breaks the structure of the multidimensional array.
So, making a vector of array can be done indirectly, by wrapping the array in a class or by using existing std::array. It will store the data im memory identically to a bidimensional array. This approach is already widely used by many libraries. At low level it will be easily interoperable with APIs that are not C++ vector aware. So without using std::array it will look like this:

int main()
{
    struct ss
    {
        int a[5];
        int& operator[] (const int& i) { return a[i]; }
    } a{ 1,2,3,4,5 }, b{ 9,8,7,6,5 };

    vector<ss> v;
    v.resize(10);
    v[0] = a;
    v[1] = b;
    //all the rest is uninitialised array
    v.push_back(a); // pushes to the end, with reallocation
    v.push_back(b); // pushes to the new end, with reallocation

    auto d = v.data();
    // cin >> v[1][3]; //input any element from stdin
    cout << "show two element: "<< v[1][2] <<":"<< v[1][3] << endl;
    return 0;
}

In memory it looks very predictable, twelve arrays, two on the beginning and two on the end initialised, the other eight in the middle uninitialised, filled with zeroes


C++11 and upper has std::array, no need to reinvent:

....
#include<array>
....
int main()
{
    vector<array<int, 5>> v;
    v.reserve(10); //set capacity
    v.resize(2);
    v[0] = array<int, 5> {1, 2, 3, 4, 5};
    v[1] = array<int, 5> {9, 8, 7, 6, 5};

    //note, since size does not exceed capacity
    //this push_back will cause no reallocation and no relocation:
    v.push_back(array<int, 5>{ 7, 2, 53, 4, 5 });
    ///cin >> v[1][1];
    auto d = v.data();

Now, this is why vectors of vectors is not the answer. Supposing following code

int main()
{
    vector<vector<int>> vv = { { 1,2,3,4,5 }, { 9,8,7,6,5 } };
    auto dd = vv.data();
    return 0;
}

How data is stored in memory can never be guessed, it is definitely not a multidimensional array

armagedescu
  • 1,758
  • 2
  • 20
  • 31
0

FFWD to 2019. Although this code worketh in 2011 too.

// g++ prog.cc -Wall -std=c++11
#include <iostream>
#include <vector>

 using namespace std;

 template<size_t N>
    inline 
      constexpr /* compile time */
      array<char,N> string_literal_to_array ( char const (&charrar)[N] )
 {
    return std::to_array( charrar) ;
 }

 template<size_t N>
    inline 
      /* run time */
      vector<char> string_literal_to_vector ( char const (&charrar)[N] )
 {
    return { charrar, charrar + N };
 }


int main()
{
   constexpr auto arr = string_literal_to_array("Compile Time");
   auto cv = string_literal_to_vector ("Run Time") ;
   return 42;
}

Advice: try optimizing the use of std::string. For char buffering std::array<char,N> is the fastest, std::vector<char> is faster.

https://wandbox.org/permlink/wcasstoY56MWbHqd

Chef Gladiator
  • 902
  • 11
  • 23
0

Here is how a std::vector of Characters is Initialized from a C-style string or std::string or an array of characters in C++ :

size_t count_O(const std::vector<char>& vectStr)
    {
        size_t counter{ 0 };
        for (const auto& item : vectStr)
        {
            std::cout << item << '\n';
            if (item == 'o')
                ++counter;
        }
        return counter;
    }


 

 int main()
{
    
    
    //1
    std::vector<char> vectCharA = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!' };
    std::cout << "count: " << count_O(vectCharA) << '\n';

    //2
    const char* str1 = "Hello World!";
    const size_t len = strlen(str1);
    std::vector<char> vectCharB(str1, str1 + len);
    std::cout << "count: " << count_O(vectCharB) << '\n';


    //3
    char arrChar[] = "Hello World!";
    std::vector<char> vectCharC(arrChar, arrChar + sizeof(arrChar) / sizeof(*arrChar));
    std::cout << "count: " << count_O(vectCharC) << '\n';

    //4
    std::string str2 = "Hello World!";
    std::vector<char> vectCharD(str2.begin(), str2.end());
    std::cout << "count: " << count_O(vectCharD) << '\n';

    //5
    std::string str3 = "Hello World!";
    std::vector<char> vectCharE(std::begin(str3), std::end(str3));
    std::cout << "count: " << count_O(vectCharE) << '\n';
 return 0;
}
Sami
  • 513
  • 4
  • 11
-2

What I found out is that it's OK to put char* into a std::vector:

//  1 - A std::vector of char*, more preper way is to use a std::vector<std::vector<char>> or std::vector<std::string>
std::vector<char*> v(10, "hi!");    //  You cannot put standard library containers e.g. char[] into std::vector!
for (auto& i : v)
{
    //std::cout << i << std::endl;
    i = "New";
}
for (auto i : v)
{
    std::cout << i << std::endl;
}
Nicholas Humphrey
  • 1,220
  • 1
  • 16
  • 33