115

Why isn't the size of an array sent as a parameter the same as within main?

#include <stdio.h>

void PrintSize(int p_someArray[10]);

int main () {
    int myArray[10];
    printf("%d\n", sizeof(myArray)); /* As expected, 40 */
    PrintSize(myArray);/* Prints 4, not 40 */
}

void PrintSize(int p_someArray[10]){
    printf("%d\n", sizeof(p_someArray));
}
Lundin
  • 195,001
  • 40
  • 254
  • 396
Chris_45
  • 8,769
  • 16
  • 62
  • 73

13 Answers13

110

An array-type is implicitly converted into pointer type when you pass it in to a function.

So,

void PrintSize(int p_someArray[10]) {
    printf("%zu\n", sizeof(p_someArray));
}

and

void PrintSize(int *p_someArray) {
    printf("%zu\n", sizeof(p_someArray));
}

are equivalent. So what you get is the value of sizeof(int*)

Lundin
  • 195,001
  • 40
  • 254
  • 396
Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
  • Ok but is there a way to print the size within the function? – Chris_45 Dec 29 '09 at 15:31
  • 2
    In C++ you can pass the array by reference to the function but you cannot do that in C. – Prasoon Saurav Dec 29 '09 at 15:32
  • Allright, great thanks! And BTW that reference stuff, I remember that one shouldn't use that word in C as it has a special meaning in C++, I guess it is the stuff you are mentioning? – Chris_45 Dec 29 '09 at 15:35
  • 14
    You'd need to pass the size of the array as a separate parameter. Then the size of the array would be sizeof(*p_someArray) * length – Aric TenEyck Dec 29 '09 at 15:38
  • 15
    Minor nit: `sizeof` operator returns an object of type `size_t`, so you should print it with `%zu` (C99), or cast it to `int` if you use `%d` like above in your `printf` calls. – Alok Singhal Dec 29 '09 at 15:41
  • @Chris_45: Yes I was referring to references(aliases) in C++ – Prasoon Saurav Dec 29 '09 at 15:46
  • 4
    Alok's statement is correct. Using incorrect format specifier in printf(..) is UB. – Prasoon Saurav Dec 29 '09 at 15:55
  • 2
    @Chris_45: C has no references, but in C you can pass an array by pointer to the entire array as in: `void PrintSize(int (*p_someArray)[10])`. The inside the function you can access the array by using dereference operator `*`: `sizeof(*p_someArray)`. This will have the same effect as using references in C++. – AnT stands with Russia Dec 31 '09 at 04:46
  • @Prasoon, Are there some gotchas we need to lookout for, or is `void PrintSize(int p_someArray[10])` *identical* to `void PrintSize(int *p_someArray)` in every aspect? – Pacerier Sep 21 '13 at 07:04
  • The sizeof() whenever has an array called, does not ever convert array name to a pointer to first element foo[0], this is three scenarios when the name of array is not converted to pointer. An array stores the elements in consequent positions and hence a pointer being incremented is enough. You can initialise an array without the size provided, but while you do provide it, you set the storage space aside and also create a chance of overflow. – Abhineet Sharma Apr 11 '16 at 22:49
18

It's a pointer, that's why it's a common implementation to pass the size of the array as a second parameter to the function

Trent
  • 13,249
  • 4
  • 39
  • 36
user240312
  • 239
  • 1
  • 5
16

As others have stated, arrays decay to pointers to their first element when used as function parameters. It's also worth noting that sizeof does not evaluate the expression and does not require parentheses when used with an expression, so your parameter isn't actually being used at all, so you may as well write the sizeof with the type rather than the value.

#include <stdio.h>

void PrintSize1 ( int someArray[][10] );
void PrintSize2 ( int someArray[10] );

int main ()
{
    int myArray[10];
    printf ( "%d\n", sizeof myArray ); /* as expected 40 */
    printf ( "%d\n", sizeof ( int[10] ) ); /* requires parens */
    PrintSize1 ( 0 ); /* prints 40, does not evaluate 0[0] */
    PrintSize2 ( 0 ); /* prints 40, someArray unused */
}

void PrintSize1 ( int someArray[][10] )
{
    printf ( "%d\n", sizeof someArray[0] );
}

void PrintSize2 ( int someArray[10] )
{
    printf ( "%d\n", sizeof ( int[10] ) );
}
Pete Kirkham
  • 48,893
  • 5
  • 92
  • 171
13

So, you will need to pass the lenght of the array as a second parameter. When you are writing code, in which you both declare an array of constant size, and later pass that array to a function, it is a pain to have the array-length constant show up several places in your code...

K&R to the rescue:

#define N_ELEMENTS(array) (sizeof(array)/sizeof((array)[0])) 

So now you can do e.g:

int a[10];
...
myfunction(a, N_ELEMENTS(a));
S.C. Madsen
  • 5,100
  • 5
  • 32
  • 50
  • what if the size of the array is not available at coding time, but only available at run time? Is there any other way to calculate the size of the array without hard-coding its size? – weefwefwqg3 Jan 30 '17 at 16:02
  • The method shown only works, when the declaration of the array is "in view". For all other cases, you have to manually pass the array-length. – S.C. Madsen Feb 07 '17 at 21:07
6

The behavior you found is actually a big wart in the C language. Whenever you declare a function that takes an array parameter, the compiler ignores you and changes the parameter to a pointer. So these declarations all behave like the first one:

void func(int *a)
void func(int a[])
void func(int a
typedef int array_plz[5];
void func(array_plz a)

a will be a pointer to int in all four cases. If you pass an array to func, it will immediately decay into a pointer to its first element. (On a 64-bit system, a 64-bit pointer is twice as large as a 32-bit int, so your sizeof ratio returns 2.)

The only purpose of this rule is to maintain backwards compatibility with historical compilers that did not support passing aggregate values as function arguments.

This does not mean that it’s impossible to pass an array to a function. You can get around this wart by embedding the array into a struct (this is basically the purpose of C++11’s std::array):

struct array_rly {
int a[5];
};
void func(struct array_rly a)
{
printf("%zd\n", sizeof(a.a)/sizeof(a.a[0]));  /* prints 5 */
}

or by passing a pointer to the array:

void func(const int (*a)[5])
{
printf("%zd\n", sizeof(*a)/sizeof((*a)[0]));  /* prints 5 */
}

In case the array size isn’t a compile-time constant, you can use the pointer-to-array technique with C99 variable-length arrays:

void func(int n, const int (*a)[n])
{
printf("%zd\n", sizeof(*a)/sizeof((*a)[0]));  /* prints n */
}
Walter
  • 443
  • 4
  • 11
5

Because arrays decay into pointers when they are passed as parameters. This is how C works, although you can pass "arrays" in C++ by reference and overcome this issue. Note that you can pass arrays of different sizes to this function:

 // 10 is superfluous here! You can pass an array of different size!
void PrintSize(int p_someArray[10]);
Khaled Alshaya
  • 94,250
  • 39
  • 176
  • 234
5

In c++ you can pass an array by reference for this very purpose :

void foo(int (&array)[10])
{
    std::cout << sizeof(array) << "\n";
}
Alexandre C.
  • 55,948
  • 11
  • 128
  • 197
3

In the C language, there is no method to determine the size of an unknown array, so the quantity needs to be passed as well as a pointer to the first element.

  • 2
    In general, you should always pass the size (number of elements) of an array along with an array to a function, unless you have some other means of determining its size (e.g., a null character terminator at the end of `char[]` string arrays). – David R Tribble Dec 29 '09 at 16:48
  • Please what's an "*an unknown array*"? – alk Dec 30 '17 at 18:09
3

You can't pass arrays to functions.

If you really wanted to print the size, you could pass a pointer to an array, but it won't be generic at all as you need to define the array size for the function as well.

#include <stdio.h>

void PrintSize(int (*p_anArray)[10]);

int main(void) {
    int myArray[10];
    printf("%d\n", sizeof(myArray)); /* as expected 40 */
    PrintSize(&myArray);/* prints 40 */
}

void PrintSize(int (*p_anArray)[10]){
    printf("%d\n", (int) sizeof(*p_anArray));
}
MR.
  • 31
  • 1
0

The behavior is by design.

Same syntax in function parameter declaration means completely different thing than in local variable definition.

The reason is described in other answers.

Pavel Radzivilovsky
  • 18,794
  • 5
  • 57
  • 67
0

In C language when you pass the array as an argument to the function , it is automatically converted into pointer ,array passing from one function other function is know as call by reference . That is the reason the called function only receives the pointer which point to the first element of function This is the reason

fun(int a[]) is similar to fun(int *a) ;

so when you print the size of array it will print the size of first element.

dagrawal
  • 39
  • 2
-1

In 'C' programming languange 'sizeof()' is the operator and he returns the size of the object in bytes.Argument of the 'sizeof()' operator must be a left-value type(integer,float number,struct,array).So if you want to know the size of an array in bytes you can do it very simple.Just use the 'sizeof()' operator and for his argument use the array name.For example:

#include <stdio.h>

main(){

 int n[10];
 printf("Size of n is: %d \n", sizeof(n)); 

}

Output on 32 bit system will be: Size of n is: 40.Because ineteger on 32 system is 4bytes.On 64x it is 8bytes.In this case we have 10 integers declared in one array.So the result is '10 * sizeof(int)'.

Some tips:

If we have an array declared like this one 'int n[]={1, 2, 3, ...155..};'. So we want to know how many elements are stored in this array. Use this alghorithm:

sizeof(name_of_the_array) / sizeof(array_type)

Code: #include

main(){

int n[] = { 1, 2, 3, 44, 6, 7 };
printf("Number of elements: %d \n", sizeof(n) / sizeof(int));
return 0;

}

  • 3
    Welcome to StackOverflow and thanks for writing up an answer. Unfortunately, this doesn't address the question, which specifically is about the difference between `sizeof(n)` for a local variable and `sizeof(arg)` for an argument to a function, even though both are seemingly of type `int[10]`. – MicroVirus Jun 11 '16 at 00:32
-3

Arrays are only loosely sized. For the most part, an array is a pointer to memory. The size in your declaration only tells the compiler how much memory to allocate for the array - it's not associated with the type, so sizeof() has nothing to go on.

plinth
  • 48,267
  • 11
  • 78
  • 120
  • 4
    Sorry, this answer is misleading. Neither are arrays "loosely sized", nor are they "pointers to memory". Arrays have a very exact size, and the places where an array name stands for a pointer to its first element is precisely specified by the C standard. – Jens May 15 '11 at 11:50