Lab 04: struct pointers
Work to complete these exercises in lab today. Whatever you do
not finish in the lab, try to complete by the start of lecture on
Wednesday.
This repository contains a few sample C++ files that you will modify
for this lab assignment. The work will give you more practice with
arrays and structs. In particular, we’re allocating these now on the
heap, and we access them through pointers.
Syntax summary
In the last week we’ve learned how to allocate arrays and structs in
heap memory. We use new
to allocate in this way, and we get
back a pointer to either a single item of that type, or to an
array of that type. For example, the lines:
int* a = new int[10];
int* p = new int;
create two pointer variables. The first allocates space for an array
of 10 integers on the heap, 40 bytes. The second allocates space for a
single integer in the heap (4 bytes of space). The contents of that
memory can be accessed using the *
operator, like so:
(*p) = 37;
(*p) = (*p) + 100;
We can allocate structs on the heap. For example, if we take the car
struct defined in the last homework:
struct car {
std::string make;
std::string model;
double odometer;
double fuel;
double mpg;
};
you can allocate an initialize a car
on the heap with
the lines:
car* aCar = new car;
(*aCar).make = "VW";
(*aCar).model = "bus";
(*aCar).odometer = 12338.0;
(*aCar).fuel = 10.8;
(*aCar).mpg = 19.09;
Notice the type car*
of the variable aCar
,
a pointer to a car
struct. Notice also the use of the
(*aCar)
notation on the subsequent lines of code. These
each give you access to the contents of the struct, using that
aCar
pointer. The term (*aCar).mpg
allows you
to access that heap struct’s mpg
field.
In C++ 2011 (often called “C++11”) and beyond (you’ll probably want
to start using C++17) you can use initializer lists to set the fields of
this new struct, like so:
car* aCar = new car {"VW","bus",12338,10.8,19.09};
Finally, when we are done with a heap-allocated struct, we use
delete
to release its storage back to the heap, like
so:
delete aCar;
Notice that, since we allocated a single struct, not an array, we
don’t include the brackets []
after the delete
keyword.
A Fleet Database
Each of the following exercises below has you extend or modify the
code in the file fleet.cc
. This code has a
main
that is the “driver” procedure for managing a fleet of
cars, stored in a “fleet database” file. When run, the code reads in a
text file describing a collection of cars, and then loops asking its
user to examine or modify the cars in that fleet. When done, it saves
the modified vehicle’s status back into that text file.
The fleet database file has a simple format. You can examine and use
the sample one called fleet.txt
. The file starts with a
line with the number of cars in that fleet, and then is followed by a
series of database entries, each a series of lines describing the car.
Here below is an example one-car fleet:
1
VW bus
112338 25.5
2.50943 10.8
19.09
100000
The top entry line contains the vehicle’s make and model. The next
line contains the miles its been driven and the reading of its trip
odometer. The third line gives the fuel in its tank followed by the fuel
capacity. The fourth gives the gas mileage in MPG. The last gives the
mileage of its last tune-up.
These get read by the program and several car
structs
are created, as an array. We’ve enhanced the struct definition slightly
to contain these three additional fields:
struct car {
std::string make;
std::string model;
double last; // odometer reading of the last tune-up
double odometer;
double trip; // miles since the last refuel stop
double fuel;
double mpg;
double tank; // capacity of the fuel tank
};
Once this file is read, the program loops requesting any of the
following commands:
list
drive <make> <model>
refuel <make> <model>
tune <make> <model>
exit
The commands “list” and “drive” are partially implemented. You’ll
complete their code for this lab. You’ll also get “refuel” and “tune”
working. These all rely on the function lookup
which is
currently broken. So, as it stands, you’ll only be able to modify the
first vehicle in the database. (Using fleet.txt
, this is
the “VW bus”.)
Your task is to fix this code, as outlined in the exercises below,
and in the comments for each function that you need to fix.
Exercises
Exercise 1. tuneUp
A car now tracks when it last had a tune-up. This is stored as a
number of miles in the field last
. It gives the reading of
the odometer when the last tune-up occurred. If the odometer reads
112338.0
and the last
field is
1000000.0
, this means that the car has driven 12338 miles
since its last tune-up.
You like to keep a well-maintained fleet, so you work to tune-up a
car every 10000 miles.
Write the code for the function tuneUp
so that it
modifies the car
struct it is given according to the
function’s comment. Note that the code should return a boolean value
indicating whether a tune-up was performed.
Exercise 2. MPG
It turns out that cars get worse gas mileage when they need a
tune-up. When they need a tune-up before a drive, then on that drive the
car is less fuel efficient. It can travel 2.0 fewer miles for each
gallon of fuel than its manufacturer rating (recorded in its
mpg
field). So our “VW bus” would get only
17.08
MPG in its current state, having needed a tune-up for
the last 2338 miles.
Part 1. Write the code for the function
MPG
that gives the actual fuel efficiency of a car, based
on its mpg
rating and its last
tune-up.
Our code, by the way, assumes that all cars are rated to get more
than 2.0 miles per gallon.
The procedure drive
now modifies a car
struct by being handed a pointer to that struct. So it takes a paramter
of type car*
.
Part 2. Update the drive
code so that
it calculates the proper fuel efiiciency of the car to determine the
fuel needed for that drive. It should call the MPG
function
rather than using the car’s mpg
field directly. It should
also update the trip
odometer field, in addition to the
manufacturer’s odometer
field.
Exercise 3. refuel
Write the code for the function refuel
which adds fuel
to a car’s fuel tank whenever that level is below the tank’s capacity.
It should return the amount (in gallons) of fuel that was added. It
should reset the car’s trip odometer back to 0.0.
Exercise 4. outputCar
The code for outputCar
gives the status of the given
vehicle by writing that info out to std::cout
. Add code to
it so that, if it needs a tune-up, it then outputs a line:
The car is due for a tune-up.
Finally, it should output the car’s trip status, with a line
like:
It has been driven 25.5 miles since the last time we refueled,
and can driven about another 42.8610 miles with the fuel it has.
Use the MPG
function to calculate that range
estimate.
Exercise 5. lookup
As the code stands, it uses the lookup
function to scan
the fleet of cars, looking for the car
struct of the
requested make/model. The code for lookup
is broken. It
always returns a pointer to the first vehicle in the fleet, the one at
index 0 in the array.
Fix the code so that it returns a pointer to the car that matches the
given make
and model
string. If no such car
exists in the fleet, return the value nullptr
.
We’ll talk about nullptr
in class, For now, you can
think of it as being used similarly here to Python’s None
value. It is the “invalid entry” response to the lookup
query.
Exercise 6 delete
Finally, note that our code uses new
in the function
readFleet
to allocate heap space for the fleet
struct and for its array of car
structs that hold the
fleet’s info. This means that their data needs to be released back to
the heap.
Add the appropriate lines at the end of main
so that
these two pointers’ data is given back to the heap.