Prima alcuni sfondi ...
The macros are NULL which expands to an implementation-defined null pointer constant; C11 §7.19 3
NULL è tipicamente una costante intera 0 o (void*)0 o simile. potrebbe avere un'implementazione o un tipo differente - Potrebbe essere ((int*) 0xDEADBEEF) così strano come potrebbe essere.
NULL potrebbe essere il tipo int . Potrebbe essere di tipo void * o qualcos'altro. Il tipo di NULL non è definito.
Quando la costante del puntatore nullo NULL viene castata su qualsiasi puntatore, è un puntatore nullo . Un intero 0 lanciato su un puntatore è anche un puntatore nullo . Un sistema può avere molti puntatori null (bit-wise) diversi. Sono tutti confronta ugualmente tra loro. Tutti si confrontano in modo ineguale con qualsiasi oggetto / funzione valido. Ricorda che questo confronto è fatto come puntatori, non come numeri interi.
An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function. C11 §6.3.2.3 3
int x;
if (&x == NULL) ... // this is false
Quindi, dopo tutto quel capitolo e verso, come distinguere NULL da 0 ?
Se la macro NULL è definita come int 0 - è game over - non c'è differenza tra 0 e NULL .
Se NULL non è un int , il codice può utilizzare _Generic() per differenziare NULL e 0 . Ciò non aiuta OP "Qualsiasi modifica apportata può essere effettuata solo all'interno della funzione stessa." requisito in quanto tale funzione accetta un int augment.
Se NULL è un int con un modello di bit diverso da 0 , allora un semplice memcmp() può differenziare.
Sospetto che l'intera ragione di questo esercizio sia capire che non esiste un metodo portatile per distinguere NULL da 0 .