For example, the following code demonstrates the simplest possible use of the heap:
int main()
{
int *p;
p = (int *)malloc(sizeof(int));
if (p == 0)
{
printf("ERROR: Out of memory\n");
return 1;
}
*p = 5;
printf("%d\n", *p);
free(p);
return 0;
}
The first line in this program calls the malloc function. This function does three things:

The program next checks the pointer p to make sure that the allocation request succeeded with the line if (p == 0) (which could have also been written as if (p == NULL) or even if (!p). If the allocation fails (if p is zero), the program terminates. If the allocation is successful, the program then initializes the block to the value 5, prints out the value, and calls the free function to return the memory to the heap before the program terminates.
There is really no difference between this code and previous code that sets p equal to the address of an existing integer i. The only distinction is that, in the case of the variable i, the memory existed as part of the program's pre-allocated memory space and had the two names: i and *p. In the case of memory allocated from the heap, the block has the single name *p and is allocated during the program's execution. Two common questions:
void main()
{
int *p, *q;
p = (int *)malloc(sizeof(int));
q = p;
*p = 10;
printf("%d\n", *q);
*q = 20;
printf("%d\n", *q);
}
The final output of this code would be 10 from line 4 and 20 from line 6. Here's a diagram:

The following code is slightly different:
void main()
{
int *p, *q;
p = (int *)malloc(sizeof(int));
q = (int *)malloc(sizeof(int));
*p = 10;
*q = 20;
*p = *q;
printf("%d\n", *p);
}
The final output from this code would be 20 from line 6. Here's a diagram:

Notice that the compiler will allow *p = *q, because *p and *q are both integers. This statement says, "Move the integer value pointed to by q into the integer value pointed to by p." The statement moves the values. The compiler will also allow p = q, because p and q are both pointers, and both point to the same type (if s is a pointer to a character, p = s is not allowed because they point to different types). The statement p = q says, "Point p to the same block q points to." In other words, the address pointed to by q is moved into p, so they both point to the same block. This statement moves the addresses.
From all of these examples, you can see that there are four different ways to initialize a pointer. When a pointer is declared, as in int *p, it starts out in the program in an uninitialized state. It may point anywhere, and therefore to dereference it is an error. Initialization of a pointer variable involves pointing it to a known location in memory.
p = 0;
or:
p = NULL;
What this does physically is to place a zero into p. The pointer p's address is zero. This is normally diagrammed as:

if (p == 0)
{
...
}
or:
while (p != 0)
{
...
}
The system also recognizes the zero value, and will generate error messages if you happen to dereference a zero pointer. For example, in the following code:
p = 0;
*p = 5;
The program will normally crash. The pointer p does not point to a block, it points to zero, so a value cannot be assigned to *p. The zero pointer will be used as a flag when we get to linked lists.
The malloc command is used to allocate a block of memory. It is also possible to deallocate a block of memory when it is no longer needed. When a block is deallocated, it can be reused by a subsequent malloc command, which allows the system to recycle memory. The command used to deallocate memory is called free, and it accepts a pointer as its parameter. The free command does two things:
The following example shows how to use the heap. It allocates an integer block, fills it, writes it, and disposes of it:
#include <stdio.h>
int main()
{
int *p;
p = (int *)malloc (sizeof(int));
*p=10;
printf("%d\n",*p);
free(p);
return 0;
}
This code is really useful only for demonstrating the process of allocating, deallocating, and using a block in C. The malloc line allocates a block of memory of the size specified -- in this case, sizeof(int) bytes (4 bytes). The sizeof command in C returns the size, in bytes, of any type. The code could just as easily have said malloc(4), since sizeof(int) equals 4 bytes on most machines. Using sizeof, however, makes the code much more portable and readable.
The malloc function returns a pointer to the allocated block. This pointer is generic. Using the pointer without typecasting generally produces a type warning from the compiler. The (int *) typecast converts the generic pointer returned by malloc into a "pointer to an integer," which is what p expects. The free statement in C returns a block to the heap for reuse.
The second example illustrates the same functions as the previous example, but it uses a structure instead of an integer. In C, the code looks like this:
#include <stdio.h>
struct rec
{
int i;
float f;
char c;
};
int main()
{
struct rec *p;
p=(struct rec *) malloc (sizeof(struct rec));
(*p).i=10;
(*p).f=3.14;
(*p).c='a';
printf("%d %f %c\n",(*p).i,(*p).f,(*p).c);
free(p);
return 0;
}
Note the following line:
(*p).i=10;
Many wonder why the following doesn't work:
*p.i=10;
The answer has to do with the precedence of operators in C. The result of the calculation 5+3*4 is 17, not 32, because the * operator has higher precedence than + in most computer languages. In C, the . operator has higher precedence than *, so parentheses force the proper precedence.
Most people tire of typing (*p).i all the time, so C provides a shorthand notation. The following two statements are exactly equivalent, but the second is easier to type:
(*p).i=10;
p->i=10;
You will see the second more often than the first when reading other people's code.
More Options: