I am having trouble reading in a file into a typedef struct
that includes an enum
. I am a beginner in C, so I don't really know how to read in the file with the enum.
I am able to read the file and print out the contents in simple code, but I need to read the file in and assign each string in the line into the type from the typedef struct.
The input file ooks like this:
random.num year model category
Example:
54 2012 model1 type1
These are the relevant parts of my code:
typedef enum { type1, type2, type3, type4} category;
typedef struct {
int num;
int year;
char make[MAX_MAKE_CHARS];
category category; //enum from above
}item;
//reading in the file I have this:
int create_db(char *f){
char file_contents[100]; // read the file --> ("r") FILE *f = fopen(f, "r");
// check if file can be used
if(f == NULL){
printf("File not found");
exit(1);
}
int i = 0; item item_array[100];
while(fscanf(f, "%d %d %s %s", &item[i].num, &item[i].year, item[i].make, item[i].category) != EOF){
// can't get past the while look where it says "item[i].category
I get the error:
format ‘%s’ expects argument of type ‘char *’, but argument 6 has type ‘category * {aka enum *}’
Since I am completely new to C, I am confused on how to read in the file into a struct. What do I do for the item[i].category
?
Unfortunately an enum is a symbol that is valid only in the code, and there's no way to access this symbol at runtime as a string. Any enum
variable is actually stored as an integer
But there is something you can do:
char *
containing the symbols of the enum as stringsenum
symbol contained in the input file within a temporary stringscanf
In the following example code I omit your while
for clarity (you will be able to add it back according to your requirements not described in the question):
int tmp_num;
int tmp_year;
char tmp_make[100];
char tmp_category_str[10]; // <-- define the size according to the max enum symbol length
if(fscanf(f, "%d %d %99s %9s", &tmp_num, &tmp_year, tmp_make, tmp_category_str) == 4)
{
int tmp_category;
if( ( tmp_category = check_enum( tmp_category_str ) ) != -1 )
{
Item.num = tmp_num;
Item.year = tmp_year;
strcpy( make, tmp_make );
Item.category = ( category )tmp_category; // The numeric value is stored in the struct
}
else
{
printf( "Invalid 'category' value!\n" );
}
}
Note that:
fscanf
to be 4make
size to 100. The purpose is showing in a simple way that the format specifier %s
should contain the limit to arr_size-1
characters, for safetycheck_enum()
will return -1 if a strange string value, not matching any enum symbol, is providedNow, only check_enum()
implementation is missing. Just loop on enumSymbols[]
elements searching for the input string.
char* enumSymbols[] = { "type1", "type2", "type3", "type4" };
int check_enum(char * str)
{
int ret = -1;
if( str )
{
for( int i=0; i<(sizeof(enumSymbols)/sizeof(enumSymbols[0])); i++ )
{
if( strcmp(enumSymbols[i], str) == 0 )
{
ret = i;
break;
}
}
}
return ret;
}
Note: this works but you'll have to keep the array and the enum aligned. In order to prevent human alignment mistakes, a solution like this one can be implemented. In this answer I explain how to create an aligned enum/struct pair, but in the same way and using the preprocessor stringifier operator #
also an aligned enum/string array pair can be generated.