Help!!! What will be the problem in the below program?

Discussion in 'C++' started by Santa, Jun 29, 2003.

  1. Santa

    Santa Guest

    Guys:

    I am sorry to ask this question. I am trying to print the addresses of
    the below two printf's, both are not printing the same, what was the
    problem, can somebody correct me. Thanks in advance.
    ===================

    #include <stdio.h>

    typedef struct T_USER_CONF {
    int x;
    int y;
    }t_conf;

    typedef struct devData {
    t_conf tConf[2][12];

    }t_dev;


    main()
    {
    t_dev Dev;
    int i, j;

    printf("Dev 0x%x\n",Dev);

    printf("===FIRST PRINT BEGIN ===========\n");
    for(i=0; i < 24; i++)
    printf(" addr : 0x%x \n",Dev.tConf);
    printf("===FIRST PRINT END ===========\n");

    printf("===SECOND PRINT BEGIN ===========\n");
    for(i=0; i < 2; i++)
    for(j=0; j < 12; j++)
    printf(" addr : 0x%x \n",Dev.tConf[j]);
    printf("===SECOND PRINT END ===========\n");



    }
     
    Santa, Jun 29, 2003
    #1
    1. Advertising

  2. In 'comp.lang.c', (Santa) wrote:

    > I am sorry to ask this question. I am trying to print the addresses of
    > the below two printf's, both are not printing the same, what was the
    > problem, can somebody correct me. Thanks in advance.
    > ===================
    >
    > #include <stdio.h>
    >
    > typedef struct T_USER_CONF {
    > int x;
    > int y;
    > }t_conf;
    >
    > typedef struct devData {
    > t_conf tConf[2][12];
    >
    > }t_dev;
    >
    >
    > main()
    > {
    > t_dev Dev;
    > int i, j;
    >
    > printf("Dev 0x%x\n",Dev);
    >
    > printf("===FIRST PRINT BEGIN ===========\n");
    > for(i=0; i < 24; i++)
    > printf(" addr : 0x%x \n",Dev.tConf);


    printf (" addr : %p\n", (void*) Dev.tConf + i);

    > printf("===FIRST PRINT END ===========\n");
    >
    > printf("===SECOND PRINT BEGIN ===========\n");
    > for(i=0; i < 2; i++)
    > for(j=0; j < 12; j++)
    > printf(" addr : 0x%x \n",Dev.tConf[j]);


    printf (" addr : %p\n", (void*) Dev.tConf + j);

    > printf("===SECOND PRINT END ===========\n");
    >
    >
    >
    > }


    --
    -ed- [remove YOURBRA before answering me]
    The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
    <blank line>
    FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/
     
    Emmanuel Delahaye, Jun 29, 2003
    #2
    1. Advertising

  3. (Santa) wrote (29 Jun 2003) in
    news: / comp.lang.c:

    > Guys:
    >
    > I am sorry to ask this question. I am trying to print the addresses of
    > the below two printf's, both are not printing the same, what was the
    > problem, can somebody correct me. Thanks in advance.


    As nearly as I can make out from your code and question, you need at
    least to make the changes below. Note that it makes no sense "to print
    the address of the below two printf's"; I have interpreted this as
    meaning "to print the addresses of objects in the below printfs." Note
    that there a *three* instances in which you do this wrong.

    17c17
    < main()
    ---
    > int main(void)

    22c22
    < printf("Dev 0x%x\n", Dev);
    ---
    > printf("Dev %p\n", (void *) &Dev);

    26c26
    < printf(" addr : 0x%x \n", Dev.tConf);
    ---
    > printf(" addr : %p\n", (void *) Dev.tConf);

    32c32
    < printf(" addr : 0x%x \n", Dev.tConf[j]);
    ---
    > printf(" addr : %p\n", (void *) &Dev.tConf[j]);





    > ===================
    >
    > #include <stdio.h>
    >
    > typedef struct T_USER_CONF {
    > int x;
    > int y;
    > }t_conf;
    >
    > typedef struct devData {
    > t_conf tConf[2][12];
    >
    > }t_dev;
    >
    >
    > main()
    > {
    > t_dev Dev;
    > int i, j;
    >
    > printf("Dev 0x%x\n",Dev);
    >
    > printf("===FIRST PRINT BEGIN ===========\n");
    > for(i=0; i < 24; i++)
    > printf(" addr : 0x%x \n",Dev.tConf);
    > printf("===FIRST PRINT END ===========\n");
    >
    > printf("===SECOND PRINT BEGIN ===========\n");
    > for(i=0; i < 2; i++)
    > for(j=0; j < 12; j++)
    > printf(" addr : 0x%x \n",Dev.tConf[j]);
    > printf("===SECOND PRINT END ===========\n");
    >
    >
    >
    > }
    >




    --
    Martin Ambuhl
    Returning soon to the
    Fourth Largest City in America
     
    Martin Ambuhl, Jun 29, 2003
    #3
  4. Emmanuel Delahaye, Jun 29, 2003
    #4
  5. Santa

    Chris Torek Guest

    (This article is cross-postd to comp.lang.c and comp.lang.c++. It
    seems to me the original poster should decide which language he is
    using and stick with that one. Emmanuel Delahaye apparently saw this
    in comp.lang.c, given the quoting below.)

    >In 'comp.lang.c', (Santa) wrote:
    >> I am sorry to ask this question. I am trying to print the addresses of
    >> the below two printf's ...


    I do not understand this claim -- there is something quite suspect
    about the phrase "address of [a specific] printf". (To obtain the
    address of the printf() function, simply declare the function, then
    write its name without subsequent parentheses. The result has
    type "pointer to function (const char *, ...) returning int.") I
    will run with E.D.'s interpretation, though.

    [edited slightly for readability]
    >> #include <stdio.h>
    >>
    >> typedef struct T_USER_CONF {
    >> int x;
    >> int y;
    >> } t_conf;
    >>
    >> typedef struct devData {
    >> t_conf tConf[2][12];
    >> } t_dev;


    If you are using C++, note that "struct blah" also declares "blah"
    as a type-declaring name (with some special contortions for handling
    legacy code that, for the most part, you can ignore). In C, you
    can express the same thing by writing:

    typedef struct blah blah;
    struct blah { ... };

    and, if you are going to use typedefs at all for struct-names, I
    recommend that you do it this way so that you can use the new name
    inside the {} pair:

    typedef struct list_of_foo list_of_foo;
    struct list_of_foo {
    list_of_foo *next;
    ...
    };

    (I prefer not to use typedef to hide C's "struct" keyword at all,
    in general -- but this is purely a style issue. See below.)

    >> main()
    >> {
    >> t_dev Dev;


    "Dev" has type "struct devData" (a.k.a. "t_dev"). It is therefore
    a struct type. In C++ this is not as crucial, but in C, it is
    often necessary to know that something that has a "struct" type
    does indeed have such a type -- for instance, only such things can
    have "." member-extractor operators applied. If you have to *know*
    it is a struct in order to use it, you might as well use the "struct"
    keyword to declare it.

    >> int i, j;
    >> printf("Dev 0x%x\n",Dev);


    The %x format in printf requires a value of type "unsigned int"
    (and possibly also plain and explicitly-signed "int", depending on
    whether one interprets a footnote in the C standards as clarifying
    words that seem not to be there after all). In any case, Dev has
    a struct type, so there is no way this can be correct. The effect
    of this call is undefined. (In practice, it does different and
    arbitrarily weird things on different implementations.)

    >> printf("===FIRST PRINT BEGIN ===========\n");
    >> for (i = 0; i < 24; i++)
    >> printf(" addr : 0x%x \n", Dev.tConf);


    Looking a bit more closely at the type of "Dev", we find that it
    is a struct with a single member named "tConf". That member has
    array type -- "array 2 of <element-type-1>", in fact -- where the
    first element type is in turn another array type. The actual
    element type does not matter yet; what matters is that the array
    has size 2. That means the only valid subscripts are 0 and 1, yet
    "i" will run from 0 through 23 inclusive. Fully twenty-two of the
    subscripts will be out of range, hence produce undefined behavior.

    Although we are clearly already in trouble, we can take a look at
    what the first two calls do, by examining the element-type of
    the array in Dev.tConf. The size is 2 -- tConf is an "array 2
    of T" for some type T -- and the element-type is "array 12 of
    <element-type-2>". In other words, tConf is an array of arrays.

    This is how C handles "two-dimensional" arrays, as one-dimensional
    arrays whose elements are in turn one-dimensional arrays. Indeed,
    one can say (of both C and C++) that the way it handles any arrays
    of higher dimensions is that "it doesn't". This is no big deal in
    C++, which provides better ways to deal with such things in the
    first place, but it is often crucial in C programming.

    Just for completeness, <element-type-2> here is "struct T_USER_CONF"
    (aka "t_conf"), which is a structure type containing two "int"s
    named "x" and "y". So Dev.tConf has type "array 2 of array 12 of
    struct T_USER_CONF". Each of these "array N of T" constructs can
    fall under what I call "The Rule" about arrays and pointers in C.
    The Rule, with capital letters and all, is *the* key to understanding
    arrays and pointers, and the odd way in which pointers can simulate
    arrays and vice versa. (C++ inherits The Rule from C, but --
    because C++ is such a wildly different language, despite the
    superficial syntactic similarity -- in C++ it probably does not
    need this sort of capitalization. One simply uses the STL, and
    mostly ignores the existence of arrays, with their peculiar C-derived
    semantics, entirely.)

    Here is The Rule about arrays and pointers in C. Note that it
    requires careful distinction between "objects" and "values", and
    needs one to think about whether something is in "object context"
    or "value context".

    In a value context, an object of type "array N of T" (for some
    suitable integer N and valid element-type T) becomes a value
    of type "pointer to T", pointing to the first element of that
    array, i.e., the one with subscript 0.

    Object and value contexts are actually quite straightforward, as
    concepts go. When you write something like:

    int i, j;
    ...
    i = j;

    how does the compiler know to take the *value* of j and put it into
    the *object* named i? The answer is: from context. Here "i" is
    on the left side of a simple assignment operator, and "j" is on
    the right side, so we mean "the object i" and "the value of the
    object j". In other words, "i" has "object context" and "j" has
    "value context".

    When you place an array object in a value context, the "value" that
    a C or C++ compiler produces is the one prescribed by The Rule.
    According to The Rule, you drop the integer "N" part and get a
    value of type "pointer to T", where T is the element-type of
    the array. Hence in:

    int *p, a[50];
    ...
    p = a;

    one applies The Rule to "array 50 of int" and finds that p is set
    to a value of type "pointer to int", pointing to the first element
    of the array "a", i.e., &a[0].

    Again, note that C (and thus also C++) does not have true
    multi-dimensional arrays, but rather arrays whose element type is
    in turn another array. Suppose we have an array named "b", of size
    5, whose element-type is "array M of T2" (for some suitable integer
    M and type T2):

    T2 b[5][M];

    Now, if we place b in some value context, what value do we get,
    according to The Rule?

    In a value context,

    (yep)

    an object of type "array N of T"

    (ok; N is 5 and T is "array M of T2")

    becomes a value of type "pointer to T" ...

    -- which is the answer: the value has type "pointer to T", or
    "pointer to array M of T2", and points to the first element of
    b, i.e., &b[0]. To write the type "pointer to array M of T2"
    in C, we must use the rather peculiar-looking declaration:

    T2 (*p)[M];

    and we can then write:

    p = b;

    to set p to &b[0]. This pointer value points to an entire array
    -- in this case, the first of N such arrays. This is hard to draw
    in text; for a graphical representation of the concept, see
    <http://67.40.109.61/torek/c/pa.html>. This pointer is much like
    the red-arrow-and-circle in the diagram there.

    Why does all this matter? Well, remember that Dev, in the original
    code we started with, has type "struct devData", which is a structure
    type with one member, "tConf". The member has type "array 2 of
    array 12 of struct T_USER_CONF". We thus have one of these "array
    N of array M of ..." constructs, which will, under The Rule, produce
    values of type "pointer to array M of" whatever. And indeed, this
    is precisely what happens next:

    In article <Xns93A9C67A1B09hsnoservernet@130.133.1.4>
    Emmanuel Delahaye <> writes:
    > printf (" addr : %p\n", (void*) Dev.tConf + i);


    Since Dev.tConf is an "array 2 of array 12 of struct T_USER_CONF",
    taking its "value" produces a value of type "pointer to array 12
    of struct T_USER_CONF". This pointer points to an entire "array
    12 of struct T_USER_CONF" -- the first one in Dev.tConf, i.e.,
    Dev.tConf[0] -- but it is a pointer value and can be converted
    to "void *".

    Here things go wrong, though. The expression:

    (void *) Dev.tConf + i

    parses the same as:

    ((void *) Dev.tConf) + i

    because casts bind more tightly than addition. The result is that
    we first convert Dev.tConf's value (as produced by The Rule) to
    one of type "void *", then attempt to add an integer value to that.
    C and C++ both forbid arithmetic on "void *", so a diagnostic is
    required. (Incidentally, note that gcc by default compiles a
    different language from C, in which "void *" arithmetic *is* allowed,
    and you have to supply special compiler flags to get it to complain
    as the C Standards require.)

    Clearly E.D. meant:

    (void *)(Dev.tConf + i)

    which is considerably closer to correct, and even compiles. But
    this still suffers from undefined behavior. As you may or may not
    recall by now :) the tConf member has type "array 2 of array 12
    of ...", but the variable "i" is going to run from 0 through 23
    inclusive. The only valid subscripts for tConf are 0 and 1, and
    a pointer of type "pointer to array 12 of ..." steps forward by
    units of "array-12-of" (as illustrated at the above URL), so when
    you add 2, you point just past the end of the object. C does allow
    such a pointer as a special concession, but then i goes on to become
    3, and C does not define the result of this computation. A very
    few (perhaps even "no", today) C compilers will catch the error at
    runtime, to prevent you from getting the wrong answer fast. (Most
    C compilers will just give you the wrong answer fast though. For
    some reason, most people seem to prefer to get wrong answers as
    fast as possible, rather than having a slightly slower system catch
    such errors.)

    If one were to change the loop to read:

    for (i = 0; i < 2; i++)
    printf(" addr : %p\b", (void *)(Dev.tConf + i));

    then this final version would be correct and would do something
    reasonably well defined.

    >> printf("===FIRST PRINT END ===========\n");
    >>
    >> printf("===SECOND PRINT BEGIN ===========\n");
    >> for (i = 0; i < 2; i++)
    >> for (j = 0; j < 12; j++)
    >> printf(" addr : 0x%x \n", Dev.tConf[j]);


    Here the subscripts are valid -- the tConf member (still) has type
    "array 2 of array 12 of struct T_USER_DATA", and "i" and "j" are
    always in range -- but once again, this passes an entire "struct"
    value to printf() when printf() is expecting an unsigned int, so
    the effect is undefined. E.D.'s correction again suffers from
    misplaced (or missing) parentheses, so that the "void *" binds
    to the wrong sub-expression:

    > printf (" addr : %p\n", (void*) Dev.tConf + j);


    but this is easily fixed:

    printf(" addr : %p\n", (void *)(Dev.tConf + j));

    As always in C, array objects in "value contexts" fall under The
    Rule, and since Dev.tConf is an array object, and the "+"
    (addition) operator needs values, we must apply The Rule. Since
    Dev.tConf has type "array 12 of struct T_USER_DATA", the "value"
    of this is a pointer of -- what type? As always, we must discard
    the integer N (12) and keep the type T (struct T_USER_DATA). We
    get a pointer of type "pointer to struct T_USER_DATA", pointing
    to the first element of the array, i.e., &Dev.tConf[0].

    Note that we could equally write:

    printf(" addr : %p\n", (void *)(&Dev.tConf[0] + j));

    Moreover, because pointer addition moves forward by "whole
    object" units (as determined by the type of the thing to which
    the pointer points), we could also write this as:

    printf(" addr : %p\n", (void *)(&Dev.tConf[j]));

    and now the final parentheses are redundant (casts bind less
    tightly than & and [] operators), so this is just:

    printf(" addr : %p\n", (void *)&Dev.tConf[j]);

    The cast *is* required in all cases, though, because C's %p format
    directive needs a value of type "void *". In C++, there are no
    automatic, cast-free conversions to and from "void *", and even in
    C, this particular parameter matches up with the ", ..." part of
    printf()'s prototype, so the cast is still needed.
    --
    In-Real-Life: Chris Torek, Wind River Systems (BSD engineering)
    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    email: forget about it http://67.40.109.61/torek/index.html (for the moment)
    Reading email is like searching for food in the garbage, thanks to spammers.
     
    Chris Torek, Jun 29, 2003
    #5
  6. Santa

    Jack Klein Guest

    On 29 Jun 2003 10:26:42 -0700, (Santa) wrote
    in comp.lang.c:

    > Guys:
    >
    > I am sorry to ask this question. I am trying to print the addresses of
    > the below two printf's, both are not printing the same, what was the
    > problem, can somebody correct me. Thanks in advance.
    > ===================


    Do not multi-post. I already answered this question in
    alt.comp.lang.learn.c-c++.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c /faq
     
    Jack Klein, Jun 29, 2003
    #6
  7. Santa

    Santa Guest

    Sorry Jack, Thanks for your help and thanks for others to help me, appreciated.
     
    Santa, Jun 30, 2003
    #7
    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. Ranpha
    Replies:
    3
    Views:
    603
    Ranpha
    Apr 4, 2005
  2. Santa
    Replies:
    6
    Views:
    710
    Santa
    Jun 30, 2003
  3. Replies:
    4
    Views:
    295
  4. MrHelpMe

    Could someone help with my ASP code below

    MrHelpMe, Feb 17, 2008, in forum: ASP General
    Replies:
    2
    Views:
    195
    s_m_b
    Feb 22, 2008
  5. kiran
    Replies:
    12
    Views:
    1,216
    Scott Sauyet
    Dec 7, 2011
Loading...

Share This Page