u = telegram_free_updates(u)
Ese código es extraño y se ve forzado y tienes muy en cuenta la buena voluntad del cliente de tu función, cuándo debería ser al revés y pensar en el peor de los casos.
Si esa persona hace lo siguiente
telegram_free_updates(u)
u seguirá apuntando a algún sitio.
Debería ser la función mismo la que llevara u a NULL.
Tendría que estar definida tal que así
void telegram_free_updates(Updates **updates) {
Updates *u = *updates;
if(u) {
int i;
for(i = 0; i < u->length; ++i)
if(u->list[i])
telegram_free_updates(&u->list[i]);
}
*updates = NULL;
}
Con esto la variable obtendrá el valor NULL.
Una cosa más. Para que esto tenga sentido entiendo que has definido Updates de la siguiente forma
typedef struct updates_t {
/*
* Aquí van definidos
* campos para el uso
* del programa
*/
unsigned length;
struct updates_t **list;
} Updates;
De nuevo el código me parece extraño pues el mismo tipo de datos contiene un array dinámico de sí mismo. De esta manera uno puede meter Updates dentro de Updates dentro de Updates... con lo que se pierde rápidamente el control de lo que ocurre.
Podrías implementar un tipo de dato contenedor de Updates, para que te sirviera de array dinámico, y el tipo Updates por otra parte. Con un struct anónimo tal que así
typedef struct update_t {
/*
* Aquí van definidos
* campos para el uso
* del programa
*/
} Update;
struct {
unsigned length;
Update **list;
} Updates;
Así te aseguras que solo hay un único array de Update en todo el programa.