Nel primo caso potresti invocare f2 cosi:

codice:
int x = 1;
f2(x, f1);
Un conto è passare una funzione ad un'altra come parametro (primo codice). Altra è passare il valore di ritorno (secondo codice). Il passare una funzione (B) come parametro ad un'altra funzione (A) ha senso se A conosce solo durante l'esecuzione quale B necessita.

Ad esempio, A potrebbe dover gestire diversi tipi di dato ed a seconda della loro tipologia necessita, al suo interno, l'invocare una funzione specifica per ciascuno di essi (a quel punto gli passi il tipo di dato e la funzione per gestirli).

Funzioni di questo tipo hanno generalmente tutta la signature (o quasi) definita tramite puntatori a void, proprio per indicare la capacità di gestire diverse situazioni.