Reputation: 170
TL;DR:
printf()
prints garbage in printLotInfo()
when passing by value.
Code
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <math.h>
#include <string.h>
typedef struct Time
{
int hour; //Hour of day
int minute; //Minute of hour
} Time;
typedef struct Car
{
char * plateNumber; //String to hold plate
char hasPermit; //True/False
Time * enteringTime; //Time Struct
int lotParkedIn; //Where is the car located
} Car;
typedef struct ParkingLot
{
int lotNumber; //Lot identifier
double hourlyRate; //$$/h
double maxCharge; //Maximum daily charge
int capacity; //How many cars can be parked in the lot?
int currentCarCount; //Tracks # of cars in lot
double revenue; //How much money has this lot made?
} ParkingLot;
// Sets the hours and minutes amount for the given time t based
// on the specified hours h. (e.g., 1.25 hours would be 1 hour
// and 15 minutes)
void setHours(Time *t, double h)
{
if(h != -1)
{
t->hour = (int) h; //Bad practice but no overflow expected here
t->minute = (h - t->hour) * 60.0; //Cast truncates h. h - t.hour is h-truncated h
}
else
{
t->hour = -1;
t->minute = -1;
}
}
// Takes two Time objects (not pointers) and computes the difference
// in time from t1 to t2 and then stores that difference in the diff
// Time (which must be a pointer)
void difference(Time t1, Time t2, Time *diff)
{
diff->hour = t2.hour - t1.hour;
diff->minute = t2.minute - t1.minute;
if(diff->minute < 0)
{
diff->hour--; //If minutes are negative, decrement hour
diff->minute += 60; //and set minutes to complement of 60.
}
}
// Initialize the car pointed to by c to have the given plate and
// hasPermit status. The car should have it’s lotParkedIn set to
// 0 and enteringTime to be -1 hours and -1 minutes.
void initializeCar(Car *c, char *plate, char hasPermit)
{
Time * t = malloc(sizeof(Time)); //Allocate memory for time object
setHours(t, -1); //Set time with call to setHours()
c->plateNumber = plate;
c->hasPermit = hasPermit; //Set variables
c->lotParkedIn = 0;
c->enteringTime = t;
}
/********************** PROBLEM SECTION ************************************/
// Initialize the lot pointed to by p to have the given number,
// capacity, hourly rate and max charge values. The currentCarCount
// and revenue should be at 0.
void initializeLot(ParkingLot * p, int num, int cap, double rate, double max)
{
p->lotNumber = num;
p->hourlyRate = rate;
p->maxCharge = max;
p->capacity = cap;
p->currentCarCount = 0;
p->revenue = 0;
printf("PRINTING IN initializeLot():\nLot is: %d Capacity is: %d Rate is: %.2lf Maximum is: %.2lf\n",
p->lotNumber, p->capacity, p->hourlyRate, p->maxCharge);
}
// Print out the parking lot parameters so that is displays as
// follows: Parking Lot #2 - rate = $3.00, capacity 6, current cars 5
void printLotInfo(ParkingLot p)
{
printf("PRINTING IN printLotInfo():\n");
printf("Parking Lot #%d - rate = $%.2lf, capacity %d, current cars %d\n",
p.lotNumber, p.capacity, p.currentCarCount);
}
/************************* END PROBLEM SECTION *****************************/
// Simulate a car entering the parking lot
// ...
void carEnters(ParkingLot * p, Car * c, int hour, int minute)
{
if((p->capacity - p->currentCarCount) <= 0)
{
printf("Car %s arrives at Lot %d at %d:%1.2d, but the lot is full\n",
c->plateNumber, p->lotNumber, hour, minute);
return;
}
double timeToSet = (hour + (minute / 60.0));
setHours(c->enteringTime, timeToSet);
c->lotParkedIn = p->lotNumber;
p->currentCarCount += 1;
printf("Car %s arrives at Lot %d at %d:%1.2d.\n", c->plateNumber,
p->lotNumber, hour, minute);
}
// Simulate a car leaving the parking lot
// ...
void carLeaves(ParkingLot * p, Car * c, int hour, int minute)
{
Time * leaveTime = malloc(sizeof(Time));
Time * timeDifference = malloc(sizeof(Time)); //Allocate memory for time object
double timeToSet = (hour + (minute / 60.0));
setHours(leaveTime, timeToSet); //Set time with call to setHours()
difference(*(c->enteringTime), *leaveTime, timeDifference);
if(c->hasPermit == 0)
{
double carRevenue = p->hourlyRate * timeDifference->hour;
if(timeDifference->minute != 0)
carRevenue += p->hourlyRate;
if(carRevenue > p->maxCharge)
carRevenue = p->maxCharge;
p->revenue += carRevenue;
printf("Car %s leaves Lot %d at %d:%1.2d paid $%.2lf.\n",
c->plateNumber, p->lotNumber, hour, minute, carRevenue);
}
else
printf("Car %s leaves Lot %d at %d:%1.2d.\n",
c->plateNumber, p->lotNumber, hour, minute);
p->currentCarCount--;
free(c->enteringTime);
free(c);
free(leaveTime);
free(timeDifference);
}
/*BEGIN PROFESSOR'S CODE*/
int main() {
Car car1, car2, car3, car4, car5, car6, car7, car8, car9;
ParkingLot p1, p2;
// Set up 9 cars
initializeCar(&car1, "ABC 123", 0);
initializeCar(&car2, "ABC 124", 0);
initializeCar(&car3, "ABD 314", 0);
initializeCar(&car4, "ADE 901", 0);
initializeCar(&car5, "AFR 304", 0);
initializeCar(&car6, "AGD 888", 0);
initializeCar(&car7, "AAA 111", 0);
initializeCar(&car8, "ABB 001", 0);
initializeCar(&car9, "XYZ 678", 1);
// Set up two parking lots
initializeLot(&p1, 1, 4, 5.5, 20.0);
initializeLot(&p2, 2, 6, 3.0, 12.0);
printLotInfo(p1);
printLotInfo(p2);
printf("\n");
// Simulate cars entering the lots
carEnters(&p1, &car1, 7, 15);
carEnters(&p1, &car2, 7, 25);
carEnters(&p2, &car3, 8, 0);
carEnters(&p2, &car4, 8, 10);
carEnters(&p1, &car5, 8, 15);
carEnters(&p1, &car6, 8, 20);
carEnters(&p1, &car7, 8, 30);
carEnters(&p2, &car7, 8, 32);
carEnters(&p2, &car8, 8, 50);
carEnters(&p2, &car9, 8, 55);
printf("\n");
printLotInfo(p1);
printLotInfo(p2);
printf("\n");
// Simulate cars leaving the lots
carLeaves(&p2, &car4, 9, 0);
carLeaves(&p1, &car2, 9, 5);
carLeaves(&p1, &car6, 10, 0);
carLeaves(&p1, &car1, 10, 30);
carLeaves(&p2, &car8, 13, 0);
carLeaves(&p2, &car9, 15, 15);
carEnters(&p1, &car8, 17, 10);
carLeaves(&p1, &car5, 17, 50);
carLeaves(&p2, &car7, 18, 0);
carLeaves(&p2, &car3, 18, 15);
carLeaves(&p1, &car8, 20, 55);
printf("\n");
printLotInfo(p1);
printLotInfo(p2);
printf("\n");
// Display the total revenue
printf("Total revenue of Lot 1 is $%4.2f\n", p1.revenue);
printf("Total revenue of Lot 2 is $%4.2f\n", p2.revenue);
}
The above code is for an assignment. We were given the function prototypes and tasked with making them perform certain actions relating to a parking lot structure. The data manipulation actually works as intended, giving the expected output for both lots at the end of the program.
This leads me to think that printf()
is causing trouble, rather than the underlying values. The only difference between the dedicated printLotInfo()
function and the provisional printf
statement in initializeLot()
is that one prints from a struct *
while the other prints from a struct.
I have spent several hours researching this, and I've come across plenty of threads showing how to print from a struct *
in a function or a struct in main, but I haven't found a good example of printing from a struct in a separate function call. I think I'm missing something obvious like an incorrect dereference operator or something along those lines.
Upvotes: 0
Views: 1028
Reputation: 2371
Not directly pertinent to the question, but with a few tweaks, the program can become a little bit more robust and also a valid C++ program. This facilitates finding some of the things that improve the C program.
Make Car
hold a pointer to const characters.
typedef struct Car
{
char const *plateNumber; //String to hold plate
...
Same change to the interface of initializeCar
:
void initializeCar(Car *c, char const *plate, char hasPermit)
{
Time * t =(Time*) malloc(sizeof(Time)); //Allocate memory for time object
Cast your malloc
's return value to the desired type. (See above and below.)
void carLeaves(ParkingLot * p, Car * c, int hour, int minute)
{
Time * leaveTime = (Time*)malloc(sizeof(Time));
Time * timeDifference = (Time*)malloc(sizeof(Time)); //Allocate memory for time object
And finally, have the signature of main
deliberately say it takes zero arguments.
int main(void) {
Without void
old interface said it takes between zero and unlimited arguments. (In C++ main()
already means zero arguments.)
Upvotes: -1
Reputation: 223872
You're missing an argument:
printf("Parking Lot #%d - rate = $%.2lf, capacity %d, current cars %d\n",
p.lotNumber, p.capacity, p.currentCarCount);
Your format string has 4 format specifiers, but you only give 3 arguments. As a result, the second format specifier %f
is looking for a double
where an int
was passed, and the fourth one is looking for an int
where no parameter was passed. Using the wrong format specifier or not supplying enough arguments invokes undefined behavior.
Use need to put in the hourlyRate
field in the list of parameters:
printf("Parking Lot #%d - rate = $%.2lf, capacity %d, current cars %d\n",
p.lotNumber, p.hourlyRate, p.capacity, p.currentCarCount);
Upvotes: 5