Functions and Structure Double Dimension Array

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 {
        type1 member1;
        type2 member2;
        type3 member3;
        etc.,
};

struct ABC array_name[Row][Column];

Consider a structure double dimension array

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

struct ABC x[3][4];

Let us answer few basic questions in this array

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

Function Call

Function Definition

Observations

fun(x[0][0])

void fun(struct ABC x) {}

  • Call by Value

fun(x[1][0])

void fun(struct ABC x) {}

  • Call by Value

fun(x[2][0])

void fun(struct ABC x) {}

  • Call by Value

fun(&x[0][0])

void fun(struct ABC *p) { }

  • Call by Reference

fun(&x[1][0])

void fun(struct ABC *p) { }

  • Call by Reference

fun(&x[2][0])

void fun(struct ABC *p) { }

  • Call by Reference

fun(**x)

void fun(struct ABC x) {}

  • Call by Value

fun(*(*(x + 1) + 0))

void fun(struct ABC x) {}

  • Call by Value

fun(*(*(x + 2) + 0))

void fun(struct ABC x) {}

  • Call by Value

fun(x[0])

void fun(struct ABC *p) { }

  • Call by Reference

fun(x[1])

void fun(struct ABC *p) { }

  • Call by Reference

fun(x[2])

void fun(struct ABC *p) { }

  • Call by Reference

fun(&x[0])

void fun(struct ABC (*p)[4]) { }

  • Call by Reference

fun(&x[1])

void fun(struct ABC (*p)[4]) { }

  • Call by Reference

fun(&x[2])

void fun(struct ABC (*p)[4]) { }

  • Call by Reference

fun(*x)

void fun(struct ABC *p) { }

  • Call by Reference

fun(*(x + 1))

void fun(struct ABC *p) { }

  • Call by Reference

fun(*(x + 2))

void fun(struct ABC *p) { }

  • Call by Reference

fun(x)

void fun(struct ABC (*p)[4]) { }

  • Call by Reference

fun(x + 1)

void fun(struct ABC (*p)[4]) { }

  • Call by Reference

fun(x + 2)

void fun(struct ABC (*p)[4]) { }

  • Call by Reference

fun(&x)

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

  • 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 an array

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

struct ABC x[2][3] = {
        {
                {.a = 1, .b = 2, .c = 3},
                {.a = 4, .b = 5, .c = 6},
                {.a = 7, .b = 8, .c = 9},
        },
        {
                {.a = 10, .b = 11, .c = 12},
                {.a = 13, .b = 14, .c = 15},
                {.a = 16, .b = 17, .c = 18},
        },
};

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

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

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

Note : [ ] and * are dereference operators

Condition 3 : Expression DOES NOT have & operator

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

  • Step 1 : Consider an array

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

struct ABC x[2][3] = {
        {
                {.a = 1, .b = 2, .c = 3},
                {.a = 4, .b = 5, .c = 6},
                {.a = 7, .b = 8, .c = 9},
        },
        {
                {.a = 10, .b = 11, .c = 12},
                {.a = 13, .b = 14, .c = 15},
                {.a = 16, .b = 17, .c = 18},
        },
};

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

  • Step 2 : Consider an expression **x

Condition 2 : Expression has TWO dereference operators * and *

Note : [ ] and * are dereference operators

Condition 3 : Expression DOES NOT have & operator

Hence **x 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 : &x[0][0]

If Declaration has two dereference operators, and

  • Expression has one dereference operator [ ] or *, and

  • then it is call by reference

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

If Declaration has two dereference operators, and

  • Expression has zero dereference operators, and

  • then it is call by reference

  • Example : x, &x, x + 1, x + 2

  • Step 1 : Consider an array

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

struct ABC x[2][3] = {
        {
                {.a = 1, .b = 2, .c = 3},
                {.a = 4, .b = 5, .c = 6},
                {.a = 7, .b = 8, .c = 9},
        },
        {
                {.a = 10, .b = 11, .c = 12},
                {.a = 13, .b = 14, .c = 15},
                {.a = 16, .b = 17, .c = 18},
        },
};

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

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

Condition 2 : Expression has TWO dereference operators * and *

Note : [ ] and * are dereference operators

Condition 3 : Expression has & operator

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

  • Step 1 : Consider an array

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

struct ABC x[2][3] = {
        {
                {.a = 1, .b = 2, .c = 3},
                {.a = 4, .b = 5, .c = 6},
                {.a = 7, .b = 8, .c = 9},
        },
        {
                {.a = 10, .b = 11, .c = 12},
                {.a = 13, .b = 14, .c = 15},
                {.a = 16, .b = 17, .c = 18},
        },
};

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

  • Step 2 : Consider an expression a[1]

Condition 2 : Expression has ONE dereference operators

Note : [ ] and * are dereference operators

Condition 3 : Expression DOES NOT have & operator

Hence x[1] is Call By Reference

Let us look at examples of Call by Value

  • Step 1 : Consider a two dimensional array

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

struct ABC x[2][3] = {
        {
                {.a = 1, .b = 2, .c = 3},
                {.a = 4, .b = 5, .c = 6},
                {.a = 7, .b = 8, .c = 9},
        },
        {
                {.a = 10, .b = 11, .c = 12},
                {.a = 13, .b = 14, .c = 15},
                {.a = 16, .b = 17, .c = 18},
        },
};
  • Step 2 : Pass x[0][0], x[1][0], x[1][1] to a function fun

fun(x[0][0]);

fun(x[1][0]);

fun(x[1][1]);
  • Step 3 : Define function fun

void fun(struct ABC y)
{
        y.a = 99;
        y.b = 100;
        y.x = 101;
}
  • Step 4 : 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 !

  • See full program below

#include <stdio.h>

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

void fun(struct ABC y)
{
        y.a = 99;
        y.b = 100;
        y.c = 101;
}

int main(void)
{
        struct ABC x[2][3] = {
                {
                        {.a = 1, .b = 2, .c = 3},
                        {.a = 4, .b = 5, .c = 6},
                        {.a = 7, .b = 8, .c = 9},
                },
                {
                        {.a = 10, .b = 11, .c = 12},
                        {.a = 13, .b = 14, .c = 15},
                        {.a = 16, .b = 17, .c = 18},
                },
        };

        printf("----- Before Call By Value -----\n");
        printf("x[0][0].a = %d\n", x[0][0].a);
        printf("x[1][0].a = %d\n", x[1][0].a);
        printf("x[1][1].a = %d\n", x[1][1].a);

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

        printf("----- After Call By Value -----\n");
        printf("x[0][0].a = %d\n", x[0][0].a);
        printf("x[1][0].a = %d\n", x[1][0].a);
        printf("x[1][1].a = %d\n", x[1][1].a);

        return 0;
}
  • Output is as below

----- Before Call By Value -----
x[0][0].a = 1
x[1][0].a = 10
x[1][1].a = 13

----- After Call By Value -----
x[0][0].a = 1
x[1][0].a = 10
x[1][1].a = 13
  • Step 1 : Consider a two dimensional array

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

struct ABC x[2][3] = {
        {
                {.a = 1, .b = 2, .c = 3},
                {.a = 4, .b = 5, .c = 6},
                {.a = 7, .b = 8, .c = 9},
        },
        {
                {.a = 10, .b = 11, .c = 12},
                {.a = 13, .b = 14, .c = 15},
                {.a = 16, .b = 17, .c = 18},
        },
};
  • Step 2 : Pass **x, *(*(x + 1) + 0), *(*(x + 1) + 1) to a function fun

fun( **x );

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

fun( *(*(x + 1) + 1) );
  • Step 3 : Define function fun

void fun(struct ABC y)
{
        y.a = 99;
        y.b = 100;
        y.c = 101;
}
  • Step 4 : 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 !

  • See full program below

#include <stdio.h>

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

void fun(struct ABC y)
{
        y.a = 99;
        y.b = 100;
        y.c = 101;
}

int main(void)
{
        struct ABC x[2][3] = {
                {
                        {.a = 1, .b = 2, .c = 3},
                        {.a = 4, .b = 5, .c = 6},
                        {.a = 7, .b = 8, .c = 9},
                },
                {
                        {.a = 10, .b = 11, .c = 12},
                        {.a = 13, .b = 14, .c = 15},
                        {.a = 16, .b = 17, .c = 18},
                },
        };

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

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

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

        return 0;
}
  • Output is as below

----- Before Call By Value -----
 (**x).a = 1
 (*(*(x + 1) + 0)).a = 10
 (*(*(x + 1) + 1)).a = 13

----- After Call By Value -----
 (**x).a = 1
 (*(*(x + 1) + 0)).a = 10
 (*(*(x + 1) + 1)).a = 13

Let us look at examples of Call by Reference

  • Step 1 : Consider a two dimensional array

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

struct ABC x[2][3] = {
        {
                {.a = 1, .b = 2, .c = 3},
                {.a = 4, .b = 5, .c = 6},
                {.a = 7, .b = 8, .c = 9},
        },
        {
                {.a = 10, .b = 11, .c = 12},
                {.a = 13, .b = 14, .c = 15},
                {.a = 16, .b = 17, .c = 18},
        },
};

There are 2 single dimension arrays in struct ABC x[2][3]

  • x[0]

  • x[1]

x[0] is also equal to *x

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

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

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

  • Step 2.1 : Method 1 : Pass &x[0][0], &x[1][0] to a function fun

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

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

fun( x[0] );

fun( x[1] );
  • Step 2.3 : Method 3 : Pass *a, *(a + 1) to a function fun

fun( *x );

fun( *(x + 1) );
  • Step 3.1 : Define function fun

void fun(struct ABC *ptr)
{

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

void fun(struct ABC *ptr)
{
        for (int i = 0; i < 4; i++)
        {
                ptr[i].a = 99;
                ptr[i].b = 100;
                ptr[i].c = 101;
        }
}
  • See full program below

#include <stdio.h>

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

void fun(struct ABC *ptr)
{
        for (int i = 0; i < 3; i++)
        {
                ptr[i].a = 99;
                ptr[i].b = 100;
                ptr[i].c = 101;
        }
}

int main(void)
{
        struct ABC x[2][3] = {
                {
                        {.a = 1, .b = 2, .c = 3},
                        {.a = 4, .b = 5, .c = 6},
                        {.a = 7, .b = 8, .c = 9},
                },
                {
                        {.a = 10, .b = 11, .c = 12},
                        {.a = 13, .b = 14, .c = 15},
                        {.a = 16, .b = 17, .c = 18},
                },
        };

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

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

        // Method 1 : Access Single dimension arrays

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

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

        // Method 2 : Access Single dimension arrays

        fun( x[0] );

        fun( x[1] );

        // Method 3 : Access Single dimension arrays

        fun( *x );

        fun( *(x + 1) );

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

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

        return 0;
}
  • Output is as below

----- Before Call By Reference -----
x[0][0].a = 1
x[0][0].b = 2
x[0][0].c = 3
x[0][1].a = 4
x[0][1].b = 5
x[0][1].c = 6
x[0][2].a = 7
x[0][2].b = 8
x[0][2].c = 9
x[1][0].a = 10
x[1][0].b = 11
x[1][0].c = 12
x[1][1].a = 13
x[1][1].b = 14
x[1][1].c = 15
x[1][2].a = 16
x[1][2].b = 17
x[1][2].c = 18

----- After Call By Reference -----
x[0][0].a = 99
x[0][0].b = 100
x[0][0].c = 101
x[0][1].a = 99
x[0][1].b = 100
x[0][1].c = 101
x[0][2].a = 99
x[0][2].b = 100
x[0][2].c = 101
x[1][0].a = 99
x[1][0].b = 100
x[1][0].c = 101
x[1][1].a = 99
x[1][1].b = 100
x[1][1].c = 101
x[1][2].a = 99
x[1][2].b = 100
x[1][2].c = 101
  • Step 1 : Consider a two dimensional array

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

struct ABC x[2][3] = {
        {
                {.a = 1, .b = 2, .c = 3},
                {.a = 4, .b = 5, .c = 6},
                {.a = 7, .b = 8, .c = 9},
        },
        {
                {.a = 10, .b = 11, .c = 12},
                {.a = 13, .b = 14, .c = 15},
                {.a = 16, .b = 17, .c = 18},
        },
};

There are 2 single dimension arrays in struct ABC x[2][3]

  • x[0]

  • x[1]

Address of single dimension arrays is simply

  • &x[0]

  • &x[1]

  • &x[0] is also equal to a

  • &x[1] is also equal to a + 1

  • Step 2.1 : Method 1 : Pass address of single dimension arrays to a function fun

fun( &x[0] );

fun( &x[1] );
  • Step 2.2 : Method 2 : Pass address of single dimension arrays to a function fun

fun( a );

fun( a + 1 );
  • Step 3.1 : Define the function fun

void fun(struct ABC (*ptr)[3] )
{
}
  • Step 3.2 : Define the function fun to change the contents of single dimension array structure by structure

void fun(struct ABC (*ptr)[3] )
{
        (*ptr)[0].a = 777;
        (*ptr)[1].a = 888;
        (*ptr)[2].a = 999;
}
  • See full program below

#include <stdio.h>

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

void fun(struct ABC (*ptr)[3] )
{
        (*ptr)[0].a = 777;
        (*ptr)[1].a = 888;
        (*ptr)[2].a = 999;
}

int main(void)
{
        struct ABC x[2][3] = {
                {
                        {.a = 1, .b = 2, .c = 3},
                        {.a = 4, .b = 5, .c = 6},
                        {.a = 7, .b = 8, .c = 9},
                },
                {
                        {.a = 10, .b = 11, .c = 12},
                        {.a = 13, .b = 14, .c = 15},
                        {.a = 16, .b = 17, .c = 18},
                },
        };

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

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

        // Method 1 : Access Single dimension arrays

        fun( &x[0] );

        fun( &x[1] );

        // Method 2 : Access Single dimension arrays

        fun( x );

        fun( x + 1 );

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

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

        return 0;
}
  • Output is as below

----- Before Call By Reference -----
x[0][0].a = 1
x[0][0].b = 2
x[0][0].c = 3
x[0][1].a = 4
x[0][1].b = 5
x[0][1].c = 6
x[0][2].a = 7
x[0][2].b = 8
x[0][2].c = 9
x[1][0].a = 10
x[1][0].b = 11
x[1][0].c = 12
x[1][1].a = 13
x[1][1].b = 14
x[1][1].c = 15
x[1][2].a = 16
x[1][2].b = 17
x[1][2].c = 18

----- After Call By Reference -----
x[0][0].a = 777
x[0][0].b = 2
x[0][0].c = 3
x[0][1].a = 888
x[0][1].b = 5
x[0][1].c = 6
x[0][2].a = 999
x[0][2].b = 8
x[0][2].c = 9
x[1][0].a = 777
x[1][0].b = 11
x[1][0].c = 12
x[1][1].a = 888
x[1][1].b = 14
x[1][1].c = 15
x[1][2].a = 999
x[1][2].b = 17
x[1][2].c = 18
  • Step 1 : Consider a two dimensional array

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

struct ABC x[2][3] = {
        {
                {.a = 1, .b = 2, .c = 3},
                {.a = 4, .b = 5, .c = 6},
                {.a = 7, .b = 8, .c = 9},
        },
        {
                {.a = 10, .b = 11, .c = 12},
                {.a = 13, .b = 14, .c = 15},
                {.a = 16, .b = 17, .c = 18},
        },
};
  • Step 2 : Pass Address of Double Dimension array to a function

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

void fun(struct ABC (*ptr)[2][3] )
{

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

void fun(struct ABC (*ptr)[2][3] )
{
        for (int i = 0 ; i < 2; i++) {
                for (int j = 0 ; j < 3; j++) {
                        (*ptr)[i][j].a = 777;
                        (*ptr)[i][j].b = 888;
                        (*ptr)[i][j].c = 999;
                }
        }
}
  • See full program below

#include <stdio.h>

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

void fun(struct ABC (*ptr)[2][3] )
{
        for (int i = 0 ; i < 2; i++) {
                for (int j = 0 ; j < 3; j++) {
                        (*ptr)[i][j].a = 777;
                        (*ptr)[i][j].b = 888;
                        (*ptr)[i][j].c = 999;
                }
        }
}

int main(void)
{
        struct ABC x[2][3] = {
                {
                        {.a = 1, .b = 2, .c = 3},
                        {.a = 4, .b = 5, .c = 6},
                        {.a = 7, .b = 8, .c = 9},
                },
                {
                        {.a = 10, .b = 11, .c = 12},
                        {.a = 13, .b = 14, .c = 15},
                        {.a = 16, .b = 17, .c = 18},
                 },
        };

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

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

        fun(&x);

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

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

        return 0;
}
  • Output is as below

----- Before Call By Reference -----
x[0][0].a = 1
x[0][0].b = 2
x[0][0].c = 3
x[0][1].a = 4
x[0][1].b = 5
x[0][1].c = 6
x[0][2].a = 7
x[0][2].b = 8
x[0][2].c = 9
x[1][0].a = 10
x[1][0].b = 11
x[1][0].c = 12
x[1][1].a = 13
x[1][1].b = 14
x[1][1].c = 15
x[1][2].a = 16
x[1][2].b = 17
x[1][2].c = 18

----- After Call By Reference -----
x[0][0].a = 777
x[0][0].b = 888
x[0][0].c = 999
x[0][1].a = 777
x[0][1].b = 888
x[0][1].c = 999
x[0][2].a = 777
x[0][2].b = 888
x[0][2].c = 999
x[1][0].a = 777
x[1][0].b = 888
x[1][0].c = 999
x[1][1].a = 777
x[1][1].b = 888
x[1][1].c = 999
x[1][2].a = 777
x[1][2].b = 888
x[1][2].c = 999