Pointers In C -  Structure and Pointer to Pointer 
Tags: beginners, c, pointers, codenewbie
Published: 2020-08-13 06:34:42

Pointers are arguably the most difficult feature of C to understand. But, it is one of the features which make C an excellent language.

---
###Topics-
0.[ Pointer to Structure](#structure)
1.[ Array Of Structure](#array)
2.[ Pointer to Structure as an Argument](#argument)
3.[ Pointer to Pointer](#ptop)

---

###0. Pointer to Structure<a name="structure"></a>

Like integer pointers, array pointers and function pointers, we have pointer to structures or **structure pointers** as well.

```c
struct records {
    char name[20];
    int roll;
    int marks[5];
    char gender;
};

struct records student = {"Alex", 43, {76, 98, 68, 87, 93}, 'M'};

struct records *ptrStudent = &student;
```
Here, we have declared a pointer `ptrStudent` of type `struct records`. We have assigned the address of `student` to `ptrStudent`.

`ptrStudent` stores the base address of `student`, which is the base address of the first member of the structure. Increment by 1 would increase the address by `sizeof(student)` bytes.

```c
printf("Address of structure = %d\n", ptrStudent);
printf("Adress of member `name` = %d\n", &student.name);
printf("Increment by 1 results in %d\n", ptrStudent + 1);

/* Output */
Address of structure = 6421984
Adress of member `name` = 6421984
Increment by 1 results in 6422032
```

We can access the members of `student` using `ptrStudent` in two ways. Using our old friend `*` or using `->` ( **infix or arrow operator**).

With `*`, we will continue to use the `.`( dot operator) whereas with `->` we won't need dot operator.

```c
printf("Name w.o using ptrStudent : %s\n", student.name);
printf("Name using ptrStudent and * : %s\n", ( *ptrStudent).name);
printf("Name using ptrStudent and -> : %s\n", ptrStudent->name);

/* Output */
Name without using ptrStudent: Alex
Name using ptrStudent and *: Alex
Name using ptrStudent and ->: Alex
```

Similarly, we can access and modify other members as well. Note that the brackets are necessary while using `*` since the dot operator(`.`) has higher precedence over `*`.

###1. Array Of Structure<a name="array"></a>

We can create an array of type `struct records` and use a pointer to access the elements and their members.

```c
struct records students[10];

 /* Pointer to the first element ( structure) of the array */
struct records *ptrStudents1 = &students;

 /* Pointer to an array of 10 struct records */
struct records (*ptrStudents2)[10] = &students;
```

Note that `ptrStudent1` is a pointer to `student[0]` whereas `ptrStudent2` is a pointer to the whole array of  10 `struct records`. Adding 1 to `ptrStudent1` would point to `student[1]`.

We can use `ptrStudent1` with a loop to traverse through the elements and their members.

```c

for( int i = 0; i <  10; i++)
printf("%s, %d\n", ( ptrStudents1 + i)->name, ( ptrStudents1 + i)->roll);
```

###2. Pointer to Structure as an Argument<a name="argument"></a>

We can also pass the address of a structure variable to a function. 

```c
#include <stdio.h>

struct records {
    char name[20];
    int roll;
    int marks[5];
    char gender;
};

main(){
 struct records students = {"Alex", 43, {76, 98, 68, 87, 93}, 
'M'};
 printRecords(&students);
}

void printRecords( struct records *ptr){
  printf("Name: %s\n", ptr->name);
  printf("Roll: %d\n", ptr->roll);
  printf("Gender: %c\n", ptr->gender);
  for( int i = 0; i < 5; i++)
   printf("Marks in %dth subject: %d\n", i, ptr->marks[i]);
}

 /* Output */
Name: Alex
Roll: 43
Gender: M
Marks in 0th subject: 76
Marks in 1th subject: 98
Marks in 2th subject: 68
Marks in 3th subject: 87
Marks in 4th subject: 93
```

Note that the structure `struct records` is declared outside `main()`. This is to ensure that it is available globally and `printRecords()` can use it.

If the structure is defined inside `main()`, its scope will be limited to `main()`. Also structure **must be** declared before the function declaration as well.

>Like structures, we can have pointers to unions and can access members using the arrow operator (`->`). 

###3. Pointer to Pointer<a name="ptop"></a>

So far we have looked at pointer to various primitive data types,  arrays, strings, functions, structures and unions. 

The automatic question that comes to the mind is - what about pointer to pointer?

Well, good news for you! They too exist.

```c
int var = 6;
int *ptr_var = &var;

printf("Address of var = %d\n", ptr_var);
printf("Address of ptr_var = %d\n", &ptr_var);

/* Output */
Address of var = 6422036
Address of ptr_var = 6422024
```

To store the address of `int` variable `var`, we have the pointer to `int` `ptr_var`. We would need another pointer to store the address of `ptr_var`.

Since `ptr_var` is of type `int *`, to store its address, we would have to create a pointer to `int *`. The code below shows how this can be done.

```c
int * *ptr_ptrvar = &ptr_var; /* or int* *ppvar or int **ppvar */
```
We can use `ptr_ptrvar` to access the address of `ptr_var` and use double dereferencing to access var.

```c
printf("Address of ptr_var = %d\n", ptr_ptrvar);
printf("Address of var = %d\n", *ptr_ptrvar);
printf("Value at var = %d\n", *(*ptr_ptrvar));

/* Output */
Address of ptr_var = 6422024
Address of var = 6422036
Value at var = 6
```

It is not required to use brackets when dereferencing `ptr_ptrvar`. But it is a good practice to use them. We can create another pointer `ptr_ptrptrvar`, which will store the address of `ptr_ptrvar`.

Since `ptr_ptrvar` is of type `int**`, the declaration for `ptr_ptrptrvar` will be 

```c
int** *ptr_ptrptrvar = &ptr_ptrvar;
``` 
We can again access `ptr_ptrvar`, `ptr_var` and `var` using `ptr_ptrptrvar`.

```c
printf("Address of ptr_ptrvar = %d\n", ptr_ptrptrvar);
printf("Value at ptr_ptrvar = %d\n",*ptr_ptrptrvar);
printf("Address of ptr_var = %d\n", *ptr_ptrptrvar);
printf("Value at ptr_var = %d\n", *(*ptr_ptrptrvar));
printf("Address of var = %d\n", *(*ptr_ptrptrvar));
printf("Value at var = %d\n", *(*(*ptr_ptrptrvar)));

/* Output */
Address of ptr_ptrvar = 6422016
Value at ptr_ptrvar = 6422024
Address of ptr_var = 6422024
Value at ptr_var = 6422036
Address of var = 6422036
Value at var = 6
```

If we change the value at any of the pointer(s) using `ptr_ptrptrvar` or `ptr_ptrvar`, the pointer(s) will stop pointing to the variable.

---

In this series of 4 articles, I tried to cover as much as possible about pointers. We covered pointer notation, definition, types and arithmetic. That was followed by its uses with arrays, strings and functions. Finally, we talked about structures and pointers itself! A full circle, isn't it?

But, pointers aren't something that can be encapsulated in just 4 articles. One can further look into *dynamic memory allocation* and other such topics, to learn more about pointers and its use cases. 

Stay home and stay safe!!!