Skip to main content
Basic Programming In C
Basic Programming In C
2h

Arrays

When one wants to use a large number of variables in a program, it becomes tedious to have an identifier for each variable. Similarly, some data is not suited to basic types and requires a certain amount of memory to be stored. To solve these two problems, a sequence of adjacent memory cells is used, indicated by a single identifier. Thus data is represented in the form of a vector (or array in C). The objective of this chapter is to address the declaration and use of static one-dimensional arrays (vectors) and two-dimensional arrays (matrices). Classic examples of integer arrays and character arrays are given.

Principle and Use

:::warning Array Definition A vector or array is a sequence of cells whose content is of the same type and whose cells are numbered (or indexed) from 0 to N-1 (for an array of size N). :::

In C, the syntax for declaring an array is as follows:


#define N 50

int t[N];           // array of 50 cells where each cell is an integer
char tab[512];      // array of 512 cells where each cell is a character
float ftab[465789]; // array of ...... each cell is a real number

And its use:


int w = t[10];                  // access to the cell at index 10 (11th cell) of array t
int x = 10[t];                  // same
char y = tab[1024];             // see note below
float z = ftab[56 * 3 - 84];    // OK
int t2[N] = {0};                // declaration and initialization of all cells to 0

:::info Note Although algorithmically illegal (accessing the cell at index 1024 of an array of 512 cells), the second line does not systematically generate an error at runtime. If the memory space following the array tab is not used (by another program for example), then no error will be generated. Otherwise, your program causes a segmentation fault error at runtime. Therefore, verify that you do not access outside the array bounds. :::

The arrays we use in this course have a size fixed in advance (at declaration) and cannot be resized. These are called static arrays. However, a number of functions must be effective for arrays of any size. For this, constants can be used to define the size of the arrays used, or functions can be defined for which the size of the arrays used is a parameter (this second approach is preferable). The following program illustrates both approaches:

010_tab_fonction.c
#include <stdio.h>

const int N = 10;

void affiche_tab (int t[N])
{
    for (int i = 0; i < N; ++i)
    {
        printf ("%d ", t[i]);
    }
    printf ("\n");
}

void affiche_tab2 (int t[], int m)
{
    for (int i = 0; i < m; ++i)
    {
        printf ("%d ", t[i]);
    }
    printf ("\n");
}

int main ()
{
    int tab[N] = { 0 };

    affiche_tab (tab);
    affiche_tab2 (tab, N);

    return 0;
}

:::info Note In the declaration of affiche_tab2, you can see that the size of array t is not specified. On one hand because m is not known by the compiler and therefore it is not possible to write int t[m], and on the other hand because the size is optional in the declaration. Thus, in the declaration of affiche_tab, it is perfectly possible not to specify the size. :::

:::warning Important: Passing Arrays as Parameters When passing an array as a function parameter, only the identifier is passed, not the brackets and the size, because outside of an array declaration, the bracket operator [] indicates accessing a cell and not the entire array. :::

Algorithms on Integer Arrays

Here are some classic algorithm examples for integer arrays.

Swapping Two Array Cells

The swap algorithm in C is:

011_echange.c
void echange (int i, int j, int t[])
{
    int tmp;
    tmp  = t[i];
    t[i] = t[j];
    t[j] = tmp;
}

int main ()
{
    const int TAILLE = 32;
    int       t[TAILLE];

    // ... init du tableau ...

    echange (2, 3, t);

    return 0;
}

:::warning C and Array-Type Parameters Arrays are modifiable parameters in C, unlike basic types (more details will be given in the chapter on pointers). In the preceding code, the array t will have its cells at indices 2 and 3 swapped. :::

Traversing an Array

Below is an algorithm that displays all elements of an array:

011b_affiche_tab.c
#include <stdio.h>

void print_tab (int tab[], int size_tab)
{
    for (int i = 0; i < size_tab; i++)
    {
        printf ("%d\n", tab[i]);
    }
}

Copying an Array

Below is an algorithm that copies the content of one array into another array:

011c_copy_tab.c
void copy_tab (int source_tab[], int dest_tab[], int size_tab)
{
    for (int i = 0; i < size_tab; i++)
    {
        dest_tab[i] = source_tab[i];
    }
}

Searching in an Array

Below is an algorithm that finds the largest element of an array:

011d_max_tab.c
int max_tab (int tab[], int size_tab)
{
    // hypothèse que size_tab > 0
    int maximum = tab[0];

    for (int i = 1; i < size_tab; i++)
    {
        if (tab[i] > maximum) maximum = tab[i];
    }

    return maximum;
}

Below are two algorithms that determine whether an element is present in an array. The first version has an early flow break (the function exit is inside a loop), the second does not. Both versions are effective but in general the second version is recommended because it offers more readable and higher quality code (easier to maintain).

011e_find_in_tab_return.c
#include <stdbool.h>

bool find_in_tab_return (int tab[], int size_tab, int value)
{
    for (int i = 0; i < size_tab; i++)
    {
        if (tab[i] == value) return true;
    }
    return false;
}
011f_find_in_tab.c
#include <stdbool.h>

bool find_in_tab_ (int tab[], int size_tab, int value)
{
    bool found = false;
    int  i     = 0;

    while ((false == found) && (i < size_tab))
    {
        if (tab[i] == value) found = true;
        i++;
    }

    return found;
}

Algorithms on Strings

In C, any text of more than one character is represented by an array of characters. These are also called strings since this is a basic type in some programming languages (type string). In C, strings end with a special character which is \0 (ASCII code 0). Thus to store the word toto, an array of 5 characters is needed (4 + 1 for \0). The declaration and initialization of strings is done in several ways:


char chaine1[10] = {'t', 'o', 't', 'o'};
char chaine2[100] = "toto";
char chaine3[] = "toto"; // size calculated automatically, here 5

char c = chaine1[2]; // c equals `t`

Algorithms on characters follow the same principles as those on integer arrays. Below is an algorithm that counts the number of occurrences of the letter a in a string:

011g_count_occurences.c
#include <string.h>

int count_occurences (char char_tab[])
{
    int occurences = 0;

    for (unsigned long i = 0; i < strlen (char_tab); i++)
    {
        if ('a' == char_tab[i]) occurences++;
    }

    return occurences;
}

Two-Dimensional Arrays / Matrices

A matrix here is a two-dimensional array and imposes the same constraints as vectors, namely that all elements must be of the same type and that the size (number of rows and columns) must be fixed. For a matrix of size N × M, rows are indexed from 0 to N-1 and columns from 0 to M-1.

Declaration and Use

In C, the syntax is easily derived from the vector syntax and of course the same restrictions exist as for vectors (memory overflow):


int m[456][946];
char n[456][223];

int x = m[10][20]; // access to cell (10, 20)
int y = n[456 / 10][50];

Classic Examples

Below is an algorithm that displays the content of a matrix (row-by-row display):

011h_print_mat.c
const int M = 128;
const int N = 64;

void print_matrix (int mat[M][N])
{
    for (int i = 0; i < M; i++)
    {
        for (int j = 0; j < N; j++)
        {
            printf ("%d ", mat[i][j]);
        }
        printf ("\n"); // retour a la ligne apres chaque ligne de mat
    }
}

Common Errors with Arrays

No Initialization

This principle is the same as for basic type variables (int, float, char…): all variables must be initialized before use, as shown in the example below:


#include <stdio.h>

void print_tab(int t[], int n)
{
    for (int i = 0; i < n; ++i)
    {
        printf("%d ", t[i]);
    }
    printf("\n");
}

int main()
{
    const int N = 10;
    int tab[N];

    print_tab(tab, N);

    return 0;
}

jdequidt@weppes:~$ clang tab_non_init.c -Wall
jdequidt@weppes:~$ ./a.out
1583286184 32767 0 0 0 0 0 0 0 0
jdequidt@weppes:~$ ./a.out
1565579176 32767 0 0 0 0 0 0 0 0
jdequidt@weppes:~$

Memory Overflow

You must always ensure that when traversing arrays or matrices, you inspect valid cells. Otherwise, the consequences can be significant and particularly complex to fix as shown in the following example:


#include <stdio.h>

void print_tab(int t[], int n)
{
    for (int i = 0; i < n; ++i)
    {
        printf("%d ", t[i]);
    }
    printf("\n");
}

void overflow(int t[], int n)
{
    for (int i = 0; i < 2 * n; ++i)
    {
        t[i] = i * i;
    }
}

int main()
{
    const int N = 10;
    int tab[N] = {0};
    int tab2[N] = {0};

    overflow(tab2, N);

    printf("tab = ");
    print_tab(tab, N);
    printf("tab2 = ");
    print_tab(tab2, N);

    return 0;
}

jdequidt@weppes:~$ clang tab_non_init.c -Wall
jdequidt@weppes:~$ ./a.out
tab = 144 169 196 225 256 289 324 361 0 0
tab2 = 0 1 4 9 16 25 36 49 64 81
jdequidt@weppes:~$

We observe that the content of tab is modified after its initialization even though no instruction modifies it directly. The function that modifies tab2 overflows into tab and therefore indirectly modifies the values of tab. The consequences can be more serious if the function overflow is called with tab as a parameter. In this case, the result is:


jdequidt@weppes:~$ clang tab_non_init.c -Wall
jdequidt@weppes:~$ ./a.out
Segmentation Fault
jdequidt@weppes:~$ echo $?
134
jdequidt@weppes:~$

The memory overflow causes a segmentation fault which terminates the program. The command echo $? displays the return code of main; it is different from 0, confirming that the program did not execute correctly.

Array Copying

It is not possible to copy an array other than by copying its content cell by cell. Thus the expression a = b where a and b are two arrays does not work, cf:


int main()
{
    const int N = 10;
    int tab[N] = {0};
    int tab2[N] = {0};

    init(tab, N);

    tab2 = tab;

    return 0;
}

jdequidt@weppes:~$ clang affect_tab.c -Wall
jdequidt@weppes:~$ ./a.out
temp.c:7:7: error: array type 'int [10]' is not assignable
        tab2 = tab;
        ~~~~ ^
1 error generated.