Search code examples
cmalloccalloc

Why does calloc always returns NULL when I pass a "big" size?


This is my code (it is and must be pure C):

unsigned long buffSize = 65536; /* 64 KB */
char *block;

block = calloc(1, buffSize);
if (block == NULL)
{
    /* This is always triggered */
}

I want a 64 KB of zeroed memory that I will use in a loop somewhere else in my application.

Unfortunatly calloc always return NULL. When I use it with 64 (bytes) it works.

I'm not sure how to allocate "bigger" memory blocks like in my example?

Edit: After reading comments, here are some clarifications:

  1. malloc and memset have the same behavior with the same buffSize.
  2. sizeof(size_t) == 2 while sizeof(unsigned long) == 4 so it's 16-bit.
  3. The target platform is MS-DOS 6.22.

So under a 16 bits system how can you create a char * of 64 KB zero-filled?


Solution

  • You've said that sizeof (size_t) == 2 (this is for MS-DOS 6.22).

    That means that the maximum value of size_t is 65535.

    unsigned long buffSize = 65536; /* 64 KB */
    

    No problem so far. unsigned long must be at least 32 bits (and is 32 bits on your system), so it can easily hold the value 65536.

    char *block;
    
    block = calloc(1, buffSize);
    

    Both arguments to calloc are of type size_t. Any argument that's not of type size_t is implicitly converted. Converting 65536 to size_t yields 0. So you're requesting an allocation of 0 bytes. The behavior of such an allocation is implementation-defined; it can return a null pointer, or it can return a unique non-null pointer, similar to malloc(1) except that you can't necessarily dereference it. Your implementation apparently does the former.

    calloc takes two arguments, both of type size_t. Their values are not simply multiplied to yield a result of type size_t. Instead, calloc must either successfully allocate the number of bytes specified or fail to do so and return a null pointer.

    In principle, you can write:

    block = calloc(64, 1024);
    

    or something similar. If it succeeds, it will allocate a 65536-byte object.

    But since size_t is only 16 bits, that almost certainly means that the implementation cannot create objects bigger than at most 65535 bytes. There's no actual prohibition against creating objects bigger than SIZE_MAX bytes, but any implementation that's able to do so would almost certainly make its size_t bigger, so that it can represent the size of any object.

    (SIZE_MAX is the maximum value of the type size_t. It's a macro defined in <stdint.h>, which was introduced by the C99 standard. Your implementation probably doesn't support <stdint.h>. The expression ((size_t)-1) is equivalent.)

    You're probably out of luck, unless you use a different implementation (which might mean using the same compiler with different options).

    Perhaps you can redesign your program so it can use, for example, two 32768-byte objects rather than a single 65536-byte object (though that might not be supported either).

    MS-DOS systems support (supported?) multiple memory models, some of which might permit you to do what you want. I don't know the details. Consult your compiler's documentation for more information.