




Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
Data abstraction, a technique for encapsulating data details and manipulating large amounts of data. The document focuses on two methods for handling data abstraction problems: records for grouping related data and linked lists for a collection of similar or related data. Examples of defining records in c using the struct construct and accessing record fields using the dot and arrow operators.
Typology: Study notes
1 / 8
This page cannot be seen from the preview
Don't miss anything!





Introduction We often want computers to process large amounts of data, so we need ways to manipulate lists and other groupings of large amounts of data. To satisfy these needs, we require more than just the few basic data types that are built-into the language. The designers of the language can not possibly anticipate all the different ways in which their language will be utilized, however, they can provide the user with the means to āextendā the language to best suit their particular application. Data abstraction is a way to encapsulate the data details of information. In creating data abstractions we build data groupings that reflect the relationships among various data and allow us to conveniently manipulate large amounts of data. In this course weāll study two different methods for handling two different types of data abstraction problems: ļ± Records: Grouping related data items together. ļ± Linked lists: A collection of a large amount of similar or related data. Records ļ± Records are a mechanism for data grouping. ļ± Each record type is defined within its algorithm. ļ± Each record is a heterogeneous collection of data. Data of all different types (including records) are grouped into a single structure. ļ± A record is a composite structure composed of some number of fields. Each field has its own type. ļ± A data field is an individual data item within a record type. ļ± In the C language, records are created using the struct construct. Examples of defining a struct in C struct party { int house_number; int ime_starts; int time_ends; };
This construct defines the type of the struct that we have named party. Before we can use the struct we need to declare variables to be of this type, just as we do with the built-in primitive types. struct party Halloween_party; NewYears_party: Once this is done, rather than a collection of six variable, we have 2 variables each containing 3 fields. Both variables are identical in structure. If we make a change to the underlying structure (i.e., the underlying type) then it changes for all variables declared to be of that type. Using our example, suppose that we add the following field to the struct: struct party { int house_number; int ime_starts; int time_ends; char police_came: //Y or N }; Creating New Data Types ļ± In the C language, the atomic (primitive) types and arrays are built-into the language and we can simply make use of any of these types. ļ± The atomic types can be used to create new āuser-definedā data types. ļ± Once the new data type is defined, then we can declare variables to be of that type, just as we do with the built-in types. ļ± Creating variables of a new data type is a two-step process:
Before we had the capability of using arrays, the code would have looked something like this: When we added that capability of using arrays, the code immediately improved to the following: int main ( ) { int student1, student2, student3, student4; int quiz1, quiz2, quiz3, quiz4; int exam1, exam2, exam3, exam4; double avg1, avg2, avg3, avg4; printf(āEnter student #1 id, quiz, and exam score\nā); scanf(ā%d%d%d\nā, &student1, &quiz1, &exam1); avg1 = (quiz1+exam1)/200; printf(āStudent #1 average is %d\nā, avg1); printf(āEnter student #2 id, quiz, and exam score\nā); scanf(ā%d%d%d\nā, &student2, &quiz2, &exam2); avg2 = (quiz2+exam2)/200; printf(āStudent #2 average is %d\nā, avg2); printf(āEnter student #3 id, quiz, and exam score\nā); scanf(ā%d%d%d\nā, &student3, &quiz3, &exam3); avg3 = (quiz3+exam3)/200; printf(āStudent #3 average is %d\nā, avg3); printf(āEnter student #4 id, quiz, and exam score\nā); scanf(ā%d%d%d\nā, &student4, &quiz4, &exam4); avg4 = (quiz4+exam4)/200; printf(āStudent #4 average is %d\nā, avg4); } int main ( ) { int student[3]; /* declare arrays to hold data. each array has 4 cells */ int quiz[3]; int exam[3]; int avg[3]; for (int i = 0; i <= 3; i++) { printf(āEnter student #%d id, quiz, and exam score\nā, i); scanf(ā%d%d%d\nā, &student[i], &quiz[i], &exam[i]); avg[i] = (quiz[i]+exam[i])/200; printf(āStudent #%d average is %d\nā, i, avg[i]); }
However, the use of records will make this code even more readable and will group related data together even better than by simply using arrays. Using records this code would look like the following: Notice that the use of records has allowed us to group related data closely together. All of the data for a single student is now contained within a single record whereas before, it was maintained in four separate arrays. More Examples Patient record struct patient { char name[20]; int age; int height; int weight; char gender; }; struct patient p1; int main ( ) { #define SIZE 20; struct student_record{ int id; int quiz; int exam; int average; }; struct student_record student[SIZE]; for (int i = 0; i < SIZE; i++) { printf(āEnter student #%d id, quiz, and exam score\nā, i); scanf(ā%d%d%d\nā, &student[i],id, &student[i].quiz, &student[i].exam); student[i].average = (student[i].quiz + student[i].exam)/200; printf(āStudent #%d average is %d\nā, i, student[i].average); } }
In the calling function that utilizes these functions we would have statements like the following: Data Abstraction (Records) - (^7) void print_date(struct date d) { switch (d.month) { case 1: printf(āJanuary ā); break; case 2: printf(āFebraury ā); break; case 3: printf(āMarch ā); break; case 4: printf(āApril ā); break; case 5: printf(āMay ā); break; case 6: printf(āJune ā); break; case 7: printf(āJuly ā); break; case 8: printf(āAugust ā); break; case 9: printf(āSeptember ā); break; case 10: printf(āOctober ā); break; case 11: printf(āNovember ā); break; case 12: printf(āDecember ā); break; } printf(ā%dā, ā d.day); printf(ā%d.\nā, d.year); } int smaller_date (struct date d1, struct date d2) { if (d1.year < d2.year) return(1); else if (d1.year > d2.year) return (0); else { if (d1.month < d2.month) return(1); else if (d1.month > d2.month) return(0); else { if (d1.day < d2.day) return(1); else if (d1.day > d2.day) return(0); else return(0); } } } struct date today; struct date birthday1, birthday2; read_date(&today); print_date(today); if (smaller_date(birthday1, birthday2) printf(āFirst person is older.\nā);
Declaring and Using Complex Structures There is basically no limit on how complex of a structure that you can define. This allows you to tailor make a record to match virtually any application that you would need. Declaring records in records: struct student { int id; char name[20]; struct date dob; int test[3]; double average; char grade; } s1, s2; Declaring an array of records: struct student class[100], youngest; Reading and printing values: read_date(&s1.dob); print_date(s1.dob); Finding the youngest student in the class list: youngest = class[0]; for (int i = 1; i < 100; i++ { if (smaller_date(youngest.dob, class[i].dob) youngest = class[i]; }