I have the following C pseudo code:
int main()
{
int rc = 0;
for (int i = 1; i < 10; i++) {
char *data = malloc(i); // Each iteration has a different alloc size
rc = do_something(data);
if (rc != 0) goto cleanup;
rc = do_something_else();
if (rc != 0) goto cleanup;
cleanup:
free(data);
if (rc != 0) break;
}
return rc;
}
I want to emulate Python's try...finally
pattern by breaking out of a loop if a called function returns an error, but only after doing some necessary cleanup work.
So far the code looks OK to me but I'm new to C. Is there a different pattern that avoids the repeated rc != 0
test after free
? (I am aware that some people consider goto
unconditionally wrong but I see it as the cleanest solution I found for this case.)
In the specific code/case you have shown, you can remove the need for any sort of per-loop clean-up by using the realloc
function instead of malloc
. This will simply replace the memory allocated on the previous loop (if there is one) with a new block (of different size). You can then simply defer any clean-up (i.e. calling free
) to outside the loop.
You can still use the break
statements to exit the loop whenever an error occurs; or, as mentioned in the comments, you could add an rc != 0
test to the loop's condition.
Here's some C code that will do as I have indicated (but, of course, you will need actual definitions of the two called fucntions for it to work):
#include <stdlib.h>
int do_something(char* data);
int do_something_else(void);
int main()
{
int rc = 0;
char* data = NULL;
for (size_t i = 1; i < 10; i++) {
char* temp = realloc(data, i); // If "data" is NULL (1st loop) -> same as malloc
if (temp == NULL) { // Allocation failure...
// Error message
break;
}
data = temp; // Succesfull allocation, so update "data" pointer
rc = do_something(data);
if (rc != 0) break;
rc = do_something_else();
}
free(data); // We now only have to do the cleanup once (calling with NULL is allowed).
return rc;
}
Feel free to ask for further clarification and/or explanation.