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
Revisit Basics : Basics of Structure Double Pointers
Topics in this section,
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) {} |
|
fun(dp[1][0]) |
void fun(struct ABC x) {} |
|
fun(dp[2][0]) |
void fun(struct ABC x) {} |
|
fun(&dp[0][0]) |
void fun(struct ABC *p) { } |
|
fun(&dp[1][0]) |
void fun(struct ABC *p) { } |
|
fun(&dp[2][0]) |
void fun(struct ABC *p) { } |
|
fun(**dp) |
void fun(struct ABC x) {} |
|
fun(*(*(dp + 1) + 0)) |
void fun(struct ABC x) {} |
|
fun(*(*(dp + 2) + 0)) |
void fun(struct ABC x) {} |
|
fun(dp[0]) |
void fun(struct ABC *p) { } |
|
fun(dp[1]) |
void fun(struct ABC *p) { } |
|
fun(dp[2]) |
void fun(struct ABC *p) { } |
|
fun(&dp[0]) |
void fun(struct ABC **q) { } |
|
fun(*dp) |
void fun(struct ABC *p) { } |
|
fun(*(dp + 1)) |
void fun(struct ABC *p) { } |
|
fun(*(dp + 2)) |
void fun(struct ABC *p) { } |
|
fun(dp) |
void fun(struct ABC **q) { } |
|
fun(&dp) |
void fun(struct ABC ***r) { } |
|
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
Other topics of structure and functions
Current Module
Previous Module
Next Module
Other Modules