Page 189
The standard library function calloc(n,size)
returns a pointer to n
objects of
size size
, with the storage initialized to zero. Write calloc
, by calling
malloc
or by modifying it.
/* I found this SO answer very helpful in understanding some of the routines presented:
* https://stackoverflow.com/questions/13159564/explain-this-implementation-of-malloc-from-the-kr-book/36512105#36512105 */
#include <unistd.h>
typedef long Align;
union header {
struct {
union header *ptr;
unsigned size;
} s;
Align _;
};
typedef union header Header;
static Header base;
static Header *freep = NULL;
static Header *knrmorecore(unsigned nu);
void *knrmalloc(unsigned nbytes)
{
Header *currp, *prevp;
Header *morecore(unsigned);
unsigned nunits;
nunits = (nbytes + sizeof(Header) - 1) / sizeof(Header) + 1;
if ((prevp = freep) == NULL) {
base.s.ptr = freep = prevp = &base;
base.s.size = 0;
}
for (currp = prevp->s.ptr;; prevp = currp, currp = currp->s.ptr) {
if (currp->s.size >= nunits) {
if (currp->s.size == nunits) {
prevp->s.ptr = currp->s.ptr;
} else { /* allocate tail end */
currp->s.size -= nunits;
currp += currp->s.size;
currp->s.size = nunits;
}
freep = prevp;
return (void *)(currp + 1);
}
if (currp == freep) {
if ((currp = knrmorecore(nunits)) == NULL) {
return NULL;
}
}
}
}
#define NALLOC 1024
void knrfree(void *ap);
static Header *knrmorecore(unsigned nu)
{
char *cp;
Header *up;
if (nu < NALLOC) {
nu = NALLOC;
}
cp = sbrk(nu * sizeof(Header));
if (cp == (char *)-1) {
return NULL;
}
up = (Header *)cp;
up->s.size = nu;
knrfree((void *)(up + 1));
return freep;
}
void knrfree(void *ap)
{
Header *insertp, *currp;
insertp = (Header *)ap - 1;
for (currp = freep; !(insertp > currp && insertp < currp->s.ptr);
currp = currp->s.ptr) {
if (currp >= currp->s.ptr &&
(insertp > currp || insertp < currp->s.ptr)) {
break;
}
}
if (insertp + insertp->s.size == currp->s.ptr) { /* join to upper nbr */
insertp->s.size += currp->s.ptr->s.size;
insertp->s.ptr = currp->s.ptr->s.ptr;
} else {
insertp->s.ptr = currp->s.ptr;
}
if (currp + currp->s.size == insertp) {
currp->s.size += insertp->s.size;
currp->s.ptr = insertp->s.ptr;
} else {
currp->s.ptr = insertp;
}
freep = currp;
}
#include <string.h>
void *mycalloc(int n, size_t size)
{
void *res = knrmalloc(n * size);
if (res != NULL) {
memset(res, 0, n * size);
}
return res;
}
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *str = (char *)knrmalloc(100 * sizeof(char));
if (str == NULL) {
puts("error: knrmalloc failed");
exit(1);
}
strcpy(str, "hello, world!");
puts(str);
str = (char *)mycalloc(100, sizeof(char));
if (str == NULL) {
puts("error: mycalloc failed");
exit(1);
}
strcpy(str, "hello, world!");
puts(str);
}