A variable holds a value, and that value is stored somewhere in memory (at an address). A pointer is a variable that holds as a value an address.
One use of *
is in declaring a pointer; in the posted code, int *ptr;
declares a pointer to int
. The expression &x
evaluates to the address of x
, and so ptr = &x;
stores the address of the variable x
in the (pointer) variable ptr
. If you use the variable ptr
alone, as in:
printf("ptr = %p\n", (void *) ptr);
ptr
will evaluate to the value stored in ptr
, which is the address of x
. Note here that the %p
conversion specifier is needed to print a pointer value, and that it must be cast to (void *)
to avoid undefined behavior.
If you want to use the value stored in the variable pointed to by a pointer, you dereference the pointer, using the *
operator. That is, if you want to use ptr
to obtain the value stored in x
, you use *ptr
:
printf("*ptr = x = %d\n", *ptr);
Similarly, if you want to store a value in a variable pointed to by a pointer, you can dereference the pointer:
*ptr = 5;
printf("x is now %d\n", x);
Now note that in your first code snippet, x
is uninitialized (holds an indeterminate value), but x
has been defined, and has an address, so ptr
does hold a determinate value. But in the second code snippet, ptr
is uninitialized, and so holds an indeterminate value. It is undefined behavior to use an indeterminate value, so in this case the line:
*ptr = 5;
causes undefined behavior.
Here is a version of the posted code that avoids undefined behavior:
#include <stdio.h>
int main(void)
{
int x;
int *ptr;
ptr = &x;
printf("ptr = %p\n", (void *) ptr);
x = 1;
printf("*ptr = x = %d\n", *ptr);
*ptr = 5;
printf("x is now %d\n", x);
return 0;
}