Some doubts on variable-length array

Discussion in 'C Programming' started by lovecreatesbeauty, Mar 31, 2006.

  1. Hello experts,

    I have seen following the code snippet given by Marc Boyer (with slight
    changes by me for a better format), and have doubts on it. I am so
    grateful if you can give me your kindly help and hints on this problem.

    1. Does the function call `foo(3, 3, tab);' refer to the data outside
    the array `int tab[9];'. The available subscription for a 3X3 2-D array
    should be 0..2 X 0..2, I think.

    2. For the available function call `foo(2, 2, tab);' (I do not think
    the second one is unavailable, just not sure.), which element in the
    array `int tab[9];' does tab[0][0] refer to inside the body of the
    function `foo'. I want to know the exact one int the format `tab[0] ..
    tab [8]'.

    And which element in `int tab[9];' does tab[1][1] refer to.

    I can not figure it out for some while on it. The GCC4.1 says it does
    not support the variable-length array of C99, but I can compile this
    program on even GCC3.3.5, and also on GCC4.1 after I installed this
    newest one. I also get the same result of the program as Marc Boyer.

    Sincerely,

    lovecreatesbeauty



    /* sample by Marc Boyer */

    #include <stdio.h>

    void
    foo(int size_x, int size_y, int tab[size_x][size_y])
    {
    printf("tab[1][1] == %d\n", tab[1][1]);
    }

    int
    main()
    {
    int tab[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
    foo(2, 2, tab);
    foo(3, 3, tab);

    return 0;
    }

    news> ./a.out
    tab[1][1] == 3
    tab[1][1] == 4
     
    lovecreatesbeauty, Mar 31, 2006
    #1
    1. Advertising

  2. I can understand the behaviour of these statements marked `/* A. don't
    understand */' in following code, but do not understand the statements
    marked `/* B. understand */' .

    The behaviour of the following statements of A kind is different to B
    kind.

    Thank you.

    #include <stdio.h>

    void foo(int size_x, int size_y, int tab[size_x][size_y])
    {
    printf("tab[1][1] == %d\n", tab[1][1]);
    }

    int main()
    {
    /* int tab[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; */
    int tab[3][3] = {0, 1, 2, 3, 4, 5, 6, 7, 8};

    foo(2, 2, tab); /* A. don't understand */
    printf("%i\n", tab[2][2]); /* B. understand */
    printf("%i\n", *(*(tab+2)+2)); /* B. understand */
    printf("\n\n");

    foo(3, 3, tab); /* A. don't understand */
    printf("%i\n", tab[3][3]); /* B. understand */
    printf("%i\n", *(*(tab+3)+3)); /* B. understand */
    printf("\n\n");

    return 0;
    }
     
    lovecreatesbeauty, Mar 31, 2006
    #2
    1. Advertising

  3. "lovecreatesbeauty" <> wrote in message
    news:...
    >I can understand the behaviour of these statements marked `/* A. don't
    > understand */' in following code, but do not understand the statements
    > marked `/* B. understand */' .
    >
    > The behaviour of the following statements of A kind is different to B
    > kind.
    >
    > Thank you.
    >
    > #include <stdio.h>
    >
    > void foo(int size_x, int size_y, int tab[size_x][size_y])

    Here foo is being told that tab is an array with dimensions
    [size_x][size_y].
    It will assume that this is actually the case, regardless of the true size
    of the array passed to it in the calling function.
    > {
    > printf("tab[1][1] == %d\n", tab[1][1]);
    > }


    if this were void foo( int **tab),
    foo would not know the rank of the array

    >
    > int main()
    > {
    > /* int tab[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; */
    > int tab[3][3] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
    >
    > foo(2, 2, tab); /* A. don't understand */

    Call function foo, and tell foo that tab is a 2x2 array

    > printf("%i\n", tab[2][2]); /* B. understand */
    > printf("%i\n", *(*(tab+2)+2)); /* B. understand */
    > printf("\n\n");
    >
    > foo(3, 3, tab); /* A. don't understand */

    Call function foo, and tell foo that tab is a 3x3 array

    > printf("%i\n", tab[3][3]); /* B. understand */

    Error - index out of bounds
    > printf("%i\n", *(*(tab+3)+3)); /* B. understand */

    Error - index out of bounds
    > printf("\n\n");
    >
    > return 0;
    > }
    >

    --
    Fred L. Kleinschmidt
    Boeing Associate Technical Fellow
    Technical Architect, Software Reuse Project
     
    Fred Kleinschmidt, Mar 31, 2006
    #3
  4. On Fri, 31 Mar 2006 02:00:45 -0800, lovecreatesbeauty wrote:

    > I can understand the behaviour of these statements marked `/* A. don't
    > understand */' in following code, but do not understand the statements
    > marked `/* B. understand */' .


    Did you mean it that way round? I've commented on both just in case.

    > #include <stdio.h>
    >
    > void foo(int size_x, int size_y, int tab[size_x][size_y])
    > {
    > printf("tab[1][1] == %d\n", tab[1][1]);


    prints the 2nd element of the 2nd element of tab.

    > }
    >
    > int main()
    > {
    > /* int tab[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; */
    > int tab[3][3] = {0, 1, 2, 3, 4, 5, 6, 7, 8};


    My compiler (gcc 4.0.1) warns me I should write:

    int tab[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};

    although it accepts the flat list as well.

    > foo(2, 2, tab); /* A. don't understand */


    This calls "lies" to foo telling it that the array is 2x2 so foo sees it
    as if it were "int tab[2][2] = {{0, 1}, {2, 3}};". Element [1][1] is 3
    and this is what is printed.

    > printf("%i\n", tab[2][2]); /* B. understand */


    The declaration of tab is in scope here so there should be no confusion.
    The third element of the third element of tab is 8.

    > printf("%i\n", *(*(tab+2)+2)); /* B. understand */


    This is another way to write the same thing. The array name tab is
    treated as a pointer to its first element (an array of three ints).
    Adding 2 to this pointer (tab + 2) moves it by two "strides" to make a
    pointer that points to the third element (another array of three ints).
    *(tab + 2) is this array, but again, the array is treated as a pointer to
    its first element (an int). Adding 2 to that gives a pointer that points
    to the number 8. The final * de-references that pointer to give the value
    8.

    > printf("\n\n");
    >
    > foo(3, 3, tab); /* A. don't understand */


    This call does not "lie". So inside foo it is seen as it was defined and
    element [1][1] is the number 4.

    > printf("%i\n", tab[3][3]); /* B. understand */
    > printf("%i\n", *(*(tab+3)+3)); /* B. understand */


    These two are exactly as above, but the array is being index out of bounds
    so you get undefined behaviour (probably a segmentation fault, or maybe
    just garbage being printed).

    > printf("\n\n");
    >
    > return 0;
    > }


    --
    Ben.
     
    Ben Bacarisse, Mar 31, 2006
    #4
  5. Ben Bacarisse wrote:
    > > foo(2, 2, tab); /* A. don't understand */

    >
    > This calls "lies" to foo telling it that the array is 2x2 so foo sees it
    > as if it were "int tab[2][2] = {{0, 1}, {2, 3}};". Element [1][1] is 3
    > and this is what is printed.


    I know it before that functions regard an array argument same as a
    pointer. So how can the layout/dimension of an actual array argument be
    known inside the function body? Are new meanings/semantics given to
    array arguments when they are variable-length array?

    > > foo(3, 3, tab); /* A. don't understand */

    >
    > This call does not "lie". So inside foo it is seen as it was defined and
    > element [1][1] is the number 4.


    The original array is: /* int tab[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; */
    , if it is used instead, then foo(3, 3, tab); lies again, right?

    I can understand the original sample code in your way, but get more
    anxious on how a function knows the layout/dimension of actual array
    arguments.
     
    lovecreatesbeauty, Mar 31, 2006
    #5
  6. On Fri, 31 Mar 2006 09:12:25 -0800, lovecreatesbeauty wrote:

    >
    > Ben Bacarisse wrote:
    >> > foo(2, 2, tab); /* A. don't understand */

    >>
    >> This calls "lies" to foo telling it that the array is 2x2 so foo sees it
    >> as if it were "int tab[2][2] = {{0, 1}, {2, 3}};". Element [1][1] is 3
    >> and this is what is printed.

    >
    > I know it before that functions regard an array argument same as a
    > pointer. So how can the layout/dimension of an actual array argument be
    > known inside the function body? Are new meanings/semantics given to
    > array arguments when they are variable-length array?


    Yes. The special syntax of these arguments lets the compiler know how big
    each row of the parameter array is.

    >
    >> > foo(3, 3, tab); /* A. don't understand */

    >>
    >> This call does not "lie". So inside foo it is seen as it was defined and
    >> element [1][1] is the number 4.

    >
    > The original array is: /* int tab[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; */
    > , if it is used instead, then foo(3, 3, tab); lies again, right?


    Yes and this is a bigger lie. But I put "lie" in quotes, because it may
    be OK to do it. Telling a function the "shape" of the data array is fine
    so long as you know what will happen when you do that.

    If you want to treat a flat array as a collection of rows, then you are
    free to do so but you will need to persuade the compiler with a cast in
    the call to foo: foo(3, 3, (int (*)[3])tab) and you will not be able to
    write tab[2][2] within scope of the flat definition. Nor will the mess
    with all the pointer arithmetic work. In short, you need a very good
    reason to go messing about like that. If you have 2D array, then just
    declare it and use it. Pass at least the "row size" to any functions that
    use the array and all will be fine. Passing both sizes makes sense for
    many applications and helps to document the code.


    --
    Ben.
     
    Ben Bacarisse, Mar 31, 2006
    #6
  7. Ben Bacarisse wrote:
    > On Fri, 31 Mar 2006 09:12:25 -0800, lovecreatesbeauty wrote:
    >
    > >
    > > Ben Bacarisse wrote:
    > >> > foo(2, 2, tab); /* A. don't understand */
    > >>
    > >> This calls "lies" to foo telling it that the array is 2x2 so foo sees it
    > >> as if it were "int tab[2][2] = {{0, 1}, {2, 3}};". Element [1][1] is 3
    > >> and this is what is printed.

    > >
    > > I know it before that functions regard an array argument same as a
    > > pointer. So how can the layout/dimension of an actual array argument be
    > > known inside the function body? Are new meanings/semantics given to
    > > array arguments when they are variable-length array?

    >
    > Yes. The special syntax of these arguments lets the compiler know how big
    > each row of the parameter array is.
    >
    > >
    > >> > foo(3, 3, tab); /* A. don't understand */
    > >>
    > >> This call does not "lie". So inside foo it is seen as it was defined and
    > >> element [1][1] is the number 4.

    > >
    > > The original array is: /* int tab[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; */
    > > , if it is used instead, then foo(3, 3, tab); lies again, right?

    >
    > Yes and this is a bigger lie. But I put "lie" in quotes, because it may
    > be OK to do it. Telling a function the "shape" of the data array is fine
    > so long as you know what will happen when you do that.
    >
    > If you want to treat a flat array as a collection of rows, then you are
    > free to do so but you will need to persuade the compiler with a cast in
    > the call to foo: foo(3, 3, (int (*)[3])tab) and you will not be able to
    > write tab[2][2] within scope of the flat definition. Nor will the mess
    > with all the pointer arithmetic work. In short, you need a very good
    > reason to go messing about like that. If you have 2D array, then just
    > declare it and use it. Pass at least the "row size" to any functions that
    > use the array and all will be fine. Passing both sizes makes sense for
    > many applications and helps to document the code.
    >
    >
    > --
    > Ben.




    Thank you.

    How is it going whan I add `foo(0, 0, tab)' and `foo(1, 1, tab)' in the
    code snippet as following?

    Can I think each function call refers to the array element as following
    (I get inspired on it form another people goodluckyxl):

    foo(0, 0, tab) refers to: tab[1+sizeof(int[0])/sizeof(int)] or
    tab[1+0/sizeof(int)]

    foo(0, 0, tab) refers to: tab[1+sizeof(int[1])/sizeof(int)]

    foo(0, 0, tab) refers to: tab[1+sizeof(int[2])/sizeof(int)]

    foo(0, 0, tab) refers to: tab[1+sizeof(int[3])/sizeof(int)]



    #include <stdio.h>

    void
    foo(int size_x, int size_y, int tab[size_x][size_y])
    {
    printf("tab[1][1] == %d\n", tab[1][1]);
    }

    int
    main()
    {
    int tab[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8};

    foo(0, 0, (int(*)[0])tab); /* foo(0, 0, tab); */
    foo(1, 1, (int(*)[1])tab); /* foo(1, 1, tab); */

    foo(2, 2, (int(*)[2])tab);
    foo(3, 3, (int(*)[3])tab);

    return 0;
    }
     
    lovecreatesbeauty, Apr 1, 2006
    #7
  8. Ben Bacarisse wrote:
    > On Fri, 31 Mar 2006 09:12:25 -0800, lovecreatesbeauty wrote:
    >
    > >
    > > Ben Bacarisse wrote:
    > >> > foo(2, 2, tab); /* A. don't understand */
    > >>
    > >> This calls "lies" to foo telling it that the array is 2x2 so foo sees it
    > >> as if it were "int tab[2][2] = {{0, 1}, {2, 3}};". Element [1][1] is 3
    > >> and this is what is printed.

    > >
    > > I know it before that functions regard an array argument same as a
    > > pointer. So how can the layout/dimension of an actual array argument be
    > > known inside the function body? Are new meanings/semantics given to
    > > array arguments when they are variable-length array?

    >
    > Yes. The special syntax of these arguments lets the compiler know how big
    > each row of the parameter array is.
    >
    > >
    > >> > foo(3, 3, tab); /* A. don't understand */
    > >>
    > >> This call does not "lie". So inside foo it is seen as it was defined and
    > >> element [1][1] is the number 4.

    > >
    > > The original array is: /* int tab[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; */
    > > , if it is used instead, then foo(3, 3, tab); lies again, right?

    >
    > Yes and this is a bigger lie. But I put "lie" in quotes, because it may
    > be OK to do it. Telling a function the "shape" of the data array is fine
    > so long as you know what will happen when you do that.
    >
    > If you want to treat a flat array as a collection of rows, then you are
    > free to do so but you will need to persuade the compiler with a cast in
    > the call to foo: foo(3, 3, (int (*)[3])tab) and you will not be able to
    > write tab[2][2] within scope of the flat definition. Nor will the mess
    > with all the pointer arithmetic work. In short, you need a very good
    > reason to go messing about like that. If you have 2D array, then just
    > declare it and use it. Pass at least the "row size" to any functions that
    > use the array and all will be fine. Passing both sizes makes sense for
    > many applications and helps to document the code.
    >
    >
    > --
    > Ben.




    Thank you.

    How is it going whan I add `foo(0, 0, tab)' and `foo(1, 1, tab)' in the
    code snippet as following?

    Can I think each function call refers to the array element as following
    (I get inspired on it form another people goodluckyxl): (sorry to make
    mistakes on following descriptions in my previous post)

    foo(0, 0, tab) refers to: tab[1+sizeof(int[0])/sizeof(int)] or
    tab[1+0/sizeof(int)]

    foo(1, 1, tab) refers to: tab[1+sizeof(int[1])/sizeof(int)]

    foo(2, 2, tab) refers to: tab[1+sizeof(int[2])/sizeof(int)]

    foo(3, 3, tab) refers to: tab[1+sizeof(int[3])/sizeof(int)]



    #include <stdio.h>

    void
    foo(int size_x, int size_y, int tab[size_x][size_y])
    {
    printf("tab[1][1] == %d\n", tab[1][1]);
    }

    int
    main()
    {
    int tab[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8};

    foo(0, 0, (int(*)[0])tab); /* foo(0, 0, tab); */
    foo(1, 1, (int(*)[1])tab); /* foo(1, 1, tab); */

    foo(2, 2, (int(*)[2])tab);
    foo(3, 3, (int(*)[3])tab);

    return 0;
    }
     
    lovecreatesbeauty, Apr 1, 2006
    #8
  9. "Ben Bacarisse" <> wrote in message
    news:p...
    > On Fri, 31 Mar 2006 02:00:45 -0800, lovecreatesbeauty wrote:
    >
    > > #include <stdio.h>
    > >
    > > void foo(int size_x, int size_y, int tab[size_x][size_y])
    > > {
    > > printf("tab[1][1] == %d\n", tab[1][1]);

    >
    > prints the 2nd element of the 2nd element of tab.
    >
    > > }
    > >
    > > int main()
    > > {
    > > /* int tab[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; */
    > > int tab[3][3] = {0, 1, 2, 3, 4, 5, 6, 7, 8};

    >
    > My compiler (gcc 4.0.1) warns me I should write:
    >
    > int tab[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
    >
    > although it accepts the flat list as well.
    >
    > > foo(2, 2, tab); /* A. don't understand */

    >
    > This calls "lies" to foo telling it that the array is 2x2 so foo sees it
    > as if it were "int tab[2][2] = {{0, 1}, {2, 3}};". Element [1][1] is 3
    > and this is what is printed.


    This lie makes my compiler produce a warning. That is reasonable because the
    types are incompatible. So that makes me wonder: is this guaranteed to work;
    always produce the same result? I would think yes but i would like someone
    to confirm it.
     
    stathis gotsis, Apr 2, 2006
    #9
    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. Manzanita

    libraries, IDE and some doubts.

    Manzanita, Apr 1, 2004, in forum: Java
    Replies:
    1
    Views:
    329
    Andrew Thompson
    Apr 2, 2004
  2. Piotre Ugrumov

    Urgent Help, some doubts

    Piotre Ugrumov, Jan 25, 2004, in forum: C++
    Replies:
    1
    Views:
    307
    Buster
    Jan 25, 2004
  3. Replies:
    0
    Views:
    251
  4. Tim Golden
    Replies:
    1
    Views:
    381
  5. Adam Warner

    Flexible array member + variable length array

    Adam Warner, Feb 3, 2005, in forum: C Programming
    Replies:
    10
    Views:
    827
    S.Tobias
    Feb 10, 2005
Loading...

Share This Page