Explain why this prints the same

Discussion in 'C Programming' started by Eric Lilja, Dec 7, 2005.

  1. Eric Lilja

    Eric Lilja Guest

    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
    Eric Lilja, Dec 7, 2005
    #1
    1. Advertising

  2. Eric Lilja

    pemo Guest

    "Eric Lilja" <> wrote in message
    news:...
    > 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.
    pemo, Dec 7, 2005
    #2
    1. Advertising

  3. Eric Lilja

    pemo Guest

    "pemo" <> wrote in message
    news:dn705d$4r6$...
    >
    > "Eric Lilja" <> wrote in message
    > news:...
    >> 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!
    pemo, Dec 7, 2005
    #3
  4. pemo wrote:
    >
    > "Eric Lilja" <> wrote in message
    > news:...
    > > 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: <mailto:>
    Kenneth Brody, Dec 7, 2005
    #4
  5. Eric Lilja

    pemo Guest

    "Kenneth Brody" <> wrote in message
    news:...
    > pemo wrote:
    >>
    >> "Eric Lilja" <> wrote in message
    >> news:...
    >> > 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
    pemo, Dec 7, 2005
    #5
  6. Eric Lilja

    pete Guest

    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
    pete, Dec 8, 2005
    #6
  7. In article <> "Eric Lilja" <> 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/
    Dik T. Winter, Dec 8, 2005
    #7
  8. Eric Lilja

    pete Guest

    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
    pete, Dec 8, 2005
    #8
  9. Eric Lilja

    Old Wolf Guest

    Dik T. Winter wrote:

    > "Eric Lilja" <> 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.
    Old Wolf, Dec 8, 2005
    #9
  10. 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: <mailto:>
    Kenneth Brody, Dec 8, 2005
    #10
  11. Eric Lilja

    tedu Guest

    pemo wrote:
    > "Kenneth Brody" <> wrote in message
    > > 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.)

    >
    > 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].


    you could buy a new amd64 machine and experience the same pain today,
    only faster. :)
    tedu, Dec 8, 2005
    #11
  12. Eric Lilja

    pemo Guest

    "Kenneth Brody" <> wrote in message
    news:...

    <snip>

    >
    >> 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.


    "And you tell that to young. people today and. they won't believe you!"

    Yup, it was a bit 'top-loader like' if memory still serves.

    You've been programming longer then. I started as an undergrad - back then,
    there was no university in the UK that offered *just* a degree in computing,
    so I did a mixed degree, Computing and Pure Maths. Note the lack of the
    term 'Computer Science' - wasn't really invented yet.

    All my programming assignments had to be written out on coding sheets, and
    handed into the machine room - where someone entered them, and probably
    produced punched cards etc ... If you were unlucky, you'd turn up the next
    day to get your printout, and find it said syntax error. Sometimes, it even
    told you where! The *big* machine on which this stuff ran used to go on to
    'MOP' at 6.00pm everyday. I don't believe I ever knew what MOP stood for,
    but I know what it meant - the machine was hired out from 6.00 until
    midnight every evening.

    We did have one machine that we could program directly. A PDP ? In order to
    use that, you had to enter the boot strap routine by flicking switches, and
    then load the OS from seven hole punched tape.

    Ah, those were the days!
    pemo, Dec 9, 2005
    #12
  13. Eric Lilja

    pemo Guest

    "tedu" <> wrote in message
    news:...
    > pemo wrote:
    >> "Kenneth Brody" <> wrote in message
    >> > 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.)

    >>
    >> 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].

    >
    > you could buy a new amd64 machine and experience the same pain today,
    > only faster. :)


    :)
    pemo, Dec 9, 2005
    #13
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. kitty
    Replies:
    0
    Views:
    555
    kitty
    Jul 18, 2005
  2. Mr. SweatyFinger

    why why why why why

    Mr. SweatyFinger, Nov 28, 2006, in forum: ASP .Net
    Replies:
    4
    Views:
    853
    Mark Rae
    Dec 21, 2006
  3. Mr. SweatyFinger
    Replies:
    2
    Views:
    1,736
    Smokey Grindel
    Dec 2, 2006
  4. This C program prints 1 - why?

    , Dec 28, 2004, in forum: C Programming
    Replies:
    7
    Views:
    265
    Lawrence Kirby
    Dec 29, 2004
  5. Replies:
    8
    Views:
    197
    Dennis Lee Bieber
    Dec 19, 2012
Loading...

Share This Page