Complex data types Structures Defined types Structures and functions Structures and pointers.
-
Upload
richard-anderson -
Category
Documents
-
view
249 -
download
10
Transcript of Complex data types Structures Defined types Structures and functions Structures and pointers.
Structures
Structures
Complex data types Structures Defined types Structures and functions Structures and pointers
Representing Complex Data
Representing Data
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
Representing Students
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
Students without Structures
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
Parallel Arrays
index 0 1 2 ... 33 ... 97 98 99
id 1101
7234
5678
4864
1789
2457
4444
index 0 1 2 ... 33 ... 97 98 99
first Bob Kate Sue Dave Joe Ella Ann
a
index 0 1 2 ... 33 ... 97 98 99
last Wing
Smith Abel Dod
d Ng Moss
Frenc
index 0 1 2 ... 33 ... 97 98 99
gpa 3.00 3.50 2.75 3.75 2.25 4.00 3.50
Represents the student Dave Dodd
Parallel Array Drawbacks
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
Sort Error in a Parallel Array
index 0 1 2 3 4 5 6 7 8
id 9101
7234
5678
4475
4864 3459 178
9245
7444
4
index 0 1 2 3 4 5 6 7 8
first Bob Kate Sue Alan Dave Joy Joe Ella Ann
a
index 0 1 2 3 4 5 6 7 8
last Wing
Smith Abel Flim Dod
d Shae Ng Moss
Frenc
index 0 1 2 3 4 5 6 7 8
gpa 3.00 3.50 2.75 2.00 3.75 3.50 2.25 4.00 3.50
Sort index
Sort Error in a Parallel Array
index 0 1 2 3 4 5 6 7 8
id 1101
7234
5678
4475
4864 3459 178
9245
7444
4
index 0 1 2 3 4 5 6 7 8
first Bob Kate Sue Alan Dave Joy Joe Ella Ann
a
index 0 1 2 3 4 5 6 7 8
last Wing
Smith Abel Flim Dod
d Shae Ng Moss
Frenc
index 0 1 2 3 4 5 6 7 8
gpa 3.00 3.50 2.75 2.00 3.75 3.50 2.25 4.00 3.50
Sort index
index 0 1 2 3 4 5 6 7 8
id 1789
2457
3459
4444 4475 486
4567
8723
4910
1
The data is now corrupt since the IDs do not match the students
Structures
Structure Declarations
A structure declaration is essentially the definition of a complex type
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
Defining a Structure Variable 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
Tag-less structs
A struct can be declared without a tag If a variable is defined following the
declarationstruct {
int id;char first[MAXNAME];char last[MAXNAME];float gpa;
} s1; This is really only useful for one-off
structs
What Goes Where
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
Initializing a Structure
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
};
Accessing Structure Members
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
Designated Initializers
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”
};
Enter Student Data
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
Student Data – Declarations
#include "stdio.h"const int MAXNAME = 10;
// Student structurestruct student{
int id;char first[MAXNAME];char last[MAXNAME];float gpa;
};
// Forward Declarationsvoid printStudent(struct student st);
the student structure
declares the student structure
Student Data – main
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
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
CStudent Data – print
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
Structures and Functions
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!
typedef
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
Structures and typedef
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;
tag omitted
an alias for the struct defined above
Arrays of Structures
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] ...
Assigning Structures
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 structstruct student s1 = {1234, "Peter", "Parker", 3.67};
struct student s2;s2 = s1;
1234 P e t e r \0 P a r k e r \0 3.67s1
s2 1234 P e t e r \0 P a r k e r \0 3.67
More Complex Types
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)
Course and Student Structure
#include "stdio.h"const int MAXNAME = 10;const int MAXCOURSES = 20;const int DEPTLEN = 5;const int MAXFILENAME = 20;const int GRADELEN = 2;
// Course structuretypedef 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;
it’s an array of courses!
it is perfectly OK to nest structures and to make arrays of structures
Calculating GPA
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;
elseresult += 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 ==
Printing Student Data
void printStudent(student st){
printf("\n%d %s %s\n", st.id, st.first, st.last);
// Print list of courses takenfor(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
Reading Student Data
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?
File Format
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
What About Getting Data?
void readStudent(student* pst){
FILE* fp;int courses = 0;char fname[MAXFILENAME];printf("Enter a file name: ");gets(fname);
// Open filewhile((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
Reading Student Data
void readStudent(student* pst){
// ...// Read student datafscanf(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
Student Data Program
int main(){
student st1;readStudent(&st1);printStudent(st1);return 0;
}
here is the main function
passing the address of the structure
sample output
File Errors
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
Pointers and Structures
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
Dereferencing Structure Pointers
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;
Pointers in Structures
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!
Finally
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 pointervoid *base; // Pointer to the base of the fileunsigned short handle; // File handleshort flags; // Flagsshort unget; // 1-byte buffer for ungetcunsigned long alloc; // Bytes allocated for the fileunsigned short buffincrement; // Byte allocation
} FILE;