Finding Array Size
Starting Out
When first starting out, we might write some code that initializes an array, perhaps does some manipulation, and then displays the results. It might look something like this (contrived example):
void foo(void)
{
int array[10];
int i;
/* Initialize array. */
for ( i = 0; i < 10; ++i )
{
array[i] = i;
}
/* Perform calculations. */
for ( i = 0; i < 10; ++i )
{
array[i] *= 2;
}
/* Print array. */
for ( i = 0; i < 10; ++i )
{
printf("%d,", array[i]);
}
putchar('\n');
}
We notice that if we want to change the array dimension, there are several lines of code to edit to make the change. Maintaining code like this is more difficult because in larger sets of code, finding all of the places that need to be changed becomes less trivial.Using a Symbolic Constant
To avoid this, it is often recommended to use a symbolic constant instead.
#define SIZE 10
void bar(void)
{
int array[SIZE];
int i;
/* Initialize array. */
for ( i = 0; i < SIZE; ++i )
{
array[i] = i;
}
/* Perform calculations. */
for ( i = 0; i < SIZE; ++i )
{
array[i] *= 2;
}
/* Print array. */
for ( i = 0; i < SIZE; ++i )
{
printf("%d,", array[i]);
}
putchar('\n');
}
Now we can see we only need to change the#define to make a change to the array size. Unfortunately, purveyors of this wisdom often stop there.
The debugging hazard that this leads to often materializes itself in some header that is used to declare dozens of such constants. Some may like this, but I've found this to be a maintenance headache as well. For example, let's take a look at this code fragment.
for ( i = 0; i < ASIZE; ++i )
{
printf("%d,", array[i]);
}
Is it correct? You can't tell from this alone. You have to find the declaration of the array and double check. That alone is probably not that big of a deal, except when you have data that may be declared far away from this section of code.Another Way
A cure is such an old piece of code, it's hard to imagine more people aren't aware of it long before they've learned a struct. It works by dividing the total size of the array (in bytes) by the size of the first element of the array (in bytes); this gives the number of elements. This is calculated at compile time.
void baz(void)
{
int array[10];
size_t i;
/* Initialize array. */
for ( i = 0; i < sizeof array / sizeof *array; ++i )
{
array[i] = i;
}
/* Perform calculations. */
for ( i = 0; i < sizeof array / sizeof *array; ++i )
{
array[i] *= 2;
}
/* Print array. */
for ( i = 0; i < sizeof array / sizeof *array; ++i )
{
printf("%d,", array[i]);
}
putchar('\n');
}
Now if you want to change the size of the array, you do it in only one place, and that place happens to be right where you define the array. If we saw the following fragment, is it correct?
for ( i = 0; i < sizeof array / sizeof *array; ++i )
{
printf("%d,", array[i]);
}
Ifarray is an array in scope, yes.
Further Considerations
Some programmers may prefer to use a macro to make it easier to read; either of these are examples.
#define ARRAYSIZE(x) (sizeof(x)/sizeof(*(x)))
#define NELEM(x) (sizeof(x)/sizeof(x[0]))
So another way to write this is as follows.
void qux(void)
{
int array[10];
size_t i;
/* Initialize array. */
for ( i = 0; i < ARRAYSIZE(array); ++i )
{
array[i] = i;
}
/* Perform calculations. */
for ( i = 0; i < NELEM(array); ++i )
{
array[i] *= 2;
}
/* Print array. */
for ( i = 0; i < ARRAYSIZE(array); ++i )
{
printf("%d,", array[i]);
}
putchar('\n');
}
Use With Functions
Finally, if you pass "the array" to a function, you are really only passing a pointer to the first element of the array. In such cases, you should also pass a size parameter to the function.
void fum(int *array, size_t size)
{
size_t i;
/* Initialize array. */
for ( i = 0; i < size; ++i )
{
array[i] = i;
}
/* Perform calculations. */
for ( i = 0; i < size; ++i )
{
array[i] *= 2;
}
/* Print array. */
for ( i = 0; i < size; ++i )
{
printf("%d,", array[i]);
}
putchar('\n');
}
int main(void)
{
int myarray[25];
foo();
bar();
baz();
qux();
fum(myarray, ARRAYSIZE(myarray));
return 0;
}