9
#include <stdio.h>

void test(int arr[]);

int main ()
{
    int *arr[3];
    int ar1[2] = { 1, 2 };
    int ar2[3] = { 3, 4, 5 };
    int vla[ar2[1]];
    arr[0] = ar1;
    arr[1] = ar2;
    arr[2] = vla;

    for  (int i = 0; i < 3; i++)
    {
        test(arr[i]);
    }
}

void test(int arr[])
{
    printf("%zu\r\n", sizeof(arr));
}

As the title say: is this valid? and if so, is there a way to make test() output different values by using sizeof on function argument handed in like on array?

dhein
  • 6,431
  • 4
  • 42
  • 74
  • 3
    No, it's not valid to retrieve array size. By standard the compiler converts array passed as function parameters to qualified pointers. So you'll always get the size of a pointer. – Frankie_C Jan 13 '16 at 16:48
  • The array name will decay to the pointer whenever passed to the function arg. In such case sizeof() will return the size of the pointer. – Sumit Trehan Jan 13 '16 at 16:59
  • Arrays are not pointers. You must understand that. – AnArrayOfFunctions Jan 13 '16 at 18:52
  • @FISOCPP: Did anyone claim they are? – dhein Jan 13 '16 at 19:15
  • Well by the first comment and also by the OP post. I assume he thinks this because of how he stores the pointers to array first elements and then he wants to find their original size by using sizeof operator. Or maybe he doesn't but if someone does - here I pointed this fact just in-case then. By the first post - because you can in generally 'retrieve the size of an array'. – AnArrayOfFunctions Jan 13 '16 at 19:18
  • @FISOCPP: OK, thanks for claryfication. But I'm aware of that. And the way I'm storing the pointers the way I'm doing it because I know that for an array is given that `int arr[n];` the result of `arr == &arr` will be true ;) – dhein Jan 13 '16 at 19:25
  • Well then I can tell you that the only way you can achieve what you want is using VM types but in this case you need to supply this information on compile-time - i.e where to fetch the array size. – AnArrayOfFunctions Jan 13 '16 at 19:30
  • @FISOCPP: Look my comment on accepted answer. An "No it isn't possible this way" Is allready satisfying my needs ^^ – dhein Jan 13 '16 at 19:53
  • `#include "stdio.h"` should be `#include `. `argc` is an `int`, not a `char*`. You don't use `argc` or `argv` anyway, so you might as well use `int main(void)`. The result of `sizeof` should be printed with `%zu`, not `%d`. The `\r` in the format string is unnecessary and possibly harmful. – Keith Thompson Jan 13 '16 at 22:08
  • @KeithThompson: Agrred to all points except the last one. why \r might be harmfull? I learned it never is harmfull but keeping it in may result in more portable code since it is ignored where it isn't needed but where you need it then you have it there. I'm a bit confused since you claim \r isn't needed without any knowledge of the enviroment on the other hand I have never seen any sources confirming what I had been tought. So could you explain this part please? – dhein Jan 14 '16 at 07:55
  • When writing to a text file, `'\n'` is translated to whatever the system's end-of-line representation happens to be (`\n'` on Unix, `\r\n` on Windows). Writing an extra `\r` to a console or terminal emulator is very likely harmless. Writing it to a file could result in a malformed text file. – Keith Thompson Jan 14 '16 at 08:08
  • @KeithThompson: Do you have any refference for reading up when exactly `'\n'` translates that way and when it doesn't? Becuase I never noticed this behaving on windows. but would like to get corrected anyway :) – dhein Jan 14 '16 at 08:12
  • The C standard ([N1570](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf)) is not as explicit on this point as I thought it was, but see 7.21.2 paragraph 2. For a text stream, if you write `"hello\n"` to the stream, you can then read back the same `"hello\n"` -- but the `\n` is translated to the operating system's end-of-line representation, whatever it happens to be. This doesn't happen for binary streams. This is more clearly explained in the [comp.lang.c FAQ](http://www.c-faq.com/), question 12.40. – Keith Thompson Jan 14 '16 at 15:53
  • Basically, unless you're dealing with "foreign" text files, you should never need to write `'\r'` to a text stream. – Keith Thompson Jan 14 '16 at 15:54

3 Answers3

23

Yes it is valid and will give the size of an int pointer (that's what the type of the arr parameter is, there are no array parameters in C) in bytes. 1

To get the size of an array in bytes with sizeof, the argument has to be an actual array, not a pointer.

Consequently, it's not possible to get the size of an array passed as a parameter inside a function without passing an extra parameter specifying the size.

So,

is there a way to make test() output different values by using sizeof on function argument handed in like on array?

no. (Without editing the function body.)

1 If you're wondering how it's possible to pass an array as a pointer parameter, it's because of the implicit array-to-pointer conversion, known as array decaying.

Community
  • 1
  • 1
Emil Laine
  • 41,598
  • 9
  • 101
  • 157
  • 1
    You should add that `arr` in function `test` is a pointer to `int`, i.e. pointer to first element of array passed, therefore do not expect `sizeof(arr)` will give you the size of array passed. It seem OP thinks it will give size of array passed. – haccks Jan 13 '16 at 17:06
  • @haccks Thanks for the clarification. That's what I was trying to say. I made it more clear now. – Emil Laine Jan 13 '16 at 17:20
  • 2
    Actually, it is possible to pass the array with `test(sizeof(arr), &arr)` to a function with the signature `void test(size_t n, int (*arraryPtr)[n])`, which can then inquire the size of the array with `sizeof(*arrayPtr)`. – cmaster - reinstate monica Jan 13 '16 at 17:35
  • @cmaster; Stil you need to specify the size. – haccks Jan 13 '16 at 17:38
  • @haccks Not within the body of `test()` ;-) – cmaster - reinstate monica Jan 13 '16 at 19:05
  • The point was I was trying to trick the preprocessor since if this would work it wouldn't be possible to specify the sizeof had to be replaced by an constant or it has to be evaluated. And was hoping to find some UB I wasn't aware of when array is evaluated or vla is even tryed to be set as constant. But probably this is one of the few reasons why arrays decay into pointers ;) – dhein Jan 13 '16 at 19:14
  • @Deduplicator: man I wrote this code freehanded without any IDE. I'm aware of this but wasn't sure about the notation and tryed to avoid using some notation that even doesn't exist. But this isn't even the point of the post. Anyway to shut this down I'll change it. – dhein Jan 14 '16 at 07:58
  • @Deduplicator: what do you mean by this? – dhein Jan 14 '16 at 13:25
6

Is this:

void test(int arr[]) {
    printf("%d\r\n", sizeof(arr));
}

valid?

It is NOT a valid1 code, however it is equivalent to: sizeof(int*), not size of the array, arr, because as you pass the array as an argument it decays to a pointer2 i.e. it looses the information about the size of the whole array. The only way to convey this information into a function is through an additional, second, parameter.

Is there a way to make test() output different values by using sizeof on function argument handed in like on array?

If you want to print the size of the array you are passing, you could use something like: sizeof(array) as an second argument of the function, where the function signature would be:

void test(int arr[], size_t size); 

you could insert the above as second argument and get the size of the first argument.


1. There is a type mismatch between size_t(the returning type of sizeof()) and int (the expected type matching the specifier "%d" in the printf(),, which leads to undefined behaviour.

2. arr[] outside the function represents the whole array as an object and that is why if you apply sizeof() you will get the size of the whole array, however, when passed as argument, arr decays to a pointer of the array's first element and if you apply sizeof() you'll get the size of the type of the pointer.

Ziezi
  • 6,375
  • 3
  • 39
  • 49
  • 1
    *it is equivalent to: sizeof(int)*: you mean `sizeof(int *)`? – haccks Jan 13 '16 at 17:55
  • Also note that no overloading in C. – haccks Jan 13 '16 at 17:57
  • @haccks there is something about function overloading in C here: http://stackoverflow.com/questions/479207/function-overloading-in-c , but I guess it's too complex and a bit off topic ? Should I remove it? – Ziezi Jan 13 '16 at 18:00
  • I would suggest better to remove it. – haccks Jan 13 '16 at 18:02
  • @haccks fair enough! :) – Ziezi Jan 13 '16 at 18:04
  • 1
    "_`arr[]` outside the function points to the whole array_" Nope, it doesn't point. Arrays don't point. Pointers point. Outside the function, `arr` _is_ the array. – Emil Laine Jan 13 '16 at 18:26
  • There is **not** an implicit conversion from `size_t` to `int` in this code, that is why it is UB. It's hard to describe code as "valid" when it causes UB. – M.M Jan 13 '16 at 22:03
4

Is this code well defined by using sizeof operator?

Pedantically: No

sizeof() returns type size_t. "%d" expects type int. Using mis-match type results in undefined behavior (UB). Step 1: Use matching specifier

// printf("%d\r\n", sizeof(arr));
printf("%zu\r\n", sizeof(arr));
// or
printf("%d\r\n", (int) sizeof(arr));

The following prints the size of a pointer arr. The code in main() is not relevant.

void test(int arr[]) {
  printf("%zu\r\n", sizeof(arr));
}

// or simply: remove (), \r of dubious value
  printf("%zu\n", sizeof arr);
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256