In C, passing arrays gives no information as to the length of the array passed, since they decay to raw pointers. This leaves the passing of pointer information up to the programmer. I demonstrate a few methods for doing so below, and discuss some pros and cons in the comments.
// only works if array has not already decayed,
// passing a raw pointer produces incorrect results
#define foo(arr) _foo(arr, sizeof arr / sizeof *arr)
// most straightforward option, but can be unsafe
void _foo(int *arr, size_t n)
{
for (size_t i=0; i < n; i++) {
// code
}
}
// very dangerous if array not prepared properly
// simple usage and implementation, but requires sentinel value
void bar(int *arr /* arr must end in -1 */ )
{
for (size_t i=0; arr[i] != -1; i++) {
// code
}
}
/* doesn't provide type safety, pointless
// simplifies usage, still hacky in implementation
#define baz(arr) _baz(sizeof arr / sizeof *arr, &arr)
// safest option, but complex usage and hacky implementation
void _baz(size_t n, int (*pa)[n])
{
int *arr = *pa;
for (size_t i=0; i < n; i++) {
// code
}
}
*/
Are there any other methods I didn't consider? Are there more pros and cons I missed? Overall, what method would you consider to be the best for general use? Which method do you use?
The most common approach seems to be the first option with no macro. Is using the third option with the macro considered to be bad practice? To me it seems the most robust.
I see this question, however it does not mention the third method, and given that it was asked nearly 12 years ago I wouldn't be surprised if new insights could be gained.
EDIT: Upon further inspection, it seems option 3 only provides pointer type safety when the function takes a fixed size array, I incorrectly assumed the method from this answer would extend to varaiable length arrays and neglected to test it.
I'm not sure if the changes in C23 mentioned in chux's answer would fix this method, or if it could be simplified to baz(size_t n, int arr[n])
. Reading through it, nothing in the linked paper seems to suggest int arr[n]
would no longer decay to int *arr
, but I may be wrong.