An array of N pointers to arrays-of-integers of different sizes....
(Note don't cast malloc return value in C - can hide errors - see Do I cast the result of malloc?).
int i = 0;
int *p[N];
size_t sizes[] = { 4, 3, ..., 5 }; // N sizes
for(; i < N; ++i)
{
    p[i] = malloc(sizeof(int) * sizes[i]);
}
Now p is an array of pointers-to-int. p[n] is therefore the nth pointer-to-int in the array. 
int *p[n] would look something like this in memory:
int *p[n]
+-----+
|     | <------- Each element of the array is a pointer-to-an-integer
|     |
+-----+
|     |
|     |
+-----+
.
.
.
+-----+
|     |
|     |
+-----+
When we then do p[n] = malloc(sizeof(int) * sizes[i]), we are saying that the pointer p[n] (remember each element of the array p is a pointer), points to a block of memory the size of sizes[i] integers. So you get something like...
+-----+                                            +------+------+ ... +------+
|p[n] |-------- array element is a pointer to ---> | int1 | int2 |     | intm |
|     |                                            |      |      |     |      |
+-----+                                            +------+------+ ... +------+
.
.
.
+-----+
|     |
|     |
+-----+
So when you write p[n] you are accessing a pointer to the array of ints you malloc()ed...
Later on in your code you must remember to free() the memory allocated :)
for(; i < N; ++i)
{
    free(p[i]);
}
Hope this helps...
EDIT: Didn't read the last bit of your question but wilsonmichaelpatrick has answered it...
EDIT: Note, btw, that I'm not checking malloc() return for NULL and handling the possible error a this is just an example...
If you do not want to declare int *p[N]; on the stack and would prefer the heap, try the following...
int i = 0;
size_t sizes[] = { 4, 3, ..., 5 }; // N sizes
int **p = malloc(sizeof(int *) * N);
for(; i < N; ++i)
{
    p[i] = malloc( sizeof(int) * sizes[i]);
}
...
...
for(; i < N; ++i)
{
    free(p[i]);
}
free(p);
EDIT: Use #include <stdlib.h> for definitions of free() and malloc()