Pointer to a Single Dimension Array of Structures

In this section, you are going to learn

type ( *ptr ) [ size_of_array ];

An example is as below

struct ABC a[3] = {
        {.a = 1, .b = 2},
        {.a = 3, .b = 4},
        {.a = 5, .b = 6}
};

struct ABC (*ptr)[3];

ptr = &a;

Pointer to an Array when incremented, increments by size of the array to which it is pointing to !

Pointer to an Array when decremented, decrements by size of the array to which it is pointing to !

Let us see how it is done. See below

  • Step 1 : Define a single dimension array

struct ABC {
        int a;
        int b;
};

struct ABC a[3] = {
        {.a = 1, .b = 2},
        {.a = 3, .b = 4},
        {.a = 5, .b = 6}
};
  • Step 2 : Define a pointer to an array

struct ABC (*ptr)[3];
  • Step 3 : Let pointer to an array, point to single dimension array

ptr = &a;
  • Step 4 : Check pointer arithmetic

printf("Before Increment : ptr = %lx\n", (unsigned long int) ptr);

ptr++;

printf("After Increment : ptr = %lx\n", (unsigned long int) ptr);
  • See full program below

#include <stdio.h>

struct ABC {
        int a;
        int b;
};

int main(void)
{
        struct ABC a[3] = {
                {.a = 1, .b = 2},
                {.a = 3, .b = 4},
                {.a = 5, .b = 6}
        };

        struct ABC (*ptr)[3];

        ptr = &a;

        printf("Before Increment : ptr = %lx\n", (unsigned long int) ptr);

        ptr++;

        printf("After Increment : ptr = %lx\n", (unsigned long int) ptr);

        return 0;
}
  • Output is as below

Before Increment : ptr = 7ffda2b55830
After Increment : ptr = 7ffda2b55848

Observe that difference is 24 !

  • sizeof(a) is 24 Bytes

  • ptr is pointer to an array of 3 structure objects with size of 24 Bytes

When Pointer to an Array is passed as argument, Prototype of function should match the type properly !

Let us see how it is done. See below

  • Step 1 : Define a single dimension array

struct ABC {
        int a;
        int b;
};

struct ABC a[3] = {
        {.a = 1, .b = 2},
        {.a = 3, .b = 4},
        {.a = 5, .b = 6}
};
  • Step 2 : Define a pointer to an array

struct ABC (*ptr)[3];
  • Step 3 : Let pointer to an array, point to single dimension array

ptr = &a;
  • Step 4 : Pass ptr as argument to function fun

fun(ptr);
  • Step 5 : Define function fun

void fun( struct ABC (*p)[3] )
{
}
  • See full program below

#include <stdio.h>

struct ABC {
        int a;
        int b;
};

void fun( struct ABC (*p)[3] )
{

}

int main(void)
{
        struct ABC a[3] = {
                {.a = 1, .b = 2},
                {.a = 3, .b = 4},
                {.a = 5, .b = 6}
        };

        struct ABC (*ptr)[3];

        ptr = &a;

        fun(ptr);

        return 0;
}

When Pointer to an Array is passed as argument by call by reference, Prototype of function should match the type properly !

Let us see how it is done. See below

  • Step 1 : Define a Double dimension array

struct ABC a[2][3] = {
        {
                {.a = 1, .b = 2},
                {.a = 3, .b = 4},
                {.a = 5, .b = 6}
        },
        {
                {.a = 100, .b = 200},
                {.a = 300, .b = 400},
                {.a = 500, .b = 600}
        },
};
  • Step 2 : Define a pointer to an array

struct ABC (*ptr)[3];
  • Step 3 : Let pointer to an array, point to single dimension array

ptr = &a[0];
  • Step 4 : Pass ptr as argument to function fun. Call by reference

fun(&ptr);
  • Step 5 : Define function fun

void fun(struct ABC (**p)[3])
{
        for (int i = 0; i < 2; i++) {
                for (int j = 0; j < 3; j++) {
                        printf("(*p)[%d][%d].a = %d ", i, j, (*p)[i][j].a);
                        printf("(*p)[%d][%d].b = %d ", i, j, (*p)[i][j].b);
                        printf("\n");
                }
                printf("\n");
        }
}

This is easy to understand ! Let us derive the rules

  • Rule 1 : Base rule in main

ptr = &a[0];
  • Rule 2 : Base rule in fun

p = &ptr
  • Rule 2 : Move & from RHS to LHS. This becomes * on LHS

*p = ptr
  • Rule 3 : Replace ptr referring to Rule 1

*p = &a[0]
  • Rule 4 : Move & from RHS to LHS. This becomes * on LHS

**p = a[0]
  • Rule 5 : * and [ ] can be used interchangeably

(*p)[0] = a[0]
  • Rule 6 : * and [ ] can be used interchangeably

p[0][0] = a[0]
  • Rule 7 : * and [ ] can be used interchangeably

p[0][0] = &a[0][0]
  • Rule 8 : Move & from RHS to LHS. This becomes * on LHS

(*p)[0][0] = a[0][0]
  • Rule 9 : Extending Rule 8

(*p)[i][j] = a[i][j]
  • See full program below

#include <stdio.h>

struct ABC {
        int a;
        int b;
};

void fun(struct ABC (**p)[3])
{
        for (int i = 0; i < 2; i++) {
                for (int j = 0; j < 3; j++) {
                        printf("(*p)[%d][%d].a = %d ", i, j, (*p)[i][j].a);
                        printf("(*p)[%d][%d].b = %d ", i, j, (*p)[i][j].b);
                        printf("\n");
                }
                printf("\n");
        }
}

int main(void)
{
        struct ABC a[2][3] = {
                {
                        {.a = 1, .b = 2},
                        {.a = 3, .b = 4},
                        {.a = 5, .b = 6}
                },
                {
                        {.a = 100, .b = 200},
                        {.a = 300, .b = 400},
                        {.a = 500, .b = 600}
                },
        };

        struct ABC (*ptr)[3];

        ptr = &a[0];

        fun(&ptr);

        return 0;
}
  • Output is as below

(*p)[0][0].a = 1 (*p)[0][0].b = 2
(*p)[0][1].a = 3 (*p)[0][1].b = 4
(*p)[0][2].a = 5 (*p)[0][2].b = 6

(*p)[1][0].a = 100 (*p)[1][0].b = 200
(*p)[1][1].a = 300 (*p)[1][1].b = 400
(*p)[1][2].a = 500 (*p)[1][2].b = 600

We can use pointer to an array directly inorder to print the contents of array to which it is pointing to !

Let us see how it is done. See below

  • Step 1 : Define a single dimension array

struct ABC {
        int a;
        int b;
};

struct ABC a[3] = {
        {.a = 1, .b = 2},
        {.a = 3, .b = 4},
        {.a = 5, .b = 6}
};
  • Step 2 : Define a pointer to an array

struct ABC (*ptr)[3];
  • Step 3 : Let pointer to an array, point to single dimension array

ptr = &a;

We can derive other rules from this base rule !

  • Rule 1 : Base rule

ptr = &a;
  • Rule 2 : Move & from RHS to LHS. This becomes * on LHS

*ptr = a
  • Rule 3 : a is also equals to &a[0]

*ptr = &a[0]
  • Rule 4 : *ptr is equal to ptr[0]

ptr[0] = &a[0]
  • Rule 5 : Move & from RHS to LHS. This becomes * on LHS

(*ptr)[0] = a[0]
  • Rule 6 : (*ptr)[0] is equal to ptr[0][0]

ptr[0][0] = a[0]
  • Rule 7 : Extending Rule 5

(*ptr)[i] = a[i]
  • Step 4 : Access individual structures using (*ptr)[i]

for (int i = 0; i < 3; i++) {
        printf("a = %d ", (*ptr)[i].a);
        printf("b = %d ", (*ptr)[i].b);
        printf("\n");
}
  • See full program below

#include <stdio.h>

struct ABC {
        int a;
        int b;
};

int main(void)
{
        struct ABC a[3] = {
                {.a = 1, .b = 2},
                {.a = 3, .b = 4},
                {.a = 5, .b = 6}
          };

        struct ABC (*ptr)[3];

        ptr = &a;

        for (int i = 0; i < 3; i++) {
                printf("a = %d ", (*ptr)[i].a);
                printf("b = %d ", (*ptr)[i].b);
                printf("\n");
        }
        return 0;
}
  • Output is as below

a = 1 b = 2
a = 3 b = 4
a = 5 b = 6

We can use pointer to an array directly inorder to print the contents of array to which it is pointing to !

Let us see how it is done. See below

  • Step 1 : Define a single dimension array

struct ABC {
        int a;
        int b;
};

struct ABC a[3] = {
        {.a = 1, .b = 2},
        {.a = 3, .b = 4},
        {.a = 5, .b = 6}
};
  • Step 2 : Pass address of array a as an argument to function fun

fun(&a, sizeof(a) / sizeof(a[0]) );
  • Step 3 : Define function fun

void fun(struct ABC (*p)[3], int size)
{

}

Note the function definition !

  • Since first argument is passed as address of array a, prototype must have pointer to an array in first parameter

  • Step 4 : Let us write the code to access individual structures of single dimension array inside function fun

void fun(struct ABC (*p)[3], int size)
{
        for (int i = 0; i < size; i++) {
                printf("(*p)[%d].a = %d\n", i, (*p)[i].a);
                printf("(*p)[%d].b = %d\n", i, (*p)[i].b);
        }

        for (int i = 0; i < size; i++) {
                printf("p[0][%d].a = %d\n", i, p[0][i].a);
                printf("p[0][%d].b = %d\n", i, p[0][i].b);
        }
}

This is easy to understand ! Let us derive the rules

  • Rule 1 : Base rule

p = &a

Where,

  • LHS p is a variable on stack of function fun fun

  • RHS &a is actual argument passed to function fun

  • Rule 2 : Move & from RHS to LHS. This becomes * on LHS

*p = a
  • Rule 3 : a is also equals to &a[0]

*p = &a[0]
  • Rule 4 : Move & from RHS to LHS. This becomes * on LHS

**p = a[0]
  • Rule 5 : * and [ ] can be used interchangeably

(*p)[0] = a[0]
  • Rule 6 : * and [ ] can be used interchangeably

p[0][0] = a[0]
  • Rule 7 : Extending Rule 5

(*p)[i] = a[i]
  • Rule 8 : Extending Rule 5

p[0][i] = a[i]
  • See full program below

#include <stdio.h>

struct ABC {
        int a;
        int b;
};

void fun(struct ABC (*p)[3], int size)
{
        for (int i = 0; i < size; i++) {
                printf("(*p)[%d].a = %d\n", i, (*p)[i].a);
                printf("(*p)[%d].b = %d\n", i, (*p)[i].b);
        }

        for (int i = 0; i < size; i++) {
                printf("p[0][%d].a = %d\n", i, p[0][i].a);
                printf("p[0][%d].b = %d\n", i, p[0][i].b);
        }
}

int main(void)
{
        struct ABC a[3] = {
                {.a = 1, .b = 2},
                {.a = 3, .b = 4},
                {.a = 5, .b = 6}
        };

        fun(&a, sizeof(a) / sizeof(a[0]) );

        return 0;
}
  • Output is as below

(*p)[0].a = 1
(*p)[0].b = 2
(*p)[1].a = 3
(*p)[1].b = 4
(*p)[2].a = 5
(*p)[2].b = 6
p[0][0].a = 1
p[0][0].b = 2
p[0][1].a = 3
p[0][1].b = 4
p[0][2].a = 5
p[0][2].b = 6
  • Step 1 : Define a double dimension array of structures

struct ABC a[2][3] = {
        {
                {.a = 1, .b = 2},
                {.a = 3, .b = 4},
                {.a = 5, .b = 6}
        },
        {
                {.a = 100, .b = 200},
                {.a = 300, .b = 400},
                {.a = 500, .b = 600}
        },
};
  • Step 2 : Define a pointer to an array of single dimension

struct ABC (*ptr)[3];
  • Step 3 : Let the pointer to point to Single dimension array inside a Double dimension array

ptr = &a[0];
  • See full program below

#include <stdio.h>

struct ABC {
        int a;
        int b;
};

int main(void)
{
        struct ABC a[2][3] = {
                {
                        {.a = 1, .b = 2},
                        {.a = 3, .b = 4},
                        {.a = 5, .b = 6}
                },
                {
                        {.a = 100, .b = 200},
                        {.a = 300, .b = 400},
                        {.a = 500, .b = 600}
                },
        };

        struct ABC (*ptr)[3];

        ptr = &a[0];

        for (int i = 0; i < 2; i++)
        {
                for (int j = 0; j < 3; j++)
                {
                        printf("ptr[%d][%d].a = %d\n", i, j, ptr[i][j].a);
                        printf("ptr[%d][%d].b = %d\n", i, j, ptr[i][j].b);
                }
        }

        return 0;
}
  • Output is as below

ptr[0][0].a = 1
ptr[0][0].b = 2
ptr[0][1].a = 3
ptr[0][1].b = 4
ptr[0][2].a = 5
ptr[0][2].b = 6
ptr[1][0].a = 100
ptr[1][0].b = 200
ptr[1][1].a = 300
ptr[1][1].b = 400
ptr[1][2].a = 500
ptr[1][2].b = 600
  • Step 1 : Allocate a block of memory in Heap

struct ABC *a;

a = malloc(6 * sizeof(struct ABC));
  • Step 2 : Assign User Data in Heap memory

memset(a, 0xaa, 6 * sizeof(struct ABC));
  • Step 3 : Let ptr point to block of memory in Heap

struct ABC (*ptr)[3];

ptr = (struct ABC (*)[3]) a;

Note that typecasting done !

Key is to remember that, ptr should point to block of continuous memory for it to access User data properly !

  • Step 4 : Method 1 : Access the memory block in Heap using ptr

for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 3; j++) {
                printf("ptr[%d][%d].a = %x\n", i, j, ptr[i][j].a);
                printf("ptr[%d][%d].b = %x\n", i, j, ptr[i][j].b);
        }
}
  • Step 5 : Method 2 : Access the memory block in Heap using ptr

for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 3; j++) {
                printf("*ptr->a = %x\n", (*ptr)->a);
                printf("*ptr->b = %x\n", (*ptr)->b);
        }
        ptr++;
}

Remember after Step 5, ptr is NOT pointing to start of Heap !

  • Step 6 : Free Heap memory after use

free(a);
  • See full program below

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct ABC {
        int a;
        int b;
};

int main(void)
{
        struct ABC *a;

        struct ABC (*ptr)[3];

        a = malloc(6 * sizeof(struct ABC));

        memset(a, 0xaa, 6 * sizeof(struct ABC));

        ptr = (struct ABC (*)[3])a;

        for (int i = 0; i < 2; i++) {
                for (int j = 0; j < 3; j++) {
                        printf("ptr[%d][%d].a = %x\n", i, j, ptr[i][j].a);
                        printf("ptr[%d][%d].b = %x\n", i, j, ptr[i][j].b);
                }
        }

        for (int i = 0; i < 2; i++) {
                for (int j = 0; j < 3; j++) {
                        printf("*ptr->a = %x\n", (*ptr)->a);
                        printf("*ptr->b = %x\n", (*ptr)->b);
                }
                ptr++;
        }

        free(a);

        return 0;
}
  • Output is as below

ptr[0][0].a = aaaaaaaa
ptr[0][0].b = aaaaaaaa
ptr[0][1].a = aaaaaaaa
ptr[0][1].b = aaaaaaaa
ptr[0][2].a = aaaaaaaa
ptr[0][2].b = aaaaaaaa
ptr[1][0].a = aaaaaaaa
ptr[1][0].b = aaaaaaaa
ptr[1][1].a = aaaaaaaa
ptr[1][1].b = aaaaaaaa
ptr[1][2].a = aaaaaaaa
ptr[1][2].b = aaaaaaaa
*ptr->a = aaaaaaaa
*ptr->b = aaaaaaaa
*ptr->a = aaaaaaaa
*ptr->b = aaaaaaaa
*ptr->a = aaaaaaaa
*ptr->b = aaaaaaaa
*ptr->a = aaaaaaaa
*ptr->b = aaaaaaaa
*ptr->a = aaaaaaaa
*ptr->b = aaaaaaaa
*ptr->a = aaaaaaaa
*ptr->b = aaaaaaaa