CodingBison

A C array is a series of data, where all of them have the same storage type. Defining an array is simple -- we need to provide the storage type of array element, array name, and its size. Thus, if we say "int painting_array", then C defines an array, painting_array, that holds 1000 of integer records.

We can access any element using an index. For an array with n values, the first element has an index of 0, the second element has the next index value, 1, and in the end, the last element has an index of (n-1). The indices allow us to easily navigate, and update the integer values stored in this array.

The following figure shows an array, painting_array, with 5 elements.

painting_array   painting_array
|                |
painting_array   |                |
|     |                |
V     V                V
-----------------------------
| 15 | 101 | 280 | 680 | 85 |
-----------------------------

Figure: An Array with 5 elements

Next, we provide a small program to demonstrate how we can define an array and update its elements. The program begins by declaring, painting_array array that holds 4 integer elements.

#include <stdio.h>

int main () {
int painting_array; /* Define the array */
int i;

/* Assign values to array elements */
painting_array = 1000;
painting_array = 1001;
painting_array = 1002;
painting_array = 1003;

for (i=0; i < 4; i++) {
printf("[i: %d] painting id: %d \n", i, painting_array[i]);
}

printf("Length of array: %d \n",
sizeof(painting_array)/sizeof(painting_array));
return 0;
}

The above program prints elements of the array along with its size. For printing the size of the array, we use the sizeof() function twice. First, to find the total storage of the array and second, to find the storage of the first element (since all elements are of the same size, it does not matter if the element is first or any other). After that, we divide the storage of the total array with the storage of the first element and thereby, get the total number of elements in the array.

Here is the output of the above program:

\$ gcc arrays.c -o array
\$
\$ ./array
[i: 0] painting id: 1000
[i: 1] painting id: 1001
[i: 2] painting id: 1002
[i: 3] painting id: 1003
Length of array: 4

We do not necessarily have to first, declare an array and then, assign values to its elements. C allows us to declare an array and initialize its values, both in the same step. For example, the assignment of values in the previous program can also be achieved as follows: "int painting_array = {1000, 1001, 1002, 1003};".

In fact, specifying the size of the array is optional in the above step. Hence, we could have also written this as: "int painting_array[] = {1000, 1001, 1002, 1003};". With this, C automatically counts the number of elements and assigns a storage size needed to store 4 integers, to the array! What this also means is that, if we were to define an array without specifying neither its size nor initial values, then that would be an error. Thus, compiler would not allow a declaration like "int painting_array[]", since it cannot find the size of the array that it needs to allocate.

Before we move on, we would like to note that when we pass an array to a function, then C passes them by reference, instead of by value. Due to this reason, the sizeof() call would not give the correct size of the array in a called function. The called function only gets a pointer (more on pointers a little later!) and so calling a sizeof() on the passed array would simply return the size of the pointer. If we need the size of the array in the called function, then we must explicitly pass the array length as an additional parameter to the function.

Multi-dimensional Arrays

C also provides multi-dimensional arrays. A multi-dimensional array is essentially an array of arrays. For arrays, there is no limit to the number of dimensions.

Defining a multi-dimensional array is, in some ways, extension of a single-dimensional array. Thus, we can define a 2-dimensional array as "int painting_array[k][m]". This new definition means that the array has k rows and each row has m elements. Thus, the total number of elements is k * m.

Yet another interpretation of "int painting_array[k][m]" is that it is essentially an array of arrays. Thus, painting_array has an array with k values and each of these values is a 1-dimensional array with m values. In fact, this is how C stores a 2-dimensional arrays -- as arrays that in turn have arrays.

Let us see an example of a 2-dimensional array; here, the index to locate an element now has two values: the first value representing the row and the second value representing the column. In other words, "painting_array[i][j] refers to the element sitting on the ith row and the jth column. The following figure shows a 2-dimensional array with 2 rows and 4 columns; we fill each elements with some random numbers.

painting_array[0,1]
|            painting_array[0,4]
painting_array[0,0]      |                   |
|        |                   |
V        V                   V
------------------------------------
| 15   | 237  | 980  |  1   |   5  |
------------------------------------
|  15  |  10  | 280  | 680  |  85  |
------------------------------------
^       ^                    ^
|       |                    |
painting_array[1,0]     |                    |
|            painting_array[1,4]
painting_array[1,1]

Figure: An 2-dimensional array with 2n elements

With that, let us go ahead and extend our earlier program of one-dimensional array to now use a 2-dimensional array. We modify the program so that the the first row continues to have unique IDs of the paintings and in addition, the (new) second row now has the number of pieces available in the store.

Here is the modified program:

#include <stdio.h>

int main () {
int i;
int painting_array; /* 4 rows, each with 2 columns */

/* Painting Unique IDs (first column) */
painting_array = 1000;
painting_array = 1001;
painting_array = 1002;
painting_array = 1003;

/* Number of paintings available in the store (second column) */
painting_array = 100;
painting_array = 10;
painting_array = 10;
painting_array = 11;

for (i=0; i < 4; i++) {
printf("[i: %d] painting id: %d Availability: %d\n",
i, painting_array[i], painting_array[i]);
}

printf("Length of array: %d\n",
sizeof(painting_array)/sizeof(painting_array));
return 0;
}

When we compile and run the program, we output shows both the painting ID and its availability.

\$ gcc doublearrays.c -o doublearray
\$
\$ ./doublearray
[i: 0] painting id: 1000 Availability: 100
[i: 1] painting id: 1001 Availability: 10
[i: 2] painting id: 1002 Availability: 10
[i: 3] painting id: 1003 Availability: 11
Length of array: 8

Like the case of one-dimensional arrays, we can also define the above 2-dimensional array and initialize its elements in one shot. For this, we can initialize the array such that we provide each row as a one-dimensional array. This way, the compiler thinks that the array has this many elements, where each element is also an array.

In terms of defining the size of the array, we can do this in two ways. In the first style, we provide both the number of rows and columns in the declaration.

In the second style, we can skip providing the number of rows as long as we provide the number of columns in each row. Providing the column size is key since this helps the compiler know the size of storage for each row. With that, C would automatically count the number of rows from the data provided. Note that failure to provide the number of columns would be a compilation error.

/* Style 1: Declare both number of rows and columns */
int painting_array = {
{1000, 100},
{1001, 10},
{1002, 10},
{1003, 11},
};

/* Style 2: Declare only the number of columns */
int painting_array[] = {
{1000, 100},
{1001, 10},
{1002, 10},
{1003, 11},
};