Reputation: 97
The whole goal is to create generate 1000 cars with the following attributes, write them to a binary file, read them from that binary file and count them. Note that if the car is hybrid, then it will have two efficiencies, one is a float and the other is an int. The code is below because I have spent way too much time on it (two days now).
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <process.h>
typedef enum {
hybrid, ICE, electric
} engine_Type;
typedef enum {
tesla, bmw, toyota, mercedes_benz, hyundai, volkswagen, nissan
} car_Make;
typedef union {
int electricEffInt;
float iceEffFloat;
} effincy;
typedef struct {
engine_Type engine;
car_Make make;
int hybridEffInt;
float hybridEffFloat;
effincy carEfficiency;
int maximumTorque;
} car;
//Mix is used for seed generation
unsigned long mix(unsigned long a, unsigned long b, unsigned long c) {
a=a-b; a=a-c; a=a^(c >> 13);
b=b-c; b=b-a; b=b^(a << 8);
c=c-a; c=c-b; c=c^(b >> 13);
a=a-b; a=a-c; a=a^(c >> 12);
b=b-c; b=b-a; b=b^(a << 16);
c=c-a; c=c-b; c=c^(b >> 5);
a=a-b; a=a-c; a=a^(c >> 3);
b=b-c; b=b-a; b=b^(a << 10);
c=c-a; c=c-b; c=c^(b >> 15);
return c;
}
car carGeneration() {
car car;
car.engine = rand()%3;
car.make = rand()%7;
car.maximumTorque = (250 + rand()/(RAND_MAX/(3800-250)));
switch (car.engine) {
case hybrid: car.hybridEffInt = (12 + rand() / (RAND_MAX / (18 - 12)));
car.hybridEffFloat = (float)(3.3f + (float)rand() / (RAND_MAX / (8.5f - 3.3f)));
break;
case ICE: car.carEfficiency.iceEffFloat= (3.3f + (float)rand() / (RAND_MAX / (8.5f - 3.3f)));
break;
case electric: car.carEfficiency.electricEffInt = (12 + rand() / (RAND_MAX / (18 - 12)));
break;
}
return car;
}
void mulipleCarGeneartion(int carCount, car *cars){
for(int i =0;i < carCount ;i++){
cars[i]=carGeneration();
}
}
void write_file(car *cars, int amount){
FILE*out = fopen("cars.dat", "wb");
if(out == NULL){
printf("File does not exist creating file");
}
for (int i=0;i< amount ;i++) {
//fwrite(&cars[i], sizeof(car) , 1,out);
fwrite(&cars[i].engine, sizeof(car) , 1,out);
fwrite(&cars[i].make, sizeof(car) , 1,out);
fwrite(&cars[i].maximumTorque, sizeof(int) , 1,out);
switch (cars[i].engine) {
case hybrid: fwrite(&cars[i].hybridEffInt, sizeof(int) , 1,out);
fwrite(&cars[i].hybridEffFloat, sizeof(float) , 1,out);
break;
case ICE:
fwrite(&cars[i].carEfficiency.iceEffFloat, sizeof(float) , 1,out);
break;
case electric:fwrite(&cars[i].carEfficiency.electricEffInt, sizeof(int) , 1,out);
break;
}
}
fclose(out);
}
void read_file(car *cars, int amount) {
int teslaCount = 0, bmwCount=0, toyotaCount=0, mercedes_BenzCount=0, hyundaiCount=0, volkswagenCount=0, nissanCount=0;
FILE *in = fopen("cars.dat", "rb");
if (in == NULL) {
printf("Can not read file");
}
printf("Car makes (Quantity): \n");
printf("Tesla BMW Toyota Mercedes-Benz Volkswagen Nissan\n");
for (int j = 0; j<50; j++) {
printf("-");
}
printf("\n");
for (int i = 0; i < amount; i++) {
fread(&cars[i],sizeof(car), 1, in);
printf("engine Type: %d \n", cars[i].engine);
printf("car Make: %d \n", cars[i].make);
printf("Torque %d \n", cars[i].maximumTorque);
switch (cars[i].make) {
case tesla: teslaCount++;
break;
case bmw: bmwCount++;
break;
case toyota: toyotaCount++;
break;
case mercedes_benz: mercedes_BenzCount++;
break;
case hyundai: hyundaiCount++;
break;
case volkswagen: volkswagenCount++;
break;
case nissan: nissanCount++;
break;
}
switch (cars[i].engine) {
case hybrid:
printf("hybrid efficiencyINT: %d\n", cars[i].hybridEffInt);
printf("hybrid efficiencyFLOAT: %f\n", cars[i].hybridEffFloat);
break;
case ICE:
printf("ICE efficiency: %f\n", cars[i].carEfficiency.iceEffFloat);
break;
case electric:
printf("electric efficiency: %d\n", cars[i].carEfficiency.electricEffInt);
}
}
printf("Count bob %d %d %d %d %d %d", bmwCount, hyundaiCount,volkswagenCount,nissanCount, teslaCount, toyotaCount);
}
int main() {
int generationAmount = 20;
car carsArray[generationAmount];
mulipleCarGeneartion(generationAmount, carsArray);
srand(mix(clock(), time(NULL), getpid()));
write_file(carsArray, generationAmount);
read_file(carsArray,generationAmount);
return 0;
}
I started by firstly debugging and finding the values that stored in the array. The problem now seems to with either the write function or read function. I thought doing fwrite(&cars[i].engine, sizeof(car) , 1,out));
wrote everything about the array including the attributes, but to be honest I was not sure thus I tried to have mulitple fwrite
to write everything about car and read them in the same order when reading the file. I tried changing the sizeof inside the fwrite, but nothing works.
This is the current output:
engine Type: 2
car Make: 1
Torque 953
electric efficiency: 16
engine Type: 1
car Make: 1363987785
Torque 2
ICE efficiency: 0.000000
engine Type: 953
car Make: 16
Torque 32760
engine Type: 17
car Make: 1525
Torque 17
engine Type: 1525
car Make: 1
Torque 6
Count bob 2 0 0 0 0 0
which is incorrect, car make ranges from 0-7, while engine type 0-3, and torque's minimum value is 250. What makes this problem harder is that i cant look at the binary file and understand the data to see where the problem is. I know I can convert it to hex but like what am I going to do with hex?
Upvotes: 3
Views: 188
Reputation:
sizeof()
: fwrite(&cars[i].engine, sizeof(car) , 1,out);
fwrite(&cars[i].make, sizeof(car) , 1,out);
To debug this issue I then wrote a cars_print()
function, disabled the print in read_file()
(it's mixing concerns), commented out srand()
, and reduced generationAmount
to 1
which look fine then 2
which yielded a difference:
#define generationAmount 2
void print_cars(int amount, car cars[amount]) {
for(size_t i = 0; i < generationAmount; i++) {
printf("i = %zu\n", i);
printf(
"engine: %d\n"
"make: %d\n",
cars[i].engine,
cars[i].make
);
switch (cars[i].engine) {
case hybrid:
printf("hybridEffInt: %d\n"
"hybridEffFloat: %f\n",
cars[i].hybridEffInt,
cars[i].hybridEffFloat
);
case ICE:
printf("carEfficiency.iceEffFloat: %f\n", cars[i].carEfficiency.iceEffFloat);
break;
case electric:
printf("carEfficiency.electricEffInt: %d\n", cars[i].carEfficiency.electricEffInt);
break;
}
printf("maximumTorque: %d\n", cars[i].maximumTorque);
}
}
int main() {
car carsArray[generationAmount];
//srand(mix(clock(), time(NULL), getpid()));
mulipleCarGeneartion(generationAmount, carsArray);
print_cars(generationAmount, carsArray);
write_file(generationAmount, carsArray);
read_file(generationAmount, carsArray);
print_cars(generationAmount, carsArray);
}
and it produces the output:
i = 0
engine: 1
make: 4
carEfficiency.iceEffFloat: 7.451888
maximumTorque: 3030
i = 1
engine: 2
make: 3
carEfficiency.electricEffInt: 16
maximumTorque: 1440
i = 0
engine: 1
make: 4
carEfficiency.iceEffFloat: 0.000000
maximumTorque: 3
i = 1
engine: 1440
make: 16
maximumTorque: 1440
write_file()
vs read_file()
and particular paying attention to the carEfficiency.iceEffFloat
which is problematic per above output. I found that that you write out individual fields in particular carEfficiency
, hybridEffInt
and hybridEffFloat
depending on the value of engine
, but in read_file()
you read a car
struct which is not the same. The easy fix is just to write and read the whole array in one go:void write_file(int amount, car cars[amount]){
FILE *out = fopen("cars.dat", "wb");
if(!out) {
printf("File does not exist creating file");
return;
}
fwrite(cars, sizeof *cars, amount, out);
fclose(out);
}
void read_file(int amount, car cars[amount]) {
FILE *in = fopen("cars.dat", "rb");
if (!in) {
printf("Can not read file");
return;
}
fread(cars, sizeof *cars, amount, in);
fclose(in);
}
You should check the return value from both fread()
and fwrite()
. It would also be a good idea to use a different array for writing the data than to read the data so nothing gets carried simply by happenstance. This will write out an unused variable for electric
and ice
but it might be worth it for the cleaner code. If you don't want that then you have to read and write fields individually.
The order you write is also not he same as the order of your members of struct. maximumTorque
is written after make
but in the struct it's after carEfficiency
.
There is data modeling issue. efficiency
is a union, but you have hybridEffFloat
and hybridEffInt
in cars
. The easiest fix it just use same variable name across the 3 engine types, and this means you can eliminate the (union) efficiency
and just have that two fields in cars
as you don't use it elsewhere:
typedef struct {
engine_Type engine;
car_Make make;
int efficiency_electric;
float efficiency_ice;
int maximumTorque;
} car;
Don't encode types in variable names. If you need to change the type this means you also have change your variable names to avoid confusion (DRY).
Finally, re-implement the tabulation logic you had in read_file()
. I noticed with my 2 records the count 1 is. This is because you don't print out all the variables (mercedes_BenzCount
). Use an array instead:
void tabulate_cars(int amount, car cars[amount]) {
printf("Car makes (Quantity): \n");
printf("Tesla BMW Toyota Mercedes-Benz Volkswagen Nissan\n");
int counts[make_count] = { 0 };
for (int j = 0; j<50; j++)
printf("-");
printf("\n");
for(size_t i = 0; i < amount; i++)
counts[cars[i].make]++;
printf("Count bob ");
for(size_t i = 0; i < make_count; i++)
printf("%d%s", counts[i], i + 1 < make_count ? " " : "\n");
}
Notice the output is slightly different and you have two functions now to print details and to tablute. In tabulate you still hard-code the labels to match the enum order. The way to fix that is a X macro, btw, but the answer is getting pretty long already.
Minor issue but prefer the array length argument before array so you can document how they are related.
Eliminate carGeneration
in favor of just mulipleCarGeneartion()
for consistency with the rest of your functions. The former is a special-case of the latter so you don't need it. Also rename it to generate_cars()
for consistency.
srand()
should happen before rand()
to have an effect (i.e. before generate_cars()
).
Here's it's altogether:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#define generationAmount 20
typedef enum {
hybrid, ICE, electric
} engine_Type;
typedef enum {
tesla, bmw, toyota, mercedes_benz, hyundai, volkswagen, nissan, make_count
} car_Make;
typedef struct {
engine_Type engine;
car_Make make;
int efficiency_electric;
float efficiency_ice;
int maximumTorque;
} car;
//Mix is used for seed generation
unsigned long mix(unsigned long a, unsigned long b, unsigned long c) {
a=a-b; a=a-c; a=a^(c >> 13);
b=b-c; b=b-a; b=b^(a << 8);
c=c-a; c=c-b; c=c^(b >> 13);
a=a-b; a=a-c; a=a^(c >> 12);
b=b-c; b=b-a; b=b^(a << 16);
c=c-a; c=c-b; c=c^(b >> 5);
a=a-b; a=a-c; a=a^(c >> 3);
b=b-c; b=b-a; b=b^(a << 10);
c=c-a; c=c-b; c=c^(b >> 15);
return c;
}
void print_cars(int amount, car cars[amount]) {
for(size_t i = 0; i < generationAmount; i++) {
printf("i = %zu\n", i);
printf(
"engine: %d\n"
"make: %d\n",
cars[i].engine,
cars[i].make
);
switch (cars[i].engine) {
case hybrid:
printf("efficientcy_eletric: %d\n", cars[i].efficiency_electric);
printf("efficientcy_ice: %f\n", cars[i].efficiency_ice);
case electric:
printf("efficientcy_eletric: %d\n", cars[i].efficiency_electric);
break;
case ICE:
printf("efficientcy_ice: %f\n", cars[i].efficiency_ice);
break;
}
printf("maximumTorque: %d\n\n", cars[i].maximumTorque);
}
}
void generate_cars(int carCount, car cars[carCount]){
for(int i =0;i < carCount ;i++) {
cars[i].engine = rand()%3;
cars[i].make = rand()%7;
cars[i].maximumTorque = (250 + rand()/(RAND_MAX/(3800-250)));
switch (cars[i].engine) {
case hybrid:
cars[i].efficiency_electric = (12 + rand() / (RAND_MAX / (18 - 12)));
cars[i].efficiency_ice = (3.3f + rand() / ((float) RAND_MAX / (8.5f - 3.3f)));
break;
case ICE:
cars[i].efficiency_ice = (3.3f + rand() / ((float) RAND_MAX / (8.5f - 3.3f)));
break;
case electric:
cars[i].efficiency_electric = (12 + rand() / (RAND_MAX / (18 - 12)));
break;
}
}
}
void write_file(int amount, car cars[amount]){
FILE *out = fopen("cars.dat", "wb");
if(!out) {
printf("File does not exist creating file");
return;
}
fwrite(cars, sizeof *cars, amount, out);
fclose(out);
}
void read_file(int amount, car cars[amount]) {
FILE *in = fopen("cars.dat", "rb");
if (!in) {
printf("Can not read file");
return;
}
fread(cars, sizeof *cars, amount, in);
fclose(in);
}
void tabulate_cars(int amount, car cars[amount]) {
printf("Car makes (Quantity): \n");
printf("Tesla BMW Toyota Mercedes-Benz Volkswagen Nissan\n");
int counts[make_count] = { 0 };
for (int j = 0; j<50; j++)
printf("-");
printf("\n");
for(size_t i = 0; i < amount; i++)
counts[cars[i].make]++;
printf("Count bob ");
for(size_t i = 0; i < make_count; i++)
printf("%d%s", counts[i], i + 1 < make_count ? " " : "\n");
}
int main() {
car cars[generationAmount];
srand(mix(clock(), time(NULL), getpid()));
generate_cars(generationAmount, cars);
//print_cars(generationAmount, carsArray);
write_file(generationAmount, cars);
read_file(generationAmount, cars);
print_cars(generationAmount, cars);
tabulate_cars(generationAmount, cars);
}
and the resulting output:
i = 0
engine: 2
make: 6
efficientcy_eletric: 16
maximumTorque: 2850
i = 1
engine: 0
make: 2
efficientcy_eletric: 16
efficientcy_ice: 4.687404
efficientcy_eletric: 16
maximumTorque: 2232
i = 2
engine: 2
make: 3
efficientcy_eletric: 15
maximumTorque: 1824
i = 3
engine: 1
make: 1
efficientcy_ice: 3.948720
maximumTorque: 2400
i = 4
engine: 0
make: 3
efficientcy_eletric: 12
efficientcy_ice: 6.890365
efficientcy_eletric: 12
maximumTorque: 2543
i = 5
engine: 0
make: 0
efficientcy_eletric: 15
efficientcy_ice: 6.773261
efficientcy_eletric: 15
maximumTorque: 2722
i = 6
engine: 2
make: 2
efficientcy_eletric: 17
maximumTorque: 282
i = 7
engine: 2
make: 3
efficientcy_eletric: 14
maximumTorque: 2845
i = 8
engine: 0
make: 4
efficientcy_eletric: 13
efficientcy_ice: 4.352170
efficientcy_eletric: 13
maximumTorque: 261
i = 9
engine: 0
make: 0
efficientcy_eletric: 14
efficientcy_ice: 6.686623
efficientcy_eletric: 14
maximumTorque: 2542
i = 10
engine: 1
make: 3
efficientcy_ice: 7.677234
maximumTorque: 3004
i = 11
engine: 2
make: 2
efficientcy_eletric: 12
maximumTorque: 3486
i = 12
engine: 1
make: 1
efficientcy_ice: 6.545116
maximumTorque: 3264
i = 13
engine: 0
make: 2
efficientcy_eletric: 16
efficientcy_ice: 4.487165
efficientcy_eletric: 16
maximumTorque: 3457
i = 14
engine: 1
make: 4
efficientcy_ice: 3.627770
maximumTorque: 3655
i = 15
engine: 2
make: 2
efficientcy_eletric: 16
maximumTorque: 485
i = 16
engine: 0
make: 1
efficientcy_eletric: 16
efficientcy_ice: 4.707179
efficientcy_eletric: 16
maximumTorque: 1418
i = 17
engine: 0
make: 2
efficientcy_eletric: 16
efficientcy_ice: 4.103405
efficientcy_eletric: 16
maximumTorque: 1081
i = 18
engine: 2
make: 3
efficientcy_eletric: 17
maximumTorque: 485
i = 19
engine: 1
make: 5
efficientcy_ice: 7.746961
maximumTorque: 2728
Car makes (Quantity):
Tesla BMW Toyota Mercedes-Benz Volkswagen Nissan
--------------------------------------------------
Count bob 2 3 6 5 2 1 1
Upvotes: 4