CS 270
|
struct.h struct.c main.c Makefile class.txt
You should now be able to type make
to compile the program.
When we talk about standard input, we usually think of the user entering information from the keyboard. However, when you’re testing a program, entering the same information over and over can become tedious. We will automate user input by using a feature of the shell called input redirection. The user input will come from a file. We have provided an example file (class.txt). The format is as follows (the arrow and text to the right of the arrow is not part of the file). In general, the number of students in the file is not fixed.
3 <- Number of students in the class John <- First student’s first name (string) 52.5 <- First student’s quality points (float) 15 <- First student’s number of credits (integer) Jane <- Second student’s first name (string) 53.2 <- Second student’s quality points (float) 14 <- Second student’s number of credits (integer) Johnny <- Third student’s first name (string) 35.7 <- Third student’s quality points (float) 17 <- Third student’s number of credits (integer)
In order to make our C program read from this file as if it was the standard input, we will use the following command (< is the input redirection operator):
./R6 < class.txt
.h
file, complete the Student
structure so that it contains the
following three members:
firstName:
a string (array of characters
) whose size is 80 characters.
qualityPoints:
a float
.numCredits:
an int
..h
file, declare a structure using typedef
. The name of the new type
should be ClassRoster
. The structure should contain the following members:
numStudents:
an int
.students:
a Student **
(yes, a double pointer).main.c
) do the following:
scanf
function. To
use this function, you must provide a format string. The call would look something like this:
scanf("%d", address of variable);
The %d
indicates that we want to read an integer. Replace address of
variable with an expression that gets the address of the variable where you want to
store the number of students.
ClassRoster
named roster
. This allocates space for
a
ClassRoster
structure statically (as opposed to dynamically). Then, initialize the two
members of this
structure as follows:
numStudents
member should be initialized to the number you read in (a). students
member should be initialized to point to a dynamically allocated array
ofStudent
pointers
(not an array of Students!). The number of elements
in the
array should be the number of students in the class. You want all the elements in the array to
be
initialized to NULL (or 0). With this in mind, should you use malloc()
or
calloc()
? students
member is a double pointer ask the TAs for clarification. for
loop that iterates as many times as dictated by the numStudents
member of the
roster
The goal is to iterate through the students
array to read students from
the
standard input and store them in the array. In each iteration, call the
readStudentAndEnroll()
function
(this function is declared in struct.h
). Pass the address
of the current
element of the
array. Based on this, you should understand why this function takes a double pointer.for
loop that iterates as many times as dictated by the
numStudents
member of the roster
The goal is to iterate through the students
array and
display each
element in the standard output. In each iteration, call the displayStudent()
function (this
function is
declared in struct.h
). Notice that this function takes a Student
(not a
Student *
). You must call it accordingly, don’t change the declaration! After calling
displayStudent()
, call free()
to free the memory associated with this student.
for
loop, call free()
to free the memory associated with the
students
Why do we not need to call free()
to free roster?readStudentAndEnroll()
It may be tricky to understand why this
function
takes a double pointer. First, remember that in the main function, we created an array of
Student pointers
initially pointing to NULL. We can visualize this array as follows:
Then, we created a loop to call readStudentAndEnroll()
to pass the address of each element of
the
array. Since every element of the array is a Student pointer
, and this function accepts the
address
of such an element (we’ll see why shortly), the type of the parameter must be a
pointer to a Student pointer
(or Student **
). Suppose we are currently
dealing
with the second element of the array. That means that the slot
argument of the
readStudentAndEnroll()
function is a pointer to the second pointer of the array:
So, why do we accept the address of a pointer in the first place? This function will create a new
Student
dynamically and will populate it with some information:
Then, we want to make the current element in the array point to the new student. If a function wants
to change the original argument, we must pass it the address of what we want it
to change. So, if we want readStudentAndEnroll()
to change what the second element points to,
we’d better pass the address of that pointer. Hence, we end up with a double pointer. That way we can
use
the slot
argument to achieve this:
With all this in mind, here’s what you should do in this function:
Student
. We will initialize the members shortly. Do
you
need a malloc()
or a calloc()
?scanf
, which should be the first name of the
student. The first name should be stored in the firstName
member of the student you just
created.scanf
, which should be the quality points of
the
student. The quality points should be stored in the qualityPoints
member of the student you
just created.scanf
, which should be the number of credits
of
the student. The number of credits should be stored in the numCredits
member of the student
you
just created.slot
argument to make the original pointer point to the student that we
created. If you can come up with this one line on your own, you’re on your way to becoming a
pointer
master.displayStudent()
This function will calculate the GPA for a
student
and output the student’s name and the GPA. Here are the steps:
float
) of the student using the following formula:
GPA = quality points / number of credits
John, 3.50
The GPA needs to have 2 decimal places. Don’t forget the newline character at the end.
txt
file: John, 3.50
Jane, 3.80
Johnny, 2.10
Feel free to test using your own text files. You should also run your program with Valgrind
to check
for
errors and memory leaks:
valgrind --leak-check=yes ./R6 < class.txt
In the output, you should see the following two lines:
All heap blocks were freed -- no leaks are possible
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
make package
. This will generate a file named
R6.tar which contains the struct.h, struct.c, and main.c files. Submit this tar file to the Checkin tab
and wait for the testing results. Your grade for this recitation will be what you
get in the autograder. You may submit as many times as needed until the deadline.
You can get 50 points if your code simply compiles correctly