Reputation: 29
In C, I have to pass an array to a function in a single variable, and without knowing what the size the array will be before the program runs. The on-paper solution is to have an extra element to the array where you'll store the array's size (I think this is called a "sentinel value"). Ok, but I'm having problems implementing this.
Passing array[] as a function argument doesn't seem to work. I suppose I can send a pointer to the first element, but how do I then access the rest of the array?
Upvotes: 1
Views: 10775
Reputation: 8205
The choice of the sentinel value depends on the type of data the array stores. For anything involving a pointer, use NULL
, and NAN
for floating points, e.g.:
char *strings[] = {"foo", "bar", "baz", NULL};
double doubles[] = {1.0, 2.4, 6.5, NAN};
Now checking where the array ends amounts to walking along the array until you find the sentinel:
#include <stddef.h> // for NULL
size_t count_strings(char **strings) {
size_t num_strings = 0;
while ((*strings)++ != NULL) {
num_strings++;
}
return num_strings;
}
#include <math.h> // for NAN and isnan(…)
size_t count_doubles(double *doubles) {
...
while (!isnan(*doubles++)) {
...
}
}
Finding a sentinel is more difficult for some data types (say, int
), but you can then choose a conventional value.
Upvotes: 2
Reputation: 45654
In C, an array decays to a pointer to its first element in most contexts:
6.3.2.1 Lvalues, arrays, and function designators
[...] Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.
That is useful, because array indexing a[i]
, is defined using pointer arithmetic: *(a+i)
.
So, you can use the same operations on the pointer as on the array.
Still, there is one downside to this consistency: You cannot pass an array by value without wrapping it in a struct
.
Next, a sentinel
is an invalid value of the element type used as a stop marker, like for strings the 0 and for pointers mostly NULL
.
What you actually described was a counted array, having the length prepended at index ((size_t*)a)[-1]
or some such.
Upvotes: 2
Reputation: 14505
You iterate over the array whose address is passed in as the first parameter, and check the range by the array length that's passed in as the second parameter.
// Or, void f(int *a, int size) as the array decays
// to a pointer when passed into this function
void f(int a[], int size)
{
// It's your own responsibility to make sure you
// don't access the out-of-range elements.
for (int i = 0; i < size; ++i)
{
printf ("%d\n", a[i]);
}
}
// use of f()
int a[10];
// or f(&a[0], sizeof(a) / sizeof(a[0]))
f(a, sizeof(a) / sizeof(a[0]));
Upvotes: -1