Review:   user-defined struct type and variables

C's struct construct allows users to define a "class"-like structure:

 #include <stdio.h>

 struct BankAccount 
 {   
   int   ID;
   float balance;
 };

 struct BankAccount mary; // Global struct variable

 int main( int argc, char *argv[] )
 {
   struct BankAccount john; // Local struct variable

   mary.balance = 900;
   john.balance = 500;
   printf("%f\n\n", mary.balance + john.balance);
 } 
   

After defining the struct data type, we can define struct typed variables

Pointer variable to a user-defined struct type variable

  • A pointer variable to a struct type variable can be defined with a similar syntax as built-in data types:

      struct BankAccount john; // Define a struct typed variable "john"
    
      struct BankAccount *p;   // Define a struct typed reference variable p 
    

  • A struct X * typed variable will always:

    • store an address (= reference) of a struct X variable


  • Note:

    • A struct X * typed variable is similar to a Java reference variable

            C construct                    Java construct
        -------------------------       ---------------------
         struct BankAccount *p;    ≡       BankAccount p;
      

How to use a pointer variable to a user-defined struct typed variable

Consider the following program with 2 struct BankAccount variables:

 #include <stdio.h>

 struct BankAccount 
 {   
   int   ID;
   float balance;
 };

 int main( int argc, char *argv[] )
 {
   struct BankAccount john, mary;   // 2 struct BankAccount variables


   john.balance = 500;



   mary.balance = 500;


   printf("j: %f  m:%f\n\n", john.balance, mary.balance); 
 }  

How to use a pointer variable to a user-defined struct typed variable

We define a pointer variable p to a struct BankAccount typed variable:

 #include <stdio.h>

 struct BankAccount 
 {   
   int   ID;
   float balance;
 };

 int main( int argc, char *argv[] )
 {
   struct BankAccount john, mary, *p ;
           // p can store a reference to a struct BankAccount var

   john.balance = 500;



   mary.balance = 500;


   printf("j: %f  m:%f\n\n", john.balance, mary.balance); 
 }  

The pointer variable p can store an address of a struct BankAccount variable

Pointer variable to a user-defined struct typed variable

&john is a reference (= address) of struct BankAccount variable:

 #include <stdio.h>

 struct BankAccount 
 {   
   int   ID;
   float balance;
 };

 int main( int argc, char *argv[] )
 {
   struct BankAccount john, mary, *p ;
           // p can store a reference to a struct BankAccount var

   john.balance = 500;
       &john 


   mary.balance = 500;
   

   printf("j: %f  m:%f\n\n", john.balance, mary.balance); 
 }  

Pointer variable to a user-defined struct typed variable

Therefore: we can assign &john to p:

 #include <stdio.h>

 struct BankAccount 
 {   
   int   ID;
   float balance;
 };

 int main( int argc, char *argv[] )
 {
   struct BankAccount john, mary, *p ;
           // p can store a reference to a struct BankAccount var

   john.balance = 500;
   p = &john; // Now *p ≡ john


   mary.balance = 500;
  

   printf("j: %f  m:%f\n\n", john.balance, mary.balance); 
 }  

After the assignment,  *p  will be an alias for john

Pointer variable to a user-defined struct typed variable

And we can use the expression (*p).balance to update john.balance

 #include <stdio.h>

 struct BankAccount 
 {   
   int   ID;
   float balance;
 };

 int main( int argc, char *argv[] )
 {
   struct BankAccount john, mary, *p ;
           // p can store a reference to a struct BankAccount var

   john.balance = 500;
   p = &john; // Now *p ≡ john
   (*p).balance = (*p).balance + 2000;    // Updates john.balance

   mary.balance = 500;


   printf("j: %f  m:%f\n\n", john.balance, mary.balance); 
 }  

Note:   we need to use (*p).balance because of operator precedence... (later)

Pointer variable to a user-defined struct typed variable

&mary is a reference (= address) of struct BankAccount variable:

 #include <stdio.h>

 struct BankAccount 
 {   
   int   ID;
   float balance;
 };

 int main( int argc, char *argv[] )
 {
   struct BankAccount john, mary, *p ;
           // p can store a reference to a struct BankAccount var

   john.balance = 500;
   p = &john; // Now *p ≡ john
   (*p).balance = (*p).balance + 2000;    // Updates john.balance

   mary.balance = 500;
       &mary 

   printf("j: %f  m:%f\n\n", john.balance, mary.balance); 
 }  

Pointer variable to a user-defined struct typed variable

So we can assign &mary to p:

 #include <stdio.h>

 struct BankAccount 
 {   
   int   ID;
   float balance;
 };

 int main( int argc, char *argv[] )
 {
   struct BankAccount john, mary, *p ;
           // p can store a reference to a struct BankAccount var

   john.balance = 500;
   p = &john; // Now *p ≡ john
   (*p).balance = (*p).balance + 2000;    // Updates john.balance

   mary.balance = 500;
   p = &mary; // Now *p ≡ mary

   printf("j: %f  m:%f\n\n", john.balance, mary.balance); 
 }  

After the assignment, *p will be an alias for mary

Pointer variable to a user-defined struct typed variable

And we can use the expression (*p).balance to update mary.balance:

 #include <stdio.h>

 struct BankAccount 
 {   
   int   ID;
   float balance;
 };

 int main( int argc, char *argv[] )
 {
   struct BankAccount john, mary, *p ;
           // p can store a reference to a struct BankAccount var

   john.balance = 500;
   p = &john; // Now *p ≡ john
   (*p).balance = (*p).balance + 2000;    // Updates john.balance

   mary.balance = 500;
   p = &mary; // Now *p ≡ mary
   (*p).balance = (*p).balance + 9000;    // Updates mary.balance
   printf("j: %f  m:%f\n\n", john.balance, mary.balance); 
 }  

DEMO: demo/C/set2/ref2struct1.c

What happens behind the scene...

  • The definition struct BankAccount john will allocate a BankAccount "object" named john:

     

What happens behind the scene...

  • Assume the struct "object" was allocated at memory address 4000:

    Then:   &john = 4000.

We can access the members of john if we know its location (= address) !

What happens behind the scene...

  • The definition struct BankAccount *p will allocate a reference variable named p:

    p can store a reference (= address) to a BankAccount "object"

What happens behind the scene...

  • The assignment p = &john stores the address of john (= 4000) into the variable p:

    We can now access john through using *p !    (*p is the variable (= "object") at p)

Why do you need ( ) in (*p).balance

  • The expression *p.balance contains 2 operators:

          *p.balance
      
       contains these 2 operators:
      
          *   de-reference    operator
          .   member access   operator       
      

  • The precedence of the  .  operator is higher than the  *  operator    (See: click here)

  • Therefore:

         *p.balance ≡ *(p.balance)
      
       Is an illegal expression, because:  
      
           p.balance is illegal ( p  is not a struct BankAccount var)
           (You must use  *p : (*p).balance is OK) !
      

Common usage of reference variables to struct data types

  • A more common usage of struct * variables (= "object reference" variables) is:

    • reference to dynamically allocated "objects"

      E.g.: (linked) list "objects"

  • We will soon discuss:

    • How to allocate (= create) struct Node variables (= "Node" objects) dynamically in C

    • Link the struct Node variables (= "Node" objects) into a linked list


  • But before we study linked list, we need to discuss a handy-dandy:

    • short-hand operator ( -> ) to access fields (= members) inside a struct variable