## DEV Community 👩‍💻👨‍💻 # Pointers In C - Arrays and Strings

Pointers are arguably the most difficult feature of C to understand. But, it is one of the features which make C an excellent language. This is the second article in the series. You can read the first one here.

### 0. Why pointers and arrays?

In C, pointers and arrays have quite a strong relationship. The reason they should be discussed together is what you can achieve with array notation ( `arrayName[index]`) can also be achieved with pointers, generally faster.

### 1. 1-D Arrays

Let us look at what happens when we write `int myArray;`.

Five consecutive blocks of memory starting from `myArray` to `myArray` are created with garbage values in them. Each of the blocks is of size 4 bytes.

Thus, if the address of myArray is `100` (say), the address of the rest of the blocks would be `104`, `108`, `112`, and `116`.

Now, have a look at the following code -

``````int prime = {2,3,5,7,11};
printf("Result using &prime = %d\n",&prime);
printf("Result using prime = %d\n",prime);
printf("Result using &prime = %d\n",&prime);

/* Output */
Result using &prime = 6422016
Result using prime = 6422016
Result using &prime = 6422016
``````

So, `&prime`, `prime`, and `&prime` all give the same address, right? Well, wait and read because you are in for a surprise (and confusion). Let's try to increment each of `&prime`, `prime`, and `&prime` by 1.

``````printf("Result using &prime = %d\n",&prime + 1);
printf("Result using prime = %d\n",prime + 1);
printf("Result using &prime = %d\n",&prime + 1);

/* Output */
Result using &prime = 6422036
Result using prime = 6422020
Result using &prime = 6422020
``````

Wait! How come `&prime + 1` results to something different than the other two? And why `prime + 1` and `&prime + 1` are still equal? Let's answer these questions.

1.`prime` and `&prime`, both point to the 0th element of the array `prime`. Thus, name of an array is itself a pointer to the 0th element of the array.

Here, both point to the first element of size 4 bytes. When you add 1 to them, they now point to the 1st element in the array. Therefore an increase in the address by 4.

2.`&prime` on the other hand is a pointer to an `int` array of size 5. It stores the base address of the array `prime`, which is equal to the address of the first element. However, increase by 1 to it results in an address with an increase of 5 x 4 = 20 bytes.

In short, `arrayName` and `&arrayName` point to the 0th element whereas `&arrayName` points to the whole array.

We can access the array elements using subscripted variables like this -

``````int prime = {2,3,5,7,11};
for( int i = 0; i < 5; i++)
{
printf("index = %d, address = %d, value = %d\n", i, &prime[i], prime[i]);
}
``````

We can do the same using pointers which are always faster than using subscripts.

``````int prime = {2,3,5,7,11};
for( int i = 0; i < 5; i++)
{
printf("index = %d, address = %d, value = %d\n", i, prime + i, *(prime + i));
}
``````

Both methods give the output -

``````index = 0, address = 6422016, value = 2
index = 1, address = 6422020, value = 3
index = 2, address = 6422024, value = 5
index = 3, address = 6422028, value = 7
index = 4, address = 6422032, value = 11
``````

Thus, `&arrayName[i]` and `arrayName[i]` are same as `arrayName + i` and `*(arrayName + i)` respectively.

### 2. 2-D Arrays

Two-dimensional arrays are an array of arrays.

``````int marks = { { 98, 76, 89},
{ 81, 96, 79},
{ 88, 86, 89},
{ 97, 94, 99},
{ 92, 81, 59}
};
``````

Here, `marks` can be thought of as an array of 5 elements, each of which is a one-dimensional array containing 3 integers. Let us work through a series of programs to understand different subscripted expressions.

``````printf("Address of whole 2-D array = %d\n", &marks);
printf("Addition of 1 results in %d\n", &marks +1);

/* Output */
Address of whole 2-D array = 6421984
Addition of 1 results in 6422044
``````

Like 1-D arrays, `&marks` points to the whole 2-D array, `marks`. Thus, increment to it by 1 ( = 5 arrays X 3 integers each X 4 bytes = 60) results in increment by 60 bytes.

``````printf("Address of 0th array = %d\n", marks);
printf("Addition of 1 results in %d\n", marks +1);
printf("Address of 0th array =%d\n", &marks);
printf("Addition of 1 results in %d\n", &marks + 1);

/* Output */
Address of 0th array = 6421984
Addition of 1 results in 6421996
Address of 0th array = 6421984
Addition of 1 results in 6421996
``````

If `marks` was a 1-D array, `marks` and `&marks` would have pointed to the 0th element. For a 2-D array, elements are now 1-D arrays. Hence, `marks` and `&marks` point to the 0th array (element), and the addition of 1 point to the 1st array.

``````printf("Address of 0th element of 0th array = %d\n", marks);
printf("Addition of 1 results in %d\n", marks + 1);
printf("Address of 0th element of 1st array = %d\n", marks);
printf("Addition of 1 results in %d\n", marks + 1);

/* Output */
Address of 0th element of 0th array = 6421984
Addition of 1 results in 6421988
Address of 0th element of 1st array = 6421996
Addition of 1 results in 6422000
``````

And now, comes the difference. For a 1-D array, `marks` would give the value of the 0th element. An increment by 1 would increase the value by 1.

But, in a 2-D array, `marks` points to the 0th element of the 0th array. Similarly, `marks` points to the 0th element of the 1st array. An increment by 1 would point to the 1st element in the 1st array.

``````printf("Value of 0th element of 0th array = %d\n", marks);
printf("Addition of 1 results in %d", marks + 1);

/* Output */
Value of 0th element of 0th array = 98
Addition of 1 results in 99
``````

This is the new part. `marks[i][j]` gives the value of the jth element of the ith array. An increment to it changes the value stored at `marks[i][j]`. Now, let us try to write `marks[i][j]` in terms of pointers.

We know `marks[i] + j` would point to the ith element of the jth array from our previous discussion. Dereferencing it would mean the value at that address. Thus, `marks[i][j]` is equal to `*(marks[i] + j)`.

From our discussion on 1-D arrays, `marks[i]` is the same as `*(marks + i)`. Thus, `marks[i][j]` can be written as `*(*(marks + i) + j)` in terms of pointers.

Here is a summary of notations comparing 1-D and 2-D arrays.

Expression 1-D Array 2-D Array
`&ArrayName` points to the address of whole array, adding 1 increases the address by `1 x sizeof(ArrayName)` points to the address of whole array, adding 1 increases the address by `1 x sizeof(ArrayName)`
`ArrayName` points to the `0th` element, adding 1 increases the address to `1st` element points to the `0th` element (array), adding 1 increases the address to `1st` element (array)
`&ArrayName[i]` points to the the `ith` element, adding 1 increases the address to `(i+1)th` element points to the `ith` element (array), adding 1 increases the address to the `(i+1)th` element (array)
`ArrayName[i]` gives the value of the `ith` element, adding 1 increases the value of the `ith` element points to the `0th` element of the `ith` array, adding 1 increases the address to `1st` element of the `ith` array
`ArrayName[i][j]` Nothing gives the value of the `jth` element of the `ith` array, adding 1 increases the value of the `jth` element of the `ith` array
Pointer Expression To Access The Elements `*(ArrayName + i)` `*(*(ArrayName + i) + j)`

### 3. Strings

A string is a one-dimensional array of characters terminated by a `null(\0)`. When we write `char name[] = "Srijan";`, each character occupies one byte of memory with the last one always being `\0`.

Similar to the arrays we have seen, `name` and `&name` points to the `0th` character in the string, while `&name` points to the whole string. Also, `name[i]` can be written as `*(name + i)`.

``````/* String */
char champions[] = "Liverpool";

printf("Pointer to whole string = %d\n", &champions);
printf("Addition of 1 results in %d\n", &champions + 1);

/* Output */
Address of whole string = 6421974
Addition of 1 results in 6421984

printf("Pointer to 0th character = %d\n", &champions);
printf("Addition of 1 results in %d\n", &champions + 1);

/* Output */
Address of 0th character = 6421974
Addition of 1 results in a pointer to 1st character 6421975

printf("Pointer to 0th character = %d\n", champions);
printf("Addition of 1 results in a pointer to 1st character %d\n", champions + 1);

/* Output */
Address of 0th character = 6421974
Addition of 1 results in 6421975

printf("Value of 4th character = %c\n", champions);
printf("Value of 4th character using pointers = %c\n", *(champions + 4));

/* Output */
Value of 4th character = r
Value of 4th character using pointers = r
``````

A two-dimensional array of characters or an array of strings can also be accessed and manipulated as discussed before.

``````/* Array of Strings */
char top = {
"Liverpool",
"Man City",
"Man United",
"Chelsea",
"Leicester",
"Tottenham"
};

printf("Pointer to 2-D array = %d\n", &top);
printf("Addition of 1 results in %d\n", &top + 1);

/* Output */
Pointer to 2-D array = 6421952
Addition of 1 results in 6422042

printf("Pointer to 0th string = %d\n", &top);
printf("Addition of 1 results in %d\n", &top + 1);

/* Output */
Pointer to 0th string = 6421952
Addition of 1 results in 6421967

printf("Pointer to 0th string = %d\n", top);
printf("Addition of 1 results in %d\n", top + 1);

/* Output */
Pointer to 0th string = 6421952
Addition of 1 results in 6421967

printf("Pointer to 0th element of 4th string = %d\n", top);
printf("Pointer to 1st element of 4th string = %c\n", top + 1);

/* Output */
Pointer to 0th element of 4th string = 6422012
Pointer to 1st element of 4th string = 6422013

printf("Value of 1st character in 3rd string = %c\n", top);
printf("Same using pointers = %c\n", *(*(top + 3) + 1));

/* Output */
Value of 1st character in 3rd string = h
Same using pointers = h
``````

### 4. Array of Pointers

Like an array of `int`s and an array of `char`s, there is an array of pointers as well. Such an array would simply be a collection of addresses. Those addresses could point to individual variables or another array as well.

The syntax for declaring a pointer array is -

``````dataType *variableName[size];

/* Examples */
int *example1;
char *example2;
``````

Following operators precedence, the first example can be read as - `example1` is an array(`[]`) of 5 pointers to `int`. Similarly, `example2` is an array of 8 pointers to `char`.

We can store the two-dimensional array to string `top` using pointer array and save memory as well.

``````char *top[] = {
"Liverpool",
"Man City",
"Man United",
"Chelsea",
"Leicester",
"Tottenham"
};
``````

`top` will be containing the base addresses of all the respective names. The base address of `"Liverpool"` will be stored in `top`, `"Man City"` in `top`, and so on.

In the earlier declaration, we required 90 bytes to store the names. Here, we only require ( 58 (sum of bytes of names) + 12 ( bytes required to store the address in the array) ) 70 bytes.

The manipulation of strings or integers becomes a lot easier when using an array of pointers.

If we try to put `"Leicester"` ahead of `"Chelsea"`, we just need to switch the values of `top` and `top` like below -

``````char *temporary;
temporary = top;
top = top;
top = temporary;
``````

Without pointers, we would have required to exchange every character of the strings, which would have taken more time. That's why strings are generally declared using pointers.

### 5. Pointer to Array

Like "pointer to `int`" or "pointer to `char`", we have pointer to array as well. This pointer points to whole array rather than its elements.

Remember we discussed how `&arrayName` points to the whole array? Well, it is a pointer to array.

A pointer to array can be declared like -

``````dataType (*variableName)[size];

/* Examples */
int (*ptr1);
char (*ptr2);
``````

Notice the parentheses. Without them, these would be an array of pointers. The first example can be read as - `ptr1` is a pointer to an array of 5 `int`(integers).

``````int goals[] = { 85,102,66,69,67};
int (*pointerToGoals) = &goals;
printf("Address stored in pointerToGoals %d\n", pointerToGoals);
printf("Dereferncing it, we get %d\n",*pointerToGoals);

/* Output */
Dereferencing it, we get 6422016
``````

When we dereference a pointer, it gives the value at that address. Similarly, by dereferencing a pointer to array, we get the array and the name of the array points to the base address. We can confirm that `*pointerToGoals` gives the array `goals` if we find its size.

``````printf("Size of goals = %d, *pointerToGoals);

/* Output */
Size of goals = 20
``````

If we dereference it again, we will get the value stored in that address. We can print all the elements using `pointerToGoals`.

``````for(int i = 0; i < 5; i++)
printf("%d ", *(*pointerToGoals + i));

/* Output */
85 102 66 69 67
``````

Pointers and pointer to arrays are quite useful when paired up with functions. We will discuss them in the next one.