350 likes | 455 Views
Lectures 22 & 23. What will I learn in this lecture?. Understand how structure data types are implemented in C. Use “.” operator to access members of a structure. See how to declare pointers to structure variables. Use “ -> ” operator to access members of a structure when using pointers.
E N D
What will I learn in this lecture? • Understand how structure data types are implemented in C. • Use “.” operator to access members of a structure. • See how to declare pointers to structure variables. • Use “ -> ” operator to access members of a structure when using pointers. • Related Chapter: ABC 9.1 – 9.6
Example - Auto parts 1. Problem Definition Write a program that keeps an inventory for an auto parts store. Previously, the information for each auto part was kept on an index card. Each index card had the following fields: id --- a unique identifier for your parts name ---- a category name for the part, like “air filter” quantity --- the quantity in stock price ---- retail priceThe auto parts store can have as many as 30,000 different parts. Your program should define a new C data type named “part”. You will declare 30,000 variables of data type “part”. Each variable (like an index card) should hold the values for all of the fields listed above.
Auto parts 2. Refine, Generalize, Decompose the problem definition (i.e., identify sub-problems, I/O, etc.) We first define a new data type “part”. Then in main we will declare an array of 30,000 variables each of data type “part”. Your program will display a menu with the following choices: 0. Exit 1. Display the parts. 2. Find a part. 3. Enter information for a new part.For each menu item we will write a corresponding function to carry out that menu option. Input = A choice from the menu. For menu choice 2. the user must supply the part “id”. For choice 3. the user must supply all the information for the new auto part. Output= For choice 1. all the fields of all the parts will be displayed on the computer screen.
#include <stdio.h> #include <stdlib.h>#define MAX_SIZE 30000 typedef struct { /* user defined data-type called part */ int id; /* this is a definition*/ char name[32]; /* no variables are declared */ int quantity; /* location is outside any block */float price; } part; int menu(void){ int choice; /* C merges strings */ printf("\n0. Exit \n" "1. Display the parts.\n" "2. Find a part.\n" "3. Enter information for a new part.\n" "choice: "); scanf("%i",&choice); return choice; } /* end of menu */ /* continued on next slide */
void display_one_part(part p){ printf(“%-9i %-31s %-5i $%.2f \n”, p.id , p.name , p.quantity , p.price); } /* end of display_one_part */ int display_parts(part parts[],int count){ int i; for(i = 0; i < count; ++i) display_one_part(parts[i]); } /* end of display_parts */ /* continued on next slide */
int find_part(part parts[], int count){ int i, id_sought; /* return the index of the array for given id */ /* return the value -1 if id_sought not found */ printf("Enter an id number: "); scanf("%i",&id_sought); for(i= 0; i < count; ++i) if (id_sought == parts[i].id) return i; return -1; } /* end of find_part */ /* continued on next slide */
int add_part(part parts[],int count, int max_size){ int i; if (count == max_size) { printf(“insufficient space to add another part\n”); return count; } /* use C regular expression [ ] to read a string with blanks*/ /* ^ means NOT */ printf("Enter one part in format \n" printf(" id; part name ; quantity; price \n"); scanf(" %i; %[^;]; %i; %f", &parts[count].id , parts[count].name , &parts[count].quantity , &parts[count].price); return count+1; } /* end of add_part */ /* continued on next slide */
void main(void){ int choice, index; part parts[MAX_SIZE]; /* MAX_SIZE is a constant = 30000 */ int count = 0; /* actual number of parts in array */ while(1) /* infinite loop */ { choice = menu(); switch(choice) { case 0: printf("Bye bye!\n"); return; case 1: display_parts(parts,count); break; case 2: index = find_part(parts,count); if ( index != -1) display_one_part(parts[index]); else printf("Part not found!\n"); break; case 3: count = add_part(parts,count,MAX_SIZE); } /* end of switch */ } /* end of while */ } /* end of main */
Example - Execution (see demo in lecture)
Structures - How it Works Note: The built-in data types (e.g. int, float, char,…) can be used to declare variables in the C language. These data types don’t have to be defined by the user. Structures provide the user with the means to define custom designed data types. To set up a structure in C, we need to (1) Define a structure type. There are several ways to do this in C. In general, we will use the typedef mechanism to do this. (2) Declare variables to be of that type.
Structures - How it Works You can use the typedef mechanism in C to create an alias for a structure. typedef struct { int id; char name[32]; int quantity; float price; } part; The code above names “part” as a alias for, struct { int id; char name[32]; int quantity; float price; };
Structures - How it Works Structure definitions do not reserve storage, they are used to define a new data type. typedef struct { int id; char name[32]; int quantity; float price; } part; For example, the code above doesn’t allocate any storage. It doesn’t reserve memory for id, name, quantity or price --- the fields or members of the structure. Also, part is not a variable its like int, char ,float, double.
Structures - How it Works Once you have defined a new data type, you can declare (and initialize) a variable of this data type as in, part p ={1001,”Air Filter”, 100, 12.49}; The variables p is declared to be of data type “part” where “part” is a synonym for the structure, struct { int id; char name[32]; int quantity; float price; }; Structure variables, like p above, are initialized in the same way you initialize an array.
Structures - How it Works After the declaration of p, the picture of memory looks like, typedef struct { int id; char name[32]; int quantity; float price; } part; part p ={1001,”Air Filter”,100, 12.49}; 1000 .id 1001 1004 “Air Filter” .name Address 1036 .quantity 100 p .price 1040 12.49
Array of Structures We can even declare an array of structure data type. typedef struct { int id; char name[32]; int quantity; float price; } part; part parts[30000];
Array of Structures Here is a memory map showing the first two element in the array named parts. 2000 .id 2004 .name Address parts[0] 2036 .quantity .price 2040 2044 .id 2048 .name parts[1] 2080 .quantity .price 2084
Structures – without typedef A second, alternative method in using structures in C is to code the following immediately after the preprocessor directives as in slide 5, struct Part { int id; char name[32]; int quantity; float price; }; The name Part is called a “tag name”.In order to declare variable p you would write, struct Part p = {1001,”Air Filter”, 100, 12.49};
Structures – without typedef A third, alternative method in using structures in C is to combine the struct and declaration of the variable in one statement. struct Part{ int id; char name[32]; int quantity; float price; } p = {1001, "Air Filter", 100, 12.49};
Structures can have members of different data-types Structures provide the mechanism in C for grouping values of different data types. Example: typedef struct { int employeeID; float salary; int departmentID; char name[30]; /* not same as char * name; */ } Employee;
Structures - Accessing Fields Accessing(storing and fetching) values from/to fields in the structure is accomplished with the "dot operator" (.), also called the "structure member operator ".Example: (From slide 14) p.id = 1001; /* use the . to access individual fields */ p.quantity = 100; Example: (From the previous slide) Employee emp1; /* declare a variable of type Employee */ emp1.employeeID = 1004; /* initialize the variable */ emp1.salary = 45123.50;
Structures - Accessing Fields scanf("%f",&emp1.salary); /* you can also use scanf */ emp1.departmentID = 37; strcpy(emp1.name, "John");/* strcpy function */ scanf("%s",emp1.name); /* no & needed */ emp1.name[0] = ‘J’; /* this also works */ emp1.name[1] = ‘o’; emp1.name[2] = ‘h’; emp1.name[3] = ‘n’; emp1.name[4] = ‘\0’;
Structures Passed As Call-By-Value Function calls with an argument having a structure data-type are implemented as call-by-value. In this regard structures differ from arrays in that arrays are passed as call-by-reference. For example, in slide 6, function display_one_part is called with argument “parts[i]” of data-type part. display_one_part(parts[i]); The header for the function display_one_part , void display_one_part(part p) has one parameter, p . The variable p is “local” in scope to the function display_one_part. In call-by-value the value of parts[i] is copied into p. p is not a synonym for parts[i].
Functions can return values of structure data-type Functions can return values of structure data-type. For example, in slide 7, we could modify the find_part function, part find_part(part parts[], int count){ int i, id_sought; printf("Enter an id number: "); scanf("%i",&id_sought); for(i= 0; i < count; ++i) if (id_sought == parts[i].id) return parts[i]; } /* end of find_part */ so that it returns the actual part. Of course the above code won’t work if the user types an invalid part id. Also, the call to find_part in main would have to be modified in order for the program to work.
Example - Sort an array of structures 1. Problem Definition Write a program that reads in data for the elements in the periodic system, (e.g. Hydrogen, Helium,...) the name as a string , symbol as a string, atomic number as an int and atomic weight as a double. After the elements have been entered they are sorted using qsort in ascending alphabetical order and then printed back to the terminal. 2. Refine, Generalize, Decompose the problem definition (i.e., identify sub-problems, I/O, etc.) We have four values per atomic element: name,symbol,atomicNum and atomicWt Rather than using five separate arrays of 118 elements we will use one array AtomicElement of 118 elements. The data-type of AtomicElement is a user-defined structure named Element. Input = Input data from keyboard as above. Output= Sort the elements by atomic name, using qsort.
#include <stdio.h> #include <stdlib.h> typedef struct { /* user defined data-type called Element */ char name[15]; /* this is a definition, no variables are declared */ char symbol[3];/* location of this definition is outside any block */ int atomicNum; double atomicWt; } Element; int cmpnames(Element * ptr1, Element * ptr2) ; /* prototype */ /* see explanation of the above in subsequent slides */ void main(void) { int num, i; Element AtomicElement[118]; /* AtomicElement is an array */ printf("How many elements are you going to enter? "); scanf("%i",&num); for(i=0;i<num;++i) { scanf("%s %s %i %lf",AtomicElement[i].name ,AtomicElement[i].symbol ,&AtomicElement[i].atomicNum ,&AtomicElement[i].atomicWt); }
/* sort the arrays by name */ qsort(AtomicElement, num, sizeof(AtomicElement[0]), cmpnames); /* print the sorted array */ printf("\n"); for (i=0;i<num;++i) { printf("%s %s %i %.5lf ",AtomicElement[i].name ,AtomicElement[i].symbol ,AtomicElement[i].atomicNum ,AtomicElement[i].atomicWt); printf("\n"); /* print one element per line */ } /* end of for */ } /* end of main */ int cmpnames(Element * ptr1, Element * ptr2) { return strcmp(ptr1->name, ptr2->name); /* why arrow and not dot? */ } /* end of cmpnames */
Example - Execution > ./a.out How many elements are you going to enter?4 Hydrogen H 1 1.00794 Beryllium Be 4 9.01218 Gold Au 79 196.96655 Carbon C 6 12.0107 Beryllium Be 4 9.01218 Carbon C 6 12.01070 Gold Au 79 196.96655 Hydrogen H 1 1.00794 input output
strcmp From Lecture 15 slide 21: strcmp(str1, str2) - returns a negative , zero or positive int depending on whether str1 is alphabetically less than, equal or greater than str2 respectively. qsort calls our function cmpnames and passes two addresses which are assigned to the pointer variables, ptr1 and ptr2. strcmp(ptr1->name, ptr2->name) If the string ptr1->name < ptr2->name (alphabetically) then strcmp(ptr1->name, ptr2->name) has a negative value else if ptr1->name > ptr2->name then strcmp(ptr1->name, ptr2->name) has a positive value else if ptr1->name == ptr2->name then strcmp(ptr1->name, ptr2->name) has the value 0. These are the correct values we want to return to qsort and we do this by return strcmp(ptr1->name, ptr2->name);
Sorting Example When qsort calls ‘cmpnames’ prt1 ptr2 AtomicElement[0] 2000 2030 “Hydrogen” “H” 1 1.00794 Address 2000 AtomicElement[1] “Beryllium” “Be” 4 9.01218 Address 2030
Sorting Example After qsort calls ‘cmpnames’ prt1 ptr2 AtomicElement[0] 2000 2030 “Beryllium” “Be” 4 9.01218 Address 2000 AtomicElement[1] “Hydrogen” “H” 1 1.00794 Address 2030 Since ‘cmpnames’ function returns a positive value to the function ‘qsort’. The function ‘qsort’ does the work ofswapping the 30 bytes of AtomicElement[0] withthe 30 bytes of AtomicElement[1].
Arrays of structure data-type Given the data-type definition: typedef struct { int id; char name[30]; } AutoPart; We can declare an array of the struct data type Autopart. AutoPart structArray[50]; declares structArray as an array which contains 50 cells (in memory) of type AutoPart.
Pointers to variables of structure data-type We can access the field in the structure with pointers and arrow operator “ -> ” (also called the indirect component selection operator). The general format of the use of the arrow operator is: (see example on next slide) pointer_to_structure -> member_name
Pointers to variables of structure data-type typedef struct { int employeeID; float salary; int departmentID; char name[30]; } Employee; Employee emp1,emp2; Employee *empPtr; /* pointer to data-type Employee */ emp1.employeeID = 1004; emp1.salary = 45123.50; emp1.departmentID = 37;strcpy(emp1.name, "John Smith");empPtr = &emp1; /* empPtr now points to emp1 */ printf("employeeID is %i in department %i \n", empPtr->employeeID, empPtr->departmentID);emp2 = emp1;/* assigns values in ALL fields of emp1 to emp2 */
Why use the arrow " -> " ? Rather than use the arrow operator we could use “ * ” the dereferencing operator. From the last example: printf("employeeID is %i in department %i \n", (*empPtr).employeeID, (*empPtr).departmentID); However, do not write: printf("employeeID is %i in department %i \n", *empPtr.employeeID, *empPtr.departmentID); because in C this means (see operator precedence rules) printf("emplayeeID is %i in department %i \n", *(empPtr.employeeID), *(empPtr.departmentID)); and these expressions are not equivalent. Why? Therefore, it may be “safer” to use the arrow operator, so that we don’t make the mistake shown above.