I have an an integer array of values and I would like to make a double pointer to point to this array. I assume that this 1D integer array actually represents a 2D array. That is for instance that if I have an int A[2000*12] then I have 12 lines and 2000 rows. The problem is that I do not know how to initialize the pointer to point to the array A. My initial thought was like that:
int A[2000*12];
int **ptr;
ptr=&A[0];
Of course this is not correct. More precisely I get the following error:
incompatible pointer types in assignment
Remove the [0] part:
int A[2000*12];
int **ptr;
ptr = &A;
EDIT:
This however does not solve the problem with getting a 2D array. You still can't access it like
A[1][2] = 10;
because the compiler does not know the length of rows.
My favourite way of initializing a 2D array goes like:
int width = 10;
int height = 20;
int *_a = (int *) malloc(width * height * sizeof(int));
int **a = (int **) malloc(height * sizeof(int *));
The first allocation creates the 2D array, the second one creates an array pointing to each row.
int i, offset = 0;
for (i = 0; i < height; i++, offset += width)
{
a[i] = _a + offset;
}
a[0][0] = 1;
a[0][1] = 2;
a[1][0] = 2;
a[1][1] = 4;
// ...
Related
I dynamically allocated memory for 3D array of pointers. My question is how many pointers do I have? I mean, do I have X·Y number of pointers pointing to an array of double or X·Y·Z pointers pointing to a double element or is there another variant?
double*** arr;
arr = (double***)calloc(X, sizeof(double));
for (int i = 0; i < X; ++i) {
*(arr + i) = (double**)calloc(Y, sizeof(double));
for (int k = 0; k < Y; ++k) {
*(*(arr+i) + k) = (double*)calloc(Z, sizeof(double));
}
}
The code you apparently intended to write would start:
double ***arr = calloc(X, sizeof *arr);
Notes:
Here we define one pointer, arr, and set it to point to memory provided by calloc.
Using sizeof (double) with this is wrong; arr is going to point to things of type double **, so we want the size of that. The sizeof operator accepts either types in parentheses or objects. So we can write sizeof *arr to mean “the size of a thing that arr will point to”. This always gets the right size for whatever arr points to; we never have to figure out the type.
There is no need to use calloc if we are going to assign values to all of the elements. We can use just double ***arr = malloc(X * sizeof *arr);.
In C, there is no need to cast the return value of calloc or malloc. Its type is void *, and the compiler will automatically convert that to whatever pointer type we assign it to. If the compiler complains, you are probably using a C++ compiler, not a C compiler, and the rules are different.
You should check the return value from calloc or malloc in case not enough memory was available. For brevity, I omit showing the code for that.
Then the code would continue:
for (ptrdiff_t i = 0; i < X; ++i)
{
arr[i] = calloc(Y, sizeof *arr[i]);
…
}
Notes:
Here we assign values to the X pointers that arr points to.
ptrdiff_t is defined in stddef.h. You should generally use it for array indices, unless there is a reason to use another type.
arr[i] is equivalent to *(arr + i) but is generally easier for humans to read and think about.
As before sizeof *arr[i] automatically gives us the right size for the pointer we are setting, arr[i].
Finally, the … in there is:
for (ptrdiff_t k = 0; k < Y; ++k)
arr[i][k] = calloc(Z, sizeof *arr[i][k]);
Notes:
Here we assign values to the Y pointers that arr[i] points to, and this loop is inside the loop on i that executes X times, so this code assigns XY pointers in total.
So the answer to your question is we have 1 + X + XY pointers.
Nobody producing good commercial code uses this. Using pointers-to-pointers-to-pointers is bad for the hardware (meaning inefficient in performance) because the processor generally cannot predict where a pointer points to until it fetches it. Accessing some member of your array, arr[i][j][k], requires loading three pointers from memory.
In most C implementations, you can simply allocate a three-dimensional array:
double (*arr)[Y][Z] = calloc(X, sizeof *arr);
With this, when you access arr[i][j][k], the compiler will calculate the address (as, in effect, arr + (i*Y + j)*Z + k). Although that involves several multiplications and additions, they are fairly simple for modern processors and are likely as fast or faster than fetching pointers from memory and they leave the processor’s load-store unit free to fetch the actual array data. Also, when you are using the same i and/or j repeatedly, the compiler likely generates code that keeps i*Y and/or (i*Y + j)*Z around for multiple uses without recalculating them.
Well, short answer is: it is not known.
As a classic example, keep in mind the main() prototype
int main( int argc, char** argv);
argc keeps the number of pointers. Without it we do not know how many they are. The system builds the array argv, gently updates argc with the value and then launches the program.
Back to your array
double*** arr;
All you know is that
arr is a pointer.
*arr is double**, also a pointer
**arr is double*, also a pointer
***arr is a double.
What you will get in code depends on how you build this. A common way if you need an array of arrays and things like that is to mimic the system and use a few unsigned and wrap them all with the pointers into a struct like
typedef struct
{
int n_planes;
int n_rows;
int n_columns;
double*** array;
} Cube;
A CSV file for example is char ** **, a sheet workbook is char ** ** ** and it is a bit scary, but works. For each ** a counter is needed, as said above about main()
A C example
The code below uses arr, declared as double***, to
store a pointer to a pointer to a pointer to a double
prints the value using the 3 pointers
then uses arr again to build a cube of X*Y*Z doubles, using a bit of math to set values to 9XY9.Z9
the program uses 2, 3 and 4 for a total of 24 values
lists the full array
list the first and the very last element, arr[0][0][0] and arr[X-1][Y-1][Z-1]
frees the whole thing in reverse order
The code
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int n_planes;
int n_rows;
int n_columns;
double*** array;
} Cube;
int print_array(double***, int, int, int);
int main(void)
{
double sample = 20.21;
double* pDouble = &sample;
double** ppDouble = &pDouble;
double*** arr = &ppDouble;
printf("***arr is %.2ff\n", ***arr);
printf("original double is %.2ff\n", sample);
printf("*pDouble is %.2ff\n", *pDouble);
printf("**ppDouble is %.2ff\n", **ppDouble);
// but we can build a cube of XxYxZ doubles for arr
int X = 2;
int Y = 3;
int Z = 4; // 24 elements
arr = (double***)malloc(X * sizeof(double**));
// now each arr[i] must point to an array of double**
for (int i = 0; i < X; i += 1)
{
arr[i] = (double**)malloc(Y * sizeof(double*));
for (int j = 0; j < Y; j += 1)
{
arr[i][j] = (double*)malloc(Z * sizeof(double));
for (int k = 0; k < Z; k += 1)
{
arr[i][j][k] = (100. * i) + (10. * j) + (.1 * k) + 9009.09;
}
}
}
print_array(arr, X, Y, Z);
printf("\n\
Test: first element is arr[%d][%d[%d] = %6.2f (9XY9.Z9)\n\
last element is arr[%d][%d[%d] = %6.2f (9XY9.Z9)\n",
0, 0, 0, arr[0][0][0],
(X-1), (Y-1), (Z-1), arr[X-1][Y-1][Z-1]
);
// now to free this monster
for (int x = 0; x < X; x += 1)
{
for (int y = 0; y < Y; y += 1)
{
free(arr[x][y]); // the Z rows
}
free(arr[x]); // the plane Y
}
free(arr); // the initial pointer;
return 0;
}; // main()
int print_array(double*** block, int I, int J, int K)
{
for (int a = 0; a < I; a += 1)
{
printf("\nPlane %d\n\n", a);
for (int b = 0; b < J; b += 1)
{
for (int c = 0; c < K; c += 1)
{
printf("%6.2f ", block[a][b][c]);
}
printf("\n");
}
}
return 0;
}; // print_array()
The output
***arr is 20.21f
original double is 20.21f
*pDouble is 20.21f
**ppDouble is 20.21f
Plane 0
9009.09 9009.19 9009.29 9009.39
9019.09 9019.19 9019.29 9019.39
9029.09 9029.19 9029.29 9029.39
Plane 1
9109.09 9109.19 9109.29 9109.39
9119.09 9119.19 9119.29 9119.39
9129.09 9129.19 9129.29 9129.39
Test: first element is arr[0][0[0] = 9009.09 (9XY9.Z9)
last element is arr[1][2[3] = 9129.39 (9XY9.Z9)
I am exploring pointer "mechanics" in C/C++. I try to understand if and how is possible to implement a 2D matrix using two pointers (one for "rows" and one for "columns") instead of a single double pointer. I am aware that a matrix with rows*columns number of values could be stored in memory sequentially, but i am looking to comprehend deeper the mechanics of pointers and eventually to implement a function similar to
int value=getValue(vectorNr,vectorValue)
that is able to "simulate" the construct
value=Matrix[vectorNr][vectorValue]
vectorPointer vectorValue
| AddressV1 |------|valAddr11 valAddr12 valAddr13 |
| AddressV2 |------|valAddr21 valAddr22 valAddr23 |
| AddressV3 |------|valAddr31 valAddr32 valAddr33 |
I tried to begin writing a code like this but I quickly get stuck on pointer arithmetic and address offsetting. I also might chose a very dirty approach so any comment is welcome.
CODE TO IMPLEMENT A 2D ARRAY WITH POINTERS (BUT NOT USING DOUBLE POINTERS). To avoid confusion between rows and columns I refer to "Vectors as rows" and "Columns as vector values"
int vectorsNumber = 3; //Number of Vectors
int valuesNumber = 3; //Number of values stored in one Vector
//Addresses of Vectors. Since Vectors holds a reference to set of values, vectorPointer will hold an address for every set.
void* vectorPointer = malloc(vectorsNumber *sizeof(void*));
//Populating the vectorPointer with the address generated by allocating memory for every set of values
for (int i = 0; i < vectorsNumber; i++)
{
vectorPointer = (int*)malloc(valuesNumber * sizeof(int)); //Values shall be of int types
vectorPointer++; //ILLEGAL since cannot perform arithmetic on pointers of type void. What do do??
}
//Restore the initial address. In any case...ILLEGAL arithmetic. What do do??
for (int i = 0; i < vectorsNumber; i++)
{
vectorPointer--; //Restore the initial address. In any case...ILLEGAL arithmetic.
}
//Declaring the pointer to hold the address of one value. Memory was already allocated before
int* valueAddress;
for (int j = 0; j < vectorsNumber; j++)
{
//Getting the address of the first value of the first Vector
valueAddress = (int*)vectorPointer; //Is this casting valid in C language?
//Populating the value with whatever operation
for (int k = 0; k < valuesNumber; k++)
{
*valueAddress = (k + 1)*(j + 1); //populate the Vector with int values
}
vectorPointer++; //Switch to next Vector.ILLEGAL arithmetic
}
Actually, you only need one pointer. One way of doing it is by allocating enough memory to hold all the values, and then have functions that map the x/y values in the array to the respective memory location. Assume we want those to be the dimensions and our array variable:
int dimX = 10, dimY = 5;
int *array;
You can set a value this way:
void arraySet(int value, int x, int y) {
array[x + dimX * y] = value;
}
And get a value this way:
int arrayGet(int x, int y) {
return array[x + dimX * y];
}
Allocate the memory beforehand such as in the main function:
array = malloc(sizeof(int)*dimX*dimY);
Use it like this:
arraySet(123, 9, 3); // sets the value of [9, 3] to 123
printf("Memory at 9, 3 is %d\n", arrayGet(9, 3));
This "two pointers" idea doesn't make any sense and the code you posted cannot be salvaged. What you should do instead is to use a pointer to a 2D array:
int (*ptr)[x][y] = malloc(sizeof *ptr);
...
free(ptr);
That's it. However, a pointer to a 2D array is cumbersome, since we have to de-reference it before accessing the actual array. That is, we'd end up writing (*ptr)[i][j] = ...; which is ugly.
To dodge this, we can instead still allocate a 2D array, but instead of pointing at "the whole array", we point at the first element, which is a 1D array:
int (*ptr)[y] = malloc( sizeof(int[x][y]) );
...
ptr[i][j] = ... ; // more convenient syntax for access
...
free(ptr);
More info: Correctly allocating multi-dimensional arrays
You can simulate int a[2][3]; with
one dimensional array and index computing:
int* matrix = (int*) malloc(6 * sizeof(int));
int get_matrix_2_3(int* matrix, int i, int j) { return matrix[3 * i + j]; }
2-dimensional array:
int** matrix = (int**) malloc(2 * sizeof(int*));
for (int i = 0; i != 2; ++i) {
matrix[i] = (int*) malloc(3 * sizeof(int));
}
matrix[1][2] = 42;
I'm playing with pointers and stumbled accross this problem. Like in this question I wanted a generic method signature for function foo, therefore I chose void * input as parameter. For testing reasons I casted the void pointer to an int ** pointer to use it like an 2D array.
#include <stdio.h>
#include <stdlib.h>
void * foo(void *input, size_t mySize)
{
for (size_t i = 0; i < mySize; ++i)
{
for (size_t j = 0; j < mySize; ++j)
{
((int **)input)[i*mySize][j] = 10*i+j;
}
}
return input;
}
int main(int argc, char const *argv[])
{
size_t const mySize = 10;
void * myMemory, * testPtr;
myMemory = malloc(mySize * mySize * sizeof(int));
testPtr = foo(myMemory, mySize);
free(testPtr);
return 0;
}
Now I thought that using the [] operator would be same as adding an int to the pointer, e.g. that ((int **)input[i][j] would be the same like `((int **)input)+i+j
But accessing the input array in foo segfaults and using gdb shows me
(gdb) p ((int **)input)[i][j]
Cannot access memory at address 0x0
(gdb) p ((int **)input)+i+j
$25 = (int **) 0x405260
so obviously there is a difference. And therefore I'm confused.
While arrays and pointers are similar, they are not the same.
An array - single or multi dimensional - depicts a continuous chunk of memory, containing a specific datatype. For exampleint arr [10] declares arr as 10 continuous ints in memory. int multi_arr[5][10] declares multi_arr as 5 arrays of 10 continuous ints in memory.
Furthermore, the name arr would be the base address of this array, and passing it to a function would be the same as passing &arr[0].
But this is where the similarities end. A multi dimensional array can't (technically) be cast to a pointer-to-a-pointer and then back again.
If arr above pointed to a block of ints, then dereferencing the first dimension of int ** ptr would lead you to a block of pointers toint. Dereferencing that would not take you deeper into that block, as a multi dimensional array would, rather it could point anywhere.
You allocated a one dimension array with mySize*mySize elements.
int** is an array of pointers to int, what you want is
int **array2d;
int *p;
array2D = malloc(ROWS * sizeof(int*) + ROWS * COLUMNS * sizeof(int));
p = (int*) &array2d[ROWS];
for (size_t i = 0; i < ROWS; ++i)
array2d[i] = &p[i * COLUMNS];
now array2d[row][column] can work.
Or, as already suggested, use a one dimension array and use the array[row * COLUMNS + column] formulae.
I'm trying to figure out how to loop through a 2 dimensional array as a single dimensional array. Since a 2 dimensional array will occupy continuous memory, is there a way to address the two dimensional array as a single dimensional array by changing the index by 4 bytes. I'm assuming an integer array. Could some one provide an example? I tried the following but it doesn't work:
for (int i = 0; i < 2; i++){
for (int j = 0;j < 2; j++){
z[i][j] = count;
count++;
}
}
for (int i = 0; i < 4; i++)
printf("%d\n", z[i]);
2D arrays can be iterated through in a single loop like this:
#include <stdio.h>
int main()
{
int a[2][2], *p;
a[0][0] = 100;
a[0][1] = 200;
a[1][0] = 300;
a[1][1] = 400;
p = &a[0][0];
while(p!=&a[0][4])
printf("%d\n", *p++);
return 0;
}
Remember that an array index is just an offset from the first element of the array, so there is no real difference between a[0][3] and a[1][1] - they both refer to the same memory location.
Access 2D arrays like this
int *array; // note one level of pointer indirection
array = malloc(width * height * sizeof(int)); / allocate buffer somehow
for(y=0;y<height;y++)
for(x=0;x<width;x++)
array[y*width+x] = 0; // address the element by calculation
In three dimensions
int *array; // note one level of pointer indirection
array = malloc(width * height * depth * sizeof(int)); / allocate buffer somehow
for(z=0;z<depth;z++)
for(y=0;y<height;y++)
for(x=0;x<width;x++)
array[z*width*height + y*width+x] = 0; // address the element by calculation
Generally it's easier to use flat buffers than to mess around with C and C++ convoluted rules for multi-dimensional arrays. You can also of course
iterate through the entire array with a single index. If you want to set
up a 2D array, then cast the array to a single pointer, it behaves the
same way.
#define HEIGHT 50
#define WIDTH 90
int array2D[HEIGHT][WIDTH}:
int * array = reinterpret_cast<int *>(array2D):
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int arr[4][3]={{1,2,3},{4,5,6},{7,8,9},{10,11,12}};
void my_fun(int(*a)[],int m,int n)
{
for(int i=0;i<m*n;i++)
{
printf("%d\n",(*a)[i]);
}
}
int main()
{
my_fun(arr,3,4);
return 0;
}
I know there are very similar questions, but I've read them and I don't understand what is going wrong or what exactly I haven't understood about pointers to pointers.
My teacher is using a "learning by doing" approach to pointers and it has left me with approximately 100 questions. Sometimes I just change things around until it compiles, but it really isn't becoming any more clear to me, so if someone could help clarify a few things, I'd really appreciate it.
struct Matrix {
int rows; // number of rows
int cols; // number of columns
double **data;
};
typedef struct Matrix Matrix;
The pointer to a pointer, is something like this, right?
double *row1 = (double *) malloc (n_cols*sizeof(double));
double *row2 = (double *) malloc (n_cols*sizeof(double));
double *row3 = (double *) malloc (n_cols*sizeof(double));
double *data[] = { row1, row2, row3};
Data is pointing to the row number which is pointing to the doubles in the rows.
Now I am supposed to make a constructor function that makes a Matrix with a 0 in every position returns a pointer to a Matrix.
Matrix *make_matrix(int n_rows, int n_cols) {
Matrix *m = xmalloc(sizeof(Matrix));
m->rows = n_rows;
m->cols = n_cols;
double **rows_and_columns = xmalloc(n_rows * n_cols * sizeof(double));
memset(rows_and_columns, 0, m->rows * m->cols * sizeof(double));
m->data = *rows_and_columns;
return m;
}
So I made a pointer for the matrix, then I assigned the values for the rows and columns. Then I got confused (although I am not sure how confused, because this part compiles). I made a pointer to pointer for the last element of the struct Matrix (**data). Since **rows_and_columns has to hold the rows and columns, I allocated xmalloc(n_rows * n_cols * sizeof(double)) memory to it. I then set the whole thing to 0 and assign it to data. I think this m->data = rows_and_columns; says that m points to data and since data is a pointer and rows_and_columns is a pointer, we'll align their addresses, so m->data will also point to a bunch of 0s? Or is this wrong? And I am returning m, because the output is Matrix * and the m will get the * upon output, correct?
The next step is to copy a matrix, at which point I got even more lost.
Matrix *copy_matrix(double *data, int n_rows, int n_cols) {
Matrix *m = make_matrix(n_rows, n_cols);
double *row = (double *) malloc (n_cols*sizeof(double));
int i = 0;
for (int j = 0; j < n_rows; j++) {
for (; i < n_cols; i++) {
row = (double *) malloc (n_cols*sizeof(double));
row [i] = data[i + j*n_cols];
}
m->data [j] = *row [i];
}
free(row);
return m;
}
So we are returning a pointer to a Matrix again. The input is now a pointer to double values, which I am assuming are the rows. First, I made a matrix. Then I made a pointer for a row with a n columns worth of memory (double *) malloc (n_cols*sizeof(double)).
This is where I got super confused. I was imagining **data the whole time as something like above (double *data[] = { row1, row2, row3};). So, I wanted to copy each row of *data into *row, then save that as an entry in **data, like data[0] = row0, but something isn't clicking with the pointers, because I am not allowed to assign m->data [j] = row [i];, because I'm assigning incompatible types by assigning double * from type double?
xmalloc() returns a void * pointer to single block of memory.
What you need is one block of pointers, serving as an conceptual table header row, holding pointers to other memory blocks which themselves contain the actual doubles.
double **columns -> [double *col0] [double *col1] [double *col2] ...
| | |
V V V
[double col_val0] [double col_val0] ...
[double col_val1] [double col_val1]
[double col_val2] [double col_val2]
... ...
A matrix allocation could look like this:
// Allocate the double pointer array:
double **matrix_rows = xmalloc(sizeof(double *) * column_count);
// Iterate over each double-pointer in the double-pointer-array allocated above.
for(int i = 0; i < column_count; i++) {
// Allocate a new double-array, and let current double-pointer point to it:
matrix_rows[i] = malloc(sizeof(double) * row_count);
// Initialize matrix cell, iterating over allocated values.
for(int j = 0; j < row_count; j++) {
// Accessing the i'th col and j'th cell.
matrix_rows[i][j] = 0.0;
}
}
A possible implementation of a matrix copy function could be done by iteratively copying individial cells. One way to do this is using a loop composition.
for(int col = 0; col < col_count; col++) {
for(int row = 0; row < row_count; row++) {
destination_matrix[col][row] = source_matrix[col][row];
}
}
To give some intuition where an n-pointer indirection could be used:
n = 1: Strings, an array of characters.
n = 2: Paragraph, holding lines of strings.
n = 3: An article, holding a list of paragraphs.
Please be aware of using two indirections is usually not something you want. It is usually more efficient to store data in a linear fashion and compute linear indices out of two-compoment vectors and the other way around, especially in the case of this matrix example.
If you want to represent a matrix as an array of pointers to rows you need to allocate memory both for the rows and for the array of pointers to rows. It is simpler to allocate the rows consecutively as a single block.
typedef struct
{
int n_rows;
int n_cols;
double **rows;
double *data;
} Matrix;
Matrix *matrix_new (int n_rows, int n_cols)
{
// allocate matrix
Matrix *m = malloc (sizeof(Matrix));
m->n_rows = n_rows;
m->n_cols = n_cols;
// allocate m->data
m->data = malloc (n_rows * n_cols * sizeof(double));
// allocate and fill m->rows
m->rows = malloc (n_rows * sizeof(double*));
for (int i = 0; i < n_rows; i++) {
m->rows[i] = &data[i * n_cols];
}
// set the matrix to 0
for (int i = 0; i < n_rows; i++) {
for (int j = 0; j < n_cols; j++) {
m->rows[i][j] = 0.0;
}
}
return m;
}
The purpose of the rows array it to give you the convenience of being able to refer to element i,j with m->rows[i][j] instead of m->data[i * m->n_cols + j].
To free the matrix, take the inverse steps:
void matrix_free (Matrix *m)
{
free (m->rows);
free (m->data);
free (m);
}
To copy you can simply allocate a matrix of the same size and copy element by element:
Matrix *matrix_copy (Matrix *m1)
{
Matrix *m2 = matrix_new (m1->n_rows, m1->n_cols);
for (int i = 0; i < m1->n_rows; i++) {
for (int j = 0; j < m1->n_cols; j++) {
m2->rows[i][j] = m1->rows[i][j];
}
}
return m2;
}
The important thing to note is that you must not copy the rows array since it is unique to each matrix.
It is important to understand the difference between pointers-to-pointers and multi-dimensional arrays.
What makes it extra confusing is that the same syntax is used for referencing individual elements: var[i][j] will reference element (i,j) of var regardless of if var is a pointer to pointer, double **var or a two-dimensional array, double var[22][43].
What really happens is not the same. A two-dimensional array is a contiguous memory block. A pointer to pointers is an array of pointers that point to the individual rows.
// Two-dimensional array
char var1[X1][X2];
int distance = &var[4][7] - &var[0][0]; // distance = 4*X2+7
// Pointer-to-pointer
char **var2 = malloc(X1 * sizeof(char*)); // Allocate memory for the pointers
for (i=0; i<X1; i++) var2[i] = malloc(X2); // Allocate memory for the actual data
int distance2 = &var2[4][7] - &var[0][0]; // This could result in anything, since the different rows aren't necessarily stored one after another.
The calculation of distance2 invokes undefined behaviour since the C standard doesn't cover pointer arithmetic on pointers that point to different memory blocks.
You want to use pointer-to-pointer. So you need to first allocate memory for an array of pointers and then for each array:
Matrix *make_matrix(int n_rows, int n_cols) {
Matrix *m = xmalloc(sizeof(Matrix));
int i, j;
m->rows = n_rows;
m->cols = n_cols;
m->data = xmalloc(n_rows * sizeof(double*));
for (i=0; i < n_; i++) {
m->data[i] = xmalloc(n_cols * sizeof(double));
for (j=0; j < n_cols; j++) {
m->data[i][j] = 0.0;
}
}
return m;
}
Don't assume that the double 0.0 will have all bits set to 0!
To copy a matrix:
Matrix *copy_matrix(Matrix *source) {
Matrix *m = make_matrix(source->n_rows, source->n_cols);
int i, j;
for (j = 0; j < n_rows; j++) {
for (i = 0; i < n_cols; i++) {
m->data[i][j] = source[i][j];
}
}
return m;
}
I'll backup a bit and start with the basics. Pointers are one of those things that are not difficult to understand technically, but require you to beat your head into the I want to understand pointers wall enough for them to sink in. You understand that a normal variable (for lack of better words) is just a variable that holds a direct-reference to an immediate value in memory.
int a = 5;
Here, a is a label to the memory address that holds the value 5.
A pointer on the other hand, does not directly-reference an immediate value like 5. Instead a pointer holds, as its value, the memory address where 5 is stored. You can also think of the difference this way. A normal variable holds a value, while a pointer holds the address where the value can be found.
For example, to declare a pointer 'b' to the memory address holding 5 above, you would do something like:
int *b = &a;
or equivalently:
int *b = NULL;
b = &a;
Where b is assigned the address of a. To return the value stored at the address held by a pointer, or to operate directly on the value stored at the address held by a pointer, you must dereference the pointer. e.g.
int c = *b; /* c now equals 5 */
*b = 7; /* a - the value at the address pointed to by b, now equals 7 */
Now fast forward to pointer-to-pointer-to-type and simulated 2D matricies. When you declare your pointer-to-pointer-to-type (e.g. int **array = NULL), you are declaring a pointer that points to a pointer-to-type. To be useful in simlated 2D arrays (matricies, etc.), you must delcare an array of the pointer-to-pointer-to-type:
int **array = NULL;
...
array = calloc (NUM, sizeof *array); /* creates 'NUM' pointer-to-pointer-to-int. */
You now have NUM pointers to pointers-to-int that you can allocate memory to hold however many int values and you will assign the starting address for the memory block holding those int values to the pointers you previously allocated. For example, let's say you were to allocate space for an array of 5 random int values (from 1 - 1000) to each of the NUM pointers you allocated above:
for (i = 0; i < NUM; i++) {
array[i] = calloc (5, sizeof **array);
for (j = 0; j < 5; j++)
array[i][j] = rand() % 1000 + 1;
}
You have now assigned each of your NUM pointers (to-pointer-to-int) the starting address in memory where 5 random int values are stored. So your array is now complete. Each of your original NUM pointers-to-pointer-to-int now points to the address for a block of memory holding 5 int values. You can access each value with array notation (e.g. array[i][j] or with pointer notation *(*(array + i) + j) )
How do you free the memory? In the reverse order you allocated (values, then pointers):
for (i = 0; i < NUM; i++)
free (array[i]);
free (array);
Note: calloc both allocates memory and initializes the memory to 0/nul. This is particularly useful for both the pointers and arrays when dealing with numeric values, and when dealing with an unknown number of rows of values to read. Not only does it prevent an inadvertent read from an uninitialized value, but it also allows you to iterate over your array of pointers with i = 0; while (array[i] != NULL) {...}.