473,395 Members | 1,341 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

**p vs. p[][]

Is p declared as a 2D array, p[m][n], essentially the same as **p? If
I try declararing p in main() as p[m][n] and then pass it as an
argument to a routine (function) with corresponding parameter **p, I
get "incompatible pointer type". If I declare the corresponding
parameter as (*p)[m], it works.

If I declare p in main() as **p and do the double nested for-loops
malloc()'ing one row at a time and then use double indexing, [][], to
access and assign elements malloc{}'ed ealier, it works fine.

So to sum it up, p declared as p[m][n] is not the same as **p
sometimes but is other times?

---John
Nov 17 '08 #1
17 1367
jski wrote:
Is p declared as a 2D array, p[m][n], essentially the same as **p?
No. Why?
If
I try declararing p in main() as p[m][n] and then pass it as an
argument to a routine (function) with corresponding parameter **p, I
get "incompatible pointer type".
Precisely.
If I declare the corresponding
parameter as (*p)[m], it works.
Yes.
If I declare p in main() as **p and do the double nested for-loops
malloc()'ing one row at a time and then use double indexing, [][], to
access and assign elements malloc{}'ed ealier, it works fine.
Yes.
So to sum it up, p declared as p[m][n] is not the same as **p
sometimes but is other times?
It is _never_ the same. You correctly noted that if you declare '**p'
and allocate memory properly, you are able to access your manually-made
array using the 'p[i][j]' syntax. At the same time, if you declare
'q[10][20]', you are also able to access this C-array using 'q[i][j]'.
Based on this you seem to be jumping to conclusion that the 'p' and 'q'
must be "the same" in this case. Your conclusion is incorrect. Despite
the fact that you can use the '[i][j]' on both data structures, the
structures remain different, and the internal semantic meaning of that
'[i][j]' remains different.

Consider, as a loosely related example, these declarations

int a = 0;
double* b = 0;

Note that after these declarations you can increment both objects by
doing '++a' and '++b'. Does that make you conclude that 'int' must be
the same thing as 'double*'? I hope not. Just because you can apply the
same operator(s) to two different objects does not mean that these
objects must be "the same".

The same logic applies to the pair of '[]' operators applied to 'p' and
'q' in my example above. Just because you can apply '[][]' to both 'p'
and 'q' does not mean that 'p' is "the same" as 'q'. What you have in
this case is a 2D array 'q' implemented by using the built-in
array-of-arrays approach, and a 2D array 'p' implemented by using a
"manual" array-of-pointers technique. These two methods of implementing
2D arrays have very little in common internally, which is why you can't
convert one to another.

For more details, you might also want to take a look at some posts in
these search results

http://www.google.com/search?hl=en&r...+array+pointer

--
Best regards,
Andrey Tarasevich
Nov 17 '08 #2
>Is p declared as a 2D array, p[m][n], essentially the same as **p? If

No.

Attempting to get to the "array elements" of **p requires the
existence of pointers-to-type-of-p, which you don't have, so trying
to dereference them is likely to cause trouble (e.g. segfault or
return random crap from somewhere in memory).
>I try declararing p in main() as p[m][n] and then pass it as an
argument to a routine (function) with corresponding parameter **p, I
get "incompatible pointer type". If I declare the corresponding
parameter as (*p)[m], it works.
The use of function parameters declared as x[] instead of *x will
work, but only to one level, because an array as a function argument
is silently turned into a pointer to the first element of the array.
>If I declare p in main() as **p and do the double nested for-loops
malloc()'ing one row at a time and then use double indexing, [][], to
access and assign elements malloc{}'ed ealier, it works fine.
Yes, but what you have there is *NOT* a 2-D array (type p[m][n];),
it's not laid out like a 2-D array, and if you try to pretend it
is one by passing it to a function expecting one, expect disaster.
It's likely to be in N+1 discontiguous pieces. It takes more memory
than a real 2-D array (the memory for the pointers). A real 2-D
array does not work like that. (But just because it's not a real
2-D array, there's nothing wrong with using it - there are even
some advantages. Just don't lie and try to use it as one.)

For a real 2-D array, both the function and the caller of the
function need to agree on the first dimension of the array exactly,
(and for C90, this is a compiled-in constant value: you may NOT
pass in the dimensions at runtime and expect to use it like a real
2-D array) or p[j][k] will pick up the wrong value for j != 0. For
the vector of pointers to 1-D arrays, that isn't an issue, although
you still have to worry about going out of bounds. Here, you can
pass in the dimensions at runtime.
>So to sum it up, p declared as p[m][n] is not the same as **p
sometimes but is other times?
No, it's not the same. Period.
Nov 17 '08 #3
First, thanks for replying. That goes to Andrey as well.

Then the use of (*p)[m] as a parameter (in some routine) and passing p
declared as p[m][n] in main() is technically incorrect, even though it
works?

---John
On Nov 17, 1:56*am, gordonb.16...@burditt.org (Gordon Burditt) wrote:
Is p declared as a 2D array, p[m][n], essentially the same as **p? *If

No. *

Attempting to get to the "array elements" of **p requires the
existence of pointers-to-type-of-p, which you don't have, so trying
to dereference them is likely to cause trouble (e.g. segfault or
return random crap from somewhere in memory).
I try declararing p in main() as p[m][n] and then pass it as an
argument to a routine (function) with corresponding parameter **p, I
get "incompatible pointer type". If I declare the corresponding
parameter as (*p)[m], it works.

The use of function parameters declared as x[] instead of *x will
work, but only to one level, because an array as a function argument
is silently turned into a pointer to the first element of the array.
If I declare p in main() as **p and do the double nested for-loops
malloc()'ing one row at a time and then use double indexing, [][], to
access and assign elements malloc{}'ed ealier, it works fine.

Yes, but what you have there is *NOT* a 2-D array (type p[m][n];),
it's not laid out like a 2-D array, and if you try to pretend it
is one by passing it to a function expecting one, expect disaster.
It's likely to be in N+1 discontiguous pieces. *It takes more memory
than a real 2-D array (the memory for the pointers). *A real 2-D
array does not work like that. *(But just because it's not a real
2-D array, there's nothing wrong with using it - there are even
some advantages. *Just don't lie and try to use it as one.)

For a real 2-D array, both the function and the caller of the
function need to agree on the first dimension of the array exactly,
(and for C90, this is a compiled-in constant value: *you may NOT
pass in the dimensions at runtime and expect to use it like a real
2-D array) or p[j][k] will pick up the wrong value for j != 0. *For
the vector of pointers to 1-D arrays, that isn't an issue, although
you still have to worry about going out of bounds. *Here, you can
pass in the dimensions at runtime.
So to sum it up, p declared as p[m][n] is not the same as **p
sometimes but is other times?

No, it's not the same. *Period.
Nov 17 '08 #4
jski wrote:
First, thanks for replying. That goes to Andrey as well.

Then the use of (*p)[m] as a parameter (in some routine) and passing p
declared as p[m][n] in main() is technically incorrect, even though it
works?
No. It's correct.
In a declaration,
int (*K)[m];
K is a pointer to an array of m number of int elements.
If you also have
int p[m][n];
then you could assign the address of p[x] to K:
K = p + x;

On Nov 17, 1:56 am, gordonb.16...@burditt.org (Gordon Burditt) wrote:
>>Is p declared as a 2D array, p[m][n], essentially the same as **p? If
No.

--
pete
Nov 17 '08 #5
pete <pf*****@mindspring.comwrites:
jski wrote:
>First, thanks for replying. That goes to Andrey as well.

Then the use of (*p)[m] as a parameter (in some routine) and passing p
declared as p[m][n] in main() is technically incorrect, even though it
works?

No. It's correct.
In a declaration,
int (*K)[m];
K is a pointer to an array of m number of int elements.
If you also have
int p[m][n];
then you could assign the address of p[x] to K:
K = p + x;
No you couldn't. At p+x you'll find an array n ints, not m ints.

Phil
--
I tried the Vista speech recognition by running the tutorial. I was
amazed, it was awesome, recognised every word I said. Then I said the
wrong word ... and it typed the right one. It was actually just
detecting a sound and printing the expected word! -- pbhj on /.
Nov 17 '08 #6
jski wrote:
Is p declared as a 2D array, p[m][n], essentially the same as **p? If
I try declararing p in main() as p[m][n] and then pass it as an
argument to a routine (function) with corresponding parameter **p, I
get "incompatible pointer type". If I declare the corresponding
parameter as (*p)[m], it works.
May I point out that (*p)[m] is a pointer to an array[m] of int, not an
array[m] of pointer to int. If you pass
int **p;
to the function with prototype
int foo(int (*p)[m]);
it will work, but you're really getting a pointer to a "flat" array.
Unless you have some particular reason for wanting this, I'd use
int foo(int *p[m]);
which decays to a pointer to pointer to int and better reflects the
underlying structure of p.

If your real question is "How do I pass a real two-dimensional array to
a function?", my choice would be to declare foo as
int foo(int p[m][n]);
which says, definitely, that foo is a two dimensional array. Now, that
decays to:
int foo(int (*p)[n]);
but is better documentation if you are actually passing 2d arrays.

I don't know what you're trying to do, but real two-dimensional arrays
are not as flexible as arrays of pointers. They aren't interchangeable,
so you need to choose one and use it consistently.
Nov 17 '08 #7
jski wrote:
Then the use of (*p)[m] as a parameter (in some routine) and passing p
declared as p[m][n] in main() is technically incorrect, even though it
works?
What do you mean by "works"? The compiler should complain. And it
doesn't really "work", if you test it carefully.

What you can do is pass a 'p[m][n]' array as a '(*p)[n]' (note 'n'
instead of 'm'). That would be technically correct and that would work.

--
Best regards,
Andrey Tarasevich
Nov 17 '08 #8
Phil Carmody wrote:
pete <pf*****@mindspring.comwrites:
>jski wrote:
>>First, thanks for replying. That goes to Andrey as well.

Then the use of (*p)[m] as a parameter (in some routine) and passing p
declared as p[m][n] in main() is technically incorrect, even though it
works?
No. It's correct.
In a declaration,
int (*K)[m];
K is a pointer to an array of m number of int elements.
If you also have
int p[m][n];
then you could assign the address of p[x] to K:
K = p + x;

No you couldn't. At p+x you'll find an array n ints, not m ints.
Thank you. I got that mixed up.

Each element of p, is an array of n int.
Given:
int p[m][n];
to be able to assign the first element of p, to K,
you would need to have
int (*K)[n];
instead of
int (*K)[m];

--
pete
Nov 17 '08 #9
jski <jc**********@gmail.comwrites:
Is p declared as a 2D array, p[m][n], essentially the same as **p?
[...]

As others have said, no.

Read section 6 of the comp.lang.c FAQ, http://www.c-faq.com/; it
covers arrays and pointers.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Nov 17 '08 #10
jski wrote:
>
.... snip ...
>
So to sum it up, p declared as p[m][n] is not the same as **p
sometimes but is other times?
No. p[m][n] declares a chunk of memory of size (m)*(n)*sizeof
p[0][0], which can hold n entries each of m items of sizeof
p[0][0]. **p declares a single instance of a pointer to a pointer
to an item of type p. There is a large difference. The type that
precedes those declarations establishes the type of p[0][0].

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Nov 17 '08 #11
On Mon, 17 Nov 2008 00:38:39 -0800 (PST), jski
<jc**********@gmail.comwrote:
>First, thanks for replying. That goes to Andrey as well.

Then the use of (*p)[m] as a parameter (in some routine) and passing p
declared as p[m][n] in main() is technically incorrect, even though it
works?
No, it doesn't work. Using (*p)[n] would work. And this is very
technically correct.

The key you seem to be missing is how an expression with array type is
processed. Ignoring the exceptions (which don't apply in this case),
an expression with array type is automatically converted (by the
compiler) to the address of the first element of the array with type
pointer to array element type.

If you have an array of type T defined as p[m][n], you must realize
that p is an array of m arrays of n objects of type T. When you pass
p as an argument to a function, as in func(p), then that argument is
an expression with array type. It is automatically converted to the
address of the first element (&p[0]) with type pointer to array of n
objects of type T. The syntax for a pointer of this type is (*)[n].

The end result is that the two declarations of your function
func(T p[m][n]);
and
func(T (*p)[n]);
are identical in every respect as far as the language is concerned.

I personally find the first easier to use but the second has the
advantage of providing a very obvious reminder that while you are
attempting to pass an array the function actually receives a pointer.

--
Remove del for email
Nov 18 '08 #12
On Mon, 17 Nov 2008 08:10:52 -0600, Trent Josephsen
<tj******@peoplepc.comwrote:
>jski wrote:
>Is p declared as a 2D array, p[m][n], essentially the same as **p? If
I try declararing p in main() as p[m][n] and then pass it as an
argument to a routine (function) with corresponding parameter **p, I
get "incompatible pointer type". If I declare the corresponding
parameter as (*p)[m], it works.

May I point out that (*p)[m] is a pointer to an array[m] of int, not an
array[m] of pointer to int. If you pass
int **p;
to the function with prototype
int foo(int (*p)[m]);
This is a constraint violation that requires a diagnostic.
>it will work, but you're really getting a pointer to a "flat" array.
No it will not work.
>Unless you have some particular reason for wanting this, I'd use
int foo(int *p[m]);
This is completely wrong. It says you have an array of pointers which
is not the case at all.
>which decays to a pointer to pointer to int and better reflects the
underlying structure of p.
p does not contain any pointers at all.
>
If your real question is "How do I pass a real two-dimensional array to
a function?", my choice would be to declare foo as
int foo(int p[m][n]);
which says, definitely, that foo is a two dimensional array. Now, that
decays to:
int foo(int (*p)[n]);
but is better documentation if you are actually passing 2d arrays.

I don't know what you're trying to do, but real two-dimensional arrays
are not as flexible as arrays of pointers. They aren't interchangeable,
so you need to choose one and use it consistently.
--
Remove del for email
Nov 18 '08 #13
CBFalconer <cb********@yahoo.comwrites:
jski wrote:
>>
... snip ...
>>
So to sum it up, p declared as p[m][n] is not the same as **p
sometimes but is other times?

No. p[m][n] declares a chunk of memory of size (m)*(n)*sizeof
p[0][0], which can hold n entries each of m items of sizeof
p[0][0].
I think you meant "m entries each of n items". Of course there *are*
n entries of m items in there too, but these are not contiguous
(unless m == 1) so it would be odd (and confusing to a beginner) to
single them out.

--
Ben.
Nov 18 '08 #14
Barry Schwarz wrote:
On Mon, 17 Nov 2008 08:10:52 -0600, Trent Josephsen
<tj******@peoplepc.comwrote:
>May I point out that (*p)[m] is a pointer to an array[m] of int, not an
array[m] of pointer to int. If you pass
int **p;
to the function with prototype
int foo(int (*p)[m]);

This is a constraint violation that requires a diagnostic.
>it will work, but you're really getting a pointer to a "flat" array.

No it will not work.
You're quite right. Sorry about that.
>
>Unless you have some particular reason for wanting this, I'd use
int foo(int *p[m]);

This is completely wrong. It says you have an array of pointers which
is not the case at all.
In a function prototype, an array of pointers is the same thing as a
pointer to pointer. I'm thinking of
int main(int argc, char *argv[]);
which is functionally equivalent to
int main(int argc, char **argv);
but serves as a reminder that I'm using argv as an array, not "just" a
pointer. Right?
>
>which decays to a pointer to pointer to int and better reflects the
underlying structure of p.

p does not contain any pointers at all.
Allow me to clarify.

If I have a data structure in my main code like so:
int **p; /* simulation of two-dimensional array */
p = malloc(4*sizeof *p);
for (i = 0; i < 4; i++) {
p[i] = malloc(3*sizeof *p[i]);
for (j = 0; j < 4; j++) {
p[i][j] = i*i + j;
}
}
this is what the O.P. mentioned in the second part of his post. In this
case, I do have an "array" of pointers, and p does "contain" pointers,
but only in the sense that p is the functional equivalent of an array of
pointers. Naturally there are several other ways to use p, and I didn't
explicitly say where I was going, so I am willing to take blame for poor
communication here.
Nov 18 '08 #15
One more parallel, unless it's just a lucky gcc coincidence, but if I
declare a 2D array and then treat it as a pointer to a pointer (e.g.,
**p) and access and assign elements via pointer arithmetic:

float p[12][1];
for ( i = 0; i < 12; i++ )
for ( j = 0; j < 12; j++ )
*( *(p+i) + j) = (float)( i * 12 + j );
it works.

---John
On Nov 17, 1:41*am, Andrey Tarasevich <andreytarasev...@hotmail.com>
wrote:
jski wrote:
Is p declared as a 2D array, p[m][n], essentially the same as **p? *

No. Why?
If
I try declararing p in main() as p[m][n] and then pass it as an
argument to a routine (function) with corresponding parameter **p, I
get "incompatible pointer type".

Precisely.
If I declare the corresponding
parameter as (*p)[m], it works.

Yes.
If I declare p in main() as **p and do the double nested for-loops
malloc()'ing one row at a time and then use double indexing, [][], to
access and assign elements malloc{}'ed ealier, it works fine.

Yes.
So to sum it up, p declared as p[m][n] is not the same as **p
sometimes but is other times?

It is _never_ the same. You correctly noted that if you declare '**p'
and allocate memory properly, you are able to access your manually-made
array using the 'p[i][j]' syntax. At the same time, if you declare
'q[10][20]', you are also able to access this C-array using 'q[i][j]'.
Based on this you seem to be jumping to conclusion that the 'p' and 'q'
must be "the same" in this case. Your conclusion is incorrect. Despite
the fact that you can use the '[i][j]' on both data structures, the
structures remain different, and the internal semantic meaning of that
'[i][j]' remains different.

Consider, as a loosely related example, these declarations

* *int a = 0;
* *double* b = 0;

Note that after these declarations you can increment both objects by
doing '++a' and '++b'. Does that make you conclude that 'int' must be
the same thing as 'double*'? I hope not. Just because you can apply the
same operator(s) to two different objects does not mean that these
objects must be "the same".

The same logic applies to the pair of '[]' operators applied to 'p' and
'q' in my example above. Just because you can apply '[][]' to both 'p'
and 'q' does not mean that 'p' is "the same" as 'q'. What you have in
this case is a 2D array 'q' implemented by using the built-in
array-of-arrays approach, and a 2D array 'p' implemented by using a
"manual" array-of-pointers technique. These two methods of implementing
2D arrays have very little in common internally, which is why you can't
convert one to another.

For more details, you might also want to take a look at some posts in
these search results

http://www.google.com/search?hl=en&r...is+torek+array...

--
Best regards,
Andrey Tarasevich
Nov 18 '08 #16
Top posting bad. I fact, you don't need to quote anything since this
is a fresh self-contain question.

jski <jc**********@gmail.comwrites:
One more parallel, unless it's just a lucky gcc coincidence, but if I
declare a 2D array and then treat it as a pointer to a pointer (e.g.,
**p) and access and assign elements via pointer arithmetic:
No, you are not treating it as a "pointer to a pointer".
float p[12][1];
I image you intended a second 12 there.
for ( i = 0; i < 12; i++ )
for ( j = 0; j < 12; j++ )
*( *(p+i) + j) = (float)( i * 12 + j );
it works.
p[i] is defined as *(p + i) so that is not surprising. p (in this
context) is a pointer to an array (the first of 12) and adding i
yields a pointer i arrays further along.

The * takes this pointer and yields an array (the i'th sub-array).
This array is converted to a pointer to its first element (as usually
happens in all but a few special cases) and to this pointer we add j
to get a pointer to the j'th element. The * finally yields the float
you want.

A pointer to an array (p in this case) behaves very much like a
pointer to a pointer because of this automatic conversion but it helps
to keep the concepts separate.

--
Ben.
Nov 18 '08 #17
jski wrote:
One more parallel, unless it's just a lucky gcc coincidence, but if I
declare a 2D array and then treat it as a pointer to a pointer (e.g.,
**p) and access and assign elements via pointer arithmetic:

float p[12][1];
for ( i = 0; i < 12; i++ )
for ( j = 0; j < 12; j++ )
*( *(p+i) + j) = (float)( i * 12 + j );
it works.
In this case you are not really treating it any different from your
original message. In C, the '[]' operator is just a shorthand for the
combination of unary '*' and binary '+', i.e. 'p[i]' is just a shorthand
for '*(p + i)'. Note, that '*(p + i)' works for pointer 'p' as well as
for array 'p', although the semantics is different. A pointer can be
used in this expression immediately. But in case of an array, it is
implicitly converted to a temporary pointer first (array-to-pointer
conversion) and only then used in the expression.

And 'p[i][j]' is just a shorthand for '*(*(p + i) + j)', which is
exactly what you have in your code above. What I said in my previous
message still immediately applies to this code as well.

And no, you are not treating a 2D array as a "pointer to a pointer" in
this case. You are still treating it as an "array of arrays". Both '*'
operators in '*(*(p + i) + j)' are applied to the results of
array-to-pointer conversions applied to these arrays.

--
Best regards,
Andrey Tarasevich
Nov 18 '08 #18

This thread has been closed and replies have been disabled. Please start a new discussion.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.