archity
archity

Reputation: 612

Appending array into vector

I think it is a trivial question, but I couldn't find a specific solution to it. I'm trying to append array into a vector, using push_back() function. Here is the code:

int main()
{
  std::vector<int*> matchVector;

  int msmTemp[3];

  msmTemp[0] = 1;
  msmTemp[1] = 2;
  msmTemp[2] = 3;
  matchVector.push_back(msmTemp);
  msmTemp[0] = 4;
  msmTemp[1] = 7;
  msmTemp[2] = 0;
  matchVector.push_back(msmTemp);

  for(auto i : matchVector)
  {
    for(int j = 0; j<3; j++)
    {
      cout<<i[j]<<", ";
    }
    cout<<"\n";
  }

  return 0;
}

The output I'm getting is 4,7,0 two times. I don't understand as to why I'm not able to see the previous values, namely 1,2,3? Is it because of the type of vector matchVector defined above? I think it needs to be array only.

Upvotes: 5

Views: 16640

Answers (3)

Max Vollmer
Max Vollmer

Reputation: 8598

The other answers already explain how to fix your code. I think it's also good to explain why your code behaves the way it does:

Here you tell your compiler to create an std::vector that holds pointers to int:

std::vector<int*> matchVector;

Here you tell your compiler to allocate some space on the stack that fits 3 ints:

int msmTemp[3];

Here you tell your compiler to write the values 1, 2 and 3 into the memory previously allocated:

msmTemp[0] = 1;
msmTemp[1] = 2;
msmTemp[2] = 3;

Here you tell your compiler to take the address of that allocated space, treat it as a pointer and pass it to push_back. This is called array decaying:

matchVector.push_back(msmTemp);

Your matchVector now contains 1 element, which is a pointer to the address of the memory on your stack that was allocated to hold 3 ints.

Here you tell your compiler to write the values 4, 7 and 0 in the memory previously allocated. Note that this is still the same memory block as before:

msmTemp[0] = 4;
msmTemp[1] = 7;
msmTemp[2] = 0;

Here you tell your compiler to again take the address of the allocated space, treat it as a pointer and pass it to push_back:

matchVector.push_back(msmTemp);

Thus matchVector now contains 2 identical values, each a pointer to the same memory location. Specifically the memory location that you last wrote 4, 7 and 0 into.

Upvotes: 2

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275270

A int* is a pointer to an integer.

An int[3] is an array of 3 integers.

An array of 3 integers "decays" at the drop of a hat to a pointer to the first element.

When you do push_back(msmTemp), you push a pointer to the first element of msmTemp into the vector.

Pointers in C++ do not own what they point to. The vector afte the two push_backs contains two pointers, both to the same array msmTemp.

When you later iterate over the vector, you get two pointers in turn. Each points to msmTemp.

You then use [] to index those pointers. When you have a pointer to the first element of an array, you can use [] to access the other elements of the array. [0] is the first element, [1] the second, etc.

So you look at the 3 elements in msmTemp (luckily it has 3) and look at them twice, because you have two pointers into it in the vector.

You can inject elements like this:

std::vector<int> matchVector;
int msmTemp[3];
msmTemp[0]={1};
msmTemp[1]={2};
msmTemp[2]={3};
matchVector.insert( matchVector.end(), std::begin(msmTemp), std::end(msmTemp) );

etc. This ends up with a vector containing 6 elements, not two arrays.

If you want arrays as values you need std::array:

std::vector< std::array<int,3> > matchVector;
std::array<int, 3> msmTemp;

and then your code works as written. std::array is a library type that acts sort of like a raw array, but it doesn't have the decay-to-pointer problems of a raw array.

Upvotes: 10

Caleth
Caleth

Reputation: 62576

Forget that int[3] names a type. C arrays don't behave like sensible values. Arrays are named std::array<type, count>.

#include <vector>
#include <array>

int main()
{
  std::vector<std::array<int, 3>> matchVector;

  std::array<int, 3> msmTemp;

  msmTemp[0] = 1;
  msmTemp[1] = 2;
  msmTemp[2] = 3;
  matchVector.push_back(msmTemp);
  msmTemp[0] = 4;
  msmTemp[1] = 7;
  msmTemp[2] = 0;
  matchVector.push_back(msmTemp);

  for(auto & arr : matchVector)
  {
    for(auto i : arr)
    {
      std::cout << i <<", ";
    }
    std::cout<<"\n";
  }

  return 0;
}

Upvotes: 2

Related Questions