Joseph's answer explains why this program fails on your particular setup (32bit vs. 64bit). I'll try to give an answer that is based only on the C standard (C99 mostly) and platform-independent.
The problem: Your program has undefined behaviour because it violates the C standard.
Specifically, the problem is the combination of these lines:
uint32_t* address1 = NULL; // 1
uint32_t value2 = (uint32_t)address1; // 2
address2 = (uint32_t*)value2; // 3
In line 2, you are casting a "pointer to uint32_t" (uint32_t*) to a uint32_t. That by itself is ok - you will get a numeric representation of the pointer, possibly truncated to fit into unit32_t.
However, in line 3 you then proceed to cast value2 back to uint32_t*, and dereference it. This is the undefined behavior, because (according to the C standard) there is no guarantee that the resulting address2 is a valid pointer.
You may in principle cast a valid pointer to an integral type and back, and get the same (valid) pointer back. However, this only works if the integral type you use is sufficiently large for a pointer - to ensure this, you need to use uintptr_t, which is meant specifically for this purpose. If your platform does not have uintptr_t (only introduced in C99), you will need a platform-specific type.
See e.g. When is casting between pointer types not undefined behavior in C? for more details, both on casting between pointer types and between integers and pointers.
As to how to avoid these problems: There is no general solution, but modern compilers will try to warn you in many cases. For example, on my system (64bit, GCC 7.5.0), gcc (even without any warning options) will warn about the problematic pointer cast in line 3 above:
st.c: In function ‘main’:
tst.c:13:23: warning: cast from pointer to integer of different size
[-Wpointer-to-int-cast]
uint32_t value2 = (uint32_t)address1;
^
It will also warn about the second cast:
tst.c:16:16: warning: cast to pointer from integer of different size
[-Wint-to-pointer-cast]
address2 = (uint32_t*)value2;
^
And finally, it will even notice the wrong printf format string mentioned in Joseph's answer:
tst.c:17:24: warning: format ‘%x’ expects argument of type ‘unsigned int’,
but argument 2 has type ‘uint32_t * {aka unsigned int *}’ [-Wformat=]
printf("address2: %x\n", address2);
~^
%ls
Lesson: Always compile with -Wall -Wextra (or whatever switches on warning in your compiler), and heed the warnings.