Skip to content

Memory and utilities (stdlib.h)

Include stdlib.h. This header covers dynamic memory, string-to-number conversion, integer arithmetic helpers, searching and sorting, process control, and pseudo-random numbers.

Types and Macros

Name Meaning
NULL Null pointer constant.
EXIT_SUCCESS Successful program termination status.
EXIT_FAILURE Unsuccessful program termination status.
RAND_MAX Maximum value returned by rand.
ATEXIT_MAX Maximum number of functions that can be registered with atexit().
div_t Quotient and remainder pair returned by div.
ldiv_t Quotient and remainder pair returned by ldiv.
MB_CUR_MAX Maximum bytes in a multibyte character in the current locale.

Functions

Function Summary
_Noreturn void abort( void ) Terminate the program abnormally; does not call atexit handlers.
int abs(int j) Absolute value of a signed int.
int atexit( void (*func)(void) ) Register func to be called at normal program termination (LIFO order). Returns 0 on success, nonzero if the ATEXIT_MAX table is full.
float atof(const char *nptr) Convert the leading decimal text in nptr to float. Note: C89 atof normally returns double; dcc has no double type, so this returns float (IEEE 754 single precision). Accepts nan, inf, and infinity spellings. Overflow returns signed infinity; underflow returns signed zero.
int atoi(const char *nptr) Convert the leading decimal text in nptr to int.
long atol(const char *nptr) Convert the leading decimal text in nptr to long.
int bdos( int fn, int dearg ) Call the CP/M BDOS entry point.
int bdoshl( int fn, int dearg ) Call the CP/M BDOS entry point, returning the full HL result.
int bios( int fn, int dearg ) Call the CP/M BIOS jump table directly.
int bioshl( int fn, int dearg ) Call the CP/M BIOS jump table directly, returning the full HL result.
const void *bsearch(const void *key, const void *base, size_t num, size_t size, int (*compare)(const void *, const void *)) Binary-search a sorted array.
void *calloc( size_t num, size_t size ) Allocate and zero num * size bytes from the heap.
div_t div(int numer, int denom) Signed int division returning quotient and remainder.
int exec( const char *path, const char *cmdtail ) Load and run path, replacing this process. cmdtail is copied to 0x81 (e.g. " ARG1 ARG2"); the first two whitespace-delimited args also seed the default FCBs at 0x5C and 0x6C. Returns -1 if the file is not found; does not return on success.
int execv( const char *path, char **argv ) Like exec() but builds the command tail from argv[1..] (argv[0] is the conventional program name and is ignored for CP/M purposes). argv must be a NULL-terminated array of string pointers.
_Noreturn void exit( int code ) Terminate the program after flushing runtime output.
void free( void *ptr ) Release a heap allocation.
char *getenv(const char *name) Search the environment for name; always returns NULL on CP/M 2.2.
int inp( unsigned port ) Read an 8-bit Z80 I/O port.
long labs(long j) Absolute value of a signed long.
ldiv_t ldiv(long numer, long denom) Signed long division returning quotient and remainder.
void *malloc( size_t size ) Allocate size bytes from the heap.
int mblen(const char *s, size_t n) Length of the multibyte character at s, examining at most n bytes.
size_t mbstowcs(wchar_t *pwcs, const char *s, size_t n) Convert at most n multibyte characters from s into the wchar_t array pwcs.
int mbtowc(wchar_t *pwc, const char *s, size_t n) Convert the multibyte character at s into *pwc; examine at most n bytes.
void outp( unsigned port, unsigned val ) Write an 8-bit Z80 I/O port.
void qsort(void *base, size_t num, size_t size, int (*compare)(const void *, const void *)) Sort an array in place.
int rand(void) Return the next pseudo-random integer in the range 0 through RAND_MAX.
void *realloc( void *ptr, size_t size ) Resize a heap allocation, preserving contents up to the smaller size.
void srand(unsigned int seed) Seed the pseudo-random number generator.
float strtod(const char *nptr, char **endptr) Convert leading floating-point text in nptr to float; sets *endptr past consumed input. Note: C89 strtod returns double; dcc returns float (no double type).
long strtol(const char *nptr, char **endptr, int base) Convert text in nptr to long using base 2 through 36, or base 0 for auto-detection.
unsigned long strtoul(const char *nptr, char **endptr, int base) Convert text in nptr to unsigned long using base 2 through 36, or base 0 for auto-detection.
int system(const char *string) Execute a shell command; always returns -1 on CP/M 2.2 (no command processor).
size_t wcstombs(char *s, const wchar_t *pwcs, size_t n) Convert at most n wide characters from pwcs into the char array s.
int wctomb(char *s, wchar_t wc) Convert wide character wc into the multibyte sequence at s.

Runtime model

The standard functions in this header are runtime-backed. DCC C Compiler also declares a small set of CP/M and Z80 extensions here (bdos, inp, and outp); those are documented with the CP/M services rather than treated as portable C APIs.

Dynamic memory

The allocator uses a first-fit heap walk with two-byte packed boundary tags at the start and end of each block. Freeing a block coalesces it with adjacent free neighbours (including blocks freed via realloc(p, 0) and the old block released by a growing realloc), which keeps fragmentation down. realloc also grows in place at the heap top or into an immediately following free block. The heap grows on demand between the end of BSS and the stack. On CP/M this space is bounded by the program's TPA: code, data, runtime support, heap, and stack all share the same transient program area.

char *p = malloc(256);
if (!p) { fputs("out of memory\n", stderr); exit(EXIT_FAILURE); }
p = realloc(p, 512);        /* old contents preserved */
free(p);

realloc follows the standard rules: realloc(NULL, n) behaves like malloc(n), and realloc(p, 0) frees p and returns NULL.

Size cost

malloc/calloc link integer multiply/divide/modulo helpers for size arithmetic, and strdup inherits the whole malloc chain. See the appendix.

Conversion

atoi/atol skip leading spaces/tabs, accept an optional +/- sign, then consume decimal digits; conversion stops at the first non-digit. Overflow wraps modulo the type width.

int  n = atoi("  -123xyz");   /* -123  */
long m = atol("  -123456");   /* -123456L */

strtol/strtoul are the full C89 conversions. They skip leading whitespace, accept an optional sign, honour a 0x/0X prefix for base 16 and a leading 0 for base 8 when base is 0, and accept digits/letters up to base-1 for any base from 2 to 36. The unused tail is reported through *end when end is non-NULL. On overflow they clamp to LONG_MAX/LONG_MIN (or ULONG_MAX) and set errno to ERANGE.

char *end;
long  v = strtol("  -0x1Ag", &end, 0);            /* v = -26, *end = 'g'  */
unsigned long u = strtoul("4294967295", NULL, 10); /* ULONG_MAX */

atof is available as a DCC C Compiler extension: it is declared as float atof(const char *nptr) and returns IEEE 754 single precision. C89 atof normally returns double, which DCC C Compiler does not have. It accepts ordinary decimal text with an optional exponent, plus the case-insensitive spellings nan, inf, and infinity. Overflow returns signed infinity; underflow returns signed zero.

Integer arithmetic helpers

div returns a div_t with quot and rem members; ldiv returns an ldiv_t with 32-bit members. Signed division truncates toward zero; the remainder has the same sign as the numerator.

div_t  d  = div(-7, 3);          /* d.quot == -2, d.rem == -1 */
ldiv_t ld = ldiv(200000L, 7L);

Searching and sorting

Both take the standard comparator: cmp(a, b) returns negative if a sorts before b, zero if equal, positive if after. qsort uses an in-place, non-recursive Shell sort, so it is not stable; bsearch requires the array to be sorted by the same comparator. See Worked examples for complete programs.

Process control

The exit code is surfaced through CP/M 3.0 BDOS call 108, which emulators such as ntvcm reflect in their own process exit code. Returning a value from main has the same effect.

Pseudo-random numbers

RAND_MAX is 32767.

srand(1);
int roll = rand() % 6 + 1;     /* a die roll */

The runtime generator is a 16-bit xorshift with parameters 7, 9, and 8. The state is 16-bit, srand(seed) stores the state directly, and rand() clears bit 15 of the updated state so the result stays in the C89 0 .. RAND_MAX range. In C-equivalent form:

static unsigned int s_rnd = 1;

void srand(unsigned int seed)
{
    s_rnd = seed;
}

int rand(void)
{
    s_rnd ^= s_rnd << 7;
    s_rnd ^= s_rnd >> 9;
    s_rnd ^= s_rnd << 8;
    return (int)(s_rnd & 0x7fff);
}

That deterministic sequence is useful for benchmarks: if another CP/M compiler uses the same C equivalent, tests that depend on rand() can compare runtime library and code-generation performance without being skewed by different pseudo-random sequences.