Output of the printf(a,*a,**a) where a is of type int [][][]

N

Nikhil Bokare

#include<stdio.h>

int main()
{
int a[3][3][3];
printf("%d %d %d %d",a,*a,**a,&a);
}

I tried the above code and got the same value for a, *a , **a and &a.
Can anyone please tell me the reason behind such a behavior?
 
W

Walter Roberson

Nikhil Bokare said:
#include<stdio.h>
int main()
{
int a[3][3][3];
printf("%d %d %d %d",a,*a,**a,&a);
}
I tried the above code and got the same value for a, *a , **a and &a.
Can anyone please tell me the reason behind such a behavior?

You should not be printing out pointers with a %d format. A
pointer might (or might not) occupy more storage than an int,
so if you use a %d format you might be printing out only part
of the address of the pointer. It is not uncommon for pointers
to be longer than int; it is more common for pointers to -happen-
to be the same size as long, but that is not guaranteed.
You can use a %p format to write out a pointer to void
(so be sure to cast the pointer to (void *) in the argument list,
as pointers to different types may have different sizes.)

Also, you have specified that your main returns int and yet
you have not returned any value from main(). That will work in C99
but has undefined behaviour in C90.
 
R

Richard Heathfield

Nikhil Bokare said:
#include<stdio.h>

int main()
{
int a[3][3][3];
printf("%d %d %d %d",a,*a,**a,&a);
}

I tried the above code and got the same value for a, *a , **a and &a.

They can't have the same value, because they don't have the same type. a
has type int[3][3][3], *a has type int[3][3], **a has type int[3], and &a
has type (int *)[3][3][3]. None of these is type int, so %d is
inappropriate as a format specifier (and indeed the behaviour if you do
this is undefined). Since printf lacks format specifiers for the
above-mentioned types, a conversion is required, and the most obvious way
to do this is to cast to void *, which of course discards the type
information, so when you correct your program to use casts-to-void* and %p
instead of %d, you shouldn't necessarily expect to see different values.
Can anyone please tell me the reason behind such a behavior?

Mu.
 
B

Ben Pfaff

Nikhil Bokare said:
int main()
{
int a[3][3][3];
printf("%d %d %d %d",a,*a,**a,&a);

You should use %p to print pointers. To be really correct, you
should also cast all of these values to void *.
}

I tried the above code and got the same value for a, *a , **a and &a.
Can anyone please tell me the reason behind such a behavior?

All of those expressions point to the same byte. It's just in
their types that they have some differences.
 
K

Keith Thompson

Nikhil Bokare said:
#include<stdio.h>

int main()
{
int a[3][3][3];
printf("%d %d %d %d",a,*a,**a,&a);
}

I tried the above code and got the same value for a, *a , **a and &a.
Can anyone please tell me the reason behind such a behavior?

You're lucky (or unlucky) that the program worked at all. The "%d"
format requires an argument of type int. If you give it anything
else, you invoke undefined behavior. You're probably getting
meaningful results on your implementation, but there are no guarantees.

If you want to print a pointer value, use "%p" and convert the
argument to void*.

You should also terminate your output with a newline ("\n") and return
a value from main(); "return 0;" is usually the right thing.

Getting to what you're really asking about, you should read section 6
of the comp.lang.c FAQ, <http://www.c-faq.com/>. If you're still
confused after that, feel free to come back with more specific
questions.
 
N

Nikhil Bokare

Thanks for pointing out my mistakes.
This is my edited program:

#include<stdio.h>

int main()
{
int a[3][3][3];
printf("%p %p %p %p",a,*a,**a,&a);
return 0;
}

Its still printing the same value for all of them. How does it happen??
 
J

John Bode

Thanks for pointing out my mistakes.
This is my edited program:

#include<stdio.h>

int main()
{
int a[3][3][3];
printf("%p %p %p %p",a,*a,**a,&a);
return 0;

}

Its still printing the same value for all of them. How does it happen??

Because all of those expressions evaluate to the same location. The
address of an array is the same as the address of the first element of
the array. The *types* of each expression are different (int (*)[3]
[3], int (*)[3], int *, and int (*)[3][3][3], respectively), but they
all refer to the same location.
 
R

Richard Heathfield

Nikhil Bokare said:
Thanks for pointing out my mistakes.
This is my edited program:

#include<stdio.h>

int main()
{
int a[3][3][3];
printf("%p %p %p %p",a,*a,**a,&a);

That line should be:

printf("%p %p %p %p",(void *)a,(void *)*a,(void *)**a,(void *)&a);
return 0;
}

Its still printing the same value for all of them. How does it happen??

They have different types, as I explained before, so they have different
values, as I explained before. The casts to void * are required, as I
explained before. Because the casts to void * discard type information,
the differences between the values are also being discarded.

Here's a real world parallel question:

"I used a GPS to find out the location of an oxygen atom, a water molecule,
and a water spillage on a kitchen table, and the GPS gave the same
location for all three. Why?"

Obviously, these are three very different things. Equally obviously,
there's no particular reason why they shouldn't be in precisely the same
place.
 
K

Keith Thompson

Richard Heathfield said:
Nikhil Bokare said:
#include<stdio.h>

int main()
{
int a[3][3][3];
printf("%d %d %d %d",a,*a,**a,&a);
}

I tried the above code and got the same value for a, *a , **a and &a.

They can't have the same value, because they don't have the same type. a
has type int[3][3][3], *a has type int[3][3], **a has type int[3], and &a
has type (int *)[3][3][3]. None of these is type int, so %d is
inappropriate as a format specifier (and indeed the behaviour if you do
this is undefined). Since printf lacks format specifiers for the
above-mentioned types, a conversion is required, and the most obvious way
to do this is to cast to void *, which of course discards the type
information, so when you correct your program to use casts-to-void* and %p
instead of %d, you shouldn't necessarily expect to see different values.

The object ``a'' has type int[3][3][3], but the expression ``a'', in
this context, has type int(*)[3][3], or pointer to array 3 of array 3
of int; that's the type of the argument that's being passed to printf.

Similarly, the expression ``*a'' has type int(*)[3], the expression
``**a'' has type int*, and the expression ``&a'' has type
int(*p)[3][3][3]. (I *think* I got all those right; someone will
certainly correct me if I didn't.)

Certainly none of these has type int, so "%d" is the wrong format.

Here's my version of the OP's program, adding ***a to the mix:

#include<stdio.h>

int main(void)
{
int a[3][3][3] = {0};
int (*b)[3][3] = a;
int (*c)[3] = *a;
int *d = **a;
int e = ***a;
int (*f)[3][3][3] = &a;

printf("%p %p %p %d %p\n",
(void*)b, (void*)c, (void*)d, e, (void*)f);
return 0;
}
 
K

Kenneth Brody

Nikhil said:
Thanks for pointing out my mistakes.
This is my edited program:

#include<stdio.h>

int main()
{
int a[3][3][3];
printf("%p %p %p %p",a,*a,**a,&a);
return 0;
}

Its still printing the same value for all of them. How does it happen??

Given the definition of "a":

int a[3][3][3];

What do the following actually mean:

a
*a
**a
&a

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 
K

Keith Thompson

Nikhil Bokare said:
Thanks for pointing out my mistakes.
This is my edited program:

#include<stdio.h>

int main()
{
int a[3][3][3];
printf("%p %p %p %p",a,*a,**a,&a);
return 0;
}

Its still printing the same value for all of them. How does it happen??

Read section 6 of the comp.lang.c FAQ.
 
C

CBFalconer

Nikhil said:
#include<stdio.h>

int main() {
int a[3][3][3];
printf("%d %d %d %d",a,*a,**a,&a);
}

I tried the above code and got the same value for a, *a , **a and
&a. Can anyone please tell me the reason behind such a behavior?

It's accurate. Any response is accurate when behaviour is
undefined. Which is the result of lying to printf about the type
of data passed to it.
 
C

CBFalconer

Nikhil said:
Thanks for pointing out my mistakes. This is my edited program:

#include <stdio.h>

int main() {
int a[3][3][3];
printf("%p %p %p %p",a,*a,**a,&a);
return 0;
}

Its still printing the same value for all of them. How does it
happen??

Because you are still lying to printf and getting undefined
behaviour. %p requires a void* parameter. I also fixed your
#include statement.
 
R

Richard Heathfield

Keith Thompson said:

The object ``a'' has type int[3][3][3], but the expression ``a'', in
this context, has type int(*)[3][3], or pointer to array 3 of array 3
of int; that's the type of the argument that's being passed to printf.

Good spot. (Duh@me.) Thanks, Keith.

<snip>
 
B

Bartc

Richard Heathfield said:
Nikhil Bokare said:
#include<stdio.h>

int main()
{
int a[3][3][3];
printf("%d %d %d %d",a,*a,**a,&a);
}
I tried the above code and got the same value for a, *a , **a and &a.

I can't get my head around these either:
a has type int[3][3][3]

Yet you dereference a in your next statement, so a's type must be ref
something.:
*a has type int[3][3]
**a has type int[3]

And again, so it must have been ref ref something (to use Algol68 notation
for a minute).
&a has type (int *)[3][3][3].

Now that one's really got me: &a is a 3D array of ref int? I expected ref
[3][3][3]int.

An array name decomposes to a ref to the first element. Let's work from
there. In A68 mode, the variable is:

[3] [3] [3] int a /* array of array of array of int */

'a' decomposes to a reference to the first element, ie. ref [3] [3] int.
Does it decompose further, although it's not an array anymore? Assume it
does: now it's ref ref [3] int, and once more: ref ref ref int.

And that's just 'a'. *a would be ref ref int, and **a would be ref int, and
***a would be an int (although the OP didn't go that far).

Now you say that **a has type int[3] (or [3]int) and I say **a is ref int.
(Which figures: in int b[3] then b decomposes to ref int when used in an
expression).

If all this is correct, then it's also completely crazy. Typically an
int[3][3][3] would involve no pointers apart from it's static address. Yet
the ***a expression implies there are 3 levels of pointers to dereference!

I suppose they are just there to balance the &&&a[0][0][0] that the array
decomposition rules apply. And I guess *a really means a[0]. Now it almost
starts to make sense. Almost.
 
K

Keith Thompson

CBFalconer said:
Nikhil said:
Thanks for pointing out my mistakes. This is my edited program:

#include <stdio.h>

int main() {
int a[3][3][3];
printf("%p %p %p %p",a,*a,**a,&a);
return 0;
}

Its still printing the same value for all of them. How does it
happen??

Because you are still lying to printf and getting undefined
behaviour. %p requires a void* parameter. I also fixed your
#include statement.

It's true that the above program lies to printf and thereby invokes
undefined behavior. It's also true that one possible consequence of
this undefined behavior is to print the same value four times.

But it's almost certainly *not* true that the program prints the same
value four times *because* it invokes undefined behavior.

In most implementations, the behavior of passing a pointer value of a
type other than void* to printf with a "%p" is exactly the same as the
behavior of passing the same pointer value converted to void*. That's
not guaranteed by the standard, of course, but it's very common. In
the above program with that correction (casting all printf arguments
after the format string to void* -- oh, yes, and adding a trailing
"\n"), I would still expect it to print the same value four times.
I'm not sure whether it's even possible for a conforming
implementation *not* to print the same value four times.

Yes, the program exhibits undefined behavior, and yes, that absolutely
should be fixed, but that doesn't actually explain the behavior, and
there is another explanation. There's nothing wrong with pointing out
the undefined behavior *and then* answering the original question.

In other words, why does *this* program print the same value four
times? (I changed the spaces to new-lines to make it easier to see
that all for values are the same.)

#include <stdio.h>
int main(void)
{
int a[3][3][3];
printf("%p\n%p\n%p\n%p\n", (void*)a, (void*)*a, (void*)**a, (void*)&a);
return 0;
}

(My answer to that is "Read section 6 of the comp.lang.c FAQ".)
 
C

CBFalconer

Keith said:
.... snip ...

Yes, the program exhibits undefined behavior, and yes, that
absolutely should be fixed, but that doesn't actually explain
the behavior, and there is another explanation. There's
nothing wrong with pointing out the undefined behavior *and
then* answering the original question.

Undefined behaviour can do _anything_. No explanation is needed.
 
R

Richard Heathfield

CBFalconer said:
Undefined behaviour can do _anything_.

Agreed, but there's nothing wrong with pointing out the undefined behaviour
*and then* answering the original question.
No explanation is needed.

The OP needed an explanation. The fact that his program was flawed does not
change this.
 
K

Keith Thompson

CBFalconer said:
Keith Thompson wrote:
... snip ...

Undefined behaviour can do _anything_.
True.

No explanation is needed.

Nonsense. It was obvious from the beginning that the OP was
attempting to print the values of a, *a, **a, and &a, and wanted to
know why they all appeared to have the same value. He clearly did
require an explanation (i.e., he came to us for help), and digging
through the undefined behavior to get to what he was actually asking
about was easy enough that several of us managed to do it.

A C program can behave in arbitrarily obnoxious ways in the presence
of undefined behavior. We don't have to do likewise.
 

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

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top