p - указатель (на блок, динамически выделяемый в памяти ["в куче"])
Это означает, что p является переменной, которая содержит адрес в памяти определенного блока (или некоторого определенного размера, в примере блока, достаточно большого, чтобы содержать 10 целых чисел).
free(p);
указывает логике управления памятью (среды выполнения C), что память, ранее занятая блоком, на который указывает p, может быть повторно использована.
p = NULL;
устанавливает значение p в NULL (адрес, который он ранее содержал, потеряно), но блок в памяти, на который он также указывал, все еще считается используемым.
Может возникнуть некоторая путаница, потому что в таких языках, как Java, C #, Python и т. Д. Простое присвоение переменной NULL (или другому адресу в этом отношении) автоматически освободит основную память (при условии отсутствия других ссылок на этот адрес). существуют в других живых переменных).
Это не относится к C или C ++, что приводит к ошибкам, подобным следующему:
free(p);
// possibly some some code etc.
// later:
p[6] = 'a'; // <<--- Ouch we're modifying whatever new variable is there !!!
или
// didn't call free(p)
p = NULL;
// now the memory allocated for p is held in memory even though it
// is not going to be used (assuming no copies of p or of pointers to part
// of that block were made.
В последнем случае расходуются только ресурсы, первый может привести к трудностям поиска ошибок.
Вот почему типичная идиома C :
free(p);
p = NULL;