A label marks a statement; `goto` transfers execution to that label. In `if (j <= n) goto AGAIN;`, execution returns to `AGAIN` instead of continuing past the `if`. The label is visible throughout its function, but a `goto` cannot jump into another function. section 13.3 section 15.6
One cleanup path
Suppose `realloc` fails while a function is building an output buffer. The failure branch can record an error and `goto CLEANUP;`; the cleanup code then calls `free`. This keeps exceptional exits together without nesting the normal printing path inside further `if-else` statements. section 15.6
Listing 15.2 Printing an array of numbers, optimized version
int fprintnumbers_opt(FILE*restrict stream,
char const form[restrict static 1],
char const sep[restrict static 1],
size_t len, size_t nums[restrict static len]) {
if (!stream) return -EFAULT;
if (len && !nums) return -EFAULT;
if (len > INT_MAX) return -EOVERFLOW;
int err = errno;
size_t const seplen = strlen(sep);
size_t tot = 0;
size_t mtot = len*(seplen+10);
char* buf = malloc(mtot);
if (!buf) return error_cleanup(ENOMEM, err);
for (size_t i = 0; i < len; ++i) {
tot += sprintf(&buf[tot], form, nums[i]);
++i;
if (i >= len) break;
if (tot > mtot-20) {
mtot *= 2;
char* nbuf = realloc(buf, mtot);
if (nbuf) {
buf = nbuf;
} else {
tot = error_cleanup(ENOMEM, err);
goto CLEANUP;
}
}
memcpy(&buf[tot], sep, seplen);
tot += seplen;
if (tot > INT_MAX) {
tot = error_cleanup(EOVERFLOW, err);
goto CLEANUP;
}
}
buf[tot] = 0;
/* print whole line in one go */
if (fputs(buf, stream) == EOF) tot = EOF;
CLEANUP:
free(buf);
return tot;
}
The optimized number-printing function shows a failure branch jumping toward shared cleanup after `realloc` fails. section 15.6
TAKEAWAY — Keep the jump narrow and its effects visible.
- Prefer structured conditionals and loops for ordinary control flow. Reserve `goto` for exceptional changes, particularly local error cleanup. section 19.0 section 19.3
- Do not jump over variable initializations. A label’s function-wide visibility does not make such a jump a good design. section 15.6
- Check local-object lifetime when replacing a loop with a jump: similar-looking repetitions need not leave the same objects alive. section 19.3
A jump is not another loop iteration
A `while` body creates a new local compound-literal instance on each iteration; a pointer to it cannot safely be used after that body ends. In the comparable `RETRY:`/`goto RETRY;` form, the compound literal belongs to the surrounding block and remains alive until that block is left. The longer lifetime can also keep resources occupied unnecessarily. section 19.3
Listing 13.3 A contrived example for the use of a compound literal
void fgoto(unsigned n) {
unsigned j = 0;
unsigned* p = nullptr;
unsigned* q;
AGAIN:
if (p) printf("%u: p and q are %s, *p is %u\n",
j,
(q == p) ? "equal" : "unequal",
*p);
q = p; 1
p = &((unsigned){ j, });
++j;
if (j <= n) goto AGAIN;
}
Following `AGAIN` shows a subtler consequence: a jump can pass over the compound literal’s definition without making the later pointer use invalid. For `fgoto(2)`, the reported pointers are equal on the second printed line, as required by the stated C-standard rule. section 13.3

