5

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.

9
  • What do you think the 2 int* in your vector refer to? The exact same array Commented Jul 13, 2018 at 13:15
  • 2
    Arrays are not pointers. Besides, one can just do v.insert(v.end(), std::begin(arr), std::end(arr)). Commented Jul 13, 2018 at 13:16
  • Is there a reason why you are not using a vector<vector<int>>? Commented Jul 13, 2018 at 13:16
  • 2
    You save a pointer to a vector, change the values stored by that pointer and then save the same pointer to vector. After that you twice take the same pointer from vector and print values stored by that pointer Commented Jul 13, 2018 at 13:16
  • 1
    matchVector simply contains two pointers to msmTemp. So your result is just printing msmTemp twice. What's the value of msmTemp at the time you print your results? Commented Jul 13, 2018 at 13:17

3 Answers 3

10

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.

Sign up to request clarification or add additional context in comments.

Comments

2

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;
}

11 Comments

The first line in the main function defines a vector which will hold values of type array, which in turn would be of type int of size 3, is my interpretation correct?
@archity std::array is not, on it's own, a type. std::array<int, 3> is a type, which is an array of 3 ints
@archity You read matchVector as "vector of array of 3 ints"
Also, how do I break this statement into 2 parts, initialization and assignment, so that I can use it for any other varible rather than size 3? Especially, if I want to define it inside a class.
To use std::array, you have to have a compile time constant for the count. If you don't have one, use std::vector
|
2

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.

1 Comment

That's a really good explanation to the original code. Thank you so much for it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.