Problem with understanding a vector initialization - c++

This might be a dumb question but there is something I can't quite understand. When using a vector, whenever I want to 'push_back' an element to a certain position I can do that only if I initialize the vector in a certain way.
For example when I use this initialization:
std::vector<int> Myvec;
int size = 0;
int x = 0;
std::cin >> size;
for(int i = 0; i < size; i++)
{
std::cin >> x;
Myvec[i].push_back(x);
}
I receive the following error:
request for member 'push_back' in 'Myvec.std::vector<_Tp, _Alloc>::operator[] >(((std::vector::size_type)i))', which is of non-class type '__gnu_cxx::__alloc_traits >::value_type {aka int}'|
But when I use the following initialization it works:
int size = 0;
int x = 0;
std::cin >> size;
std::vector<int> Myvec[size];
for(int i = 0; i < size; i++)
{
std::cin >> x;
Myvec[i].push_back(x);
}
I don't have any problem using it and can implement it in all sorts of tasks, but it's bugging me because I'm not sure why it is actually working. Thank you for your help in advance.

In the first block you should use:
std::vector<int> Myvec;
int size = 0;
int x = 0;
std::cin >> size;
for(int i = 0; i < size; i++)
{
std::cin >> x;
Myvec.push_back(x);
}
Or you can use:
int size = 0;
int x = 0;
std::cin >> size;
std::vector<int> Myvec(size);
for(int i = 0; i < size; i++)
{
cin>>Myvec[i];
}
And print the vector using:
for(int i = 0; i < size; i++) {
std::cout<< Myvec[i]<<" ";
}
When you initialise it using vector Myvec[size], it becomes vector of vectors with size "size", means each Myvec[i] is a vector in which you can push elements.
Read more here: https://www.geeksforgeeks.org/2d-vector-in-cpp-with-user-defined-size/

You have a misunderstanding on how the std::vector::push_back function works. It basically appends a new object at the end of the vector. In particular, you don't need to index into the vector with std::vector::operator[]. Instead, change your snippet to
for(int i = 0; i < size; i++)
{
std::cin >> x;
Myvec.push_back(x);
}
The solution you came up with does something that you probably don't intend, i.e., using a raw array of vectors: when transferring user input into the objects, it creates size vectors with one element each.

You're not putting an element at position i in a vector.
You're putting an element at the back of the ith vector in an array of vectors! Worse, the array is empty, so the access is invalid.
If it weren't, though, you'd end up with i vectors each having one element. Not good!
Instead, you can make your vector be of a certain size:
MyVec.resize(SomeSize);
…then assign the elements as if the vector were an array (which it kind of is):
MyVec[i] = thing;
The key point here is that you don't have to push_back; you only do that when you want to push a new element to the back of the vector. You can access existing values with array-like [] syntax just fine.
Read more about vectors in your C++ book.

Related

Runtime error : reference binding to null pointer of type 'int' (stl_vector.h) [duplicate]

Clearly this isn't working so the code is wrong, but how do I fix it?
This whole thing could be wrong for all I know lol, but I'm trying to create a multidimensional vector that creates itself during runtime. I get an error: vector subscript out of range.
#include <iostream>
#include <vector>
int main(){
int row = 0, col = 0;
std::cout << "Size of Row: "; std::cin >> row;
std::cout << "Size of Column: "; std::cin >> col;
std::vector<std::vector<int>> td;
td.resize(row * col);
for (int i = 0; i <= row; i++){
for (int j = 0; j <= col; j++){
td[i][j];
}
}
}
When you use
td.resize(row * col);
the first dimension of td will be row*col, but its second dimension are still empty. That's why you got the error.
You should use
td.resize(row); // set first dimension
for (int i=0; i<row; i++) // set each second dimenstion
td[i].resize(col);
or simply
vector<vector<int>> td(row, vector<int>(col)); // has rows, each of them has cols
You need to allocate the appropriate amount of memory to the vector of vectors. Instead of resizing it, you can explicitly set the amount empty rows and columns with the following code.
std::vector< std::vector<int> > td(row+1, std::vector<int>(col+1));
//+1 is needed because the loop you created is <=
Otherwise, you can adjust the loop and do the following:
std::vector< std::vector<int> > td(row, std::vector<int>(col));
for (int i = 0; i < row; i++){
for (int j = 0; j < col; j++){
td[i][j];
}
}
td refers to the outer vector, so your resize creases a vector of row'col empty vectors. You'll need to resize that to just row instead, then your for i loop can say td[i].resize(col) inside to make it two dimensional.

Reading int from ifstream to 2-D dynamic array

I am relatively new to programming and am trying to read an array of ints into a 2-D dynamic array. I'm relatively sure this is just a syntax issue.
The array is dynamic and therefore is of type int**. To try to populate the array, I've used a nested for loop to populate each element of the array with the next term from the ifstream. Input is assumed to be all ints separated by
whitespace.
//declare dynamic 2-D array
int** myArray = new int*[numRows]
for (int i = 0; i < numCols; i++)
{
myArray[i] = new int[numCols];
}
//populate array from ifstream
for (int i = 0; i < numRows; i++)
{
for (int j = 0; j < numCols; j++)
{
inFile >> myArray[i][j];
}
}
I expected to be able to store the ints from the ifstream (all between 0-100) directly into the array, but I seem to be storing addresses instead (very
large negative ints). What am I doing wrong?
Fixing the typo and a missing semicolon should fix it
// declare dynamic 2-D array
int** myArray = new int*[numRows]
// ^
// ;
for (int i = 0; i < numCols; i++) {
// ^^^^^^^
// numRows
myArray[i] = new int[numCols];
}

How to pass a dynamic 2d array of strings as a parameter in C++

I am trying to implement a binary tree as a 2d array. I want the user to enter the required height of the tree and the program should give an appropriate size array. Then, I want to print the array, which is why I need to pass it as a parameter. However, I get the following error:
arrayTree/main.cpp|19|error: cannot convert ‘std::__cxx11::string** (*)[maxNumberOfNodes] {aka std::__cxx11::basic_string<char>** (*)[maxNumberOfNodes]}’ to ‘std::__cxx11::string** {aka std::__cxx11::basic_string<char>**}’ for argument ‘1’ to ‘void printTree(std::__cxx11::string*)’|
Please, what is causing the error and how can I fix it?
#include <iostream>
#include <string>
#include <math.h>
using namespace std;
void printTree(string** tree);
int main()
{
int treeHeight = 0;
int maxNumberOfNodes = 1;
cout << "enter tree height";
cin >> treeHeight;
cout << treeHeight<< "\n";
//create an array that can hold every combination for a given tree height
maxNumberOfNodes = pow(2,treeHeight) - 1;
string** tree [3][maxNumberOfNodes];
cout << maxNumberOfNodes;
printTree(tree);
}
void printTree(string** tree){
//not fully implemented yet
for(int i=0; i < sizeof(tree); i++){
cout << "*" << " ";
}
}
string** tree [3][maxNumberOfNodes];
is the syntax of a static 2D array of type string** , where both dimensions have to be declared const.
The difference between a static and a dynamic array is shown in here: Multidimensional variable size array in C++
Instead you want to write something like
string** tree = new string*[3];
for(int i = 0; i < 3; i++)
tree[i] = new string[maxNumberOfNodes];
As #Remy Lebeau commented: Every occurrence of new[] needs to be answered by a delete[] call, like this:
for (int i = 0; i < 3; i++)
delete tree[i];
delete[] tree;
to remove the dynamic allocation from the heap.
Like #drescherjm pointed out sizeof(tree) is not valid, as tree is just a pointer and does not include size information about the array.
You could solve this by additionally passing the dimensions of your array with it:
void printTree (string** tree, int dim, int dim2)
and rewriting the loop to
for(int i = 0; i < dim; i++){
for(int j = 0; j < dim2; j++){
cout << tree[i][j]; //...
}
}
string** tree [3][maxNumberOfNodes];
This declares a 2D array of string** pointers. That is not what you want. You want a 2D array of string objects instead, so drop the pointers:
string tree [3][maxNumberOfNodes];
Also, your printTree() is not implemented correctly. It would need to be implemented more like this instead:
void printTree(string** tree, int height) {
for(int i = 0; i < 3; i++) {
for(int j = 0; j < height; j++) {
// use tree[i][j] as needed ...
}
}
}
That being said, since the value of maxNumberOfNodes is not known until runtime, the string tree [3][maxNumberOfNodes] syntax is declaring a Variable Length Array, which is not officially supported by the C++ standard, only as an extension by a few C++ compilers. You need to use new[] instead to allocate the 2nd dimension:
string* tree [3];
for(int i = 0; i < 3; ++i)
tree[i] = new string[maxNumberOfNodes];
printTree(tree, maxNumberOfNodes);
for(int i = 0; i < 3; ++i)
delete[] tree[i];
Or better, use std::vector instead:
std::vector<string> tree [3];
for(int i = 0; i < 3; ++i)
tree[i].resize(maxNumberOfNodes);
Though, in this latter case, you won't be able to pass tree to a string** function parameter, so you will have to adjust the code accordingly.
the method call is given by
printTree(tree [3][maxNumberOfNodes]);
it's working for me

Why I can't input into my std::vector in C++

I'm a newbie in C++. I've just learnt about vector in STL.
However, when I tried to input an integer into my vector:
vector<int> v;
cin>>v[i]
The program returned segmentation fault. Please help me out.
Your vector doesn't have any elements in it, so the internal array is null. When you try to read something into it, you're trying to deference a null pointer (resulting in the segfault). Add elements to the vector first:
vector<int> v(100); //Create vector with 100 elements
for(int i = 0; i < 100; i++) {
cin >> v[i];
}
Alternatively, you could read elements into a local variable, then add them into the vector:
vector<int> v;
for(int i = 0; i < 100; i++) {
int new_val;
cin >> new_val;
v.push_back(new_val);
}

Dynamic 2D Array Initialization

I want to create and initialize a 2D array but the initialization is failed. I encounter "The program has unexpectedly finished." in Qt Creator.
What is wrong?
in .h file
private:
int pop;
int d;
float **uye;
in .cpp file
pop=50;
d=12;
uye = new float*[pop];
for(int i=0; i<d; i++) uye[i] = new float[d];
for(int n=0; n<pop; n++)
{
for(int m=0; m<d; m++)
{
uye[n][m] = (float) n*m;
}
}
The first loop for(int i=0; i<d; i++) should probably be for(int i=0; i<pop; i++). Otherwise, you are only reserving space for 12 elements, but later try to access 50.
Note that having raw pointer members is considered a very bad idea in modern C++, because you need to worry about copying semantics. Better use a flat std::vector<float> and do the 2D to 1D mapping manually, or use a std::vector<std::vector<float> > with convenient access syntax.
I would prefer the second version. Without seeing more context:
pop = 50;
d = 12;
uye = std::vector<std::vector<float> >(pop, std::vector<float>(d));
The nested for loops that follow work exactly the same, no changes required.
What is wrong?
You're not using std::vector (that's one of the things that's wrong, #FredO covered the other thing).
#include <vector>
int main(){
typedef std::vector<float> inner_vec;
typedef std::vector<inner_vec> outer_vec;
int pop = 50, d = 12;
// first parameter to vector is its size
// second is what every element should be initialized to
outer_vec uye(pop, inner_vec(d));
for(unsigned n = 0; n < uye.size(); ++n){
for(unsigned m = 0; m < uye[n].size(); ++m){
uye[n][m] = (float)n*m;
}
}
}