Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Explain why this prints the same

Reply
Thread Tools

Explain why this prints the same

 
 
Eric Lilja
Guest
Posts: n/a
 
      12-07-2005
Hello, I'm trying to help someone on a linux-oriented forum. I've taken
his original code and cleaned it up, but I am still wondering about
something. Here's the code:

#include <stdio.h>

int
main(void)
{
int a[][3]={ {1,2,3},{4,5,6,},{7,8,9} };
int *b = (int *)a;
int **c = (int **)a;
int i = 0;
int num_elements = sizeof(a) / sizeof(int);

for(i = 0; i< num_elements; ++i)
printf("*b = %d *c = %d\n", *b++, *c++);

return 0;
}

When compiled I get:
gcc -Wall -W -ansi -pedantic -g -O0 -c -o pointer_wonder.o
pointer_wonder.c
pointer_wonder.c: In function `main':
pointer_wonder.c:13: warning: int format, pointer arg (arg 3)
gcc pointer_wonder.o -o pointer_wonder.exe

The output is:
*b = 1 *c = 1
*b = 2 *c = 2
*b = 3 *c = 3
*b = 4 *c = 4
*b = 5 *c = 5
*b = 6 *c = 6
*b = 7 *c = 7
*b = 8 *c = 8
*b = 9 *c = 9

Why is it same for *b and *c?

/ Eric

 
Reply With Quote
 
 
 
 
pemo
Guest
Posts: n/a
 
      12-07-2005

"Eric Lilja" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) oups.com...
> Hello, I'm trying to help someone on a linux-oriented forum. I've taken
> his original code and cleaned it up, but I am still wondering about
> something. Here's the code:
>
> #include <stdio.h>
>
> int
> main(void)
> {
> int a[][3]={ {1,2,3},{4,5,6,},{7,8,9} };
> int *b = (int *)a;
> int **c = (int **)a;
> int i = 0;
> int num_elements = sizeof(a) / sizeof(int);
>
> for(i = 0; i< num_elements; ++i)
> printf("*b = %d *c = %d\n", *b++, *c++);
>
> return 0;
> }
>
> When compiled I get:
> gcc -Wall -W -ansi -pedantic -g -O0 -c -o pointer_wonder.o
> pointer_wonder.c
> pointer_wonder.c: In function `main':
> pointer_wonder.c:13: warning: int format, pointer arg (arg 3)
> gcc pointer_wonder.o -o pointer_wonder.exe
>
> The output is:
> *b = 1 *c = 1
> *b = 2 *c = 2
> *b = 3 *c = 3
> *b = 4 *c = 4
> *b = 5 *c = 5
> *b = 6 *c = 6
> *b = 7 *c = 7
> *b = 8 *c = 8
> *b = 9 *c = 9
>
> Why is it same for *b and *c?


*b gives you back an int

whereas

*c gives you back an int *

However, the 'values' of each are taken from a.

So, printf would really like a %p (at least) for the third arg.



 
Reply With Quote
 
 
 
 
pemo
Guest
Posts: n/a
 
      12-07-2005

"pemo" <(E-Mail Removed)> wrote in message
news:dn705d$4r6$(E-Mail Removed)...
>
> "Eric Lilja" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed) oups.com...
>> Hello, I'm trying to help someone on a linux-oriented forum. I've taken
>> his original code and cleaned it up, but I am still wondering about
>> something. Here's the code:
>>
>> #include <stdio.h>
>>
>> int
>> main(void)
>> {
>> int a[][3]={ {1,2,3},{4,5,6,},{7,8,9} };
>> int *b = (int *)a;
>> int **c = (int **)a;
>> int i = 0;
>> int num_elements = sizeof(a) / sizeof(int);
>>
>> for(i = 0; i< num_elements; ++i)
>> printf("*b = %d *c = %d\n", *b++, *c++);
>>
>> return 0;
>> }
>>
>> When compiled I get:
>> gcc -Wall -W -ansi -pedantic -g -O0 -c -o pointer_wonder.o
>> pointer_wonder.c
>> pointer_wonder.c: In function `main':
>> pointer_wonder.c:13: warning: int format, pointer arg (arg 3)
>> gcc pointer_wonder.o -o pointer_wonder.exe
>>
>> The output is:
>> *b = 1 *c = 1
>> *b = 2 *c = 2
>> *b = 3 *c = 3
>> *b = 4 *c = 4
>> *b = 5 *c = 5
>> *b = 6 *c = 6
>> *b = 7 *c = 7
>> *b = 8 *c = 8
>> *b = 9 *c = 9
>>
>> Why is it same for *b and *c?

>
> *b gives you back an int
>
> whereas
>
> *c gives you back an int *
>
> However, the 'values' of each are taken from a.
>
> So, printf would really like a %p (at least) for the third arg.
>


So, [I should have added] *c's value is 1, 2, 3, ... where c is an int *
(obviously, you wouldn't want to deref that!



 
Reply With Quote
 
Kenneth Brody
Guest
Posts: n/a
 
      12-07-2005
pemo wrote:
>
> "Eric Lilja" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed) oups.com...
> > Hello, I'm trying to help someone on a linux-oriented forum. I've taken
> > his original code and cleaned it up, but I am still wondering about
> > something. Here's the code:
> >
> > #include <stdio.h>
> >
> > int
> > main(void)
> > {
> > int a[][3]={ {1,2,3},{4,5,6,},{7,8,9} };
> > int *b = (int *)a;
> > int **c = (int **)a;
> > int i = 0;
> > int num_elements = sizeof(a) / sizeof(int);
> >
> > for(i = 0; i< num_elements; ++i)
> > printf("*b = %d *c = %d\n", *b++, *c++);
> >
> > return 0;
> > }
> >
> > When compiled I get:
> > gcc -Wall -W -ansi -pedantic -g -O0 -c -o pointer_wonder.o
> > pointer_wonder.c
> > pointer_wonder.c: In function `main':
> > pointer_wonder.c:13: warning: int format, pointer arg (arg 3)


Note the warning here. ("*c++" is an "int*" type.)

> > gcc pointer_wonder.o -o pointer_wonder.exe
> >
> > The output is:
> > *b = 1 *c = 1

[...]
> > *b = 9 *c = 9
> >
> > Why is it same for *b and *c?

>
> *b gives you back an int
>
> whereas
>
> *c gives you back an int *
>
> However, the 'values' of each are taken from a.


And it happens to be that sizeof(int)==sizeof(int*). Try it on a
system where this is not true, such as an old 16-bit DOS compiler
in large model mode. (sizeof int == 2, and sizeof int* is 4.)

In a test here, I get:

*b = 1 *c = 1
*b = 2 *c = 3
*b = 3 *c = 5
*b = 4 *c = 7
*b = 5 *c = 9
*b = 6 *c = 2013
*b = 7 *c = 2013
*b = 8 *c = 9
*b = 9 *c = 2680

> So, printf would really like a %p (at least) for the third arg.


Though it would still print (basically) the same thing, as *c is
still really an int being treated as int*.


In any case, this probably falls under the "UB" heading, as you are
taking int's and treating them as int*'s.

(Yes, I know the apostrophes don't really belong in the last sentence,
but it makes it more legible, IMHO.)


--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <(E-Mail Removed)>

 
Reply With Quote
 
pemo
Guest
Posts: n/a
 
      12-07-2005

"Kenneth Brody" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> pemo wrote:
>>
>> "Eric Lilja" <(E-Mail Removed)> wrote in message
>> news:(E-Mail Removed) oups.com...
>> > Hello, I'm trying to help someone on a linux-oriented forum. I've taken
>> > his original code and cleaned it up, but I am still wondering about
>> > something. Here's the code:
>> >
>> > #include <stdio.h>
>> >
>> > int
>> > main(void)
>> > {
>> > int a[][3]={ {1,2,3},{4,5,6,},{7,8,9} };
>> > int *b = (int *)a;
>> > int **c = (int **)a;
>> > int i = 0;
>> > int num_elements = sizeof(a) / sizeof(int);
>> >
>> > for(i = 0; i< num_elements; ++i)
>> > printf("*b = %d *c = %d\n", *b++, *c++);
>> >
>> > return 0;
>> > }
>> >
>> > When compiled I get:
>> > gcc -Wall -W -ansi -pedantic -g -O0 -c -o pointer_wonder.o
>> > pointer_wonder.c
>> > pointer_wonder.c: In function `main':
>> > pointer_wonder.c:13: warning: int format, pointer arg (arg 3)

>
> Note the warning here. ("*c++" is an "int*" type.)
>
>> > gcc pointer_wonder.o -o pointer_wonder.exe
>> >
>> > The output is:
>> > *b = 1 *c = 1

> [...]
>> > *b = 9 *c = 9
>> >
>> > Why is it same for *b and *c?

>>
>> *b gives you back an int
>>
>> whereas
>>
>> *c gives you back an int *
>>
>> However, the 'values' of each are taken from a.

>
> And it happens to be that sizeof(int)==sizeof(int*). Try it on a
> system where this is not true, such as an old 16-bit DOS compiler
> in large model mode. (sizeof int == 2, and sizeof int* is 4.)
>
> In a test here, I get:
>
> *b = 1 *c = 1
> *b = 2 *c = 3
> *b = 3 *c = 5
> *b = 4 *c = 7
> *b = 5 *c = 9
> *b = 6 *c = 2013
> *b = 7 *c = 2013
> *b = 8 *c = 9
> *b = 9 *c = 2680
>
>> So, printf would really like a %p (at least) for the third arg.

>
> Though it would still print (basically) the same thing, as *c is
> still really an int being treated as int*.
>
>
> In any case, this probably falls under the "UB" heading, as you are
> taking int's and treating them as int*'s.
>
> (Yes, I know the apostrophes don't really belong in the last sentence,
> but it makes it more legible, IMHO.)


That's so cool!

I really should *invest* in an 'old' compiler! And, it'd be so great to
have a 'Take me Back' experience of my own [in an archive.org kinda sense].
Like, if only I'd saved some of programs I 'cut' into 7-hole punched tape (I
never had access to the punched cards!: they were [for eyes only] in the
domain of the machine room ops!)

I used to have my first Ph.D. thesis on one of those removable hard drives -
big clunky things, with equaly big handles!

Ok, I'm 48 - anyone care to beat that?

Old Fart


 
Reply With Quote
 
pete
Guest
Posts: n/a
 
      12-08-2005
Eric Lilja wrote:
>
> Hello, I'm trying to help someone on a linux-oriented forum. I've taken
> his original code and cleaned it up, but I am still wondering about
> something. Here's the code:
>
> #include <stdio.h>
>
> int
> main(void)
> {
> int a[][3]={ {1,2,3},{4,5,6,},{7,8,9} };
> int *b = (int *)a;
> int **c = (int **)a;
> int i = 0;
> int num_elements = sizeof(a) / sizeof(int);
>
> for(i = 0; i< num_elements; ++i)
> printf("*b = %d *c = %d\n", *b++, *c++);
>
> return 0;
> }


I know this is going to be hard to believe,
but the standard doesn't actually define stepping all
the way through a two dimensional array
with anything other than a pointer to a character type,
even though all the bytes of array object are contiguous.

/* BEGIN new.c */

#include <stdio.h>

int
main(void)
{
char a[][3]={ "123","456","789" };
char *b = a[0];
size_t i = 0;
size_t num_elements = sizeof(a) / sizeof **a;

for(i = 0; i< num_elements; ++i) {
printf("*b = %c\n", *b++);
}
return 0;
}

/* END new.c */


--
pete
 
Reply With Quote
 
Dik T. Winter
Guest
Posts: n/a
 
      12-08-2005
In article <(E-Mail Removed) .com> "Eric Lilja" <(E-Mail Removed)> writes:
> Hello, I'm trying to help someone on a linux-oriented forum. I've taken
> his original code and cleaned it up, but I am still wondering about
> something. Here's the code:


Ok, let's see:

> #include <stdio.h>
>
> int
> main(void)
> {
> int a[][3]={ {1,2,3},{4,5,6,},{7,8,9} };


Well, for a a segment of 9 integers is allocated succesively filled with
the integers 1 to 9.

> int *b = (int *)a;


As 'a' in this context is a pointer to an array of three ints, you are
lying to the compiler. The result is (I think) undefined behaviour.

> int **c = (int **)a;


And more so. Here the result is certain to be undefined behaviour.

> int i = 0;
> int num_elements = sizeof(a) / sizeof(int);
>
> for(i = 0; i< num_elements; ++i)
> printf("*b = %d *c = %d\n", *b++, *c++);


And this is the third time you are lying. You are lucky that
sizeof(int) == sizeof(*int) on your system.
>
> return 0;
> }

....
> The output is:
> *b = 1 *c = 1

....
> *b = 9 *c = 9
>
> Why is it same for *b and *c?


Because on your system sizeof(int) == sizeof(*int) and the compiler
disregards all those lies.
--
dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/
 
Reply With Quote
 
pete
Guest
Posts: n/a
 
      12-08-2005
pete wrote:
>
> Eric Lilja wrote:
> >
> > Hello, I'm trying to help someone on a linux-oriented forum. I've taken
> > his original code and cleaned it up, but I am still wondering about
> > something. Here's the code:
> >
> > #include <stdio.h>
> >
> > int
> > main(void)
> > {
> > int a[][3]={ {1,2,3},{4,5,6,},{7,8,9} };
> > int *b = (int *)a;
> > int **c = (int **)a;
> > int i = 0;
> > int num_elements = sizeof(a) / sizeof(int);
> >
> > for(i = 0; i< num_elements; ++i)
> > printf("*b = %d *c = %d\n", *b++, *c++);
> >
> > return 0;
> > }

>
> I know this is going to be hard to believe,
> but the standard doesn't actually define stepping all
> the way through a two dimensional array
> with anything other than a pointer to a character type,
> even though all the bytes of array object are contiguous.


Unless you're treating it as a one dimensional array
of an array type.

/* BEGIN new.c */

#include <stdio.h>
#include <string.h>

int main(void)
{
char a[][3]={ "123","456","789" };
char *b = a[0];
char c[3][4] = {0};
char (*d)[3] = a;
char (*e)[4] = c;
size_t i;
size_t num_elements = sizeof(a) / sizeof **a;

for(i = 0; i< num_elements; ++i) {
printf("*b = %c\n", *b++);
}
putchar('\n');
num_elements = sizeof a / sizeof *a;
for(i = 0; i != num_elements; ++i) {
memcpy(e, d, sizeof *d);
printf("*e = %s\n", *e);
++d;
++e;
}
return 0;
}

/* END new.c */


--
pete
 
Reply With Quote
 
Old Wolf
Guest
Posts: n/a
 
      12-08-2005
Dik T. Winter wrote:

> "Eric Lilja" <(E-Mail Removed)> writes:
>
>> #include <stdio.h>
>>
>> int main(void) {
>> int a[][3]={ {1,2,3},{4,5,6,},{7,8,9} };

>
>> int *b = (int *)a;

>
> As 'a' in this context is a pointer to an array of three ints, you are
> lying to the compiler. The result is (I think) undefined behaviour.


I don't think there is any lying here; you are allowed to cast
one object pointer type to another as long as there are no
alignment issues. The troubles only (potentially) start when
you dereference the pointer.

&a[0] must be correctly aligned for int, because the members
of a[0] are ints, and there cannot be any padding before the
first member of an array.

> > int **c = (int **)a;

> And more so. Here the result is certain to be undefined behaviour.


Here there could be alignment issues. But if there are not,
then no UB if c is not dereferenced.

(Note: I don't think I worded that exactly right -- the code always
has UB, but on implementations where there were no alignment
problems, the code would behave in a well-defined manner).

>> int i = 0;
>> int num_elements = sizeof(a) / sizeof(int);
>>
>> for(i = 0; i< num_elements; ++i)
>> printf("*b = %d *c = %d\n", *b++, *c++);

>
> And this is the third time you are lying. You are lucky that
> sizeof(int) == sizeof(*int) on your system.


Agree (int* you mean, not *int).

IMHO, *b causes undefined behaviour iff i >= 3,
because "a" (ie. &a[0]) points to an array of 3 ints,
and a bounds checking implementation could flag this.

But if b were initialized as: int *b = &a;
then there would be no UB because &a points to
an object that is the size of nine ints.

But some people think that even as written there is
no UB because a[0] is part of the entire object "a",
I don't recall seeing any consensus when this point
has been debated in the past.

*c would cause undefined behaviour in most cases,
because either the bytes pointed to by c form a
trap representation for an int*, or if they form an address
that isn't the address of a valid object.

 
Reply With Quote
 
Kenneth Brody
Guest
Posts: n/a
 
      12-08-2005
pemo wrote:
[...]
> >> > main(void)
> >> > {
> >> > int a[][3]={ {1,2,3},{4,5,6,},{7,8,9} };
> >> > int *b = (int *)a;
> >> > int **c = (int **)a;
> >> > int i = 0;
> >> > int num_elements = sizeof(a) / sizeof(int);
> >> >
> >> > for(i = 0; i< num_elements; ++i)
> >> > printf("*b = %d *c = %d\n", *b++, *c++);
> >> >
> >> > return 0;
> >> > }

[...]
> >> *c gives you back an int *
> >>
> >> However, the 'values' of each are taken from a.

> >
> > And it happens to be that sizeof(int)==sizeof(int*). Try it on a
> > system where this is not true, such as an old 16-bit DOS compiler
> > in large model mode. (sizeof int == 2, and sizeof int* is 4.)
> >
> > In a test here, I get:
> >
> > *b = 1 *c = 1

[...]
> > *b = 9 *c = 2680

[...]
> That's so cool!
>
> I really should *invest* in an 'old' compiler! And, it'd be so great to
> have a 'Take me Back' experience of my own [in an archive.org kinda sense].
> Like, if only I'd saved some of programs I 'cut' into 7-hole punched tape (I
> never had access to the punched cards!: they were [for eyes only] in the
> domain of the machine room ops!)


Well, you could probably find a very new compiler where
sizeof(int)!=sizeof(int*). I imagine that some of the 64-bit systems
might qualify.

> I used to have my first Ph.D. thesis on one of those removable hard drives -
> big clunky things, with equaly big handles!


You mean one of those washing machines that stored data?

That reminds me... My friend never returned my DEC-Tape with the copy
of Star Trek on it that he borrowed (mumble, mumble) years ago.

> Ok, I'm 48 - anyone care to beat that?


Well, I'm "only" 44, but I do have 34+ years of programming experience.

> Old Fart


--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <(E-Mail Removed)>

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
findcontrol("PlaceHolderPrice") why why why why why why why why why why why Mr. SweatyFinger ASP .Net 2 12-02-2006 03:46 PM
Durability of inkjet prints, photo prints Bill Tuthill Digital Photography 45 05-02-2004 03:04 AM
Just recieved my 15 free digital prints from Kellards- Amazing Quality Prints! Bruce Digital Photography 5 12-29-2003 02:49 AM
Why the prints from film feel more 3D then prints from digital. Victor81 Digital Photography 35 12-12-2003 07:49 AM
Epson 1280 prints NOT Waterproof, 2200 prints ARE, Right? Dr. Slick Digital Photography 12 11-29-2003 10:19 AM



Advertisments