An array stores a fixed number of elements of one type in contiguous storage. It is useful when several values belong to the same collection, such as scores or daily measurements. C gives you direct indexing but does not automatically protect every access, so knowing the array’s length is part of using it correctly.
Declare and initialize a collection
int scores[4] reserves four int elements. Adding an initializer, such as {12, 8, 15, 5}, gives each element a starting value. You can omit the size when an initializer determines it: int scores[] = {12, 8, 15, 5}. A partially initialized array fills its remaining elements with zero.
An automatic local array declared without an initializer does not start with useful known values. Reading an element before assigning it is a bug. When you want an all-zero integer array, int counts[10] = {0} expresses that intention directly. Do not rely on a previous run appearing to leave zeroes in memory.
Indexes start at zero
For four elements, valid indexes are 0, 1, 2, and 3. scores[0] refers to the first element and scores[3] to the last. scores[4] is outside the array even though the declared length is four. The length counts elements; it is not the last legal index.
A loop should express that relationship clearly: begin at zero and continue while i < count. Using <= visits one extra location. C may not report that mistake immediately. It can corrupt another value, trap later, or appear to work, and none of those outcomes makes the access valid.
int scores[] = {12, 8, 15, 5};
size_t count = sizeof scores / sizeof scores[0];
int total = 0;
for (size_t i = 0; i < count; ++i) {
total += scores[i];
}
printf("Total: %d\n", total);Keep length separate from capacity
sizeof scores gives the size of the whole array in bytes where scores is actually an array. Dividing by sizeof scores[0] gives its element count. size_t is the unsigned type used for object sizes; print it with %zu. This expression is convenient for fixed arrays defined in the same scope.
Capacity is how many elements storage can hold. Logical length is how many currently contain meaningful data. An input buffer with room for one hundred measurements may currently contain only six. Algorithms should process the logical length and check capacity before appending another element. Confusing the two can read uninitialized values.
Functions need a length argument
An array parameter such as int values[] is adjusted to a pointer parameter. The function does not receive an independent array object with its length attached. sizeof values inside that function measures the pointer, not the caller’s array. Pass the count explicitly whenever the function needs it.
A read-only operation can accept const int values[] to express that it will not modify elements through this parameter. A function can still receive a wrong count, so caller and callee must agree on the contract. const protects against certain writes; it does not validate pointer lifetime or bounds.
int sum(const int values[], size_t count) {
int total = 0;
for (size_t i = 0; i < count; ++i) total += values[i];
return total;
}Strings are arrays with a convention
char name[] = "Circuit" stores seven visible characters and a terminating null byte, so the array occupies eight bytes. String functions look for that terminator. It is different from the digit character '0' and different from a newline. A character array without an in-bounds terminator is not a valid C string for functions that expect one.
When reading text, reserve space for the terminator and use bounded input. fgets(buffer, sizeof buffer, stdin) is useful for a line in a real array scope. It can retain the newline if there is room. A byte count is also not necessarily a count of displayed Unicode characters.
Use dimensions deliberately
int grid[2][3] describes two rows with three integers in each row. grid[row][column] selects an entry. Nested loops mirror the dimensions, with row < 2 and column < 3. Each row has a fixed size known from the type, which matters when passing multidimensional arrays to functions.
Start testing with distinctive values rather than repeated zeroes: a transposed index can be invisible in uniform data. Exercise the first and last elements, then try a one-element array where appropriate. For input-driven indexes, reject negative or too-large values before accessing storage. Bounds checks belong before the operation, not after a suspicious result.