Altermeris
Altermeris

Reputation: 71

Confused about Pointers to Pointers and Dynamic Memory Allocation

I am having a difficult time fully understanding what is going on.

This is how I am reading the code at the bottom.

  1. Define A as a pointer to an address of a pointer that points to address of a double.

  2. Allocate 4 blocks of memory on the heap that can each hold an address to a double. Return the address of the first block allocated to A.

  3. Allocate 6 blocks of memory on the heap that can each hold a double data type and return the first block's address for each of the 4 blocks allocated earlier.

  4. Variable A still contains the address of the first block of the four pointers assuming that A[0] changed the value at the address pointed by A rather than A itself.

Now this is where the diagram comes in that is linked at the bottom. Lets say that I wanted to access the data stored in the red block. How would I do so?

Would the following code work?

double data = *(*(A + 3) + 2);

My logic is that A is a pointer and incrementing by 3 should increase the address by the number of bytes that is of the size (double *). Dereferencing the address (A + 3), I would obtain the address of first block (assuming it was not re-assigned). By increasing the resulting address by 2 and dereferencing that address, I should obtain the value at the red block.

So if I understand correctly, 1 + M pointers are being stored in memory. Why? If the goal is to store MxN data, why would I need 1 + M pointers to do so? The extra pointers seem like they would be helpful if I wanted to define rows of different sizes but the objective is to define a rectangular array of data.

const int M = 4;
const int N = 6;
double **A;

A = malloc(M*sizeof(double *));

for (i = 0; i < N; i++) {
    A[i]= malloc(N*sizeof(double));
}

Diagram:

enter image description here

Side Note: I am Electrical Engineering student that is unfamiliar with C to some degree and formal programming practices. I know that I'm being pedantic about the such a simple line of code, but I want to be sure that I understand pointers and memory allocation correctly. They are pretty hard to comprehend at first glance. This is part of a matrix multiplication code given to me by my professor and I want to pass the pointer to a function and have it access and modify the correct values in memory. Personally would of liked to see two-dimensional arrays for this code, but I am assuming that there is a good reason.

Upvotes: 7

Views: 636

Answers (3)

John
John

Reputation: 31

malloc(M*sizeof(double *)) says: "Give me a pointer to M double pointers." malloc(N*sizeof(double)) says: "Give me a pointer to N doubles." Now notice the bug:

for (i = 0; i < N; i++) {
    A[i]= ...;
}

A points to an array of M double pointers, but you are writing N entries into it (where each entry is a pointer to N doubles). If M > N you waste space, and if M < N you use space that you haven't asked permission to write to.

Upvotes: 2

Guntram Blohm
Guntram Blohm

Reputation: 9819

Yes, double data = *(*(A + 3) + 2); would work, and access the "red" double.

I guess your professor will tell you soon that A[3][2] works as well, is much easier to read, and preferable to *(*(A + 3) + 2);

Lesson learned (not yet, but what your professor is trying to teach to you): in C, multidimensional arrays are not something like 'a table with N columns and M rows', in C, all arrays are really pointers, and multidimensional arrays are implemented as pointers to pointers. Whenever your write A[3][2], *(*(A + 3) + 2)is what really happens internally. This, in turn, explains why you can't allocate a N*M matrix in one statement; you have to allocate the "row pointers" first, then allocate the "columns" for each of the row pointer.

Upvotes: 2

Glenn Teitelbaum
Glenn Teitelbaum

Reputation: 10333

You can also store this contiguously and just do the math instead of letting the compiler do it for you

So:

double * A = malloc (M * N * sizeof(double));

double get(double * what, cur_x, cur_y, max_x, max_y)
{
    return *(what+cur_x*max_y+cur_y);
}

this will save all the indirection since you know the size

If you don't need to allocate sizes dynamically this is what

double A[17][14] will do for you on the stack

Upvotes: 3

Related Questions