Monday, August 27, 2018

User Defined Data Types

Structures

In real-life scenario, problems are solved by dividing them into different manageable objects and finding solutions to them by following logical manner in efficient way.

Let us see the Student Management System, which stores information of students and allows retrieving, modifying them at operator ease. It has following variables to manipulate student ID [int], student name [string], student address [string], student date-of-birth [int]. Note that all variables are related to single object called student.

Student Management System [using variables]

main()

{

int stNo , i ;

int std_Id[‘ ‘],  std_dob_yy[‘ ‘],  std_dob_mm[‘ ‘],  std_dob_dd[‘ ‘] ;

char std_name[‘ ‘][‘ ‘] ,  std_addr[‘ ‘][‘ ‘] ;

 

printf (“Enter No of students to add:”);

scanf(“%d” , &stNo );

 

for(i=0 ; i < stNo ; i++)

     {

     printf (“ Enter Student ID: “);

scanf (“%d”, &std_id[i] );

     printf (“ Enter Student Name: “); 

scanf (“%s”, &std_name[i] );

     printf (“ Enter Student Address: “); 

scanf (“%s”, &std_address[i] );

     printf (“ Enter Student Dob[dd/mm/yyyy]: “); 

     scanf (“%d/%d/%d”, &std_dob_dd[i] ,

&std_dob_mm[i] , &std_dob_yy[i] );

     }

….

}//end of main

//end of program

 

Even though all variables are part of student object in code they are loosely connect to each other. This is because arrays are used to store each variable data, which takes only one type of data in it. Such programs are very hard to read, maintain and debug. This is not a good example program of modular type.

The efficient approach is creating a student object with all its attributes and then use that object to manipulate the data. It will be easier to write code, find bugs and understand it too! The C language provides two mechanisms for such object creation called structure and union. Both mechanisms allows user to create user-defined object/data type with different variable types grouped together under single name.  

Student Management System [using structure]

main()

{

struct date

  {

  int day;

  int month;

  int year;

  };

 

struct student

  {

  int id ; 

  char name[‘ ‘] ;

  char addr[‘ ‘] ;

  struct date dob;

  };

 

int stNo , i ;

 

//create student object array

struct student std[100];

 

printf (“Enter No of students to add:”);

scanf(“%d” , &stNo );

 

for(i=0 ; i < stNo ; i++)

  {

  printf (“ Enter Student ID: “); 

scanf (“%d”, &std[i].id );

  printf (“ Enter Student Name: “);

scanf (“%s”, &std[i],name );

  printf (“ Enter Student Address: “);

scanf (“%s”, &std[i].address );

  printf (“ Enter Student Dob[dd mm yyyy]: “); 

  scanf (“%d %d %d”, &std[i].dob.dd ,

&std[i].dob.mm , &std[i].dob.yy );

  }

….

}//end of main

//end of program

 

Declaring Structures

The structure is made of many parts: key word struct, tag name, template or body, its objects declaration and template’s terminator symbol semicolon.

There are three steps in constructing and using structures: declare template, create objects from that template, and lastly use or access the objects [not template].

The body of structure is call template, as it acts as standard formatted memory map for all its objects. Whenever new object created, this template reserves set of memory for objects storage.

struct 

{

type member_name_1;

type member_name_2;

…..

type member_name_n;

} object1,object2;

struct        

     {

     int id ; 

     char name[‘ ‘] ;

     char addr[‘ ‘] ;

     struct date dob;

     }std1,std2,std3;

Declaring & creating structure template & objects in one step

 

 

 

 

 

 

 

 

std1.id = 1234;

strcpy(std1.name, “ Michael”);

strcpy(std1.addr, “JainCollege”);

std1.dob.day = 15;

std1.dob.month = 08;

std1.dob.year = 1947;

struct student std1

     {

     1234,

     Michael,

     JainCollege,

     15,

     08,

     1947

     };

 

struct student std1 =  

          {1234,     Michael, JainCollege, 15, 08, 1947 };

 

printf(“Enter student ID: ”);

scanf(“%d”,&std1.id);

printf(“Enter student Name: ”);

scanf(“%s”,&std1.name);

printf(“Enter student Address: ”);

scanf(“%s”,&std1.addr);

printf(“Enter Date of Birth[dd mm yyyy]: ”);

scanf(“%d/%d/%d”, &std1.dob.day,

                &std1.dob.month, &std1.dob.year);

 

Different methods of structure initialization.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

The tag name is optional if objects are also declaring at the time of structure creation.

Initializing & Accessing of Structures

Accessing structure fields [they are always part of structure, so refereed along with object name] with the help of dot ‘.’ operator.

The initialization of structure is done at the time of template creation or at object creation or elsewhere in code.

Functions & Structures

Passing Structure Elements to functions is as simple as passing any in-built data type variable. The data type and name of structure element entry will enough to pass them.

displayStudent(int id, char name[10]); //function prototype

 

main()

{

.....

struct student std1;//create (student type) object

….

displayStudent(std1.id, std1.name);       

//call display student info function

.....

}//end of main

 

//user-defined function implementation

void displayStudent(int s_id, char s_name[25])

{

printf("%d \t %s \n", s_id , s_name );

}

Passing whole structure object to functions is also as simple as passing any in-built data type variable. The data type as struct and name of structure object entry will enough to pass them. The function treats it as student object and accesses all its fields as normally done. However, the passing structure must be declared as global, so that it can be accessed by called function.

struct student {   //student struct must be global

......

};  

displayStudent(struct student x);

//function prototype

 

main()

{

struct student std1;//create (student type) object

….

dislayStudent(std1);//display student info to user

....

}//end of main

 

//user-defined function implementation

void dislayStudent(struct student s)

{

printf("%d %s %s %d-%d-%d \n",

s.id , s.name, s.addr, s.dob.day, s.dob.month, s.dob.year );

}

Returning whole structure object from functions is also as simple as returning any in-built data type variable. Including the name of structure’s object as return data-type in function signature, will enough. However, the passing structure must be declared as global, so that it can be accessed by called code block.

struct student {   //student struct must be global

......

};  

student getStudentInfo(int id);//function prototype

 

main()

{

struct student std1;//create (student type) object

….

std1 = getStudentInfo(5);            

//get  student info by his id=5

printf("%d %s %s %d-%d-%d \n", //display got info

std1.id,std1.name,std1.addr,std1.dob.day,std1.dob.month,std1.dob.year);

 

....

}//end of main

 

//user-defined function implementation

student getStudentInfo(int s_id)

{

struct student s;  //create student object.

s.id = s_id;       //assign received id to object.

strcpy(s.name,”defaultName”);    

//fill default values to other members.

......

return(s);

}

Array of Structures

As arrays stores similar data-type variables, declaring array of structures is also possible. Therefore, to store & manipulate 120 students information is very easy if they are declared as array of type student. Accessing them is same as any array element along with structure element dot operator.

struct student         

{

     int id ; 

     char name[‘ ‘] ;

     char addr[‘ ‘] ;

     struct date dob;

     } std[100];

.....

std[1].id = 2;

strcpy(std[1].name, “Munna.Micheal”);

Pointers of Structures

The pointer variables are used as member of structure or to refer structure object. The pointer variable with structure can be used to construct a complex data structure such as linked lists, doubly linked lists, binary tree etc.

The syntax to declare structure’s pointer variable to object is as follows:

struct tag_name  *variable_name;

The pointer variable accesses its members as following two methods:

(*object_name).field_name = sname ;

The parentheses is necessary as '.' or member operator has high precedence.  Alternatively, using arrow operator [made of minus sign & greater than sign] code can access members of structure.

object_name->field_name = sname ;

The code example is as shown below:

main()

{

struct complex

     {

     int x ;

     int y ;

     };

 

struct complex *ptrc1;

//create complex type pointer object

//(*ptrc1).x = 5; (*ptrc1).y = 10;

 

//get input from user

printf(" Enter Complex No.[real imaginary]:\n" );

scanf("%d %d", &(*ptrc1).x , &(*ptrc1).y );

 

//display inputted number to user

printf(" %d \t %d \n", ptrc1->x , ptrc1->y );

 

}//end of main

Unions

 

The shirt is also an object and it has property called its size: either it will be small, medium, large or extra large. Not all at a time. To store such objects if structure is used, waste of memory will occur as it allocates total template memory size for each object creation.

To store such objects where storage sharing is necessary C language provides one mechanism called Union. It is similar to structure, but it’s all elements share longest length for their storage. Hence, the name given Union.

Comparison of struct and union

 

struct ItemInfo

     {

     char sItem ;  //1 byte

     int mItem ;   //2 bytes

     float bItem ; //4 bytes

     }item;

 

//total memory reserved by struct template is

// 1 + 2 + 4 = 7 bytes per object

union ItemInfo

     {

     char sItem ;  //1 byte

     int mItem ;   //2 bytes

     float bItem ; //4 bytes

     }item;

 

//total memory reserved by union template is

// longest size = 4 bytes per object

 

 

 

 

 

 

 

 

 

All other processes with union are same as structure type. Creating Union object and then initialzing it at some other place is as shown below:

union ItemInfo item1, item2,item3;

.....

// initializing union member

item1.sItem =  'A';

item2.mItem = 3456;

item3.bItem = 789.2334

It is possible that creating Union object and initialzing it at same instance is as shown below:

//creating union object and initializing it

union ItemInfo item1 = { 'A'};

union ItemInfo item2 = { 3456};

union ItemInfo item3 = { 789.2334};

Bit-fields

Suppose employee information program needs to store sex of the employee in its database, and it should be either male or female only. Then programmer has to declare sex variable as char data type, that takes only one byte.

int sex;                  //2 bytes memory = 2 x 8 bits = 16 bits

char sex;      //1 byte memory = 1 x 8 bits = 8 bits

 

However, sex data is having information quantity of two: male or female and needs only one bit of memory to store it! [Sex =0 for male and 1 for female].

Since C is mid-level language, it allows programmer to store data in bit level also. That means programmer can specify the variable size in bits also. The syntax is as follows:

modifier data_type variable_name : bitfieldsizenumber;

unsigned int sex:1;   

//1 bit is used, If sex=0 male and sex=1 female

unsigned int year:7;  

//7 bits are sufficient to store any year value.

Even though bit filed optimizes the code to minimum memory load, they are not recommended in common programming practice. Because not all chips are bit filed addressable and hence code will not be portable in nature. The packing of bits is again machine dependent, either left to right or right to left. This mechanism is widely applied usually in embedded systems where target micro-controller chip is fixed or from same family 8051 or AVR or ARM etc and memory availability is very limited.

One more restriction with bit-field is, the value cannot be directly assigned to it, as it is bit addressable. Code has to read value into a temporary variable and then assign its value to the bit-field.

int s;                   //temporary variable                     

//get info from user

printf("Male: 0     Female:1  \? :" );

scanf( "%d", &s );   //store sex value

sex = s ; //transfer sex value to bit-field variable

The bit-field implementation is applied to any variable declaration in program, whether inside function, structure, or union.

typedef: user-defined alias statement

The typedef statement is use when one wants to refer to a variable type by an alternative name, or alias. This is often makes a great convenience for the programmer where application is made of many code files and programmers.

The typedef feature allows users to define new data types that are equivalent to existing data types. Once a user-defined data type has been established, then new variables, arrays, structures, and so on, can be declared in terms of this new data type.

typedef data_type new_type_name;

 

typedef float real;

//declare float data-type alias, real=float.   

real salary, irate, avg;    

// salary, irate, avg are all float type now.

 

The typedef feature makes programme more readable and secured one.

#define 32bit_System

#ifdef 32bit_System

     typedef char items;

#elseif

     typedef int items;

#endif

.....

items itemId, itemLocation, itemColor;

 

uncomment this directive, if system is 64 bit system

Code file for 32-bit system, all items are 1-byte length and hence char data type is used.

 

Code file for 64-bit system, all items are 2-byte length and hence int data type is used.

Usage of typedef. It makes code more readable, manageable, modular, and portable.

 

 

 

 

 

 

 

 

 

 

 

The typedef feature is particularly convenient when defining structures, since it eliminates the need to repeatedly write struct tag whenever a structure is referenced. As a result, the structure can be referenced more concisely.

Enum: user-defined data type

The enumerated data types helps programmer to write code easily/clearly as they represent integer type value in code.

enum flavours{ sweet, sour, salty=6, pungent, hot, bitter} pickles;

actual int values       =0     =1          =6           =7   =8      =9

enum weekdays{ Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday};

actual int values              =1           =2                =3            =4        =5           =6        =7

enum colours    { red, yellow, green, blue, white, black, ...,};

actual int values       =1       =2       =3    =4       =5      =6            

The declaring enumerated data type is simple as it contains following elements: enum keyword, name, members separated by comma with their position value between flower brackets, and terminator symbol semicolon.

enum user-defined-name { member_name1, m_n2,......};

enum weekdays

{Monday,Tuesday,Wednesday,Thursday,Friday,Saturday, Sunday};

An enumeration is a data-type similar to a structure or a union. Its members are constants that are written as identifiers, though they have signed integer value. The default value of members-of- weekday enum is as follows:

enum weekday { mon , tue , wed , thu , fri , sat };

member value is      =0        =1        =2       =3       =4       =5

This can be change to any desired value in any order.

enum weekday { mon=1 , tue , wed , thu , fri , sat };

member value is      =1            =2       =3       =4       =5        =6

 

enum colors {red=1, blue, green=8, violet, pink};

member value is   =1        =2        =8             =9           =10

Object creation and accessing its members is done as any structure or union object creation is done, as follows:

//declare weekdays enum data-type

enum weekday { mon , tue , wed , thu , fri , sat };

 

//create weekdays objects/variables

weekdays day1, day2, day3;

 

//access each member of enum object’s

int today, lastlogin;

today = day1.mon;         //today=0

lastlogin = day2.fri;     //lastlogin=4

Though the C compiler stores enumerated values as integer constants, enum variables are a distinct type, and they should not be thought of as ints.


Previous Page Main Contents Next Page

No comments:

Post a Comment