Functions and Structure Double Pointer

In this section, you are going to learn

What are the calling conventions of structure double dimension array ?

Call by Value

Call by Reference

struct ABC **dp;

Consider a structure double pointer

struct ABC {
        int a;
        int b;
        int c;
};

struct ABC **dp;

Let us answer few basic questions about structure double pointer

If fun(x) is the function call, then fun(typeof(x)) is the prototype / definition

Function Call

Function Definition

Observations

fun(dp[0][0])

void fun(struct ABC x) {}

  • Call by Value

fun(dp[1][0])

void fun(struct ABC x) {}

  • Call by Value

fun(dp[2][0])

void fun(struct ABC x) {}

  • Call by Value

fun(&dp[0][0])

void fun(struct ABC *p) { }

  • Call by Reference

fun(&dp[1][0])

void fun(struct ABC *p) { }

  • Call by Reference

fun(&dp[2][0])

void fun(struct ABC *p) { }

  • Call by Reference

fun(**dp)

void fun(struct ABC x) {}

  • Call by Value

fun(*(*(dp + 1) + 0))

void fun(struct ABC x) {}

  • Call by Value

fun(*(*(dp + 2) + 0))

void fun(struct ABC x) {}

  • Call by Value

fun(dp[0])

void fun(struct ABC *p) { }

  • Call by Reference

fun(dp[1])

void fun(struct ABC *p) { }

  • Call by Reference

fun(dp[2])

void fun(struct ABC *p) { }

  • Call by Reference

fun(&dp[0])

void fun(struct ABC **q) { }

  • Call by Reference

fun(*dp)

void fun(struct ABC *p) { }

  • Call by Reference

fun(*(dp + 1))

void fun(struct ABC *p) { }

  • Call by Reference

fun(*(dp + 2))

void fun(struct ABC *p) { }

  • Call by Reference

fun(dp)

void fun(struct ABC **q) { }

  • Call by Reference

fun(&dp)

void fun(struct ABC ***r) { }

  • Call by Reference

Let us understand the reason behind above prototypes !

If Declaration has two dereference operators, and

  • Expression has two dereference operators [] [], and

  • Expression does not have &

  • then it is call by value

If Declaration has two dereference operators, and

  • Expression has two dereference operators * *, and

  • Expression does not have &

  • then it is call by value

If Declaration has two dereference operators, and

  • Expression has two dereference operators * [ ], and

  • Expression does not have &

  • then it is call by value

Let us look at examples

  • Step 1 : Consider a double dimension array created using a structure double pointer

struct ABC {
        int a;
        int b;
        int c;
};

struct ABC **dp;

dp = malloc(3 * sizeof(struct ABC *));

for (int i = 0; i < 3; i++)
{
        dp[i] = malloc(4 * sizeof(struct ABC));
}

Condition 1 : Declaration has TWO dereference operators * and *

  • Step 2 : Consider an expression dp[1][1]

Condition 2 : Expression has TWO dereference operators [ ] and [ ]

Note : [ ] and * are dereference operators

Condition 3 : Expression DOES NOT have & operator

Hence dp[1][1] is Call By Value

  • Step 1 : Consider a double dimension array created using a structure double pointer

struct ABC {
        int a;
        int b;
        int c;
};

struct ABC **dp;

dp = malloc(3 * sizeof(struct ABC *));

for (int i = 0; i < 3; i++)
{
        dp[i] = malloc(4 * sizeof(struct ABC));
}

Condition 1 : Declaration has TWO dereference operators [ ] and [ ]

  • Step 2 : Consider an expression **dp

Condition 2 : Expression has TWO dereference operators * and *

Note : [ ] and * are dereference operators

Condition 3 : Expression DOES NOT have & operator

Hence **dp is Call By Value

If Declaration has two dereference operators, and

  • Expression has two dereference operators [] [] or * * or [] *, and

  • Expression has &

  • then it is call by reference

  • Example : &dp[0][0]

If Declaration has two dereference operators, and

  • Expression has one dereference operator [ ] or *

  • then it is call by reference

  • Example : &dp[0], dp[0], *dp

If Declaration has two dereference operators, and

  • Expression has zero dereference operators, and

  • then it is call by reference

  • Example : dp, &dp

  • Step 1 : Consider a double dimension array created using a structure double pointer

struct ABC {
        int a;
        int b;
        int c;
};

struct ABC **dp;

dp = malloc(3 * sizeof(struct ABC *));

for (int i = 0; i < 3; i++)
{
        dp[i] = malloc(4 * sizeof(struct ABC));
}

Condition 1 : Declaration has TWO dereference operators [ ] and [ ]

Condition 2 : Expression has TWO dereference operators * and *

Note : [ ] and * are dereference operators

Condition 3 : Expression has & operator

  • Step 2 : Consider an expression &dp[1][1]

Hence &dp[1][1] is Call By Reference

  • Step 1 : Consider a double dimension array created using a structure double pointer

struct ABC {
        int a;
        int b;
        int c;
};

struct ABC **dp;

dp = malloc(3 * sizeof(struct ABC *));

for (int i = 0; i < 3; i++)
{
        dp[i] = malloc(4 * sizeof(struct ABC));
}

Condition 1 : Declaration has TWO dereference operators [ ] and [ ]

  • Step 2 : Consider an expression dp[1]

Condition 2 : Expression has ONE dereference operators

Note : [ ] and * are dereference operators

Condition 3 : Expression DOES NOT have & operator

Hence dp[1] is Call By Reference

Let us look at examples of Call by Value

  • Step 1 : Consider a double dimension array created using a structure double pointer

struct ABC {
        int a;
        int b;
        int c;
};

struct ABC **dp;

dp = malloc(3 * sizeof(struct ABC *));

for (int i = 0; i < 3; i++)
{
        dp[i] = malloc(4 * sizeof(struct ABC));
}
  • Step 2 : Assign data to structure objects

int data = 99;

for (int i = 0; i < 3; i++)
{
        for (int j = 0; j < 4; j++)
        {
                dp[i][j].a = data++;
                dp[i][j].b = data++;
                dp[i][j].c = data++;
        }
}
  • Step 3 : Pass dp[0][0], dp[1][0], dp[1][1] to a function fun

fun(dp[0][0]);

fun(dp[1][0]);

fun(dp[1][1]);
  • Step 4 : Define function fun

void fun(struct ABC y)
{
        y.a = 11;
        y.b = 22;
        y.c = 33;
}
  • Step 5 : Note that it is call by Value for below reason

Condition 1 : Declaration has TWO dereference operators [ ] and [ ]

Condition 2 : Expression has TWO dereference operators [ ] and [ ]

Condition 3 : Expression DOES NOT have & operator

Means changing value of structure inside function DOES NOT affect value of structure in Caller !

  • Step 6 : Free memory after use

for (int i = 0; i < 3; i++)
{
        free(dp[i]);
}

free(dp);
  • See full program below

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

struct ABC {
        int a;
        int b;
        int c;
};

void fun(struct ABC y)
{
        y.a = 11;
        y.b = 22;
        y.c = 33;
}

int main(void)
{
        struct ABC **dp;

        dp = malloc(3 * sizeof(struct ABC *));

        for (int i = 0; i < 3; i++)
        {
                dp[i] = malloc(4 * sizeof(struct ABC));
        }

        int data = 99;

        for (int i = 0; i < 3; i++)
        {
                for (int j = 0; j < 4; j++)
                {
                        dp[i][j].a = data++;
                        dp[i][j].b = data++;
                        dp[i][j].c = data++;
                }
        }

        printf("----- Before Call By Value -----\n");

        printf("dp[0][0].a = %d\n", dp[0][0].a);
        printf("dp[1][0].a = %d\n", dp[1][0].a);
        printf("dp[1][1].a = %d\n", dp[1][1].a);

        fun(dp[0][0]);
        fun(dp[1][0]);
        fun(dp[1][1]);

        printf("----- After Call By Value -----\n");

        printf("dp[0][0].a = %d\n", dp[0][0].a);
        printf("dp[1][0].a = %d\n", dp[1][0].a);
        printf("dp[1][1].a = %d\n", dp[1][1].a);

        for (int i = 0; i < 3; i++)
        {
                free(dp[i]);
        }

        free(dp);

        return 0;
}
  • Output is as below

----- Before Call By Value -----
dp[0][0].a = 99
dp[1][0].a = 111
dp[1][1].a = 114

----- After Call By Value -----
dp[0][0].a = 99
dp[1][0].a = 111
dp[1][1].a = 114
  • Step 1 : Consider a double dimension array created using a structure double pointer

struct ABC {
        int a;
        int b;
        int c;
};

struct ABC **dp;

dp = malloc(3 * sizeof(struct ABC *));

for (int i = 0; i < 3; i++)
{
        dp[i] = malloc(4 * sizeof(struct ABC));
}
  • Step 2 : Assign data to structure objects

int data = 99;

for (int i = 0; i < 3; i++)
{
        for (int j = 0; j < 4; j++)
        {
                dp[i][j].a = data++;
                dp[i][j].b = data++;
                dp[i][j].c = data++;
        }
}
  • Step 3 : Pass **dp, *(*(dp + 1) + 0), *(*(dp + 1) + 1) to a function fun

fun( **dp );

fun( *(*(dp + 1) + 0) );

fun( *(*(dp + 1) + 1) );
  • Step 4 : Define function fun

void fun(struct ABC y)
{
        y.a = 11;
        y.b = 22;
        y.c = 33;
}
  • Step 5 : Note that it is call by Value for below reason

Condition 1 : Declaration has TWO dereference operators [ ] and [ ]

Condition 2 : Expression has TWO dereference operators * and *

Condition 3 : Expression DOES NOT have & operator

Means changing value of structure inside function DOES NOT affect value of structure in Caller !

  • Step 6 : Free memory after use

for (int i = 0; i < 3; i++)
{
        free(dp[i]);
}

free(dp);
  • See full program below

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

struct ABC {
        int a;
        int b;
        int c;
};

void fun(struct ABC y)
{
        y.a = 11;
        y.b = 22;
        y.c = 33;
}

int main(void)
{
        struct ABC **dp;

        dp = malloc(3 * sizeof(struct ABC *));

        for (int i = 0; i < 3; i++)
        {
                dp[i] = malloc(4 * sizeof(struct ABC));
        }

        int data = 99;

        for (int i = 0; i < 3; i++)
        {
                for (int j = 0; j < 4; j++)
                {
                        dp[i][j].a = data++;
                        dp[i][j].b = data++;
                        dp[i][j].c = data++;
                }
        }

        printf("----- Before Call By Value -----\n");
        printf(" (**dp).a = %d\n", (**dp).a );
        printf(" (*(*(dp + 1) + 0)).a = %d\n",  (*(*(dp + 1) + 0)).a );
        printf(" (*(*(dp + 1) + 1)).a = %d\n",  (*(*(dp + 1) + 1)).a );

        fun( **dp );

        fun( *(*(dp + 1) + 0) );

        fun( *(*(dp + 1) + 1) );

        printf("----- After Call By Value -----\n");
        printf(" (**dp).a = %d\n", (**dp).a );
        printf(" (*(*(dp + 1) + 0)).a = %d\n",  (*(*(dp + 1) + 0)).a );
        printf(" (*(*(dp + 1) + 1)).a = %d\n",  (*(*(dp + 1) + 1)).a );

        for (int i = 0; i < 3; i++)
        {
                free(dp[i]);
        }

        free(dp);

        return 0;
}
  • Output is as below

----- Before Call By Value -----
 (**dp).a = 99
 (*(*(dp + 1) + 0)).a = 111
 (*(*(dp + 1) + 1)).a = 114

----- After Call By Value -----
 (**dp).a = 99
 (*(*(dp + 1) + 0)).a = 111
 (*(*(dp + 1) + 1)).a = 114

Let us look at examples of Call by Reference

  • Step 1 : Consider a double dimension array created using a structure double pointer

struct ABC {
        int a;
        int b;
        int c;
};

struct ABC **dp;

dp = malloc(3 * sizeof(struct ABC *));

for (int i = 0; i < 3; i++)
{
        dp[i] = malloc(4 * sizeof(struct ABC));
}

There are 3 single dimension arrays

  • dp[0]

  • dp[1]

  • dp[2]

dp[0] is also equal to *dp

dp[1] is also equal to *(dp + 1)

dp[2] is also equal to *(dp + 2)

dp[0] is also equal to &dp[0][0]

dp[1] is also equal to &dp[1][0]

dp[2] is also equal to &dp[2][0]

  • Step 2 : Assign data to structure objects

int data = 99;

for (int i = 0; i < 3; i++)
{
        for (int j = 0; j < 4; j++)
        {
                dp[i][j].a = data++;
                dp[i][j].b = data++;
                dp[i][j].c = data++;
        }
}
  • Step 3.1 : Method 1 : Pass &dp[0][0], &dp[1][0], &dp[2][0] to a function fun

fun( &dp[0][0] );

fun( &dp[1][0] );

fun( &dp[2][0] );
  • Step 3.2 : Method 2 : Pass dp[0], dp[1], dp[2] to a function fun

fun( dp[0] );

fun( dp[1] );

fun( dp[2] );
  • Step 3.3 : Method 3 : Pass *dp, *(dp + 1), *(dp + 2) to a function fun

fun( *dp );

fun( *(dp + 1) );

fun( *(dp + 2) );
  • Step 4 : Define function fun

void fun(struct ABC *ptr)
{

}
  • Step 5 : Note that it is call by Reference. Means contents of single dimension array can be changed inside function fun

void fun(struct ABC *ptr)
{
        int data = 666;

        for (int i = 0; i< 4; i++)
        {
                ptr[i].a = data++;
                ptr[i].b = data++;
                ptr[i].c = data++;
        }
}
  • Step 6 : Free memory after usage

for (int i = 0; i < 3; i++)
{
        free(dp[i]);
}

free(dp);
  • See full program below

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

struct ABC {
        int a;
        int b;
        int c;
};

void fun(struct ABC *ptr)
{
        int data = 666;

        for (int i = 0; i< 4; i++)
        {
                ptr[i].a = data++;
                ptr[i].b = data++;
                ptr[i].c = data++;
        }
}

int main(void)
{
        struct ABC **dp;

        dp = malloc(3 * sizeof(struct ABC *));

        for (int i = 0; i < 3; i++)
        {
                dp[i] = malloc(4 * sizeof(struct ABC));
        }

        int data = 99;

        for (int i = 0; i < 3; i++)
        {
                for (int j = 0; j < 4; j++)
                {
                        dp[i][j].a = data++;
                        dp[i][j].b = data++;
                        dp[i][j].c = data++;
                }
        }

        printf("----- Before Call By Reference -----\n");

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

        // Method 1 : Access Single dimension arrays

        fun( &dp[0][0] );

        fun( &dp[1][0] );

        fun( &dp[2][0] );

        // Method 2 : Access Single dimension arrays

        fun( dp[0] );

        fun( dp[1] );

        fun( dp[2] );

        // Method 3 : Access Single dimension arrays

        fun( *dp );

        fun( *(dp + 1) );

        fun( *(dp + 2) );

        printf("----- After Call By Reference -----\n");

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

        for (int i = 0; i < 3; i++)
        {
                free(dp[i]);
        }

        free(dp);

        return 0;
}
  • Output is as below

----- Before Call By Reference -----

dp[0][0].a = 99 dp[0][0].b = 100 dp[0][0].c = 101
dp[0][1].a = 102 dp[0][1].b = 103 dp[0][1].c = 104
dp[0][2].a = 105 dp[0][2].b = 106 dp[0][2].c = 107
dp[0][3].a = 108 dp[0][3].b = 109 dp[0][3].c = 110

dp[1][0].a = 111 dp[1][0].b = 112 dp[1][0].c = 113
dp[1][1].a = 114 dp[1][1].b = 115 dp[1][1].c = 116
dp[1][2].a = 117 dp[1][2].b = 118 dp[1][2].c = 119
dp[1][3].a = 120 dp[1][3].b = 121 dp[1][3].c = 122

dp[2][0].a = 123 dp[2][0].b = 124 dp[2][0].c = 125
dp[2][1].a = 126 dp[2][1].b = 127 dp[2][1].c = 128
dp[2][2].a = 129 dp[2][2].b = 130 dp[2][2].c = 131
dp[2][3].a = 132 dp[2][3].b = 133 dp[2][3].c = 134

----- After Call By Reference -----

dp[0][0].a = 666 dp[0][0].b = 667 dp[0][0].c = 668
dp[0][1].a = 669 dp[0][1].b = 670 dp[0][1].c = 671
dp[0][2].a = 672 dp[0][2].b = 673 dp[0][2].c = 674
dp[0][3].a = 675 dp[0][3].b = 676 dp[0][3].c = 677

dp[1][0].a = 666 dp[1][0].b = 667 dp[1][0].c = 668
dp[1][1].a = 669 dp[1][1].b = 670 dp[1][1].c = 671
dp[1][2].a = 672 dp[1][2].b = 673 dp[1][2].c = 674
dp[1][3].a = 675 dp[1][3].b = 676 dp[1][3].c = 677

dp[2][0].a = 666 dp[2][0].b = 667 dp[2][0].c = 668
dp[2][1].a = 669 dp[2][1].b = 670 dp[2][1].c = 671
dp[2][2].a = 672 dp[2][2].b = 673 dp[2][2].c = 674
dp[2][3].a = 675 dp[2][3].b = 676 dp[2][3].c = 677
  • Step 1 : Consider a double dimension array created using a structure double pointer

struct ABC {
        int a;
        int b;
        int c;
};

struct ABC **dp;

dp = malloc(3 * sizeof(struct ABC *));

for (int i = 0; i < 3; i++)
{
        dp[i] = malloc(4 * sizeof(struct ABC));
}
  • Step 2 : Assign data to structure objects

int data = 99;

for (int i = 0; i < 3; i++)
{
        for (int j = 0; j < 4; j++)
        {
                dp[i][j].a = data++;
                dp[i][j].b = data++;
                dp[i][j].c = data++;
        }
}
  • Step 2 : Pass Address of Double Dimension array to a function

fun(&dp);
  • Step 3.1 : Define function fun

void fun(struct ABC ***ptr )
{

}
  • Step 3.2 : Access and change individual structures inside function fun

int data = 666;

for (int i = 0 ; i < 3; i++) {
        for (int j = 0 ; j < 4; j++) {
                (*ptr)[i][j].a = data++;
                (*ptr)[i][j].b = data++;
                (*ptr)[i][j].c = data++;
        }
}
  • Step 4 : Free memory after usage

for (int i = 0; i < 3; i++)
{
        free(dp[i]);
}

free(dp);
  • See full program below

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

struct ABC {
        int a;
        int b;
        int c;
};

void fun(struct ABC ***ptr)
{
        int data = 666;

        for (int i = 0 ; i < 3; i++) {
                for (int j = 0 ; j < 4; j++) {
                        (*ptr)[i][j].a = data++;
                        (*ptr)[i][j].b = data++;
                        (*ptr)[i][j].c = data++;
                }
        }
}

int main(void)
{
        struct ABC **dp;

        dp = malloc(3 * sizeof(struct ABC *));

        for (int i = 0; i < 3; i++)
        {
                dp[i] = malloc(4 * sizeof(struct ABC));
        }

        int data = 99;

        for (int i = 0; i < 3; i++)
        {
                for (int j = 0; j < 4; j++)
                {
                        dp[i][j].a = data++;
                        dp[i][j].b = data++;
                        dp[i][j].c = data++;
                }
        }

        printf("----- Before Call By Reference -----\n");

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

        fun(&dp);

        printf("----- After Call By Reference -----\n");

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

        for (int i = 0; i < 3; i++)
        {
                free(dp[i]);
        }

        free(dp);

        return 0;
}
  • Output is as below

----- Before Call By Reference -----

dp[0][0].a = 99 dp[0][0].b = 100 dp[0][0].c = 101
dp[0][1].a = 102 dp[0][1].b = 103 dp[0][1].c = 104
dp[0][2].a = 105 dp[0][2].b = 106 dp[0][2].c = 107
dp[0][3].a = 108 dp[0][3].b = 109 dp[0][3].c = 110

dp[1][0].a = 111 dp[1][0].b = 112 dp[1][0].c = 113
dp[1][1].a = 114 dp[1][1].b = 115 dp[1][1].c = 116
dp[1][2].a = 117 dp[1][2].b = 118 dp[1][2].c = 119
dp[1][3].a = 120 dp[1][3].b = 121 dp[1][3].c = 122

dp[2][0].a = 123 dp[2][0].b = 124 dp[2][0].c = 125
dp[2][1].a = 126 dp[2][1].b = 127 dp[2][1].c = 128
dp[2][2].a = 129 dp[2][2].b = 130 dp[2][2].c = 131
dp[2][3].a = 132 dp[2][3].b = 133 dp[2][3].c = 134

----- After Call By Reference -----

dp[0][0].a = 666 dp[0][0].b = 667 dp[0][0].c = 668
dp[0][1].a = 669 dp[0][1].b = 670 dp[0][1].c = 671
dp[0][2].a = 672 dp[0][2].b = 673 dp[0][2].c = 674
dp[0][3].a = 675 dp[0][3].b = 676 dp[0][3].c = 677

dp[1][0].a = 678 dp[1][0].b = 679 dp[1][0].c = 680
dp[1][1].a = 681 dp[1][1].b = 682 dp[1][1].c = 683
dp[1][2].a = 684 dp[1][2].b = 685 dp[1][2].c = 686
dp[1][3].a = 687 dp[1][3].b = 688 dp[1][3].c = 689

dp[2][0].a = 690 dp[2][0].b = 691 dp[2][0].c = 692
dp[2][1].a = 693 dp[2][1].b = 694 dp[2][1].c = 695
dp[2][2].a = 696 dp[2][2].b = 697 dp[2][2].c = 698
dp[2][3].a = 699 dp[2][3].b = 700 dp[2][3].c = 701