0

I want to pass an array as a parameter to another function:

int i;
int main()
{
    int a[5] = {1, 2, 3, 4, 5};

    printf("Main:\n");
    for(i=0; i<sizeof(a)/sizeof(int); i++)
    {
        printf("%i\n", a[i]);
    }

    func(a);

    return;
}
void func(int a[])
{
    printf("Func:\n");
    for(i=0; i<sizeof(a)/sizeof(int); i++)
    {
        printf("%i\n", a[i]);
    }
}

The loop in the main function prints all 5 values:

Main:
1
2
3
4
5

But the loop in the function func only prints 2 values:

Func:
1
2

Why this strange behaviour?

Evgenij Reznik
  • 17,916
  • 39
  • 104
  • 181
  • Possibly a duplicate of http://stackoverflow.com/questions/8154911/passing-arrays-as-parameters-in-c – LSerni Nov 17 '13 at 21:56

3 Answers3

3

I want to pass an array as a parameter to another function:

This is a common pitfall. Arrays do not bring along their length, as they do in other languages. A C "array" is just a bunch of contiguous values, so sizeof will not (necessarily) return the length of the array.

What actually happens is that the function gets passed a pointer to the area of memory where the array is stored (and therefore, to the first element of the array), but no information about that area's size. To "pass an array with size", you must do something to provide the extra information:

  • explicitly pass also its length as an extra parameter. Safer: you can pass uninitialized arrays.

  • use a special "terminating" value on the array. More compact: you pass only one parameter, the pointer to the array.

  • (suggested implicitly by @CisNOTthatGOODbutISOisTHATBAD's comment): pass a pointer to a struct holding a pointer to the memory and a size_t length in elements (or in bytes). This has the advantage of allowing to store yet more metadata about the array.

For arrays of integral type, you could even store the length in the first (zeroth) element of the array. This can sometimes be useful when porting from languages that have 'measured' arrays and indexes starting from 1. In all other cases, go for method #1. Faster, safer, and in my opinion clearer.

Strings are arrays of characters that employ a variation of method #2: they are terminated by a special value (zero).

Using method #1, your function would become:

void func(size_t n, int a[])
{
    printf("Func:\n");
    for (i=0; i < n; i++)
    {
        printf("%i\n", a[i]);
    }
}

(it is equivalent to void func(size_t n, int *a) ).

LSerni
  • 55,617
  • 10
  • 65
  • 107
  • Arrays always bring their length with them unless they're incomplete or being variable length with unspecified size (but in both cases (or at least in the first one) - trying to apply `sizeof` on them will normally generate compiler error). It's just that you can't actually pass arrays as parameters. You could look the answer below - it contain more truth on the question. – AnArrayOfFunctions Jun 10 '16 at 21:13
  • I read @StuartGolodetz 's answer, at the time, and upvoted it, for I felt we were saying the same thing (he possibly more tersely and canonically than I): "arrays", at least in standard C, *don't* bring their length with them. They *do* have a length of course, the amount of memory allocated to them, but the problem here is that the callee has no way of knowing what that amount might be. You could pass a pointer to a `struct` holding the length, and call it a "better array". This specific solution was not put forward -- but, if you did, I'd upvote it. – LSerni Jun 10 '16 at 21:52
  • In case of function parameters - they can only be syntactically declared as "array of type" but in-fact their type is being adjusted into "pointer to type". So in this case we are not dealing with arrays but instead with pointers. Which makes your assumption wrong. Unless you are talking about arrays in general and not as an C type which I don't think is the case. If your edit your question - I may consider up-voting it. – AnArrayOfFunctions Jun 10 '16 at 22:20
  • You may mention that normally arrays are stored (and passed) in therms of pointer to their first element and not using their built-in type and that's it I think. – AnArrayOfFunctions Jun 10 '16 at 22:28
  • I'm afraid I can't do that -- it's not *my* question. But I edited the answer to try and make it clearer that an "array" is a simpler object than what other languages also call "array". – LSerni Jun 10 '16 at 22:33
  • I've never implicitly suggested anything like what you've written there and an `sizeof` operator applied to "C" array will always result in it's length (unless the "C" array is incomplete in which case the compiler will most likely complain and stop compiling because such code is non-conformant). – AnArrayOfFunctions Jun 10 '16 at 22:57
2

Declaring a function with a parameter of array type is equivalent to declaring it with a parameter of pointer type, i.e. your function is equivalent to:

void func(int *a)

As such, the computation of sizeof(a) inside func computes the size of an int *, not the size of the original array (5 * sizeof(int)).

Since the size of an int * on your platform is apparently twice the size of an int, you see two values printed inside the function in contrast to the five printed outside it (where sizeof(a) correctly computes the size of the array).

This is all related to the fact that when you pass an array to a function, what you're actually doing is passing a pointer to its first element.

Note in passing that this is a FAQ of the comp.lang.c newsgroup:

http://c-faq.com/~scs/cgi-bin/faqcat.cgi?sec=aryptr#aryparmsize

Stuart Golodetz
  • 20,238
  • 4
  • 51
  • 80
0

I would change the code to this:

int i;
const int N = 5;
int main()
{
    int a[N] = {1, 2, 3, 4, 5};

    printf("Main:\n");
    for(i=0; i<N; i++)
    {
        printf("%i\n", a[i]);
    }

    func(a);

    return;
}
void func(int a[])
{
    printf("Func:\n");
    for(i=0; i<N; i++)
    {
        printf("%i\n", a[i]);
    }
}

Parameter N is constant and define size of array. I think it is better way, then 2 parameters in function.

jesusko
  • 3
  • 1
  • 2