# I don't understand the following..

Discussion in 'C Programming' started by mt, Aug 4, 2011.

1. ### mtGuest

I am trying to understand the following code and I am having some
problems..

1. What is the meaning of double*** pdata? Why the need to declare a
pointer to a pointer to a pointer?
2. same thing for int*** pmask

static int
{ int i;
double** data;
data = malloc(nrows*sizeof(double*));
if(!data) return 0;
{ free(data);
return 0;
}
for (i = 0; i < nrows; i++)
{ data = malloc(ncols*sizeof(double));
if(!data) break;
{ free(data);
break;
}
}
if (i==nrows) /* break not encountered */
{ *pdata = data;
return 1;
}
*pdata = NULL;
nrows = i;
for (i = 0; i < nrows; i++)
{ free(data);
}
free(data);
return 0;
}

mt, Aug 4, 2011

2. ### NobodyGuest

On Thu, 04 Aug 2011 12:48:26 -0700, mt wrote:

> I am trying to understand the following code and I am having some
> problems..
>
> 1. What is the meaning of double*** pdata?

It means that pdata is a pointer to a pointer to a pointer to a double.

> Why the need to declare a pointer to a pointer to a pointer?
> 2. same thing for int*** pmask
> Please elucidate this for me.

The function allocates a pair of what are effectively two-dimensional
arrays, in the sense that elements are accessed as data[row][col] and
mask[row][col]. data[row][col] is a double, so data[row] is a pointer to
double and data is a pointer to pointer to double.

In order to return these pointers to the caller, the function accepts
arguments which are pointers to where to store the pointers.

Nobody, Aug 4, 2011

3. ### Jens Thoms ToerringGuest

mt <> wrote:
> I am trying to understand the following code and I am having some
> problems..

> 1. What is the meaning of double*** pdata? Why the need to declare a
> pointer to a pointer to a pointer?
> 2. same thing for int*** pmask
> Please elucidate this for me.

> static int
> { int i;
> double** data;
> data = malloc(nrows*sizeof(double*));
> if(!data) return 0;
> { free(data);
> return 0;
> }
> for (i = 0; i < nrows; i++)
> { data = malloc(ncols*sizeof(double));
> if(!data) break;
> { free(data);
> break;
> }
> }
> if (i==nrows) /* break not encountered */
> { *pdata = data;
> return 1;
> }

<Further error handling snipped>

Basically, what this code is meant to do is to create two arrays
of pointers, with each of the pointers in the first array poin-
ting to an array of doubles and in the second to an array of ints.
(this could be e.g. an implementation of two matrices when using
fixed sized, two-dimensional arrays won't do for whatever reasons).

But the resulting pointers (to array of pointers), namely 'data'
and 'mask' only exist in that function. How to return them to
the caller? You can't pass their addresses back via the single
return value, and the return value is used for error signaling
anyway. Since passing arguments to functions in C is always by
value, you can't pass the pointers you wan't to be set to the
function - in that case all the function would get would be
copies of those pointers and modifying them wouldn't change
anything about the values the arguments have outside of the
function. So the way to go is to pass two pointers to the
pointers to the function that then get set within the function
(to the values of 'data' and 'mask'). In the caller you thus
would do something like

double **a;
int **b;

makedatamask( numRows, numCols, &a, &b );

I.e. 'a' and 'b' are, like 'data' and 'mask' in the function,
pointers to pointers. And in order to allow modification of
what 'a' and 'b' point to within the function a pointer to
each of them gets passed. Thus you end up with a triple in-
direction.

There's actually no more to it then when you have to pass a
simple integer to a function that is to be modified within
the function. You could have (as contrived example)

void set_a( int *a ) { *a = 17; }

int x;
set_a( &x );

Now 'x' will be set to 17.

The principle is exactly the same as in your case: in order
to have 'x' modified in the function (and the change being
visible in the caller) you need to pass a pointer to what
you want to modify.

The only thing that makes you're code a bit more "hairy" ist
that you want to have something modified that is already a
pointer to a pointer, thus you have to pass a pointer to a
pointer to a pointer.
Regards, Jens
--
\ Jens Thoms Toerring ___
\__________________________ http://toerring.de

Jens Thoms Toerring, Aug 4, 2011
4. ### John GordonGuest

In <> mt <> writes:

> I am trying to understand the following code and I am having some
> problems..

> 1. What is the meaning of double*** pdata? Why the need to declare a
> pointer to a pointer to a pointer?
> 2. same thing for int*** pmask
> Please elucidate this for me.

In general, if you want to pass an object into a function and have the
function change that object's value, you must pass a pointer-to-the-object
instead of passing the object directly.

For example, this won't work:

void set_value_to_seven(int i)
{
i = 7;
}

int main(void)
{
int x = 5;
set_value_to_seven(x);
printf("x is now %d\n"); // will print "x is now 5"
}

However, this will work:

void set_value_to_seven(int *i)
{
*i = 7;
}

int main(void)
{
int x = 5;
set_value_to_seven(&x);
printf("x is now %d\n"); // will print "x is now 7"
}

Along similar lines, if you want to pass a pointer into a function which
malloc's space for the pointer, it won't work if you pass it directly:

void allocate_ten_ints(int *i)
{
i = malloc(10 * sizeof(int));
}

int main(void)
{
int *x = NULL;
allocate_ten_ints(x);
x[0] = 5; // will crash because i is still NULL
}

But it will work if you pass a pointer-to-the-pointer:

void allocate_ten_ints(int **i)
{
*i = malloc(10 * sizeof(int));
}

int main(void)
{
int *x = NULL;
allocate_ten_ints(&x);
x[0] = 5; // will work
}

Look closely at these lines in makedatamask:

if (i==nrows) /* break not encountered */
{ *pdata = data;
return 1;
}
*pdata = NULL;

This function wants to modify the value of pdata -- either by setting it
to point to data, or by setting it point to NULL. Therefore the caller
must pass a pointer-to-pdata. I'm assuming pdata is declared like this

double **pdata;

Therefore, since the caller wants makedatamask to change pdata's value,
it must pass a pointer-to-pdata, so makedatamask gets an argument of
type "double ***".

--
John Gordon A is for Amy, who fell down the stairs
B is for Basil, assaulted by bears
-- Edward Gorey, "The Gashlycrumb Tinies"

John Gordon, Aug 4, 2011
5. ### Paul NGuest

On Aug 4, 8:48 pm, mt <> wrote:
> I am trying to understand the following code and I am having some
> problems..
>
> 1. What is the meaning of double*** pdata? Why the need to declare a
> pointer to a pointer to a pointer?

Other people have answered this, but I'll have a go as well.

Let's take it a bit at a time.

> { data = malloc(ncols*sizeof(double));

data points at some memory that stores ncols doubles. This memory
is alloocated using malloc but we are treating it a bit like an array
of doubles. So data has type double *.

> data = malloc(nrows*sizeof(double*));

We are also treating data like an array. It's an array of things like
data. So data itself has a type of double **.

> static int

....
> { *pdata = data;

Here we want to pass the value of data out of the routine, as well as
the value of mask. The function can only have one return value, and
we're using that to say whether the function succeeded or not. So to
pass the value of data out, we pass in a pointer telling the function
where to put the value. That pointer is pdata, and as data has type
double **, pdata has type double ***.

Hope that helps...
Paul.

Paul N, Aug 10, 2011