A global array does not have to be declared in a header file. However, doing so allows the array to be used, without having to copy/paste the declaration to everywhere it is needed. As soon as there are declarations that are copy/pasted multiple times, there is an opportunity to get things wrong (e.g. have to declarations that are not equivalent). Header files allow avoidance of copy/paste.
As to what I would do, it depends on whether the array is being initialised at the point of definition, and whether code that uses the array needs to know its actual size.
If it is NOT being initialised at the point of definition (in other words the size has to be specified overtly) then I would do this.
Code:
/* in header */
#define ARRAY_SIZE 42
extern int array[ARRAY_SIZE];
/* in one and only one source file which has #include'd the header */.
int array[ARRAY_SIZE];
If it is being initialised when it is defined and other code needs to be able to directly access the array size, then I would do this;
Code:
/* in header */
extern int array[];
extern int array_size;
/* in one and only one source file which has #include'd the header */.
int array[] = {1,2,3,4,5};
int array_size = sizeof(array)/sizeof(*array);
/* in code that uses the array and has #include'd the header */
int main()
{
for (i = 0; i < array_size; ++i)
{
/* do something with array[i] */
}
}
(I'd probably specify that array_size be of type size_t, not int, but you get the idea).
If the array is being initialised when being defined, but code which uses the array does NOT need to know the array size (for example, a sentinel value is used to mark the last element) then I wouldn't supply the size. For example;
Code:
/* in header */
extern int array[];
extern int sentinel;
/* in one and only one source file which has #include'd the header */.
int array[] = {1,2,3,4,5, -1};
int sentinel = -1;
/* in code that uses the array and has #include'd the header */
int main()
{
for (i = 0; array[i] != sentinel; ++i)
{
/* do something with array[i] */
}
}
As to your second question, the whole point of extern is allowing a SINGLE definition for an array that is shared between compilation units. If the array is not declared extern (and defined once) then EVERY compilation unit which defines the array has its own local instance of the array. Changes made to one array, in one compilation unit, do not affect the array defined in another compilation unit.
If you really want to confuse yourself, declare the array extern in some compilation units but not in others. The ones that have declared it extern will share one array among themselves. The ones that don't have an extern declaration will each have a local instance of an array with that name. The two don't mix well.