【问题标题】:Print from struct passed by value in C从 C 中按值传递的结构打印
【发布时间】:2019-07-16 23:01:13
【问题描述】:

TL;DR:

printf() 在按值传递时在printLotInfo() 中打印垃圾。

代码

#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);
}

以上代码用于赋值。我们获得了功能原型,并负责让它们执行与停车场结构相关的某些操作。数据操作实际上按预期工作,在程序结束时为两个批次提供预期的输出。

这让我认为printf() 造成了麻烦,而不是潜在的价值。专用printLotInfo() 函数和initializeLot() 中的临时printf 语句之间的唯一区别是,一个从struct * 打印,而另一个从结构打印。

我花了几个小时研究这个问题,我遇到了很多线程来展示如何从函数中的 struct * 或 main 中的结构中打印,但我还没有找到一个很好的打印示例一个单独的函数调用中的结构。我想我遗漏了一些明显的东西,比如不正确的取消引用运算符或类似的东西。

【问题讨论】:

  • 您是否尝试过在printLotInfo、*p 和例如p-&gt;lotNumber 中使用指针?
  • 打开编译器警告!
  • 1) 打开编译器警告,2) 在发布之前创建一个minimal reproducible example。
  • 作为旁注,尝试动态分配内存后检查分配是否成功。 Time * t = malloc(sizeof(Time)); setHours(t, -1); 使用前t 与if (t!=NULL) 核对。

标签: c struct printing printf


【解决方案1】:

你错过了一个论点:

printf("Parking Lot #%d - rate = $%.2lf, capacity %d, current cars %d\n",
  p.lotNumber, p.capacity, p.currentCarCount);

您的格式字符串有 4 个格式说明符,但您只提供 3 个参数。结果,第二个格式说明符%f 正在寻找double,其中传递了int,第四个格式说明符正在寻找int,其中传递了no 参数。使用错误的格式说明符或未提供足够的参数会调用 undefined behavior。

使用需要在参数列表中放入hourlyRate字段:

printf("Parking Lot #%d - rate = $%.2lf, capacity %d, current cars %d\n",
  p.lotNumber, p.hourlyRate, p.capacity, p.currentCarCount);

【讨论】:

  • 你是对的!显然,下次我需要更仔细地阅读我的代码。非常感谢。
  • @LH1395 或者另一个选项是打开编译器警告,例如如果您使用gcc 作为编译器,使用-Wall 开关可以捕获这些错误。
【解决方案2】:

与问题不直接相关,但通过一些调整,程序可以变得更健壮一点,并且也是一个有效的 C++ 程序。这有助于找到一些可以改进 C 程序的东西。

让Car 持有指向 const 字符的指针。

typedef struct Car
{
    char const *plateNumber;  //String to hold plate
...

initializeCar的界面不变:

void initializeCar(Car *c, char const *plate, char hasPermit)
{
    Time * t =(Time*) malloc(sizeof(Time));       //Allocate memory for time object

将malloc 的返回值转换为所需的类型。 (见上文和下文。)

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

最后,让main 的签名故意说它接受零参数。

int main(void) {

没有void 旧接口表示它需要零和无限参数。 (在 C++ 中,main() 已经意味着零参数。)

【讨论】:

  • @dbush,为什么不呢?有什么缺点?
  • 阅读链接的问题。
  • 我做到了,但由于我的回答是关于在 C++ 编译器看到的代码中捕获 other 错误,所以 malloc 中的转换是需要。这就是权衡。
  • 这个问题与 C++ 无关。你不应该用 C++ 编译器编译 C 代码。
猜你喜欢
  • 1970-01-01
  • 2015-01-21
  • 2020-01-21
  • 2022-01-25
  • 1970-01-01
  • 2011-02-14
  • 1970-01-01
  • 1970-01-01
  • 2014-09-08
相关资源
最近更新 更多