In addition to the other reviews, some misc comments:
The switch
RUN_REAL_PROGRAM
is weird, doesn't seem like something that should be part of the final program - remove it.In general, avoid non-standard C if there is no good reason for it. That is, replace for example non-standard
#pragma once
with standard C#ifndef SOMETHING_H #define SOMETHING_H ... #endif
.Don't create some generic header called "defines.h". Instead place those defines in the module where they actually belong.
AVOGADROS_NUMBER
should probably be in material.h (?),INPUT_BUFFER_SIZE
should be in prompt.h and so on.I prefer to place all includes in the .h file rather than the .c file since the former is the interface to the user. The user needs to know all file dependencies of a .h + .c pair and shouldn't need to go digging through the .c file (which might not even be available) to find them.
For very long function declarations/definitions, consider using new line style:
char prompt_quit(const char * msg, char * buffer, size_t num_chars, const char * quit_str);
Avoid "for ever" loops when they aren't called for. Also, the presence of
continue
in a C program is almost always an indication of a poorly designed loop. So instead of the somewhat obscure:while(1) { ... if(conversion_error) { ... continue; } ... return result; }
, write something like this instead:char conversion_error = /* non-zero value */; while(conversion_error) { ... long result = cstr_to_long(buf, &conversion_error); if(conversion_error) { fputs("Invalid input\n\n", stdout); } } *request_quit = 0; return result;} // end of function
If
conversion_error
is only either 1 or 0 then it should bebool
notchar
. Overall, it is common convention to reserve the return type of functions for the error handling, especially when supported more detailed errors (through an enum type etc).Your list of different materials should be implemented as an array of struct instead.
All constants like
36.0
and39
have a type in C, in this casedouble
andint
respectively. Always avoid mixing floating point and fixed point in the same expression, since that's an easy way to get subtle bugs. For example123 / 456 + 789.0
first gets the 123 / 456 calculated onint
then implicitly promoted todouble
afterwards.So for example change
return 0.127 * pow(92, (36.0 - awg) / 39);
toreturn 0.127 * pow(92.0, (36.0 - awg) / 39.0);
Is AWG 0 really a thing?