Your parsing code has problems as well.
For one, you copy and paste code. Don't do that. Write a helper function to "copy from the string up to the next comma". This, in turn, can make use of standard C library functions.
For another, you set the Task object's members to point at the buffers you've malloc()'ed, and then immediately free() them. This is bad. The pointers are now immediately invalid. The whole point of free() is to say "I don't need the pointed-at thing any more". This is clearly not what you intend. That's only appropriate for reading the integer values, where you throw away the string after getting the integer.
/* EDIT: Expecting to be able to modify the input is a needless restriction; thanks to visitor for pointing out the value of avoiding that. *//* EDIT 2: shortened logic, taking full advantage of my clever idea to copy the pointer. ;) */char *next_item(char **begin_ptr) { /* before: *begin_ptr points at a string (possibly in the middle). after: *begin_ptr points just past the next comma, and the return value is a newly allocated string representing everything up to the first comma. Repeatedly calling this, therefore, will extract each comma-delimited item of the string, as *begin is updated to the appropriate place each time. (You could also loop while the pointer is non-NULL.) */ char *result, *begin = *begin_ptr, end; if (!begin) return NULL; /* Find the comma, if any, and update the out-parameter to point past it (or set to NULL if there is no comma). 'begin' is untouched by this */ end = strchr(begin, ','); if (end) { *begin_ptr = end + 1; } else { *begin_ptr = NULL; end = begin + strlen(begin); } /* Copy the appropriate string data and return it. */ result = malloc(end - begin); strncpy(result, begin, end - begin); return result;} int next_item_as_int(char **begin_ptr) { int result; char *result_str = next_item(begin_ptr); if (!result_str) return 0; result = atoi(result_str); free(result_str); return result;}Task *load_task(char *data) { /* BTW, C89 doesn't allow you to declare variables in the middle of a scope (at least if the compiler is strict), although C99 does. */ Task *result = malloc(sizeof(Task)); char *priority_str, *done_str, *next_str; result->task = next_item(&data); result->project = next_item(&data); result->context = next_item(&data); result->priority = next_item_as_int(&data); result->done = next_item_as_int(&data); result->nextAction = next_item_as_int(&data); return result;}
Hopefully this gives you a few good ideas about how to organize code, particularly as concerns memory management. Many of these ideas apply to C++ as well, although in C++ you have a lot of other more powerful tools too.