Pointers In C - Arrays and Strings
Tags: beginners, codenewbie, c, pointers
Published: 2020-07-30 09:49:08

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](https://dev.to/its_srijan/pointers-in-c-definition-notation-types-and-arithmetic-2f9n).

---
###Topics - 
   0.[ Why pointers and arrays?](#why)
   1.[ 1-D Arrays](#1D)
   2.[ 2-D Arrays](#2D)
   3.[ Strings](#strings)
   4.[ Array of Pointers](#arrayofpointers)
   5.[ Pointer to Array](#pointertoarray)  

---

###0. Why pointers and arrays?<a name="why"></a>

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<a name="1D"></a>

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

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

Thus, if the address of myArray[0] 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 - 
```c
int prime[5] = {2,3,5,7,11};
printf("Result using &prime = %d\n",&prime);
printf("Result using prime = %d\n",prime);
printf("Result using &prime[0] = %d\n",&prime[0]);

/* Output */
Result using &prime = 6422016
Result using prime = 6422016
Result using &prime[0] = 6422016
```

So, `&prime`, `prime`, and `&prime[0]` 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[0]` by 1.

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

/* Output */
Result using &prime = 6422036
Result using prime = 6422020
Result using &prime[0] = 6422020
```

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

1.`prime` and `&prime[0]`, 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[5]`, 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[0]` point to the 0th element whereas `&arrayName` points to the whole array.

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

```c
int prime[5] = {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.

```c
int prime[5] = {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 - 

```c
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<a name="2D"></a>

Two-dimensional arrays are an array of arrays.

```c
int marks[5][3] = { { 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.

```c
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[5][3]`. Thus, increment to it by 1 ( = 5 arrays X 3 integers each X 4 bytes = 60) results in increment by 60 bytes.

```c
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[0]);
printf("Addition of 1 results in %d\n", &marks[0] + 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[0]` would have pointed to the 0th element. **For a 2-D array, elements are now 1-D arrays**. Hence, `marks` and `&marks[0]` point to the 0th array (element), and the addition of 1 point to the 1st array.

```c
printf("Address of 0th element of 0th array = %d\n", marks[0]);
printf("Addition of 1 results in %d\n", marks[0] + 1);
printf("Address of 0th element of 1st array = %d\n", marks[1]);
printf("Addition of 1 results in %d\n", marks[1] + 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[0]` 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[0]` points to the 0th element of the 0th array. Similarly, `marks[1]` points to the 0th element of the 1st array. An increment by 1 would point to the 1st element in the 1st array.

```c
printf("Value of 0th element of 0th array = %d\n", marks[0][0]);
printf("Addition of 1 results in %d", marks[0][0] + 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 name="strings"></a>

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[0]` points to the `0th` character in the string, while `&name` points to the whole string. Also, `name[i]` can be written as `*(name + i)`.

```c
/* 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[0]);
printf("Addition of 1 results in %d\n", &champions[0] + 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[4]);
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.

```c
/* Array of Strings */
char top[6][15] = {
                    "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[0]);
printf("Addition of 1 results in %d\n", &top[0] + 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[4]);
printf("Pointer to 1st element of 4th string = %c\n", top[4] + 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[3][1]);
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<a name = "arrayofpointers"></a>

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 - 

```c
dataType *variableName[size];

/* Examples */
int *example1[5];
char *example2[8];
```

Following [operators precedence](http://unixwiz.net/techtips/reading-cdecl.html), 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.

```c
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[0]`, `"Man City"` in `top[1]`, 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[3]` and `top[4]` like below - 

```c
char *temporary;
temporary = top[3];
top[3] = top[4];
top[4] = 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<a name = "pointertoarray"></a>

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 - 

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

/* Examples */
int (*ptr1)[5];
char (*ptr2)[15];
```

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)*.

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

/* Output */
Address stored in pointerToGoals 6422016
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.

```c
printf("Size of goals[5] = %d, *pointerToGoals);

/* Output */
Size of goals[5] = 20
```
If we dereference it again, we will get the value stored in that address. We can print all the elements using `pointerToGoals`.

```c
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.