In the array
int a[][5] = {{1},{1,2}};
what is "the" size of its second dimension and what value will
a[0][1]
have?
Does it even make sense to speak about the size or does it differ from "row" to "row"?
Is this considered bad practice?
In your code
int a[][5] = {{1},{1,2}};
the size of the first dimension is 2 (because there are two elements inside the outer {}), and the size of the second dimension is 5. Unmentioned elements in the initialiser are initialised to zero. So, your code is equivalent to:
int a[][5] = {{1,0,0,0,0},{1,2,0,0,0}};
This is invalid. It won't even compile:
test.cc:1:9: error: declaration of ‘a’ as multidimensional array must have bounds for all dimensions except the first
When you are using the curly bracket initialization notation with arrays, you must specify all the elements for all the dimensions your array is gonna have, so that piece of code would just give you a compile-time error.
If you want to have an array of containers of different size, consider using an array of vectors, or even a vector of vectors. To use them, just do an #include <vector> and you're done.
Related
Is there performance or size difference between the the following ways of declaring a large array -
int a[4000][4000] and int a[4000 * 4000] ? Should we prefer one over the other if possible?
There's zero difference in memory layout.
Should be no difference in access speed, but you need to measure to be sure.
The 1D array is more versatile. If you want to make a function that can accept arrays of different sizes, with a 1D array you can simply do void foo(int *arr, std::size_t w, std::size_t h). But for a 2D array there's no good solution. Even though their memory layout is the same, attempting to pass a 2D array to such a function would cause UB, just because the standard says so.
If you later decide that you want to allocate the array on the heap, the transition is easier with a 1D array, because you can keep the same [] syntax. For 2D arrays, you would either have to use an array of pointers to arrays (which is less efficient), or write a class that wraps a 1D array and overloads operator[] (which is the proper way of doing it, but takes time).
Any array is accessed using pointer arithematic by the code generated by compiler in a way like this:
A[i] == *(&A+i)
in case of two dimensional array A[d1][d2]:
A[i][j] == *(&A+(i*d2)+j)
for multi-dimensional arrays it keep getting more complex but internally it is always a linear memory block starting at memory location stored in array variable.
If your code has no row-column logic then it is better to use linear array but if you need that kind of code then it is always better to use multi-dimensional array as per your need because pointer arithmetic can be optimized very efficiently by the compiler.
I don't understand the syntax of a multidimensional vector.
Multidimensional arrays are pretty straight forward.
foo[3][5];
That's 5 elements with 3 elements each.
Vectors are not so much straight forward.
vector<vector<int>> foo(n);
I read this as for every foo, the "type" is vector. How does using a vector for another vector's type make it bidimensional? And also, is vector<int> still the same as a vector with an identifier, a vector with empty ints?
You've got the understanding of int foo[3][5]; correct: it's an outer array of three inner arrays, each one of which contains 5 ints.
Oversimplfying a little for the sake of this discussion, but if you consider arrays and vectors as interchangeable vector<vector<int>> foo; isn't really any different.
It's an outer vector, each member of which is an inner vector containing ints.
So thinking in terms of matrices, outer array/vector is the column, inner array/vector is the row. It's really not that different. And that row / column nature is what makes it two dimensional.
No arguments that under the hood the implementations are extremely different, but when you're using them, they will behave very similar to one another.
foo isn't really a "multidimensional" array, it's an array whose elements are also arrays.
With
int foo[3][5];
foo is an array with three elements, each of which is an array with five elements.
That is, foo[1] is an array of five ints (its type is int[5]).
A vector of vectors works like an array of arrays, except their sizes are not fixed.
vector<vector<int>> foo(n);
creates a vector with n elements, each of which is an empty vector (because vectors are empty by default).
vector<vector<int>> bar(3, vector<int>(5));
would create a vector with three vector<int> elements, and bar[1] would be a vector with five int elements.
I was trying the vector implementation in C++ stl and couldn't figure out what exactly does this mean:
vector< int > vec[N]
If we simply write int a[10],it's an array of 10 elements. Doesn't the same logic apply to vectors as well?
Isn't it a vector of arrays containing N elements each.Also,when I tried the .size() function on vec it gave an error" error: request for member ‘size’ in ‘vec’, which is of non-class type ‘std::vector [3]'"(Considering N=3)
Please correct me if I misunderstood the concept.
Thanks
Vector is a template class, with array as underlying data structure. Although you don't need to assign size to a vector because it increases its size dynamically, but you may want to reserve space to it while declaring. You can do it by "std::vector< int> vec(size)".
Your syntax actually seems an array of vector of int type, and not a vector of arrays.
I'm new to C++ STL, and I'm having trouble comprehending the graph representation.
vector<int> adj[N];
So does this create an array of type vector or does this create a vector of arrays? The BFS code seems to traverse through a list of values present at each instance of adj[i], and hence it seems works like an array of vectors.
Syntax for creating a vector is:
vector<int> F;
which would effectively create a single dimensional vector F.
What is the difference between
vector< vector<int> > N;
and
vector<int> F[N]
So does this (vector<int> adj[N];) create an array of type vector or does this create a
vector of arrays?
It creates array of vectors
What is the difference between
vector< vector<int> > N;
and
vector<int> F[N]
In the first case you are creating a dynamic array of dynamic arrays (vector of vectors). The size of each vector could be changed at the run-time and all objects will be allocated on the heap.
In the second case you are creating a fixed-size array of vectors. You have to define N at compile-time, and all vectors will be placed on the stack†, however, each vector will allocate elements on the heap.
I'd always prefer vector of vectors case (or the matrix, if you could use third-party libraries), or std::array of std::arrays in case of compile-time sizes.
I'm new to C++ STL, and I'm having trouble comprehending the graph
representation.
You may also represent graph as a std::unordered_map<vertex_type,std::unordered_set<vertex_type>>, where vertex_type is the type of vertex (int in your case). This approach could be used in order to reduce memory usage when the number of edges isn't huge.
†: To be precise - not always on stack - it may be a part of a complex object on the heap. Moreover, C++ standard does not define any requirements for stack or heap, it provides only requirements for storage duration, such as automatic, static, thread or dynamic.
Short Answer:
It's an array of vector <int>s.
Long Answer:
When reading a declaration such as
vector<int> adj[N];
The compiler uses a method known as the "spiral-" or "clockwise-rule" in order to interpret what it means. The idea behind the spiral rule is that you start at the variable name, and move outwards in a clockwise spiral in order to figure out what type of variable it is. For example:
char* str [10];
Can be interpreted like this:
____
| |
char* str [10];
|_________|
Making str an array of 10 char*s.
Therefore, vector<int> adj[N]; is an array of vectors rather than a vector of arrays
Practice makes perfect:
1: What does int * foo [ ]; mean?
Answer:
"foo" is an array of pointers to integers
2: What does int * (*foo [ ] )(); mean?
Answer:
"foo" is an array of pointers to functions returning pointers to integers
3: What does int * (*(*foo [ ] )())(); mean?
Answer:
"foo" is an array of pointers to functions returning pointers to functions returning pointers to integers
vector<int> arr[N];
It displays an array of vector, each array[i] would have a vector stored in it that can traverse through many values. It is like a an Array of Linked List where the heads are only stored in array[i] positions.
vector<vector<int> > N vs vector<int> F[N]
The difference between 2D Vector and an Array of Vector is that 2D Vectors can span in size while array of vectors have their dimension fixed for the array size.
Under the hood a vector still uses array, it is implementation specific but is safe to think that:
vector<int>
internally creates an int[].
What vectors gives you is that it abstract from you the part where if you want to re-size you don't have to re-allocate manually etc, it does that for you (plus much more of course).
When you do: vector<vector<int>> you are going to create a vector of vectors, meaning a 2D matrix. You can nest it as much as you want.
Vector takes in a type T and allocates an array of that type. so if you pass vector as type T, it will effectively do what you did in your first line, an array of vector<int>.
Hope it makes sense
I am having something i can't seem to figure out myself again. I don't know how to call this problem.
vector<int> *integerVectors[2] = { new vector<int>, new vector<int>};
(*integerVectors)[0].push_back(1);
(*integerVectors)[1].push_back(1);
When i run this i get an unhandled exeption. What I want is an Array with 2 indexes and each of them holding a vector.
EDIT: The Problem seems to appear when i start pushing back.
this syntax:
MyType *var[size];
creates an array of pointers to MyType of size size, which means that this:
vector<int> *integerVectors[2];
produces a size 2 array of pointers to integer vectors, a fact which is backed up by your ability to initialize integerVectors with an initializer-list of pointers to integer vectors produced by calls to new.
this:
(*integerVectors)
produces a pointer to your first vector pointer. You then call operator[] on it, which offsets the pointer by the size of a vector. But this is no longer a pointer to your array--if you call it with an argument of greater than 0, you'll be referencing an imaginary vector next to the one pointed by your first vector element.
Then you call push_back on the imaginary vector, naturally leading to massive problems at run time.
You either want to offset before dereferencing, as in #Abstraction's suggestion of
integerVectors[i]->push_back(1);
or you want to avoid C-style arrays. You're already using one vector, and nesting them rather than making arrays of them will avoid much confusion of this type in the future, while preserving the correct syntax:
vector<vector<int>*> integerVectors = {new vector<int>, new vector<int>};
integerVectors[1]->push_back(1);
Without the c-style array, your needed syntax is vastly clearer.
Even better, you could just avoid the pointers altogether and use
vector<vector<int>> integerVectors = {vector<int>{}, vector<int>{}};
integerVectors[1].push_back(1);
The first line of which has a few equivalent syntaxes, as pointed out by #NeilKirk:
vector<vector<int>> integerVectors(2);
vector<vector<int>> integerVectors{{},{}};
vector<vector<int>> integerVectors(2, vector<int>{});
vector<vector<int>> integerVectors(2, {});
The curly braces I'm using in initialization are another way to initialize an object, without the possibility of the compiler confusing it for a function in the most vexing parse. (However, you have to be careful with it around things which can be initialized with initializer lists like here, which is why some of these initializations use parentheses, instead) The first syntax default-initializes two vectors, and so does the second, though it explicitly states the same thing. It can also be modified to produce more complex structures: two vectors both with the elements {1,2,3} could be one of the below:
vector<vector<int>> integerVectors = {{1,2,3},{1,2,3}};
vector<vector<int>> integerVectors{{1,2,3},{1,2,3}};
vector<vector<int>> integerVectors(2, vector<int>{1,2,3});
vector<vector<int>> integerVectors(2, {1,2,3});
This line is the problem
(*integerVectors)[1].push_back(1);
Dereferencing *integerVectors gives you the first vector pointer (equivalent of integerVectors[0]. Then you call you call operator[] with 1 as arguent on this pointer which will give reference to vector with address shifted with one vector size forward (equivalent to *(integerVectors[0]+1) ) which is not valid.
The right syntax is
integerVectors[1]->push_back(1);