Matrix Class in C++: An Explanation - c++

I am currently browsing over some old college snippets of c++ code. Back then, one of the other class was assigned with doing a matrix class using double pointers and 2D arrays. Luckily (or unluckily upon hindsight) I never did get a chance to learn stuff like that. I borrowed their code when we graduated for future review. If anyone can please explain to me what exactly happens in this snippet:
//This is a constructor of a 1x1 matrix
signal::signal(){
_nrows = 1;
_ncols = 1;
_coef = new double*[_nrows];
_coef[0] = new double[_ncols];
_coef[0][0] = 0.0;
}
Just a sidenote, _coef is a ** of type double.
From what I understand, _nrows and _ncols are given a value of 1 (meaning their sizes). Then, the code dynamically creates a double* out in the heap with elements equal to _nrows; the problem is, I dont exactly know what happens next. Why is the array corresponding to _ncols not a pointer? Why is it assigned _coef[0]?

In memory, a two dimensional array (n, m) looks more or less like this
_coef -> | _coef[0] -> {1, 2, 3, ..., m}
| _coef[1] -> {1, 2, 3, ..., m}
| _coef[2] -> {1, 2, 3, ..., m}
| ...
| _coef[n] -> {1, 2, 3, ..., m}
_coef points to an array of n pointers. And each of these pointers point to an array of m doubles.
So, in your case _coef points to an array of 1 pointer and this pointer points to an array of one double.
Now to your questions
It is not a pointer, because in your second dimension, you finally want to store the doubles, not pointers.
It is assigned to _coef[0], because it is the first, and only, row of your two dimensional array.

The first two lines, as you say, assign the value 1 to each of _nrows and _ncols.
The following line dynamically allocates an array of double* (pointers to double). The number of double* objects allocated is _nrows (which is 1 in your case). Think of that syntax as similar to defining a normal automatic array, double* array[1], where the number of elements is 1. Then _coef is a pointer to the first of those double pointers. I'll represent the memory representation diagrammatically:
_nrows = 1
_ncols = 1
_coef ---> _coef[0] ---> Currently points nowhere in particular
So now you have _nrows amount of double* lined up in memory. _coef[0] refers to the first of those double*. A new dynamically allocated array, this time of doubles, is created of size _ncols. A pointer to the first of those doubles is assigned to _coef[0]. That is, the first double* in the first dynamically allocated array now points to the first double in the second dynamically allocated array.
_nrows = 1
_ncols = 1
_coef ---> _coef[0] ---> _coef[0][0]
Then _coef[0][0] = 0.0 sets the first double in the second dynamically allocated array to 0. Since it's the only double, because the sizes of both of your dynamically allocated arrays are 1, you have initialized all doubles to 0.
_nrows = 1
_ncols = 1
_coef ---> _coef[0] ---> _coef[0][0] = 0

Related

Why is a hard coded width required when declaring a two dimensional array?

Pointers to pointers seem to be the only way to dynamically declare a two dimensional (or multidimensional) array besides doing the leg work myself and coding the pointer arithmetic to create a "fake" multidimensional array out of a one dimensional array. I understand this is the way it is but why?!
First of all, a two dimensional array is not the same as a pointer to a pointer.
While the latter is a pointer to an array of pointers (to arrays), the former looks like this in memory:
char v[2][3] = {{1,3,5},{5,10,2}};
Content: | 1 | 3 | 5 | 5 | 10 | 2
Address: v v+1 v+2 v+3 v+4 v+5
To access v[x][y], the compiler rewrites it as: *(v + y * WIDTH + x)
So as you can see, WIDTH (the second dimension specified) is needed to do the calculation.
You can omit the first dimension in function parameters since they are adjusted to pointers:
int f (int v[3][10])
is the same as
int f (int v[][10])
and the same as
int f (int (*v)[100])
(Since arrays are adjusted to pointers in function parameters)
but not the same as
int f (int *v[100])
(Since this is an array[100] (that is
adjusted to a pointer) of pointers)
Anyway I suggest you to use std::vector<std::vector<Type>> if you need a two-dimensional array.
Why is a hard coded width required when declaring a two dimensional array?
C++ arrays require their dimensions to be constant expressions. For 2D arrays (really arrays of arrays), this applies to both dimensions. There is no exception for the "width" or the "height".

Designating a pointer to a 2D array

If I declare a 2D array
int A[sz][sz];
How can I create a pointer to this object?
I ask because I want to return an array via pointer to a pointer, int**, from a function but I want to build the array without knowing the size beforehand. The size will be passed as an argument. I want to know if there is a way to do this without using dynamic allocation.
The problem is if I do something like int** A inside the function this gives A no information about the size I want.
How can I create the array and then assign a pointer to this array, if it's a 2D array.
I should be more clear. I want return a pointer to a pointer so it wouldn't be a pointer to the 2D array but a something like int**.
Your problem is, that a 2D array in the form int** requires an array of int* for the two step dereferencing, which simply does not exist when you declare an array with int A[sz][sz];.
You can build it yourself like this:
int* pointers[sz];
for(size_t i = sz; i--; ) pointers[i] = A[i];
This might seem absurd, but is rooted in the way C handles arrays: A[i] is of type int ()[sz], which is the subarray of row i. But when you use that array in the assignment, it decays to a pointer to the first element in that subarray, which is of type int*. After the loop, A and pointers are two very different things (the type of A is int ()[sz][sz])
Sidenote: You say that you want to return this from a function. If your array is allocated on the stack, you must not return a pointer to its data, it will disappear the moment your function returns. You can only return pointers/references to objects that have either static storage or are part of another existing object. If you fail to comply with this, you are likely to get stack corruption.
Edit:
A little known fact about C is, that you can actually pass around pointers to real C arrays, not just the pointer types that an array decays to. Here is a small program to demonstrate this:
#include <stddef.h>
#include <stdio.h>
int (*foo(int size, int (*bar)[size][size], int y))[] {
return &(*bar)[y];
}
int main() {
int mySize = 30;
int baz[mySize][mySize];
int (*result)[mySize];
result = foo(mySize, &baz, 15);
printf("%ld\n", (size_t)result - (size_t)baz);
}
The expected output of this example program is 1800. The important thing is that the actual size of the array must be known, either by being a compile time constant, or by being passed along with the array pointer (and if it's passed along with the array pointer, the size argument must appear before the array pointer does).
Let me flesh out your question a little bit. You mention:
I ask because I want to return an array [...] from a function but I
want to build the array without knowing the size beforehand. The size
will be passed as an argument. I want to know if there is a way to do
this without using dynamic allocation.
For the I want to return an array from a function [...] size passed as an argument, it seems reasonable to me that you can use std::vector everywhere, and call its .data() method when you need access to the underlying array (which is guaranteed to be contiguous). For example:
std:vector<double> myfun(size_t N) {
std::vector<double> r(N);
// fill r[0], r[1], ..., r[N-1]
return r;
}
// later on:
r.data(); // gives you a pointer to the underlying double[N]
And for the I want to to do this without dynamic allocation, that is not possible unless you know the size at compile time. If that is the case, then do exactly as before but use std::array, which can implement optimizations based on known compile-time size:
std::array<double, N> myfun() {
std::array<double, N> r;
// fill r[0], r[1], ..., r[N-1]
return r;
}
// later on:
r.data(); // gives you a pointer to the underlying double[N]
And to be generic, I would actually use a template function capable of working with arbitrary containers:
template<typename T>
void myfun(T& data) {
for(int k=0; k<data.size(); k++) {
// do stuff to data[k]
}
}
// call as, for example:
std::vector<double> data(10);
myfun(data);
// or equally valid:
std::array<double, 10> data;
myfun(data);
Finally, if you are working with two-dimensional data, please remember that when you store the Matrix in row-major order that is:
Matrix [1, 2; 3 4] is stored as [1 2 3 4]
then you can refer to element (i, j) of the matrix by calling data[i * ncols + j]. For example: consider a three by four matrix:
a b c d
e f g h
i j k l
The element (2, 2) (that is: third row, third column because we assume zero-based C-type indexing) is calculated as: M[2][2] = M[2 * 4 + 2] = M[10] = k. This is the case because it was stored as:
[a b c d e f g h i j k l]
[0 1 2 3 4 5 6 7 8 9 10 11]
and k is the element with index 10.
the responses to your question are weird. Just do this:
int A[2][2];
int**p =NULL;
*p = A[0]; // **p==A[0][0] , *(*p+1)==A[0][1]

Can I access elements of a 2D array using pointers in C++?

For 1D array, I can use array name as a pointer and add offset to it to access each element of the array. Is there something similar for 2D arrays?
I defined a 2D array as follows
int arr[2][3] = {{1,2,3}, {4,5,6}};
int** arrPtr = arr;
but I got compiler error for the second line. Shouldn't 2D array have type int**?
I came across another thread here:
C++ Accessing Values at pointer of 2D Array
and saw this:
2dArray = new int*[size];
Could someone please tell me what int*[size] means? (size is an int, I presume).
Thanks a lot.
A multidimensional array defined as yours is is only a single pointer, because the data is encoded in sequence. Therefore, you can do the following:
int arr[2][3]={{1,2,3},{4,5,6}};
int* arrPtr = (int*)arr;
In general, the pointer to the element at arr[a][b] can be accessed by arrPtr + a*bSize + b where bSize is the size of the first array dimension (in this case three).
Your second question relates to dynamic memory allocation - allocating memory at runtime, instead of defining a fixed amount when the program starts. I recommend reviewing dynamic memory allocation on cplusplus.com before working with dynamically allocated 2D arrays.
int* array[10] means an array of 10 pointers to integer.
You can access a 2D array with a simple pointer to its first entry and do some maths exploiting the spacial location principle.
int array[2][2] = {{1,2}, {3, 4}};
int* p = &array[0][0];
for(int i=0; i<2*2; i++)
printf("%d ", *(p++));
If you have a matrix:
1 2
3 4
in memory it is encoded as 1 2 3 4 sequentially ;)

2D-array as argument to function

Why can't you declare a 2D array argument in a function as you do with a normal array?
void F(int bar[]){} //Ok
void Fo(int bar[][]) //Not ok
void Foo(int bar[][SIZE]) //Ok
Why is it needed to declare the size for the column?
Static Arrays:
You seem not to have got the point completely. I thought to try to explain it somewhat. As some of the above answers describe, a 2D Array in C++ is stored in memory as a 1D Array.
int arr[3][4] ; //consider numbers starting from zero are stored in it
Looks somewhat like this in Memory.
1000 //ignore this for some moments 1011
^ ^
^ ^
0 1 2 3 4 5 6 7 8 9 10 11
|------------| |-----------| |-------------|
First Array Second Array Third Array
|----------------------------------------------|
Larger 2D Array
Consider that here, the Bigger 2D Array is stored as contiguous memory units. It consists of total 12 elements, from 0 to 11. Rows are 3 and columns are 4. If you want to access the third array, you need to skip the whole first and second arrays. That is, you need to skip elements equal to the number of your cols multiplied by how many arrays you want skip. It comes out to be cols * 2.
Now when you specify the dimensions to access any single index of the array, you need to tell the compiler beforehand exactly how much elements to skip. So you give it the exact number of cols to perform the rest of the calculation.
So how does it perform the calculation? Let us say it works on the column major order, that is, it needs to know the number of columns to skip. When you specify one element of this array as...
arr[i][j] ;
Compiler performs this calculation automatically.
Base Address + (i * cols + j) ;
Let us try the formula for one index to test its veracity. We want to access the 3rd element of the 2nd Array. We would do it like this...
arr[1][2] ; //access third element of second array
We put it in the formula...
1000 + ( 1 * 4 + 2 )
= 1000 + ( 6 )
= 1006 //destination address
And we reach at the address 1006 where 6 is located.
In a nutshell, we need to tell the compiler the number of cols for this calculation. So we send it as a parameter in a function.
If we are working on a 3D Array, like this...
int arr[ROWS][COLS][HEIGHT] ;
We would have to send it the last two dimensions of the array in a function.
void myFunction (int arr[][COLS][HEIGHT]) ;
The formula now would become this..
Base Address + ( (i * cols * height) + (j * height) + k ) ;
To access it like this...
arr[i][j][k] ;
COLS tell the compiler to skip the number of 2D Array, and HEIGHT tells it to skip the number of 1D Arrays.
And so on and so forth for any dimension.
Dynamic Arrays:
As you ask about different behavior in case of dynamic arrays which are declared thus..
int ** arr ;
Compiler treats them differently, because each index of a Dynamic 2D Array consists of an address to another 1D Array. They may or may not be present on contiguous locations on heap. Their elements are accessed by their respective pointers. The dynamic counterpart of our static array above would look somewhat like this.
1000 //2D Pointer
^
^
2000 2001 2002
^ ^ ^
^ ^ ^
0 4 8
1 5 9
2 6 10
3 7 11
1st ptr 2nd ptr 3rd ptr
Suppose this is the situation. Here the 2D Pointer or Array on the location 1000. It hold the address to 2000 which itself holds address of a memory location. Here pointer arithmetic is done by the compiler by virtue of which it judges the correct location of an element.
To allocate memory to 2D Pointer, we do it..
arr = new int *[3] ;
And to allocate memory to each of its index pointer, this way..
for (auto i = 0 ; i < 3 ; ++i)
arr[i] = new int [4] ;
At the end, each ptr of the 2D Array is itself an array. To access an element you do...
arr[i][j] ;
Compiler does this...
*( *(arr + i) + j ) ;
|---------|
1st step
|------------------|
2nd step
In the first step, the 2D Array gets dereferenced to its appropriate 1D Array and in the second step, the 1D Array gets dereferenced to reach at the appropriate index.
That is the reason why Dynamic 2D Arrays are sent to the function without any mention of their row or column.
Note:
Many details have been ignored and many things supposed in the description, especially the memory mapping just to give you an idea.
You can't write void Foo(int bar[][]), because bar decays to a pointer. Imagine following code:
void Foo(int bar[][]) // pseudocode
{
bar++; // compiler can't know by how much increase the pointer
// as it doesn't know size of *bar
}
So, compiler must know size of *bar, therefore size of rightmost array must be provided.
Because when you pass an array, it decays to a pointer, so excluding the outer-most dimension is ok and that's the only dimension you can exclude.
void Foo(int bar[][SIZE])
is equivalent to:
void Foo(int (*bar)[SIZE])
The compiler needs to know how long the second dimension is to calculate the offsets. A 2D array is in fact stored as a 1D array.
If you want to send an array with no known dimensions, consider using pointer to pointers and some sort of way to know the dimension yourself.
This is different from e.g. java, because in java the datatype also contains the dimension.
Since static 2D arrays are like 1D arrays with some sugar to better access data, you have to think about the arithmetic of pointers.
When the compiler tries to access element array[x][y], it has to calculate the address memory of the element, that is array+x*NUM_COLS+y. So it needs to know the length of a row (how many elements it contains).
If you need more information I suggest this link.
there are basically three ways to allocate a 2d array in C/C++
allocate on heap as a 2d array
you can allocate a 2d array on the heap using malloc such as:
const int row = 5;
const int col = 10;
int **bar = (int**)malloc(row * sizeof(int*));
for (size_t i = 0; i < row; ++i)
{
bar[i] = (int*)malloc(col * sizeof(int));
}
this is actually stored as an array of arrays therefore isn't necessarily
contiguous in memory. note that this also means there will be a pointer for
each array costing yout extra memory usage (5 pointers in this example, 10
pointers if you allocate it the other way around). you can pass this array to
a function with the signature:
void foo(int **baz)
allocate on heap as 1d array
for various reasons (cache optimizations, memory usage etc.) it may be
desirable to store the 2d array as a 1d array:
const int row = 5;
const int col = 10;
int *bar = (int*)malloc(row * col * sizeof(int));
knowing second dimension you can access the elements using:
bar[1 + 2 * col] // corresponds semantically to bar[2][1]
some people use preprocessor magic (or method overloading of () in C++) to
handle this automatically such as:
#define BAR(i,j) bar[(j) + (i) * col]
..
BAR(2,1) // is actually bar[1 + 2 * col]
you need to have the function signature:
void foo(int *baz)
in order to pass this array to a function.
allocate on stack
you can allocate a 2d array on stack using something like:
int bar[5][10];
this is allocated as a 1d array on the stack therefore compiler needs to know
the second dimension to reach the element you need just like we did in the
second example, therefore the following is also true:
bar[2][1] == (*bar)[1 + 2 * 10]
function signature for this array should be:
void foo(int baz[][10])
you need to provide the second dimension so that compiler would know where to reach in memory. you don't have to give the first dimension since C/C++ is not a safe language in this respect.
let me know if I mixed up rows and columns somewhere..

C++ pointer to different array

Assume I have an array a and an array b. Both have the same type and size but different values.
Now I create 3 or so pointers that point to different elements in a, you could say a[0], a[4] and a[13].
Now if I overwrite a with b via a=b - Where will the pointers point?
Do the pointers still point to their original positions in a but the values they point to are now those of b?
Arrays are not assignable in C++. Once you declare an array:
int a[10];
there is no way of overwriting it, only of changing the values it contains. Specifically, you can't do:
int a[10], b[10];
a = b; // cannot work in C++ (or C)
If you create the array dynamically and assign pointers:
int * a = new int[10];
int * p = a + 1;
int * b = new int[10];
a = b;
then the pointer p still points into the first array, but you have a memory leak.
In the case of a struct containing an array:
struct S {
int a[10];
};
S s1, s2;
int * p = s1.a + 1;
s1 = s2;
then the pointer p still points into the first struct's array, but the array contents will have been overwritten with the array contents from the second struct.
That's an interesting question. So lets break it down:
Where will the pointers point?
Same place as they did before. They only contain the address of the memory, nothing more. Changing "a" will not change the pointers.
Will the pointers point to their original positions in a but the values they point to are now those of b?
If a was created as
int *a = new int[34];
then no.
If you don't directly change the variables that are storing your pointers, nothing is going to change the location they point to. Changing the values stored in the "pointed to" locations will change the dereferenced values of your pointers, but they still point to the same place.
Learning how to use a good graphical debugger and stepping through a test program would help illustrate what is going on. I don't know if you are on the windows platform, but the visual studio (and I would think Visual C++ Express) debugger will show you everything you need to know so you can run your own experiment and see exactly what your code is doing.
You can not overwrite anything with a=b. Effectively this will leak memory, by leaving your whole 'a' array somewhere into the memory with no pointer to it. 'a' will point to the first element of 'b' after a=b.
After a declaration like int * a = new a[5]; , your 'a' point to the first element of the array. You can do pointer arithmetic like a++, which will then go to the second element in the array, leaving your first element with no pointer to it. The same way a=b will point it to the first element of the b array.
Your other pointers a[3], a[14] e.t.c. will still point to the same memory as before.
Note that a[0] is the same as 'a'.
You must make a difference between arrays and pointers. If you use arrays you cannot make a=b.
If you use pointers you can make a = b and that will mean that a points where b points. The values inside them will not change, but it will be impossible to access. Once you make a = b, when accessing a[3] you will access b[3], because a[3] means: "where a points + 3", and a points where b points, hence b[3].
If you don't free where a was allocated, that info is still in memory, so if you made 3 pointers that point where a used to point + some value, that info is still accessible and not modified.
a=b won't work, but you can copy array b into a using STL.
As an example :
int a[15] = {0};
int b[15] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
int *p1 = a; // pointer to a[0]
int *p2 = a+4; // pointer to a[4]
int *p3 = a+13; // pointer to a[13]
std::copy(&b[0], &b[15], a);
If you have pointers to array a elements declared before the copy :
pointers' address won't change if you copy b into a
only pointers' values
change