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?
malloc()in C.rowafter callingfree(row)until you assign a new memory torow.double **rows_and_columns = xmalloc(n_rows * n_cols * sizeof(double));Unary stars don't count up. You have zero inside and two outside. No go. You need one more on the outside than you have inside. Exactly one. Not zero, not two. Base case,X* ... = malloc(sizeof(X) * count). One/zero. IfXisY*, you haveY** ... = malloc(sizeof(Y*) * count). Two/one. IfYisZ*, you haveZ*** ... = malloc(sizeof(Z**) * count). Three/two. No rocket science.