0

I am reading the TCPL by K&R, when I read something about array and pointer, I write this small code below:

#include <stdio.h>
int sum(int a[])
{
    int t = 0;
    int length = sizeof(a) / sizeof(a[0]) ;
//  printf("%d\n",length);
    for(int i = 0; i != length; ++i)
    {
        t += a[i];
    }
    return t;
}
int main()
{
    int b[5] = {1, 2, 3, 4, 5};
    printf("%d\n",sum(b));
    return 0;
}

The output answer is 1 NOT 15, then I debug this code by adding printf("%d\n",length); the output length is 1 NOT 5. The TCPL tells that a array name converts to pointer when the array name used as argument, but the output answer is wrong, so I wonder that:

  1. What happend when call a funcion with array name used as argument?
  2. The array a[] used parameter in sum(int a[]) has storage or not?
  3. I see two styles when calling a array : fun(int a[]); fun(b) and fun(int *a);fun(b),what the difference?

Thx very much :-)

Jens
  • 69,818
  • 15
  • 125
  • 179
skyline09
  • 129
  • 1
  • 6
  • 1
    `int length = sizeof(a) / sizeof(a[0]) ;` sizeof(a) is 4 bytes, sizeof(a[0]) is 4 bytes as well. How about using length()? – Sergio Mar 19 '13 at 07:59
  • 5
    This gets asked roughly 3-4 times a day. – cnicutar Mar 19 '13 at 07:59
  • 1
    plus, your `for` isn't correct. it should be `for (int i = 0; i <= length; ++i){...}` – varnie Mar 19 '13 at 08:03
  • 2
    @Sergio: There's no `length()` in C. – Jens Mar 19 '13 at 08:05
  • @varnie: No, if length were 5, your loop accessed a non-existing element a[5]. Undefined behavior. – Jens Mar 19 '13 at 08:06
  • @Jens was a long time ago, forgot c :), but guess there is some sort of – Sergio Mar 19 '13 at 08:06
  • 1
    @varnie concur with Jens. Your loop termination condition will reach beyond the end of the array and into undefined behavior. There is nothing wrong with the OP's for-loop. His length calculation is wrong; the usage of the length calculation in the for-loop, however, is correct. – WhozCraig Mar 19 '13 at 08:08
  • 1
    @Sergio: No, there isn't. – alk Mar 19 '13 at 08:10

5 Answers5

3

You cannot call a function and pass a whole array; if you use an array name as a function argument, it is implicitly rewritten as ("decays to") a pointer to its first element. It is equivalent to writing

 int sum(int *a) { ... }

Thus, within the function, sizeof array, does NOT give you the size of the array, only the size of a pointer to its first element.

So how do you know how many elements there are in the array? You need to pass this number explicitly to functions (or define a macro with the number of elements and use it where needed).

Jens
  • 69,818
  • 15
  • 125
  • 179
1

Calling sizeof on an array declared as follows

 int a[5];

will return the size of the array how you currently think it will (ie the full size in bytes of the array - in this case 20 bytes on my machine). When you pass an array like this to a function, the array will decay to a pointer to its first element. Thus when you call sizeof on your function argument you are actually calling it on a pointer type. Had you declared your function to take an int * argument, the error would be more obvious as the type of the variable that you call sizeof is explicit.

mathematician1975
  • 21,161
  • 6
  • 59
  • 101
1

Your third question gets to the heart of the matter: there is no difference between those two as far as the compiler is concerned. Everything about how the argument is passed is the same.

Therefore, in response to your second question, the a parameter doesn't have storage for the underlying array, nor are the members of that array copied. The only storage allocated is for an int * pointer, and that pointer is stored in a. (That somewhat answers your first question as well.)

So, in your function:

int length = sizeof(a) / sizeof(a[0]) ;

is equivalent to

int length = sizeof(int *) / sizeof(int);

which returns 1 on systems where pointers and ints are the same size. If you run this on 64-bit Linux, you will get 2 instead, since pointers are 64 bits and ints are 32 bits.

rra
  • 3,807
  • 18
  • 29
  • If I add 'int length = sizeof(b) / sizeof(b[0]) ;' and return the right answer:5. Two different usage of 'sizeof'?? – skyline09 Mar 19 '13 at 08:39
  • In `main`? Yes, because `b` in `main` is declared as an array and has a size. It's only as a function parameter that arrays "decay" to pointers and lose their size information. The `sizeof` calculation works for arrays declared as local or global variables rather than parameters. – rra Mar 19 '13 at 08:41
0

There is no problem with your call, and there is no difference between fun(int a[]) and fun(int *a) (expect that it is more obvious to the reader that you expect an array and not any pointer). Bot arguments are a pointer to an int.

Your problem here is how you try to determine the length of the array. As the square brackets are empty, there is no way for the compiler to know how long the array behind a is. You can for example provide the length of the array as a second argument. Note: When calling the function, sizeof(b) will provide the correct length, because the compiler knows its length.

SvenS
  • 795
  • 7
  • 15
-1

The sizeof() operator can not be used for getting a dynamically allocated array length.

Here you can find examples of the sizeof() using.

When you try to do sizeof(array_ptr) it is actually gives you size of the pointer.

Thus, you have to pass array length as parameter of the function

Alex
  • 9,891
  • 11
  • 53
  • 87
  • -1, your first setence is just wrong. – Jens Gustedt Mar 19 '13 at 08:41
  • Still not completely correct, VLA are allocated dynamically, too. What C sees as arrays, will always work with `sizeof`. The thing is just that in the function you get a pointer and not an array. – Jens Gustedt Mar 19 '13 at 12:58