I have a function that reads a csv file and then updates a struct
with it's parameters.
I wanted to be able to cycle through a structs elements, so I turned to macros. The output of parsing the csv files is a 2 dimensional array of strings for rows and columns of the file. To convert the strings to their respective data type (currently the structs only have int
and char*
) I used a conversion macro within the macro used to cycle through the struct.
CVT_INT atoi(str)
CVT_STR str
However, when it comes to freeing the memory allocated by parsing the csv file, it gets tricky if in the file the strings are not grouped together at the start or end.
csv[row][col]
string|string|int|string|int
string|string|int|string|int
...
for(int row = 0; row < number_of_rows; row++)
for(int col = 2; col < number_of_cols; col++)
free(csv[row][col]) // frees string when row[i][3]
I could just make sure all the strings are at the beginning of the structure, but I want it to be dynamic and I don't want to have to think about making sure the data types are grouped.
I could free the allocated strings that were converted by CVT_INT, but freeing the strings used by CVT_STR would result in the struct's strings being freed. I could think of one workaround: 1. Allocate new space 2. Copy in the old string 3. Free the old string.
CVT_STR strcpy((char*)malloc(sizeof(char)*(1+strlen(str))), str)
However, on implementing the above, it leads to a crash whenever it is called, and I don't understand why. Could anyone offer me an explanation and a way to solve it/a different route that does the same job? I'm aware it's not very efficient, so suggestions on improving that aspect are also welcome.
Another possibility, I could free only int
. However, I couldn't work out how to do this in the macro, as it has to return an int.
Below is an example of me calling the cycle-through-struct macro, containing the conversion macro.
#define STRUCT(type, name, converter) \
obj->struct.name = converter(csv[row][col++]);
STRUCT_FIELDS
#undef PLAYER
Thanks for any help
UPDATE:
Replacing
CVT_STR strcpy((char*)malloc(sizeof(char)*(1+strlen(str))), str)
with
CVT_STR strdup(str)
worked, but I don't understand why. Perhaps someone could enlighten me?
strdup()
? – jxhstrdup
does something different fromstrcpy(malloc(strlen(str)+1), str)
- sure, it does some checking if malloc is null, and such, but otherwise it's the same. – Mats Peterssonstrcpy
, but for some reason it works where my code didn't. Maybe the macro didn't like the typecasting ofmalloc
. Inline functions - I am not familiar with them, but I was recommended to use macros to cycle through thestruct
. I am guessing that using the macro to to do this therefore dictates I can't use inline functions? I will look into this however, as the lack of debugging functionality is already frustrating. – Richard#include <stdlib.h>
, so your cast hid the missing prototype. With the missing prototype, and ifint
is smaller than a pointer, youmalloc()
s return value will get truncated, resulting in an invalid pointer. – jxh