lh1395
lh1395

Reputation: 170

Print from struct passed by value in C

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

Answers (2)

Bo R
Bo R

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

dbush
dbush

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

Related Questions