Разница только в том, что calloc обнуляет выделенную память перед тем, как возвратить указатель, а malloc этого не делает. Внутри calloc, наверняка вызывает malloc для выделения памяти, а потом memset для обнуления. Так что calloc это просто надстройка над malloc для удобства. Вот схематично реализация calloc:
void * calloc (size_t num, size_t size)
{
void * mem = malloc(num * size);
memset(mem, 0, num * size);
return mem;
}
Сами эти функции оперируют исключительно размером выделяемой области в байтах, им все равно что вы в дальнейшем будете делать с выделенной памятью - инты туда писать или "стринги".
Ну и как бы никто не мешает вам одну и ту же область памяти сначала использовать как массив интов, а потом как массив байт. Или так например:
int a = 0x33323130;
char * c = (char*)&a;
printf("%c %c %c %c\n", c[0], c[1], c[2], c[3]);
Пример не использует malloc/calloc для выделения памяти, память выделяется в стеке просто объявлением int a. Тут я попытался показать, что содержимое памяти можно интерпретировать как угодно, главное находится в границах выделенного диапазона.
Причем языки С/С++/asm это позволяют делать, а другие - нет.
Пример предполагает, что int имеет размер 32 бита, не для всех платформ это так, но в основном - именно так.
Кстати этот пример можно использовать для определения порядка байтов платформы: если выведется "1 2 3 4" значит у вас LITTLE ENDIAN, а если "2 1 4 3" - BIG ENDIAN.
PS: free() - это Си, а delete - C++