There is at least one very good use of goto in C: error handling.
In a function that allocates and initializes complex structures, an earlier allocation can succeed but a later allocation fail. When this happens, the earlier allocation must be released before returning NULL to avoid leaking memory.
something *
alloc_something(void)
{
something * ret = malloc(sizeof(something));
if (ret == NULL) goto out;
ret->another_thing = alloc_another_thing();
if (ret->another_thing == NULL) goto out_free_ret;
return ret;
/* error exits */
out_free_ret:
free(ret);
out:
return NULL;
}
I learned this style from reading Linux kernel sources and it makes error handling much more readable and maintainable by keeping the successful path and the error path separate. While this example was very simple, this pattern especially shines when more than one allocation must be backed out before returning failure because it avoids duplicating the code to release the earlier allocations.