Array passed as function parameters

Discussion in 'C Programming' started by Why Tea, Aug 16, 2012.

  1. Why Tea

    Why Tea Guest

    Could anyone please explain the differences between
    the following array passing? Thanks!

    1) int get_data(char d[100]) {...}

    2) int get_data(char *d) {...}

    /WT
    Why Tea, Aug 16, 2012
    #1
    1. Advertising

  2. Why Tea

    Mark Bluemel Guest

    On 16/08/2012 16:02, Kenneth Brody wrote:
    > On 8/16/2012 9:25 AM, Why Tea wrote:
    >> Could anyone please explain the differences between
    >> the following array passing? Thanks!
    >>
    >> 1) int get_data(char d[100]) {...}
    >>
    >> 2) int get_data(char *d) {...}

    >
    > In (1), the function gets passed a pointer to an array of 100 chars. In
    > (2), the function gets passed a "generic" pointer to char.


    Not quite. In 1) the function is passed a pointer to the first char of
    an array of 100 chars which is not the same as a pointer to an array of
    100 chars.

    FAQ 6.4 is probably a good start point for Why Tea... The FAQs are at
    c-faq.com.
    Mark Bluemel, Aug 16, 2012
    #2
    1. Advertising

  3. Why Tea

    Eric Sosman Guest

    On 8/16/2012 11:02 AM, Kenneth Brody wrote:
    > On 8/16/2012 9:25 AM, Why Tea wrote:
    >> Could anyone please explain the differences between
    >> the following array passing? Thanks!
    >>
    >> 1) int get_data(char d[100]) {...}
    >>
    >> 2) int get_data(char *d) {...}

    >
    > In (1), the function gets passed a pointer to an array of 100 chars. In
    > (2), the function gets passed a "generic" pointer to char.


    (Counter-trolling, Kenneth? If so, I apoligize for spoiling
    the fun -- But there's enough confusion on this point that it
    seems dangerous to leave things alone.)

    There's no difference. See Question 6.21 in the comp.lang.c
    Frequently Asked Questions (FAQ) page, <http://www.c-faq.com/>.

    --
    Eric Sosman
    d
    Eric Sosman, Aug 16, 2012
    #3
  4. Why Tea

    John Bode Guest

    On Thursday, August 16, 2012 8:25:57 AM UTC-5, Why Tea wrote:
    > Could anyone please explain the differences between
    >
    > the following array passing? Thanks!
    >
    >
    >
    > 1) int get_data(char d[100]) {...}
    >
    >
    >
    > 2) int get_data(char *d) {...}
    >
    >
    >
    > /WT


    Both are treated the same; in the context of an array parameter declaration, "T a[N]" and "T a[]" are both interpreted as "T *a"; all three declare "a" as a pointer to "T" (this is *only* true for function parameter declarations, though).

    Except when it is the operand of the sizeof or unary "&" operators, or is astring literal being used to initialize another array in a declaration, anexpression of type "N-element array of T" will be converted or "decay" to an expression of type "pointer to T", and the value of the converted expression will be the address of the first element in the array.

    So, assuming code like

    int arr[20];
    foo(arr);

    the expression "arr" in the call to "foo" will be converted from type "20-element array of int" to "pointer to int", and the value will be the same as"&arr[0]"; thus, "foo" receives a pointer value as its argument, not an array.

    You can declare "foo" as either

    void foo(int a[20])

    or

    void foo (int a[])

    or

    void foo (int *a)

    and all will be interpreted the same way.
    John Bode, Aug 16, 2012
    #4
  5. Why Tea

    Varun Tewari Guest

    In 1, you actually duplicating the array in the funciton.
    in 2, rather you are happy using a reference to the array, hence no duplication.
    Varun Tewari, Aug 16, 2012
    #5
  6. Why Tea <> writes:
    > Could anyone please explain the differences between
    > the following array passing? Thanks!
    >
    > 1) int get_data(char d[100]) {...}
    >
    > 2) int get_data(char *d) {...}


    There is no difference in meaning; they're effectively different
    spellings of the same thing.

    See http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
    6.7.6.3p7, or the corresponding paragraph in the section on "Function
    declarators" in earlier versions of the standard.

    And yes, that means the "100" in the first example is silently ignored
    (unless the compiler chooses to warn about it, but I know of none that
    do).

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Will write code for food.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Aug 16, 2012
    #6
  7. Keith Thompson wrote:
    > Why Tea <> writes:
    >> Could anyone please explain the differences between the following array
    >> passing? Thanks!
    >>
    >> 1) int get_data(char d[100]) {...}
    >>
    >> 2) int get_data(char *d) {...}

    >
    > There is no difference in meaning; they're effectively different
    > spellings of the same thing.
    >
    > See http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf 6.7.6.3p7,
    > or the corresponding paragraph in the section on "Function declarators"
    > in earlier versions of the standard.
    >
    > And yes, that means the "100" in the first example is silently ignored
    > (unless the compiler chooses to warn about it, but I know of none that
    > do).


    Yes, however you can get around this by using the static keyword.

    ~Edward
    Edward Rutherford, Aug 16, 2012
    #7
  8. Why Tea

    James Kuyper Guest

    On 08/16/2012 02:10 PM, Varun Tewari wrote:
    > In 1, you actually duplicating the array in the funciton.
    > in 2, rather you are happy using a reference to the array, hence no duplication.


    Both declarations declare a pointer which provides a reference to the
    array (or more precisely, the first element of the array. Neither
    declaration involves duplication of the array.
    James Kuyper, Aug 16, 2012
    #8
  9. Why Tea

    Eric Sosman Guest

    On 8/16/2012 3:00 PM, James Kuyper wrote:
    > On 08/16/2012 02:10 PM, Varun Tewari wrote:
    >> In 1, you actually duplicating the array in the funciton.
    >> in 2, rather you are happy using a reference to the array, hence no duplication.

    >
    > Both declarations declare a pointer which provides a reference to the
    > array (or more precisely, the first element of the array. Neither
    > declaration involves duplication of the array.


    Still more precisely: To any element of any array, or even to a
    free-standing object. (For purposes of pointer arithmetic, single
    objects are treated as one-element arrays.)

    void f(int array[42]) {
    printf("*(%p) = %d\n", (void*)array, *array);
    }
    ...
    int alone = 66;
    f(&alone); // OK
    ...
    int small[] = { 1, 2, 3 };
    f(small); // OK
    f(small + 1); // OK
    f(&small[2]); // OK
    ...
    int array[99] = { 3, 1, 4, 1, 5, 9, /* rest zero */ };
    f(array); // OK
    f(&array[12]); // OK
    f(array + 97); // OK

    --
    Eric Sosman
    d
    Eric Sosman, Aug 16, 2012
    #9
  10. Varun Tewari <> writes:
    > In 1, you actually duplicating the array in the funciton.
    > in 2, rather you are happy using a reference to the array, hence no duplication.


    No, they are semantically identical.

    Please read the other answers before posting your own.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Will write code for food.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Aug 16, 2012
    #10
  11. Edward Rutherford <> writes:
    > Keith Thompson wrote:
    >> Why Tea <> writes:
    >>> Could anyone please explain the differences between the following array
    >>> passing? Thanks!
    >>>
    >>> 1) int get_data(char d[100]) {...}
    >>>
    >>> 2) int get_data(char *d) {...}

    >>
    >> There is no difference in meaning; they're effectively different
    >> spellings of the same thing.
    >>
    >> See http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf 6.7.6.3p7,
    >> or the corresponding paragraph in the section on "Function declarators"
    >> in earlier versions of the standard.
    >>
    >> And yes, that means the "100" in the first example is silently ignored
    >> (unless the compiler chooses to warn about it, but I know of none that
    >> do).

    >
    > Yes, however you can get around this by using the static keyword.


    Not really. Even if you write:

    int get_data(char d[static 100]) { ... }

    the compiler is free to silently ignore both the "static" and the "100".

    The "static 100" means that "the value of the corresponding
    actual argument shall provide access to the first element of an
    array with at least as many elements as specified by the size
    expression" (N1370 6.7.6.3p7). But since the "shall" is not
    part of a constraint, it just means that violating it causes the
    behavior to be undefined. Compilers may use the information for
    diagnostics and/or optimizations, but they're not required to.
    And "d" is still a pointer, not an array.

    gcc 4.7, for example, produces no warnings for this program:

    #include <stdio.h>

    int get_data(char d[static 100])
    {
    printf("sizeof d = %zu\n", sizeof d);
    return sizeof d;
    }

    int main(void) {
    char tiny[10];
    char huge[1000];
    get_data(tiny);
    get_data(huge);
    return 0;
    }

    The output is:

    sizeof d = 4
    sizeof d = 4

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Will write code for food.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Aug 16, 2012
    #11
  12. Keith Thompson wrote:
    > gcc 4.7, for example, produces no warnings for this program:
    >
    > #include <stdio.h>
    >
    > int get_data(char d[static 100])
    > {
    > printf("sizeof d = %zu\n", sizeof d); return sizeof d;
    > }
    >
    > int main(void) {
    > char tiny[10];
    > char huge[1000];
    > get_data(tiny);
    > get_data(huge);
    > return 0;
    > }
    >
    > The output is:
    >
    > sizeof d = 4
    > sizeof d = 4


    However as this code produces undefined behavior, isn't it difficult to
    read anything much into what it outputs?
    Edward Rutherford, Aug 16, 2012
    #12
  13. Why Tea

    James Kuyper Guest

    On 08/16/2012 05:11 PM, Edward Rutherford wrote:
    > Keith Thompson wrote:
    >> gcc 4.7, for example, produces no warnings for this program:
    >>
    >> #include <stdio.h>
    >>
    >> int get_data(char d[static 100])
    >> {
    >> printf("sizeof d = %zu\n", sizeof d); return sizeof d;
    >> }
    >>
    >> int main(void) {
    >> char tiny[10];
    >> char huge[1000];
    >> get_data(tiny);
    >> get_data(huge);
    >> return 0;
    >> }
    >>
    >> The output is:
    >>
    >> sizeof d = 4
    >> sizeof d = 4

    >
    > However as this code produces undefined behavior, isn't it difficult to
    > read anything much into what it outputs?


    True - the relevant information was "no warnings" - which implies that
    gcc (correctly, IMO) does not think that a diagnostic is required by
    this code. Diagnosis of such cases would have to be mandatory for this
    feature to be of much use.
    James Kuyper, Aug 16, 2012
    #13
  14. Vincenzo Mercuri <> writes:
    > Il 16/08/2012 20:10, Varun Tewari ha scritto:
    >> In 1, you actually duplicating the array in the funciton.
    >> in 2, rather you are happy using a reference to the array, hence no duplication.

    >
    > Wrong, AFAIK the only way to "pass an array by value" is by using a common
    > "trick": declare an array inside a struc and pass that struct as argument
    > to a function:

    [snip]

    Yes, but you can only do that with arrays whose size is known at
    compile time (you can't have a VLA as a struct member), which limits
    its usefulness.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Will write code for food.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Aug 17, 2012
    #14
  15. Kenneth Brodyæ–¼ 2012å¹´8月16日星期四UTC+8下åˆ11時02分26秒寫é“:
    > On 8/16/2012 9:25 AM, Why Tea wrote:
    >
    > > Could anyone please explain the differences between

    >
    > > the following array passing? Thanks!

    >
    > >

    >
    > > 1) int get_data(char d[100]) {...}

    >
    > >

    >
    > > 2) int get_data(char *d) {...}

    >
    >
    >
    > In (1), the function gets passed a pointer to an array of 100 chars. In
    >
    > (2), the function gets passed a "generic" pointer to char.
    >
    >
    >
    > I expected some differences in the compiler's treatment of the code, but a
    >
    > test here shows none.
    >


    This is the famous and notorious rule in C for arrays.

    It is assumed that the caller is responsible.

    No boundary checking for allocated arrays or pointers is the default in C.

    >
    >
    > Which brings me to a related question... The following gives me no errorsor
    >
    > warnings, even with warnings set to max. Shouldn't it at least warn me, if
    >
    > not downright fail?
    >
    >
    >
    > extern void foo(char array[100]);
    >
    >
    >
    > void bar(void)
    >
    > {
    >
    > char array[50];
    >
    > foo(array);
    >
    > }
    >
    >
    >
    > Also, this gives no warnings:
    >
    >
    >
    > void foo(char array[100])
    >
    > {
    >
    > array++;
    >
    > }
    >
    >
    >
    > (Note that "array" is incremented by 1, not 100.)
    >
    >
    >
    > --
    >
    > Kenneth Brody




    Kenneth Brodyæ–¼ 2012å¹´8月16日星期四UTC+8下åˆ11時02分26秒寫é“:
    > On 8/16/2012 9:25 AM, Why Tea wrote:
    >
    > > Could anyone please explain the differences between

    >
    > > the following array passing? Thanks!

    >
    > >

    >
    > > 1) int get_data(char d[100]) {...}

    >
    > >

    >
    > > 2) int get_data(char *d) {...}

    >
    >
    >
    > In (1), the function gets passed a pointer to an array of 100 chars. In
    >
    > (2), the function gets passed a "generic" pointer to char.
    >
    >
    >
    > I expected some differences in the compiler's treatment of the code, but a
    >
    > test here shows none.
    >
    >
    >
    > Which brings me to a related question... The following gives me no errorsor
    >
    > warnings, even with warnings set to max. Shouldn't it at least warn me, if
    >
    > not downright fail?
    >
    >
    >
    > extern void foo(char array[100]);
    >
    >
    >
    > void bar(void)
    >
    > {
    >
    > char array[50];
    >
    > foo(array);
    >
    > }
    >
    >
    >
    > Also, this gives no warnings:
    >
    >
    >
    > void foo(char array[100])
    >
    > {
    >
    > array++;
    >
    > }
    >
    >
    >
    > (Note that "array" is incremented by 1, not 100.)
    >
    >
    > --
    >
    > Kenneth Brody


    Of course, there are programming languages do check arrays in both
    the caller part and the callee part to be easy to be tracked by
    novices in debugging programs with the prices of slower execution speeds.
    88888 Dihedral, Aug 17, 2012
    #15
  16. Il 17/08/2012 01:10, Keith Thompson ha scritto:
    > Vincenzo Mercuri <> writes:
    >> Il 16/08/2012 20:10, Varun Tewari ha scritto:
    >>> In 1, you actually duplicating the array in the funciton.
    >>> in 2, rather you are happy using a reference to the array, hence no duplication.

    >>
    >> Wrong, AFAIK the only way to "pass an array by value" is by using a common
    >> "trick": declare an array inside a struc and pass that struct as argument
    >> to a function:

    > [snip]
    >
    > Yes, but you can only do that with arrays whose size is known at
    > compile time (you can't have a VLA as a struct member), which limits
    > its usefulness.
    >


    True. I've never used that trick so far. I didn't think about
    a VLA, thanks for the heads-up!

    --
    Vincenzo Mercuri
    Vincenzo Mercuri, Aug 17, 2012
    #16
  17. Why Tea

    Jens Gustedt Guest

    Am 16.08.2012 18:43, schrieb John Bode:
    > You can declare "foo" as either
    >
    > void foo(int a[20])
    >
    > or
    >
    > void foo (int a[])
    >
    > or
    >
    > void foo (int *a)
    >
    > and all will be interpreted the same way.


    There is a fourth way that is valid since C99

    void foo(int a[static 20])

    which still is compatible with the above declarations, but in addition
    reclaims that the pointer passed to the function has at least 20
    elements. In particular in implies that foo shouldn't be called with a
    null pointer. If a caller does not respect that semantics, the
    behavior is undefined.

    So this is still the same ABI and still the caller is responsible for
    the check. And if on the calling side the actual argument is an array
    and not a plain pointer that check should almost be trivial to
    implement.

    Unfortunately, there doesn't seem to be compilers that implement
    it. Or does anybody know of such a compiler?

    Jens
    Jens Gustedt, Aug 17, 2012
    #17
  18. Why Tea

    Guest

    Sometimes they differ, in your particular case - they don't.
    #include <iostream>

    void f(int (*p)[3])
    // void f(int (*p)[5]) // error: cannot convert ‘int (*)[3]’ to ‘int (*)[5]’ for argument ‘1’ to ‘void f(int (*)[5])’
    // void f(int **p) // error: cannot convert ‘int (*)[3]’ to ‘int**’for argument ‘1’ to ‘void f(int**)
    {
    std::cout << (*p)[1];
    }

    int main(int argc, char* argv[])
    {
    int a[3] = {1, 2, 3};
    f(&a);
    }
    , Aug 17, 2012
    #18
  19. writes:
    > Sometimes they differ, in your particular case - they don't.
    > #include <iostream>
    >
    > void f(int (*p)[3])
    > // void f(int (*p)[5]) // error: cannot convert ‘int (*)[3]’ to ‘int (*)[5]’ for argument ‘1’ to ‘void f(int (*)[5])’
    > // void f(int **p) // error: cannot convert ‘int (*)[3]’ to ‘int**’ for argument ‘1’ to ‘void f(int**)
    > {
    > std::cout << (*p)[1];
    > }
    >
    > int main(int argc, char* argv[])
    > {
    > int a[3] = {1, 2, 3};
    > f(&a);
    > }


    The question was about the difference between
    int get_data(char d[100]) {...}
    and
    int get_data(char *d) {...}

    i.e., between a parameter defined as "array of foo" and one defined as
    "pointer to foo".

    Your examples involve pointers of different types, namely

    pointer to array 3 of int
    pointer to array 5 of int
    pointer to pointer to int

    Your examples are not relevant to the question.

    Oh, and your sample code is C++, not C.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Will write code for food.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Aug 17, 2012
    #19
  20. Why Tea

    ais523 Guest

    Keith Thompson wrote:

    > Vincenzo Mercuri <> writes:
    >> Il 16/08/2012 20:10, Varun Tewari ha scritto:
    >>> In 1, you actually duplicating the array in the funciton.
    >>> in 2, rather you are happy using a reference to the array, hence no duplication.

    >>
    >> Wrong, AFAIK the only way to "pass an array by value" is by using a common
    >> "trick": declare an array inside a struc and pass that struct as argument
    >> to a function:

    > [snip]
    >
    > Yes, but you can only do that with arrays whose size is known at
    > compile time (you can't have a VLA as a struct member), which limits
    > its usefulness.


    You could use a flexible array member instead, which would come to much
    the same thing. (Or the infamous C89 "struct hack", which as far as I
    know was never guaranteed to work, but which does in every C compiler
    anyone's tested.)

    --
    ais523
    ais523, Aug 26, 2012
    #20
    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. dee
    Replies:
    9
    Views:
    493
    Joseph Byrns
    Apr 15, 2005
  2. Will
    Replies:
    4
    Views:
    468
    Raymond DeCampo
    Aug 27, 2005
  3. Anand
    Replies:
    2
    Views:
    887
    Anand
    Sep 11, 2003
  4. Replies:
    3
    Views:
    1,504
  5. Steve Neill
    Replies:
    4
    Views:
    67
    Steve Neill
    Oct 27, 2004
Loading...

Share This Page