Why should I declare a C array parameter's size in a function header?

27.4k Views Asked by At

Can anyone enlighten me as to why I should bother to specify the size of a C array argument in a function header? For example:

void foo (int iz[6]) { iz[42] = 43; }

With:

int is[2] = {1,2,3};

we get a useful error. Perhaps it helps with commenting/documentation?

5

There are 5 best solutions below

4
On BEST ANSWER

Can anyone enlighten me as to why I should bother to specify the size of a C array argument in a function header? For example:

void foo (const char sz[6]) { sz[42] = 43; }

IMO, you shouldn't. When you try to pass an array to a function, what's really passed is a pointer to the beginning of the array. Since what the function receives will be a pointer, it's better to write it to make that explicit:

void foo(char const *sz)

Then, since it's now clear that the function has been given no clue of the size, add that as a separate parameter:

void foo(char const *sz, size_t size)
0
On

It's a comment. Arrays are demoted to pointers in function parameters. Comments can still be useful however, even if the compiler doesn't read them.

0
On

Imho, in modern compiler version (like modern gcc), the previous answers are now wrong. Indeed, in modern version of those compilers, the size of the arraw specified in the header of a function is used by the compiler to through very useful warning.

Example : On gcc 12, if you specify :

int f(char string[32]) 

And call the function with :

int main{
char paul[6]="paul"
f(paul);
}

The compiler will through a warning that say that you may does things in f that use 32 char, but that you point only to a 6 bytes memory space.

So : in modern compiler, it help to precise your intention and to let the compiler do additional checking about the concordance of your intention and what you have coded.

Full example :

#include <stdio.h>

void f(char string[32])
{
        printf("%s\n",string);
}

int main(){
        char paul[5]="paul";
        f(paul);
}

Will through :

testi.c: In function ‘main’:
testi.c:12:9: warning: ‘f’ accessing 32 bytes in a region of size 5 [-Wstringop-overflow=]
   12 |         f(paul);
      |         ^~~~~~~
 testi.c:12:9: note: referencing argument 1 of type ‘char[32]’
 testi.c:5:6: note: in a call to function ‘f’
    5 | void f(char string[32])
      |      ^

for a simple call to gcc testi.c -o my_executable

1
On

It is a useful comment when you want to tell to client code that it must pass an array of defined size, i.e:

void foo(const char bar[5]);
/* It is expected that foo function receives an array of size 5 */

Yet, documentation doesn't replace in code checks:

void foo(const char bar[5])
{
    if (!bar) error();
    if (strlen(bar) != 4) error();
    /* ... */
}
4
On

The only meaningful reason to do that is for documentation purposes - to tell the future users that functions expect to receive an array of at least that many elements. But even that is a matter of convention - something that you have to agree upon with other users in advance. The language (the compiler) ignores that size anyway. Your function declaration is equivalent to void foo(int iz[]) and to void foo(int *iz).

The only way to make it somewhat meaningful for the compiler is to declare it as

void foo (int iz[static 6])

which acts as a promise to the compiler that the array will have at least 6 elements, meaning that the compiler will be able to optimize that code using that assumption. Moreover, if you really want to adopt the convention mentioned above, it makes more sense to declare array parameter sizes with static specifically, since the language explicitly defines the semantics of this construct.

What you mean by "we get a useful error" is not clear to me. The code

int is[2] = {1,2,3};
is[42] = 42;

does not contain any constraint violations. It produces undefined behavior, but it is not required to produce a diagnostic message during compilation. In other words, no, we don't get any "useful error" from this.