Question about pointers and multi-dimension arrays


D

DiAvOl

Hello everyone, merry christmas!

I have some questions about the following program:

arrtest.c
------------

#include <stdio.h>

int main(int agc, char *argv[]) {
int array2d[2][2] = { {1,2} , {3,4} };
int (* arrp)[2] = array2d;

printf("&array2d = %p\tarray2d = %p\t*array2d = %p\n", &array2d,
array2d, *array2d);
printf("&arrp = %p\tarp = %p\t*arrp = %p\t**arp = %d\n", &arrp,
arrp, *arrp, **arrp);

return 0;
}

When I compile and run the program I get the following results:

&array2d = 0xbfd9e880 array2d = 0xbfd9e880 *array2d = 0xbfd9e880
&arrp = 0xbfd9e890 arrp = 0xbfd9e880 *arrp =
0xbfd9e880 **arrp = 1

My questions are:

Why is the address of array2d (&array2d), the value (array2d) and the
contents of that value (*array2d) all the same ? (0xbfd9e880)

array2d contains the value: 0xbfd9e880. When dereferenced (*array2d)
it gives the same value, 0xbfd9e880
But when the same address is dereferenced again (**array2d) it gives
an integer (1) and not an address like above.

How does the compiler "understands" if it should return a pointer or
the value stored in that address?

How does the compiler stores array variables so that &array == array ?

Thanks for your time, I hope you will understand my questions
 
Ad

Advertisements

R

Richard Heathfield

DiAvOl said:

int array2d[2][2] = { {1,2} , {3,4} };

Why is the address of array2d (&array2d), the value (array2d) and the
contents of that value (*array2d) all the same ?

They aren't the same, because they have different types. &array2d has type
int (*)[2][2], array2d has type int[2][2] (which is converted into a value
of type int(*)[2] when used in value contexts), and *array2d has type
int[2] (which is converted into a value of type int * when used in value
contexts).
 
M

Malcolm McLean

DiAvOl said:
int main(int agc, char *argv[]) {
int array2d[2][2] = { {1,2} , {3,4} };
int (* arrp)[2] = array2d;

printf("&array2d = %p\tarray2d = %p\t*array2d = %p\n", &array2d,
array2d, *array2d);
printf("&arrp = %p\tarp = %p\t*arrp = %p\t**arp = %d\n", &arrp,
arrp, *arrp, **arrp);

return 0;
}
The important thing to know about multidimensional arrays in C 89 is that
they are effectively broken. Whilst they can be declared and used, the
syntax needed to do anything much with them, like pass them to other
functions, is too complicated. They also cannot be resized at runtime.

So just forget about them until you are familiar with most of the rest of
the language. Any multi-dimensional array can easily be emulated with a
single dimension.
 
D

DiAvOl

0xbfd9e880 <=== Memory address
------------
| 1 | <=== Contents
------------

My point is, how can the address 0xbfd9e880 hold both an address and a
number ?

When array2d is dereferenced (*array2d) it should return the contents
of it's value (contents of memory location 0xbfd9e880) but it returns
the same address.

When array2d is double dereferenced (**array2d) it's the same as
*(*array2d), *array2d as we saw before is the address 0xbfd9e880 so
when it is dereferenced this time, it returns an integer.

How can the compiler determine when to return an integer and when to
return the address?

Thanks for your fast reply
 
R

Richard Heathfield

Malcolm McLean said:

The important thing to know about multidimensional arrays in C 89 is that
they are effectively broken.

I disagree. They work just fine if you treat them right.
 
R

Richard Heathfield

DiAvOl said:
0xbfd9e880 <=== Memory address

Please switch, if necessary, to a non-proportional font such as Courier. It
will make the following diagram clearer.

| M |
| a +-----+-----+-----+-----+---
| i | 1 | 3 | 5 | 7 |
| n X-----+-----+-----+-----+--
| High Street
| R +-----+-----+-----+-----+---
| o | 2 | 4 | 6 | 8 |
| a +-----+-----+-----+-----+-
| d |

See the X? It represents a single point on the Earth's surface. We can
think of this point as "1 High Street" if we like - so in that sense it
can be thought of as an address. On the other hand, it's also the corner
of a living room. On the other other hand, it's also a brick. On the other
other other hand, it's also a Carbon atom. The question "what will we find
at X?" depends on the level at which we're asking the question.

When array2d is dereferenced (*array2d) it should return the contents
of it's value (contents of memory location 0xbfd9e880) but it returns
the same address.

Crank up the magnification on your binoculars, and what you see at X will
change - but it's still at the same place, isn't it?
 
Ad

Advertisements

D

DiAvOl

I perfectly understand what you are saying. I'll try to describe my
question better.

Suppose I am the C compiler and I see the following constructs:

1) printf("%d", *p); // p is an int pointer

I should fetch the address which p contains and find an int value
there.

All fine with this one

2)
Having:

int array2d[2][2] = { {1,2} , {3,4} };

&array2d = 0xbfd9e880 array2d = 0xbfd9e880 *array2d = 0xbfd9e880

I (the compiler) see the construct: printf("%p", *array2d); .

I should fetch the address which array2d contains (0xbfd9e880) and
find an int pointer there. This returns 0xbfd9e880, so the address
0xbfd9e880 contains the int pointer 0xbfd9e880.

Then I see the construct: printf("%d", **array2d);

I should fetch the address which *array2d contains (0xbfd9e880 as we
saw above) and find an int value there

But I saw before that 0xbfd9e880 contains the int pointer 0xbfd9e880
not an int number... I am confused





Thanks very much for your time and example and sorry for my bad
english.
 
R

Ravishankar S

DiAvOl said:
Hello everyone, merry christmas!

I have some questions about the following program:

arrtest.c
------------

#include <stdio.h>

int main(int agc, char *argv[]) {
int array2d[2][2] = { {1,2} , {3,4} };
int (* arrp)[2] = array2d;

printf("&array2d = %p\tarray2d = %p\t*array2d = %p\n", &array2d,
array2d, *array2d);
printf("&arrp = %p\tarp = %p\t*arrp = %p\t**arp = %d\n", &arrp,
arrp, *arrp, **arrp);

return 0;
}

When I compile and run the program I get the following results:

&array2d = 0xbfd9e880 array2d = 0xbfd9e880 *array2d = 0xbfd9e880
&arrp = 0xbfd9e890 arrp = 0xbfd9e880 *arrp =
0xbfd9e880 **arrp = 1

My questions are:

Why is the address of array2d (&array2d), the value (array2d) and the
contents of that value (*array2d) all the same ? (0xbfd9e880)

Here is what I can think of (subject to correction of the experts..)

the typeof(array2d) = "pointer to an array of 2 ints". But array2d is an
r-value , not an l-value. This may be the reason why
&array2d evaluates to the same address even though the typeof(&array2d) ==
"pointer to a pointer to array of 2 ints".
Finally *array2d has the type "array of 2 ints". But in C array is not first
class type and *array2d is not a "lvalue". Thus *array2d evaluates
to the same as array2d.
A case where the expressions have different types , but same values..!
array2d contains the value: 0xbfd9e880. When dereferenced (*array2d)
array2d does not "contain" the value 0xbfd9e880 but rather evaluates to that
value but having the type "pointer to an array of 2 ints".


it gives the same value, 0xbfd9e880
But when the same address is dereferenced again (**array2d) it gives
an integer (1) and not an address like above.
I am not sure how the compiler understands **array2d. Perhaps someone could
help here..
How does the compiler "understands" if it should return a pointer or
the value stored in that address?

How does the compiler stores array variables so that &array == array ?

Thanks for your time, I hope you will understand my questions

You have to read the C FAQ by Steve Summit on Arrays and Pointers for
clarity on "pointers to arrays". I dont have the link handy though..
 
A

army1987

DiAvOl said:
I perfectly understand what you are saying. I'll try to describe my
question better.
You should quote relevant parts of the post you're replying to, to make
context clear.
Suppose I am the C compiler and I see the following constructs:

1) printf("%d", *p); // p is an int pointer

I should fetch the address which p contains and find an int value
there.

All fine with this one Right.
2)
Having:

int array2d[2][2] = { {1,2} , {3,4} };

&array2d = 0xbfd9e880 array2d = 0xbfd9e880 *array2d = 0xbfd9e880

I (the compiler) see the construct: printf("%p", *array2d); .

I should fetch the address which array2d contains (0xbfd9e880) and
find an int pointer there. This returns 0xbfd9e880, so the address
0xbfd9e880 contains the int pointer 0xbfd9e880.

Then I see the construct: printf("%d", **array2d);

I should fetch the address which *array2d contains (0xbfd9e880 as we
saw above) and find an int value there

But I saw before that 0xbfd9e880 contains the int pointer 0xbfd9e880
not an int number... I am confused

A pointer corresponds both to an address and a type. The type determines
how much stuff the address refers to, and how to interpret it.
Supposing an int is four bytes:
+-----------+
|00 00 00 01| 0xbfd9e880
+-----------+
|00 00 00 02| 0xbfd9e884
+-----------+
|00 00 00 03| 0xbfd9e888
+-----------+
|00 00 00 04| 0xbfd9e88c
+-----------+

Now the object declared `int array2d[2][2] = { {1,2} , {3,4} };` is an
array of arrays of ints, and spans 16 bytes. Thus, &array2d has type
"pointer to array of two arrays of two ints", and value 0xbfd9e880. Now,
an array, when is not used as the operand of & (or sizeof, or, in the case
of a string literal, as the initializer of an array of char), evaluates to
a pointer to its first element. Now, the first element of array2d is still
an array, but this time it is an array of ints.
So, array2d evaluates to &array2d[0], which is a pointer equal to &array2d,
except for its type: the former is a pointer to array of arrays of ints,
whereas the latter is a pointer to array of ints.
Now, *array2d what &array2d[0] points to, that is an array of two ints
starting at 0xbfd9e880. Since it is itself an array, it evaluates to a
pointer to its first element. This pointer still has value 0xbfd9e880, but
its type is pointer to int. Dereference it another time and you get the
int contained at that location, i.e. 1.

Resuming: &array2d, array2d, and *array2d all are (or evaluate to)
pointers to objects starting at that address. But the first points to the
whole 2d array (16 bytes), the second points to its first row (8 bytes),
and the third points to its first element (4 bytes, the int 1).
I hope I've been clear.

Nitpick: printf expects "%p" to correspond a pointer to void, that is a
pointer with no type information. You can convert a pointer of another
type to a pointer to void with a cast:
printf("%p\n", (void *)&array2d);
On most modern machines this makes no difference, as all pointers are the
same size. But on older machines pointers to void are larger, so on those
printf("%p\n", &array2d);
tries to read more data it was passed to. According to the C standard, the
latter has undefined behavior, that is the standard allows a program with
it to behave whatever the implementation likes most. Even if nowadays that
is almost always the same thing as the former, the cost of adding the cast
to be safe is so low that there is no reason not to do that.
 
M

murali.marimekala

DiAvOl said:
I perfectly understand what you are saying. I'll try to describe my
question better.

You should quote relevant parts of the post you're replying to, to make
context clear.


Suppose I am the C compiler and I see the following constructs:
1) printf("%d", *p); // p is an int pointer
I should fetch the address which p contains and find an int value
there.
All fine with this one Right.
2)
Having:

int array2d[2][2] = { {1,2} , {3,4} };
&array2d = 0xbfd9e880 array2d = 0xbfd9e880 *array2d = 0xbfd9e880
I (the compiler) see the construct: printf("%p", *array2d); .
I should fetch the address which array2d contains (0xbfd9e880) and
find an int pointer there. This returns 0xbfd9e880, so the address
0xbfd9e880 contains the int pointer 0xbfd9e880.
Then I see the construct: printf("%d", **array2d);
I should fetch the address which *array2d contains (0xbfd9e880 as we
saw above) and find an int value there
But I saw before that 0xbfd9e880 contains the int pointer 0xbfd9e880
not an int number... I am confused

A pointer corresponds both to an address and a type. The type determines
how much stuff the address refers to, and how to interpret it.
Supposing an int is four bytes:
+-----------+
|00 00 00 01| 0xbfd9e880
+-----------+
|00 00 00 02| 0xbfd9e884
+-----------+
|00 00 00 03| 0xbfd9e888
+-----------+
|00 00 00 04| 0xbfd9e88c
+-----------+

Now the object declared `int array2d[2][2] = { {1,2} , {3,4} };` is an
array of arrays of ints, and spans 16 bytes. Thus, &array2d has type
"pointer to array of two arrays of two ints", and value 0xbfd9e880. Now,
an array, when is not used as the operand of & (or sizeof, or, in the case
of a string literal, as the initializer of an array of char), evaluates to
a pointer to its first element. Now, the first element of array2d is still
an array, but this time it is an array of ints.
So, array2d evaluates to &array2d[0], which is a pointer equal to &array2d,
except for its type: the former is a pointer to array of arrays of ints,
whereas the latter is a pointer to array of ints.
Now, *array2d what &array2d[0] points to, that is an array of two ints
starting at 0xbfd9e880. Since it is itself an array, it evaluates to a
pointer to its first element. This pointer still has value 0xbfd9e880, but
its type is pointer to int. Dereference it another time and you get the
int contained at that location, i.e. 1.

Resuming: &array2d, array2d, and *array2d all are (or evaluate to)
pointers to objects starting at that address. But the first points to the
whole 2d array (16 bytes), the second points to its first row (8 bytes),
and the third points to its first element (4 bytes, the int 1).
I hope I've been clear.

Nitpick: printf expects "%p" to correspond a pointer to void, that is a
pointer with no type information. You can convert a pointer of another
type to a pointer to void with a cast:
printf("%p\n", (void *)&array2d);
On most modern machines this makes no difference, as all pointers are the
same size. But on older machines pointers to void are larger, so on those
printf("%p\n", &array2d);
tries to read more data it was passed to. According to the C standard, the
latter has undefined behavior, that is the standard allows a program with
it to behave whatever the implementation likes most. Even if nowadays that
is almost always the same thing as the former, the cost of adding the cast
to be safe is so low that there is no reason not to do that.

Hi ,

I just want to give a small clue to make you understand your problem.

Since, array2d is an double dimension array, If you want to access
array2d you need to deference it double time.
If you deference it once you will get the address.

Its just a clue for you. I hope you can easily analyse the problem.

bye
MMK
 
B

Ben Bacarisse

DiAvOl said:
I perfectly understand what you are saying. I'll try to describe my
question better.
2)
Having:

int array2d[2][2] = { {1,2} , {3,4} };

&array2d = 0xbfd9e880 array2d = 0xbfd9e880 *array2d = 0xbfd9e880

I (the compiler) see the construct: printf("%p", *array2d); .

I should fetch the address which array2d contains (0xbfd9e880) and
find an int pointer there.

No. array2d is an array of two arrays (type int [2][2]). When used
in most contexts it is converted to a pointer to it's first element
(type int(*)[2]). But note, this "first element" is an array so
*array2d denotes an array, not a single int (the type is int [2]).
How is this expression treated when it is passed to printf? Like any
other array-valued expression, it is converted to a pointer to its
first element. Of course, numerically, this looks the same as
array2d, but you could see the difference if you printed the size as
well:

printf("Pointer: %p, size: %zu\n", (void *)array2d, sizeof array2d);
printf("Pointer: %p, size: %zu\n", (void *)*array2d, sizeof *array2d);

[If %zu does not work for you -- it is C99 -- replace with %lu and
cast the sizeof expressions to (unsigned long). I have cast the
pointers to (void *) because that is what %p requires -- it does not
have any impact on the argument above.]

sizeof is one of the special places where the conversion from array to
pointer does *not* happen, so sizeof *array2d is the size of the
(sub-)array and not just the size of a pointer on your system.
 
Ad

Advertisements

D

DiAvOl

so if I'm not mistaken *array2d does NOT fetch (dereference) any
value, it just changes the type of the pointer. Only **array2d really
fetches the value. Is this correct?

Thanks
 
B

Ben Bacarisse

In the context of:

int array2d[2][2];

[Snipping is good, but pleas keep enough context for each message to
stand alone if need be.]
so if I'm not mistaken *array2d does NOT fetch (dereference) any
value, it just changes the type of the pointer. Only **array2d really
fetches the value. Is this correct?

Not quite. The trouble is that "fetch" is not the same as
"dereference". array2d (in most expressions) is converted to a
pointer to an array. The * in *array2d removes the "pointer" part.
I.e. it does do a dereference, but nothing is fetched from anywhere.

It helps to think at the level of the so-called C "abstract machine".
This is not the level of machine addresses and load and stores, but
the level of values and types. At this level, a * always turns a
pointer into the thing to which it points, but if that thing is an
array which needs to be turned into a pointer right away you will not
see any "fetching" associated with the *.
 
B

Barry Schwarz

DiAvOl said:
Hello everyone, merry christmas!

I have some questions about the following program:

arrtest.c
------------

#include <stdio.h>

int main(int agc, char *argv[]) {
int array2d[2][2] = { {1,2} , {3,4} };
int (* arrp)[2] = array2d;

printf("&array2d = %p\tarray2d = %p\t*array2d = %p\n", &array2d,
array2d, *array2d);
printf("&arrp = %p\tarp = %p\t*arrp = %p\t**arp = %d\n", &arrp,
arrp, *arrp, **arrp);

return 0;
}

When I compile and run the program I get the following results:

&array2d = 0xbfd9e880 array2d = 0xbfd9e880 *array2d = 0xbfd9e880
&arrp = 0xbfd9e890 arrp = 0xbfd9e880 *arrp =
0xbfd9e880 **arrp = 1

My questions are:

Why is the address of array2d (&array2d), the value (array2d) and the
contents of that value (*array2d) all the same ? (0xbfd9e880)

Here is what I can think of (subject to correction of the experts..)

the typeof(array2d) = "pointer to an array of 2 ints". But array2d is an

The type of array2d is array of 2 arrays of 2 int. In syntax form, it
is exactly as in the original post, int [2][2]
r-value , not an l-value. This may be the reason why
&array2d evaluates to the same address even though the typeof(&array2d) ==
"pointer to a pointer to array of 2 ints".

The type of &array2d is pointer to array of 2 array of 2 int. In
syntax form, int(*)[2][2].
Finally *array2d has the type "array of 2 ints". But in C array is not first
class type and *array2d is not a "lvalue". Thus *array2d evaluates
to the same as array2d.

No they don't. While they do evaluate to the same address, each has a
distinct type (as you note below). In situations other than the three
exceptions which don't apply here, an expression of array type is
converted to a pointer to the first element of the array with type
pointer to element type. Therefore:

*array2d (which is by definition exactly the same as
array2d[0]) evaluates to &array2d[0][0] with type pointer to int
(int*).

array2d evaluates to &array2d[0] with type pointer to array of
2 int (int(*)[2]).
A case where the expressions have different types , but same values..!

Only in the conceptual sense similar to a double of 1.0 and an int of
1 having the same value.
array2d does not "contain" the value 0xbfd9e880 but rather evaluates to that
value but having the type "pointer to an array of 2 ints".

Pointer to array of 2 array of 2 int.
I am not sure how the compiler understands **array2d. Perhaps someone could
help here..

**array2d is by definition exactly the same as array2d[0][0].
You have to read the C FAQ by Steve Summit on Arrays and Pointers for
clarity on "pointers to arrays". I dont have the link handy though..

www.c-faq.com


Remove del for email
 
D

David Thompson

You have to read the C FAQ by Steve Summit on Arrays and Pointers for
clarity on "pointers to arrays". I dont have the link handy though..
I wouldn't say you absolutely _must_ but it does often help.

Web at http://c-faq.com or the usual places for (big8) FAQs:
news:comp.answers,$group ftp://rtfm.mit.edu http://faqs.org

Chris Torek's http://web.torek.net/c is also good for the particular
topics it covers, which are fewer but does include this one.

- formerly david.thompson1 || achar(64) || worldnet.att.net
 
K

Keith Thompson

Ad

Advertisements

R

Ravishankar S

David Thompson said:
I wouldn't say you absolutely _must_ but it does often help.
I'd say it helps a lot, especially the printed version. For me it put the
array pointer relation in the right prespective
 
Ad

Advertisements

J

John Bode

Hello everyone, merry christmas!

[snip]

How does the compiler stores array variables so that &array == array ?

It's not about how the array variables are stored, but about how
they're treated in various contexts.

In most contexts, when the compiler sees an array identifier or an
expression that evaluates to an array, it implicitly converts the type
of the identifier or expression from "array of T" to "pointer to T",
and converts the value to a pointer to the first element of the array.

So, given the following:

int arr1[N];

wherever the compiler sees "arr1" in the code, it will convert the
type of arr from "N-element array of int" to "pointer to int", and
will set the value to be a pointer to the first element of arr (for
illustration's sake, call it 0x8000).

The exceptions to this rule are when arr1 is an operand of either the
address-of (&) operator or the sizeof operator; instead of returning a
pointer to the first element of the array, the & operator returns a
pointer to the whole array. However, given how C arrays work, these
two things (the pointer to the first element of the array and the
pointer to the array) turn out to be the same *value*. IOW, the
address of "arr1" is the same as the address of "arr1[0]"; the value
is just interpreted differently. So, assuming that the base address
of our array is 0x8000:

&arr == arr

in terms of the *value* of the pointer. However, the *types* are not
equivalent:

typeof &arr1 == int (*)[N] // pointer to N-element array of int
typeof arr1 == int *

Since this is a 1-d array,

typeof *arr1 == int

Bumping this up to multiple dimensions, assume we have the following:

int arr2[N][M];

Again, &arr2 evaluates to a pointer to the whole array and arr2
evaluates to a pointer to the first element of the array. But now,
the type of arr2[0] is no longer an int, but an M-element array of
int. Since the expression *arr2 evaluates to an array type, the same
rules that applied to the identifier arr1 apply to the expression
*arr2; namely, the type of *arr2 is converted from "M-element array of
int" to "pointer to int", and the value of the expression is set to
point to the first element of the array (&arr2[0][0]). Again, the
address of arr2 is the same as the address of arr2[0] which is the
same as the address of arr2[0][0]. It's the types of each expression
that change:

typeof &arr2 == int (*)[N][M]
typeof arr2 == int (*)[M]
typeof *arr2 == int *

Hope that helps (and was minimally correct).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top