18

a simple question that bugs me. Say I have an array defined in main like so int arr[5]. Now, if I'm still inside main and I set int i = sizeof(arr)/sizeof(arr[0]) then I is set to be 5, but if I pass the array as a function parameter and do the exact same calculation in this function, I get a different number. Why is that? At first I thought its because in a function arr is a pointer, but as far as I know arr is a pointer inside main too!

Also, if I do something very similar only I initialize the array dynamically, I get weird results:

int *arr = (int*) malloc(sizeof(int) * 5);
int length = sizeof(*arr) / sizeof(arr[0]);
printf("%d\n",length);

Here the output is 1. Any ideas why? Thanks in advance!

rdvdijk
  • 4,400
  • 26
  • 30
yotamoo
  • 5,334
  • 13
  • 49
  • 61
  • 3
    sizeof(*arr) / sizeof(arr[0]); // I think *arr is arr[0]. Why not sizeof(arr) – venj Sep 25 '11 at 12:22
  • Don't cast the return value of `malloc`, or else you will eventually duplicate this question: http://stackoverflow.com/questions/7545365/segfault-interview-question-c-puzzle – Steve Jessop Sep 25 '11 at 12:31

6 Answers6

25

C arrays don't store their own sizes anywhere, so sizeof only works the way you expect if the size is known at compile time. malloc() is treated by the compiler as any other function, so sizeof can't tell that arr points to the first element of an array, let alone how big it is. If you need to know the size of the array, you need to explicitly pass it to your function, either as a separate argument, or by using a struct containing a pointer to your array and its size.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Staven
  • 3,113
  • 16
  • 20
  • 5
    ...or by storing a sentinel value in the array, or using some property of the array elements that implies the length.... – Tony Delroy Apr 19 '13 at 09:56
6

This is because arr is now a pointer and it could point to a single int or an array of 1000 ints the function just does not know. You will have to pass the size of the array into the function.

In main arr is declared as an int[5] and so the size can be calculated by the compiler.

mmmmmm
  • 32,227
  • 27
  • 88
  • 117
5

I didn't understand the first question (post some code, please), but for the second:

sizeof(*arr) ;   // is sizeof(int) as arr is of type "int *"
sizeof(arr[0]) ; // is sizeof(int), as arr[0] is the first
                 //     item of an array of int

Fact is, *arr and arr[0] mean exactly the same thing, but said differently. In fact, let say n is an index: *(arr + n) is the same than arr[n].

paercebal
  • 81,378
  • 38
  • 130
  • 159
4

as far as I know arr is a pointer inside main too!

That's the mistake. In main, where you defined int arr[5], arr is an array, not a pointer. Its size is equal to the size of the array, so 5*sizeof(int). When you passed it as a function parameter, that parameter had type int*, so inside the function, you were taking the size of an int* rather than an int[5].

Here the output is 1. Any ideas why?

This time, arr really is a pointer, since you declared it int *arr. But either way, whether it's int *arr or int a[5], *arr and arr[0] mean exactly the same thing: the first element. So of course they have the same size, and sizeof(*arr) / sizeof(arr[0]) is 1.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
3

It's because of the difference between an array of known size and a pointer to an array of unknown size. sizeof is done at compile time and it's not possible for the compiler to tell the size of a dynamically created memory region in advance.

Daniel Trebbien
  • 38,421
  • 18
  • 121
  • 193
David van Laatum
  • 634
  • 4
  • 13
  • 1
    "sizeof is calculated at compile time" - except for VLAs. – Steve Jessop Sep 25 '11 at 12:37
  • @SteveJessop: In a way, I don't think that that is an exception. If `n` is the variable holding the number of elements of a VLA, then `sizeof (int[n])` is calculated to be the expression `n * (sizeof (int))`. Oh well. I restored David's original word "done" rather than "calculated". – Daniel Trebbien Sep 25 '11 at 12:52
  • @Daniel: the important difference is that the result of `sizeof(type)` is a compile-time integer constant unless `type` is a VLA type. It would not be what I understand the meaning of the term "calculated" to be, if you said that the expression `(5+5) * x` is "calculated at compile time" just because the compiler knows to emit code to multiply `x` by the constant `10`. OK, so *some* of the working is done at compile time, but the value isn't calculated at compile time. – Steve Jessop Sep 25 '11 at 12:55
3

You should understand the difference between static and dynamic arrays. Static arrays are types like int, float, double etc. They are different. Even

int a[10];

has a different type from

int b[11];

At compile time, the number of elements in static arrays are known and the sizeof operator returns the number of bytes they occupy.

With pointers that were initialized, either to point to some variable, or to an allocated memory, it is at run-time that it would be apparent where they are pointing to and the compiler cannot determine what would be the size of that array in the future. Therefore, the sizeof a pointer gives you 4 (or 8 in 64bits systems for example).

Note that sizeof operator works at compile-time and not at run-time.

If you need to know the size of an allocated memory (through malloc), you have no choice but to save the size of the array in another variable, for example right after you did the malloc.

Shahbaz
  • 46,337
  • 19
  • 116
  • 182