Some additional thoughts to @dbush good answer.
Should I execute hello->value = NULL; inside the free_hello in order to reset the hello->value to the default NULL status?
Right after free(hello);, as hello is indeterminant, attempting hello->value is undefined behavior (UB).
Debugging: Yet performing hello->value = NULL; before the free(hello) can improve debugging as it may improve the chance of detecting later invalid use of the pointer that was in hello->value. This generally improves detection yet not a certainly. The assignment hello->value = NULL; before the free(hello) may get optimized out by an intelligent compiler. One might need additional code (e.g. a cast to a volatile data) to prevent such optimization. Code could perform hello->value = NULL; only in debug mode, yet that carries a disadvantage of injecting a small change between the debug compilation and release one yet has consequences.
Security: performing hello->value = NULL; before the free(hello) might improve security by not leaving tell-tale information in the free'd memory. Again, this assignment may get optimized out as discussed above. Note that security of data is a deep subject and zeroing is only a beginner step.
I see usefulness in always performing hello->value = NULL; and little downside. Since it is not obviously needed, a comment should accompany such code to outline why it is there.
C23 offers a clean way to assign data that might otherwise get optimized out. memset_explicit() is self documenting, lessening the the needed for a comment as suggested above. As a standard library function, a good compiler can be expected to emit efficient code - perhaps just a simple assignment.
The purpose of this function is to make sensitive information stored in the object inaccessible C23dr § 7.26.6.2 2
The intention is that the memory store is always performed (i.e. never elided), regardless of optimizations. This is in contrast to calls to the memset function. Footnote 367
memset_explicit(&data, 0, sizeof data);
// or in OP's case: zero entire object that `hello` points to
memset_explicit(hello, 0, sizeof hello[0]);
Should I execute hello = NULL; inside the free_hello() or test_function() after freeing the struct with free()?
Again, this can improve debugging, yet may get optimized out. Likewise, if used, comment such code to explain its apparent unnecessity.
As @wohlstad suggested, a re-write of the function signature is useful to alleviate the calling code's needed to zero the pointer.
hello = NULL;intest_functionhas no effect becausehellois a local. You could changetest_functionto get avoid**(pointer to pointer), so that you'll be able to set the pointer on the caller side to NULL.