Download presentation
Presentation is loading. Please wait.
Published byRichard Anderson Modified over 9 years ago
2
Complex data types Structures Defined types Structures and functions Structures and pointers
4
Many programs require complex data to be represented That cannot easily be represented using base type variables and arrays ▪ Base types are the defined C types like int, char, float, etc. C allows structures to be defined and used in a program A structure is a complex type that collects a number of variables, arrays or even other structures
5
Let’s assume that we want to represent student data for a small university For each student we want to maintain First name – a string Last name – a string Student number – an integer GPA – a float this is a simplified version of what would be necessary, some of the complicating issues will be discussed later
6
If we wanted to maintain a list of a hundred students we could use four separate arrays One for each of the four attributes ▪ First name, last name, student number, GPA Referred to as parallel arrays Whenever we want to retrieve student data we would use the same index in all arrays
7
index012...33...979899 id1101723456784864178924574444 index012...33...979899 firstBobKateSueDaveJoeEllaAnna index012...33...979899 lastWingSmithAbelDoddNgMossFrenc index012...33...979899 gpa3.003.502.753.752.254.003.50 Represents the student Dave Dodd
8
Maintaining parallel arrays can be hard We must make consistent changes to all arrays ▪ If we delete an element from one, elements at the same index must be deleted from the others ▪ If we sort one array then all the other arrays must be sorted in the same way Passing student data to functions is tedious ▪ A function to print student data needs four parameters Or we can use structures
9
index012345678 id910172345678447548643459178924574444 index012345678 firstBobKateSueAlanDaveJoyJoeEllaAnna index012345678 lastWingSmithAbelFlimDoddShaeNgMossFrenc index012345678 gpa3.003.502.752.003.753.502.254.003.50 Sort index
10
index012345678 id110172345678447548643459178924574444 index012345678 firstBobKateSueAlanDaveJoyJoeEllaAnna index012345678 lastWingSmithAbelFlimDoddShaeNgMossFrenc index012345678 gpa3.003.502.752.003.753.502.254.003.50 Sort index index012345678 id178924573459444444754864567872349101 The data is now corrupt since the IDs do not match the students
12
A structure declaration is essentially the definition of a complex type struct student { int id; char first[MAXNAME]; char last[MAXNAME]; float gpa; }; struct student { int id; char first[MAXNAME]; char last[MAXNAME]; float gpa; }; keyword optional tag student variables the tag is optional but if we are going to declare the struct in one place and use it in another we need a tag
13
A structure declaration describes what data types are associated with a struct It does not allocate space for any variables Space is allocated when a variable is defined struct student s1; Instructs the compiler to reserve space for an int, two character arrays and a float ▪ The four components of s1 are allocated memory on the stack in sequence
14
A struct can be declared without a tag If a variable is defined following the declaration struct { int id; char first[MAXNAME]; char last[MAXNAME]; float gpa; } s1; This is really only useful for one-off structs
15
It is common for struct definitions to appear outside any function So that they are available anywhere in the file If a struct is defined inside a function it is only available in that function Variables of a struct type are declared wherever they are needed Just like any other variable
16
A structure can be initialized in much the same way as an array Using a comma separated list of values enclosed in curly brackets struct student s1 = { 12345, “Bob”, “Smith”, 2.75 }; struct student s1 = { 12345, “Bob”, “Smith”, 2.75 };
17
Variables of a structure have to be accessed individually using the member operator (.) To access a structure variable use the structure name and the variable name separated by a dot ▪ s1.id = 12345; They can then be used like any variable of the same type ▪ And can be accessed, assigned new values, passed to functions and so on
18
Individual attributes of a structure can be initialized using dot notation The initializers can be in any order struct student s2 = {.last = "Doe",.first = “Jane” }; struct student s2 = {.last = "Doe",.first = “Jane” };
19
We will look at an example that enters and prints student data The student structure is declared A student variable is defined The user is requested to enter values for the structure attributes The student data is printed
20
#include "stdio.h" const int MAXNAME = 10; // Student structure struct student { int id; char first[MAXNAME]; char last[MAXNAME]; float gpa; }; // Forward Declarations void printStudent(struct student st); #include "stdio.h" const int MAXNAME = 10; // Student structure struct student { int id; char first[MAXNAME]; char last[MAXNAME]; float gpa; }; // Forward Declarations void printStudent(struct student st); the student structure declares the student structure
21
int main() { struct student s1; printf("Enter ID: "); scanf("%d",&s1.id); while(getchar() != '\n'); printf("Enter first name: "); gets(s1.first); printf("Enter last name: "); gets(s1.last); printf("Enter GPA: "); scanf("%f",&s1.gpa); printStudent(s1); return 0; } int main() { struct student s1; printf("Enter ID: "); scanf("%d",&s1.id); while(getchar() != '\n'); printf("Enter first name: "); gets(s1.first); printf("Enter last name: "); gets(s1.last); printf("Enter GPA: "); scanf("%f",&s1.gpa); printStudent(s1); return 0; } note the important precedence here, as (&s1).id would make little sense note the important precedence here, as (&s1).id would make little sense the one and only student define a student variable and enter data clear the input buffer these variables are strings (char *) so we don’t need the address operator
22
void printStudent(struct student st) { printf("\n%d %s %s GPA = %.2f\n", st.id, st.first, st.last, st.gpa); } void printStudent(struct student st) { printf("\n%d %s %s GPA = %.2f\n", st.id, st.first, st.last, st.gpa); } passed by value and finally print the student data
23
Structures can be used as function parameters and arguments In the same way as any other variable Parameter passing is pass by value ▪ Structure variables are not pointers ▪ Unlike array variables When a structure is passed to a function the parameter is a copy of the original Even if the original structure contained arrays!
24
Declaring student variables with the keyword struct is somewhat verbose It would be nicer if we could just declare a variable of type student The typedef keyword allows a programmer to use their own name for a type Somewhat similarly to #define It can be used to name a struct
25
This allows student structures to be declared using just the type name student typedef struct { int id; char first[MAXNAME]; char last[MAXNAME]; float gpa; } student; typedef struct { int id; char first[MAXNAME]; char last[MAXNAME]; float gpa; } student; tag omitted an alias for the struct defined above
26
It is possible to create arrays of structures They are declared like any other kind of array ▪ e.g. struct student class[100]; Individual elements are also accessed like any other array struct attributes are accessed with dot notation Let's say we want to find the first name of the student with index 15 ▪ class[15].first not class.first[15]...
27
Unlike arrays one structure can be assigned to another Think of the assignment as copying the bits that represent the RH struct into the LH struct struct student s1 = {1234, "Peter", "Parker", 3.67}; struct student s2; s2 = s1; struct student s1 = {1234, "Peter", "Parker", 3.67}; struct student s2; s2 = s1; 1234Peter\0Parker 3.67 s1 s2 1234Peter\0Parker 3.67
28
Let’s make the example more complex It isn’t realistic to just record GPA GPA is calculated from the grades that a student receives for courses Create a simple course structure Department (like CMPT) Number (like 130) Grade (A+, A, and so on)
29
#include "stdio.h" const int MAXNAME = 10; const int MAXCOURSES = 20; const int DEPTLEN = 5; const int MAXFILENAME = 20; const int GRADELEN = 2; // Course structure typedef struct { char dept[DEPTLEN]; int number; char grade[GRADELEN]; }course; #include "stdio.h" const int MAXNAME = 10; const int MAXCOURSES = 20; const int DEPTLEN = 5; const int MAXFILENAME = 20; const int GRADELEN = 2; // Course structure typedef struct { char dept[DEPTLEN]; int number; char grade[GRADELEN]; }course; here is the course structure using typedef typedef struct { int id; char first[MAXNAME]; char last[MAXNAME]; course grades[MAXCOURSES]; int coursesTaken; } student; typedef struct { int id; char first[MAXNAME]; char last[MAXNAME]; course grades[MAXCOURSES]; int coursesTaken; } student; it’s an array of courses! it is perfectly OK to nest structures and to make arrays of structures
30
float gpa(student st) { float result= 0; for(int i=0; i < st.coursesTaken; i++){ if(strcmp(st.grades[i].grade, "A") == 0) result += 4; else if(strcmp(st.grades[i].grade, "B") == 0) result += 3; else if(strcmp(st.grades[i].grade, "C") == 0) result += 2; else if(strcmp(st.grades[i].grade, "D") == 0) result += 1; else result += 0; } return result / st.coursesTaken; } float gpa(student st) { float result= 0; for(int i=0; i < st.coursesTaken; i++){ if(strcmp(st.grades[i].grade, "A") == 0) result += 4; else if(strcmp(st.grades[i].grade, "B") == 0) result += 3; else if(strcmp(st.grades[i].grade, "C") == 0) result += 2; else if(strcmp(st.grades[i].grade, "D") == 0) result += 1; else result += 0; } return result / st.coursesTaken; } now we need a function to calculate GPA grades[i] is a course which contains a grade variable you can imagine that this would really include A+, A-,... its a string so can’t use ==
31
void printStudent(student st) { printf("\n%d %s %s\n", st.id, st.first, st.last); // Print list of courses taken for(int i=0; i < st.coursesTaken; i++){ printf("%-4s %d: %s\n", st.grades[i].dept, st.grades[i].number, st.grades[i].grade); } printf("GPA: %.2f\n", gpa(st)); } void printStudent(student st) { printf("\n%d %s %s\n", st.id, st.first, st.last); // Print list of courses taken for(int i=0; i < st.coursesTaken; i++){ printf("%-4s %d: %s\n", st.grades[i].dept, st.grades[i].number, st.grades[i].grade); } printf("GPA: %.2f\n", gpa(st)); } we also need a new function to print student data prints the result of calling the gpa function
32
At the moment we can calculate GPA and print student data But, imagining this is part of a larger system, we need a way get data into the students It would be useful to read student data from a file This brings up some issues ▪ What will the file look like? ▪ How can we write a function to read data into a structure defined outside the function?
33
We need a format for the student files The main thing is to make some rules and then ensure that they are followed Let’s assume that a file contains the data for a single student The first line contains the student’s ID and name Subsequent lines contain courses and grades The number of courses taken can be derived from the number of course lines
34
void readStudent(student* pst) { FILE* fp; int courses = 0; char fname[MAXFILENAME]; printf("Enter a file name: "); gets(fname); // Open file while((fp = fopen(fname, "r")) == NULL){ printf("Try again, q to quit: "); gets(fname); if(strcmp(fname, "q") == 0){ exit(1); } void readStudent(student* pst) { FILE* fp; int courses = 0; char fname[MAXFILENAME]; printf("Enter a file name: "); gets(fname); // Open file while((fp = fopen(fname, "r")) == NULL){ printf("Try again, q to quit: "); gets(fname); if(strcmp(fname, "q") == 0){ exit(1); } finally we will write a function to read student data from a file prompts user to enter an existing file name its a pointer because we need the address of the student we want to store data in
35
void readStudent(student* pst) { //... // Read student data fscanf(fp, "%d%s%s", &pst->id, pst->first, pst->last); while(fscanf(fp, "%s%d%s", pst->grades[courses].dept, &pst->grades[courses].number, pst->grades[courses].grade) == 3) { courses++; } pst->coursesTaken = courses; printf("courses = %d\n", courses); } void readStudent(student* pst) { //... // Read student data fscanf(fp, "%d%s%s", &pst->id, pst->first, pst->last); while(fscanf(fp, "%s%d%s", pst->grades[courses].dept, &pst->grades[courses].number, pst->grades[courses].grade) == 3) { courses++; } pst->coursesTaken = courses; printf("courses = %d\n", courses); } now read the data from the file sets number of courses expects an int, and two strings checks that three values were read accesses course attributes an int
36
int main() { student st1; readStudent(&st1); printStudent(st1); return 0; } int main() { student st1; readStudent(&st1); printStudent(st1); return 0; } here is the main function passing the address of the structure sample output
37
The file reading program is not very robust It will read incorrect data from a file that is not in the right format ▪ Although it does illustrate the use of fscanf One solution would be to check the number and types of values on each line And reject the file if they were incorrect This is hard to do with fscanf as it ignores whitespace
38
It is common to create pointers to structures In the example this was done to change the variable passed to the read function's parameter It also saves time and storage to pass structures to functions via pointers ▪ Particularly if the structure is large Structures may also be function return values Returning structures and passing structures as parameters was not allowed in older C compilers
39
Consider this This fails to compile Because the dot operator has precedence over the dereference operator ▪ The statement is therefore attempting to dereference an integer variable! Here is a corrected version This is ugly, and easy to get wrong Therefore the equivalent -> operator was created *pst.id = 123; //pst is a student* (*pst).id = 123; pst->id = 123;
40
A structure can contain pointers to arrays or other structures If this is desired, care must be taken to ensure that memory is allocated to such pointers Otherwise data might be assigned to a pointer that has not been allocated storage In short – be careful!
41
Since we've talked about it a lot here is a (not the) definition for the FILE struct typedef struct { char *fpos; //position of file pointer void *base; // Pointer to the base of the file unsigned short handle; // File handle short flags; // Flags short unget; // 1-byte buffer for ungetc unsigned long alloc; // Bytes allocated for the file unsigned short buffincrement; // Byte allocation } FILE; typedef struct { char *fpos; //position of file pointer void *base; // Pointer to the base of the file unsigned short handle; // File handle short flags; // Flags short unget; // 1-byte buffer for ungetc unsigned long alloc; // Bytes allocated for the file unsigned short buffincrement; // Byte allocation } FILE;
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.