calloc() gives you a zero-initialized buffer, while
malloc() leaves the memory uninitialized.
For large allocations, most
calloc implementations under mainstream OSes will get known-zeroed pages from the OS (e.g. via POSIX
mmap(MAP_ANONYMOUS) or Windows
VirtualAlloc) so it doesn’t need to write them in user-space. This is how normal
malloc gets more pages from the OS as well;
calloc just takes advantage of the OS’s guarantee.
calloc memory can still be “clean” and lazily-allocated, and copy-on-write mapped to a system-wide shared physical page of zeros. (Assuming a system with virtual memory.) The effects are visible with performance experiments on Linux, for example.
Some compilers even can optimize malloc + memset(0) into calloc for you, but it’s best to just use calloc in the source if you want zeroed memory. (Or if you were trying to pre-fault it to avoid page faults later, that optimization will defeat your attempt.)
If you aren’t going to ever read memory before writing it, use
malloc so it can (potentially) give you dirty memory from its internal free list instead of getting new pages from the OS. (Or instead of zeroing a block of memory on the free list for a small allocation).
Embedded implementations of
calloc may leave it up to
calloc itself to zero memory if there’s no OS, or it’s not a fancy multi-user OS that zeros pages to stop information leaks between processes.
On embedded Linux, malloc could
mmap(MAP_UNINITIALIZED|MAP_ANONYMOUS), which is only enabled for some embedded kernels because it’s insecure on a multi-user system.