C - Pointers, arrays and strings
Tags: c, pointers, arrays, string
Published: 2022-10-04 10:03:01

Pointer is one of the most confusing concept in c and c++, In this blog post we are going to make it easy to understand this concept.

---

## #Types and memory

When we declare a vaialbe or store any data temporarily the computer will reserve memory for this variable or data and it will store that variable or data in the reserved space in byte.

The example of the memory structure representation we are going to use to understand pointers is 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zy7s0prir42vwsg7no3u.png)

Where the address is just put in numbers to make it easy to understand, normally it is put in hexadecimal, variable is the name and the value is the assigned ascii number attached to the variable.

Depending on the type of a variable the computer will reserve a vary amount of space in memory.

`1 byte = 8 bits, each bit being 0 or 1` 

- char = 256 different value = 2^8 = 8 bits = 1 byte

- int = 4294967296 different `value = 2^32 = 32 bits = 4 byte
`
- float = 4294967296 different value = 2^32 = 32 bits = 4 byte

You can check the size of a variable type using `sizeof` operator.

**Example**

When we declare a variable `l` of type `char`.

```
char l;
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m1hjcke09beh8lgtcbby.png) 

Int this example we created the address of l is 6.

```
char l;

l = 'A';
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cj0042ry0f1eq5ca74q9.png)

We assigned the value `'A'` to the variable  `l` but the byte will not hold a letter `'A'`, it will hold ascii code, which is 65 (man ascii).



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ak058bgcspefmgfsg7bq.png)

In the `int` and `float` case we use 4 bytes.

```
int n;  

n = 8;
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5mumd5b3xr32vreq8mo7.png)

**& operator**

when we want to find the address of a variable we use the & operator.

**Example**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n7bs150mfu66cem4a9yd.png)
 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dvhqzcgjng2k766w22b6.png)

> The modifier `%p` is used to print address 

---

## #Storing memory addresses

Up to now we learned how to store a character, decimal and floats in a variable.

We also learned how to get the address of variable using `&` operator.

**pointer** is simply the address of a piece of data in memory.
**pointer variable** is a variable that stores the address of that piece of data.

To declare a pointer variable

`VARIBALE_TYPE *VARIABLE_NAME`

**Example**

```
char *p;
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ykikacvnildnyt6ybjez.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yt0bg9jircfgg26ovbpl.png)

A pointer variable holds the address of other variable data
A pointer variable has a size of 8 byte
A pointer variable has his own variable address


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g00ryspzc33g4tay6ycn.png)

**Example**

```
int n;
int *p; 

n = 10;
p = &n; 
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/28yosacso8hp9got6ah0.png)

Now the address of n is 3 and the address of n is &n, So we stored the address of n in p pointer variable.
In this example the the address of n is 3,then the value of p is 3 which holds the address of n.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/coefkcm2inwmh5c778jq.png)



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0d7lkdb28m695dvq1j76.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/358a3mhs4gsyayluudqt.png)

---


## #Dereferencing

Dereferencing is a way of using pointers manipulate values stored at the memory address they point to.

We use the * dereference operator to Dereference the value.

First off * has two functions

- used in the declaration. e.g `int *p;`

- used in dereferencing. e.g `*p = 20;`

Example
```
int n;
int *p;

n = 11;
p = &n;
*p = 20; 
```
So now: 

- `p == &n` holds the address of n

- `*p == n` points the value of n

Now let's break this example using the memory representation.

Up to the part n = 11 and p = &n = 7 the memory representation is 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l1nnusy5a71fhf5y25l2.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ert2bl0nlutnf1hm5miu.png)

After dereferencing `*p = 20` the memory will look like this



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j3bxkzgzahlemk1j6r8e.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q49sucft0gvlfzz2hz7f.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/suv3dei0c782w4irvxge.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/blfunef0di5wgkwszpah.png)

---

## #Functions parameters are passed by value

We have covered in the c function blog post that there are two way of passing parameter in functions.

- Pass by value: passing the copy of the variable.

- Pass by reference: passing the pointer to the variable.

**Pass by value**: this method only copies the value of the variable in the main function and the change made in the other function doesn't affect the value in the main function because it is just a copy.

**Example**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9uz9u7n94bavfwg6ug37.png)

Before the execution of `i = 20;` the memory layout looks like this

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nomvri5at5qjaai4n3w4.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k2n88jetmhf0cfpknpq4.png)

After the execution of the `i = 20;` the memory layout will look like this

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qk6gl35rt6j1d8of5ihq.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dss3o8hrkeemdd6fl64g.png)

When the fun is done executing the variable i is removed and the memory layout looks like this

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nes3hqiz89zeqj2scmlq.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v00e0dlf536290d2vrlo.png)

To modify a variable from outside the function it is declared, using a pointer.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/643mxluo4r3nze9fxit6.png)

Before the function fun the memory layout looks like this

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/167ka6mex0s3wc2ze9p5.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wi7keu9zz0c86i90lnny.png)
when we call the function fun the value of `p` is  stored in a new variable called  `i`.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fqlaqz0bn3uigc7chu9h.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jx4tba8m0kzhqvsxxiom.png)

Since i stores the same memory address, it points to the same address, and so both p and i now point to n. Therefore, when we execute the line *i = 20; we modify the value of n and n now holds 20.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/897npji10qpj3wfbqgif.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pmwqg21zdb2yki3woi77.png)

When we leave the function fun, the variable i is destroyed, but i’s value is still 20

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4jjs6evrvoz1n83ltomv.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8rk52k1l7a1ckh6q4vyx.png)

---

## #Arrays
Arrays in C are contiguous memory areas that hold a number of values of the same type and all elements of an array have the same type.

To declare an array

`TYPE ARRAY_NAME[ARRAY_SIZE];`

To assign a value
`TYPE ARRAY_NAME[ARRAY_SIZE] = {ELEMENTS}`
 
Example

```
int arr[5];
```
arr[0] will access the first element, arr[1] the second element, and so on. 

In this example the computer will reserve a continuous space for 5 integers in memory.



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bf42wmg79n5slztxevze.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qxh2erfefm015gqah4z2.png)

The memory layout will look like 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z6zup9egq2z4h1k5sh19.png)


---

## #Pointers vs Arrays
Arrays are not pointers they don't hold memory address, But the name of an array is the address of the first element of the array. 

Example

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cxfyd3tojzgemoyiy3ca.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/48nip2pfzpo89srynd07.png)

So why this it outputting the address, when an array `a`  is used in an expression the array type gets automatically implicitly converted to pointer-to-element type(array type decay).

There are two exceptions to this rule in two cases:

- `sizeof()` operator

Example


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3rhcq47wh0z2t2upbrmj.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8rc3vkt96ulkev7oqps9.png)

- `&` operator

Example


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ua455p8yzs08p36o81n2.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xq5gpk3jzyt9xdqb0b7i.png)

## #Pointers Arithmetic

We can access the elements of an array using a different method as *(var + x), where var is the name of an array, and x is the (x+1)th element.

Example

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fhtqxuvpmbnhjrsqor92.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yl3j2pcdmh5b6phtz9lw.png)

The memory is a layout


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iwuevlj4g3v1ejn930wc.png)

---

## #Strings

Strings are actually one-dimensional array of characters terminated by a null character '\0'.

`TYPE STRING_NAME[SIZE] = {ELEMENT} `

Example


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/99o02w79juak6exaye3e.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nrh2q81yfhirtiy4nx3f.png)

You probably notice that we used an array with a size of 6,this is because in C, strings end with the char '\0' (ascii value = 0). 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1d3dntglm61cmi25rwkx.png)

---

## #Memory Layout of C program

Memory layout of C program contains five segments:

- stack segment

- heap segment

- BSS (block started by symbol)

- DS (Data Segment)

- text segment


Each segment has own read, write and executable permission. If a program tries to access the memory in a way that is not allowed then **segmentation fault**, which is a common problem that causes programs to crash.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nw3fp4d5qb2b9u22qd2m.png)

**stack**

The stack contains local variables from functions, return value and each function has one stack frame.
The stack contains a LIFO(last in first out) structure, Function variables are pushed onto the stack when called and functions variables are popped off the stack when return.

To understand how LIFO work check out the stack data structure.

```
#include <stdio.h>
int main(void)
{
    int data; //local variable stored in stack
    return 0;
}
```

**Heap**

Heap is used to allocate the memory at run time and heap area managed by the memory management functions like malloc, calloc, free, etc 

```
#include <stdio.h>
int main(void)
{
    char *pStr = malloc(sizeof(char)*4); //stored in heap
    return 0;
}
```

**BSS(Uninitialized data segment)**

It contains all uninitialized global and static variables.

```
#include <stdio.h>

int data1; 
// Uninitialized global variable stored in BSS

int main(void)
{
    static int data2;
    // Uninitialized static variable stored in BSS
    return 0;
}
```
**DS(Initialized data segment)**

It contains the explicitly initialized global and static variables and this segment can be further classified into an initialized read-only area and an initialized read-write area.

```
#include <stdio.h>

int data1 = 10 ; 
//Initialized global variable stored in DS
int main(void)
{
    static int data2 = 3;  
    //Initialized static variable stored in DS
    return 0;
}
```

**Text**

The text segment contains a binary of the compiled program and he text segment is a read-only segment that prevents a program from being accidentally modified.

```
#include <stdio.h> 
  
int main(void) 
{ 
    return 0; 
}
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l0haf3y8weiv7gh6ciw1.png)

> Tip: `NULL` is for pointers which is the absence of address and '\0' is the is for strings