int * - указатель, который может быть разыменован. int ** - указатель на указатель, который может быть разыменован дважды. Так что это значит? Ну, указатель - не более чем целое число. Адреса памяти начинаются с нуля до максимального диапазона. Для 32-разрядных систем диапазон адресуемой памяти составляет от 0 до 2 ^ 32-1 (или 4294967295). Каждый из этих адресов имеет байтовое значение. Если у вас есть int *, то он будет обращаться к адресу 4 байта за раз.
Также, для простоты, давайте предположим, что это виртуальный адрес, вы не можете просто получить доступ ко всей этой памяти, некоторые будут защищены (системные), некоторые недействительны (не зафиксированы). Чтобы получить больше памяти, вы можете попросить систему выделить больше из этого диапазона. sbrk в Linux, VirtualAlloc в Windows, но вы будете обращаться к ним, как правило, через malloc или calloc на C.
Допустим, у вас есть начиная с 0x100:
0x100: «h», «e», «l», «l», «o», «\ 0»
Таким образом, эта строка занимает память от 0x100 до 0x105 (включая нулевой терминатор). Если у вас есть указатель:
char * p = 0x100;
Тогда у вас есть:
p // 0x100
*p // 'h'
p+1 // 0x101
*(p+1) // 'e'
p += 2 // 0x102
*p // 'l'
p = 0x200;
p // now points to 0x200 in memory
*p // contains whatever value is in 0x200
Если у вас есть указатели на int, то вы обращаетесь к памяти по 4 байта за раз (или как бы велико ни было int в вашей системе).
Таким образом, со всем этим фоном, когда вы запускаете calloc, он возвращает адрес запрашиваемого блока.
int *memoryBlock = calloc(count, sizeof(int));
// memoryBlock is an array of int, assuming sizeof(int) == 4, then
// you have 40 bytes of memory starting from the address of what is
// returned by calloc.
memoryBlock++; // now memoryBlock is at base address + 4
*memoryBlock = 10; // now that address contains the value 10
(*memoryBlock)++; // now that address contains the value 11
memoryBlock++; // now memoryBlock is 4 bytes further