190 likes | 333 Views
Today’s Material. Aggregate Data Types: Structures and Unions Motivation Definition and Declaration Representation Initialization Access Array of Structures Structures as function parameters Layout in Memory Unions. Motivation. Data frequently occurs in groups
E N D
Today’s Material • Aggregate Data Types: Structures and Unions • Motivation • Definition and Declaration • Representation • Initialization • Access • Array of Structures • Structures as function parameters • Layout in Memory • Unions
Motivation • Data frequently occurs in groups • For example a school has to keep track of some information for each of its students • This information can be things such as • Name • Department • Gpa • Email address • Courses takes & grades • Address • …
Motivation (cont) • Accessing these values are simplified if they are stored together • We cannot use an array to store these values together. Why? • Because they are of different type • C provides what is called a “structure” to store values with dissimilar types together • Also known as a “record” • A structure is a collection of values called members that can be of different types
Structure: Definition & Declaration • A structure is a collection of values called members that can be of different types structTAG {member list} variableList; /* TAG and variableList are optional */ /* No tag. Just declare * one variable */ struct { int i; char c; float f; } x; /* Give a name (tag) */ structSimple { int i; char c; float f; }; /* declare a variable later */ structSimple y;
typedef + Structures • It is usually a good idea to define a new type using typedef instead of using “struct TAG” typedef structStudent{ char name[40]; int dept; float gpa; char email[30]; } Student; /* Declare a variable */ struct Student s1; Student s2;
Structure Initialization • Just like any other variable, you can initialize structure members during declaration Student s1={“Ali Veli”, 101, 3.10, “aliveli@anadolu.edu.tr”}; Student s2={“Veli Kasap”, 102, 2.10, “vkasap@anadolu.edu.tr”}; • As with array initializers, an initializer can be shorter than the structure it is initializing • Any leftover members are set to 0 typedef structSimple { int i; char c; float f; } Simple; Simple z = {2}; /* c and f are set to 0 */
Accessing Structure Members (2) • How to access structure members through a pointer? typedef structSimple { int i; char c; float f; } Simple; Simple x; Simple *ps = &x; x.i = 4; (*ps).i = 4; (*ps).c = ‘A’; (*ps).f = 3.33; /* C provides an alternative * way to access the members * of a structure through a * pointer using -> operator */ ps->i = 4; ps->c = ‘A’; ps->f = 3.33;
Array of Structures • It is possible to declare an array of structures Student students[2]; strcpy(students[0].name, “Veli Gocer”); students[0].dept = 101; students[0].gpa = 2.85; strcpy(students[0].email, “vgocer@anadolu.edu.tr”); /* It is possible to assign a structure to another */ students[1] = students[0]; /* Assignment copies the contents of structure * students[0] to the structure students[1]. * This is a memory-to-memory copy in its entirety */
Structures as Function Parameters • As with all function arguments, structures are passed by value • Thus any change made to a function parameter is not reflected to the function argument void F1(Simple s){ s.i = 2; s.c = ‘T’; s.f = 5.32; } /* end-F1 */ main(){ Simple x = {3, ‘A’, 4.35}; F1(x); printf(“x.i: %d, x.c: %c, x.f: .2f\n”, x.i, x.c, x.f); } /* end-main */ x.i: 3, x.c: A, x.f: 4.35
Structures as Function Parameters • To change a structure argument inside a function, pass the structure’s address void F2(Simple *ps){ ps->i = 2; ps->c = ‘T’; ps->f = 5.32; } /* end-F2 */ main(){ Simple x = {3, ‘A’, 4.35}; F2(&x); printf(“x.i: %d, x.c: %c, x.f: .2f\n”, x.i, x.c, x.f); } /* end-main */ x.i: 2, x.c: T, x.f: 5.32
Returning Structures from Functions • You can return a structure from a function • This is very inefficient and not recommended Simple F4(int i, char c, float f){ Simple s; s.i = i; s.c = c; s.f = f; return s; } /* end-F4 */ Simple F3(Simple s){ s.i = 22; s.c = ‘Y’; s.f = 6.66; return s; } /* end-F3 */ main(){ Simple x = {3, ‘A’, 4.35}; x = F3(x); printf(“x.i: %d, x.c: %c, x.f: .2f\n”, x.i, x.c, x.f); x = F4(8, ‘Z’, 9.99); printf(“x.i: %d, x.c: %c, x.f: .2f\n”, x.i, x.c, x.f); } /* end-main */ x.i: 22, x.c: Y, x.f: 6.66 x.i: 8, x.c: Z, x.f: 9.99
Complex Structure Declarations • You can declare complex structures by nesting one structure inside another typedef struct { int i; char c; float f; } Simple; typedef struct { int a; Simple s; struct{ int a; float b; }x; float f; } Complex; Complex c; /* Access members of c */ c.a = 5; c.s.i = 3; c.s.c = ‘B’; c.s.f = 4.44; c.x.a = 2; c.x.b = 4.52; c.f = 3.45;
Address &s 100 &s.i 101 s.i 102 103 104 &s.c s.c 105 unused 106 unused 107 unused &s.f 108 109 s.f 110 111 Layout of Structures in Memory(1) • Structure members are stored consecutively in memory typedef struct{ int i; char c; float f; } Simple; Simple s; • 3 bytes (105, 106, 107) are unused • s.f starts at a 4-byte boundary due to alignment constraints
Layout of Structures in Memory(2) • Member alignment plays a crutial role to determine the amount of space a structure will occupy in memory struct Y { int i; char c1; char c2; }; struct X { char c1; int i; char c2; }; • sizeof(struct X) = 12 • sizeof(struct Y) = 8 • Not 6 because if we declare an array of structures, the next structure must start at a 4-byte boundary
Union: Definition • A union is a structure that consists of one or members which may be of different types • However, the compiler allocates only enough space for the largest of the members in a union • Thus the members of a union overlay each other within this space • Assigning a new value to one member alters the values of all the other members as well
100 100 100 u1.c[0] 101 101 101 u1.c[1] u2.i u1.i s.i 102 102 u1.c[2] 102 u2.f 103 103 u1.c[3] 103 u2.d 104 104 s.c[0] sizeof(u1) = 4 s.c[1] 105 105 106 106 s.c[2] 107 s.c[3] 107 sizeof(s) = 8 sizeof(u2) = 8 Union: Declaration & Layout union { int i; float f; double d; } u2; union { int i; char c[4]; } u1; struct { int i; char c[4]; }s;
Union: Manipulation union { int i; float f; double d; } u2; union { int i; char c[4]; } u1; struct { int i; char c[4]; }s; /* set s.c only. s.i is not changed */ s.c[0]=1; s.c[1]=2; s.c[2]=3; s.c[4]=4; /* set s.c */ s.i = 0x12345678; /* changes s.i only. s.c is not changed */ printf(“%x-%x-%x-%x\n”, s.c[0], s.c[1], s.c[2], s.c[3]); /* Set u1.c. Changes u1.i as well */ u1.c[0]=1; u1.c[1]=2; u1.c[2]=3; u1.c[4]=4; u1.i = 0x12345678; /* Changes u1.c as well */ printf(“%x-%x-%x-%x\n”, u1.c[0], u1.c[1], u1.c[2], u1.c[3]); /* Changes the first 4 bytes of union u2 */ u2.i = 8; /* Changes all 8 bytes of union u2 */ u2.d = 2.35;
Union: Usage (1) • If you can store a number of values in a union, a typical method is to specify a tag that tell you what is really stored in the union /* due to alignment */ sizeof(number) = 16; /* Store an int */ number.type = 0; number.u.i = 8; /* Store a float */ number.type = 1; number.u.f = 8.2; /* Store a double */ number.type = 2; number.u.d = 10.5; struct Number { /* 0: int * 1: float * 2: double */ int type; union { int i; float f; double d; } u; } number;
Union: Usage (2) struct Number { /* 0: int * 1: float * 2: double */ int type; union { int i; float f; double d; } u; } number; /* Thus we can store different type * of numbers in an array */ struct Number A[5]; A[0].type = 0; A[0].u.i = 2; A[1].type = 1; A[1].u.f = 2.3; A[2].type = 2; A[2].u.d = 3.4; A[3].type = 2; A[3].u.d = 5.8; A[4].type = 0; A[4].u.i = 4;