Why Do C and C++ Compilers Allow Array Lengths in Function Signatures When They'Re Never Enforced

Why do C and C++ compilers allow array lengths in function signatures when they're never enforced?

It is a quirk of the syntax for passing arrays to functions.

Actually it is not possible to pass an array in C. If you write syntax that looks like it should pass the array, what actually happens is that a pointer to the first element of the array is passed instead.

Since the pointer does not include any length information, the contents of your [] in the function formal parameter list are actually ignored.

The decision to allow this syntax was made in the 1970s and has caused much confusion ever since...

In C++, whether int a[] and int *a are the same for function definitions?

The function signatures are the same.
You may check this out by naming all functions with one name.

void f1(int *a) {}
void f1(int a[]) {}
void f1(int a[3]) {}

Your compiler will throw a compile error saying something like "redefinition of void f1(int *)". Now notice this, if you rearrange functions as following:

void f1(int a[3]) {}
void f1(int a[]) {}
void f1(int *a) {}

You will get the same error message about "redefinition of void f1(int *)", not of "void f1(int a[3])". It is because in C++ there's only a way to pass a pointer to an array and function arguments that look like arrays are just syntax ease to pass pointers.
Also check this out: Why do C and C++ compilers allow array lengths in function signatures when they're never enforced?

C++ Array Pass to Function gets cut off

If you really want to pass an array, then pass it by reference (or const reference if you don't intend to change it) via a template, like

template<std::size_t N>
void listElements(/*const*/ char (&arr)[N])
{
// sizeof(arr) will be equal to N
// rest of the function body here
}

If you pass it by value, then it decays to a pointer, i.e. void listElements(char arr[]) is the same as void listElements(charr arr[1024]) is the same as void listElements(char* arr).

PS: note that if you pass the array by reference like above, then your function won't work with pointers anymore, as in this case the compiler differentiate between pointers and arrays. That is, listElements(p) won't compile for char* p;. If you want to use it with pointers (which may be convenient), then you must specify the size manually as an additional parameter of the function, or use some convention for an end-of-array delimiter, such as a zero-terminated strings in C.

Where is an array defined in C, and why don't I have to define it again when I pass it as a function parameter?

Fundamentally in C strings are character arrays. To be very technical they should be terminated with a null character '\0' for use with cstd string lib, string.h.

So what then is an array? It is a continuous block of elements that all have the same type. You can consider array notation just another form of pointer notation to access that contiguous block of memory**.

Saying x = array[0] is really the same as x = *array, and x = array[5] is really the same as x = *(array+5)

When you pass an array in C as a function parameter you're really just passing a pointer to the head of the character array. Your code could just as easily be

int stringstats(char * sString, ... )

So to answer your question:

why do I have to declare cString in the main function, and not sString?

Your array is defined in main() - that's where it exists in memory. It is allocated on the stack and its scope is limited to main(). You did not need to declare it in stringstats(), nor could you. But when you passed a pointer to sString you referenced the array. In doing so you actually defined a pointer to the array on the stack - another auto variable whose scope is limited to stringstats().

If cString was global variable in the same file as main() and stringstats() were in another file you could have then declared cString in stringstats() via extern. This is not the same as defining cString because you wouldn't be allocating new storage for it.

Here is a related post:
C pointer notation compared to array notation: When passing to function

** They are almost the same thing, but I would like to point out one caveat. In C there is something called the array type. Because of it sizeof() (which runs at compile time) can give you the size of the entire array. But when you pass this array it will 'decay' to a pointer, even if you pass it with a size, e.g. foo(array[x]). That x is effectively useless. sizeof() will now just give you the size of the element you are pointing at.

Why does this template for an array's size not work?

The issue is that T array[] is really T* array. To get the actual size you need to pass an array by reference, i.e, parameter T (&array)[N], with N being an integer template parameter.



Related Topics



Leave a reply



Submit