Array of strings in C

A string is a 1-D array of characters, so an array of strings is a 2-D array of characters.

Just like we can create a 2-D array of int, float, etc we can also create a 2-D array of character or array of strings. Here is how we can declare a 2-D array of characters.

char ch_arr[3][10] = {
{'s', 'p', 'i', 'k', 'e', '\0'},
{'t', 'o', 'm','\0'},
{'j', 'e', 'r', 'r', 'y','\0'}
};

It is important to end each 1-D array by the null character otherwise, it's just an array of characters. We can't use them as strings.

Declaring an array of string this way is a tedious and error-prone process that's why C provides a more compact way to it. This above initialization is equivalent to:

char ch_arr[3][10] = {
"spike",
"tom",
"jerry"
};

The first subscript of the array i.e 3 denotes the number of strings in the array and the second subscript denotes the maximum length of the string. Recall the that in C, each character occupies 1 byte of data, so when the compiler sees the above statement it allocates 30 bytes (3*10) of memory.

We already know that name of an array is a pointer to the 0th element of the array. Can you guess the type of ch_arr ?

ch_arr is a pointer to an array of 10 characters or int(*)[10] ?

Therefore if ch_arr points to address 1000 then ch_arr + 1 will point to address 1010.

From here we can conclude that:

ch_arr + 0 points to the 0th string or 0th 1-D array.
ch_arr + 1 points to the 1st string or 1st 1-D array.
ch_arr + 2 points to the 2nd string or 2nd 1-D array.

In general ch_arr + i points to the ith string or ith 1-D array.

We know that when we dereference a pointer to an array, we get the base address of the array. So, on dereferencing ch_arr + i we get the base address of the 0th 1-D array.

From this we can conclude that:

*(ch_arr + 0) + 0 points to the 0th character of 0th 1-D array
*(ch_arr + 0) + 1 points to the 1st character of 0th 1-D array
*(ch_arr + 1) + 2 points to the 1st character of 0th 1-D array

Here the type of ch_arr is pointer to char  or char*.

In general, we can say that:

*(ch_arr + i) + j points to the jth character of ith 1-D array. To get the element at jth position of ith 1-D array just dereference the expression.

*(*(ch_arr + i) + j)

We have learned in chapter Pointers and 2-D arrays that in a 2-D array the pointer notation is equivalent to subscript notation. So the above expression can be written as follows:

ch_arr[i][j]

The following program demonstrates how to print an array of strings.

#include<stdio.h>

int main()
{
int i;

char ch_arr[3][10] = {
"spike",
"tom",
"jerry"
};

printf("1st way \n\n");

for(i = 0; i < 3; i++)
{
printf("string = %s \t address = %u\n", ch_arr + i, ch_arr + i);
}

// signal to operating system program ran fine
return 0;
}

Expected Output:

string = spike address = 2686736
string = tom address = 2686746
string = jerry address = 2686756

Some invalid operation on array of string

char ch_arr[3][10] = {
{'s', 'p', 'i', 'k', 'e', '\0'},
{'t', 'o', 'm','\0'},
{'j', 'e', 'r', 'r', 'y','\0'}
};

It allocates 30 bytes of memory. The compiler will do the same thing even if we don't initialize the elements of the array at the time of declaration.

We already know that the name of an array is a constant pointer so the following operations are invalid.

ch_arr[0] = "tyke"; // invalid
ch_arr[1] = "dragon"; // invalid

Here we are trying to assign a string literal (a pointer) to a constant pointer which is obviously not possible.

To assign a new string to ch_arr use the following methods.

strcpy(ch_arr[0], "type"); // valid
scanf(ch_arr[0], "type"); // valid

Let's conclude this chapter by creating another simple program.

This program asks the user to enter a username. If the username entered is one of the names in the master list then the user is allowed to calculate the factorial of a number. Otherwise, an error message is displayed.

#include<stdio.h>
#include<string.h>
int factorial(int );

int main()
{
int i, found = 0, n;

char master_list[5][20] = {
"tom",
"bob",
"tim",
"jim"
}, name[10];

gets(name);

for(i = 0; i < 5; i++)
{
if(strcmp(name, master_list[i]) == 0 )
{
found = 1;
break;
}
}

if(found==1)
{
printf("\nWelcome %s !\n", name);
printf("\nEnter a number to calculate the factorial: ");
scanf("%d", &n);
printf("Factorial of %d is %d", n, factorial(n));
}

else
{
printf("Error: You are not allowed to run this program.", name);
}

// signal to operating system program ran fine
return 0;
}

int factorial(int n)
{
if(n == 0)
{
return 1;
}

else
{
return n * factorial(n-1);
}
}

Expected Output:

1st run:

Enter a number to calculate the factorial: 4
Factorial of 4 is 24

2nd run: