DEV Community

Cover image for Pointers In C -  Structure and Pointer to Pointer
Srijan
Srijan

Posted on

Pointers In C - Structure and Pointer to Pointer

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
1. Array Of Structure
2. Pointer to Structure as an Argument
3. Pointer to Pointer


0. Pointer to Structure

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

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.

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.

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

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

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.


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

2. Pointer to Structure as an Argument

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

#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

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.

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.

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.

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

int** *ptr_ptrptrvar = &ptr_ptrvar;

We can again access ptr_ptrvar, ptr_var and var using ptr_ptrptrvar.

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!!!

Top comments (1)

Collapse
 
futurephoria profile image
Mel McGovern (they/them)

In example 0, the %d in the print statement throws an error of 'format specifies type 'int' but the argument has type 'struct records *' I had to use %p format specifier to get the address to print (in hexadecimal format).