sscanf
/* Function: read_line* --------------------* Reads one line from file and stores in buf. Skips lines that are all-white or beginning with* comment char #. Increments pass-by-ref counter of number of lines read/skipped. Removes* trailing newline. Returns true if did read valid line, false otherwise.*/static bool read_line(char buf[], size_t bufsz, FILE *fp, int *pnread){while (true) {if (fgets(buf, bufsz, fp) == NULL) return false;(*pnread)++;if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] ='\0'; // remove trailing newlinechar ch;if (sscanf(buf, " %c", &ch) == 1 && ch != '#') // scan first non-white char, check not #return true;}}

The scanf() function reads input from the standard input stream stdin, fscanf() reads input from the stream pointer stream, and sscanf() reads its input from the character string pointed to by str.
1) Code study: test harness
// struct for a single allocator requesttypedef struct {enum {ALLOC=1, FREE, REALLOC} op; // type of requestint id; // id for free() to use latersize_t size; // num bytes for alloc/realloc requestint lineno; // which line in file} request_t;// struct for facts about a single malloc'ed nodetypedef struct {void *ptr;size_t size;} block_t;// struct for info for one script filetypedef struct {char name[128]; // short name of scriptrequest_t *ops; // array of requests read from scriptint num_ops; // number of requestsint num_ids; // number of distinct block idsblock_t *blocks; // array of blocks returned by malloc when executingsize_t peak, lifetime, segment_size;} script_t;
/* Function: eval_correctness* --------------------------* Check the allocator for correctness on given script. Interprets the earlier parsed* script operation-by-operation and reports if it detects any "obvious"* errors (returning blocks outside the heap, unaligned, overlapping blocks, etc.)*/static bool eval_correctness(script_t *script){init_heap_segment(script->segment_size);if (!myinit(heap_segment_start(), heap_segment_size())) {allocator_error(script, 0, "myinit() returned false");return false;}if (!validate_heap()) { // check heap consistency after initallocator_error(script, 0, "validate_heap() returned false, called after myinit");return false;}memset(script->blocks, 0, script->num_ids*sizeof(script->blocks[0]));for (int req = 0; req < script->num_ops; req++) {int id = script->ops[req].id;size_t requested_size = script->ops[req].size;size_t old_size = script->blocks[id].size;void *p, *newp, *oldp = script->blocks[id].ptr;switch (script->ops[req].op) {case ALLOC:if ((p = mymalloc(requested_size)) == NULL && requested_size != 0) {allocator_error(script, script->ops[req].lineno, "heap exhausted, malloc returned NULL");return false;}// Test new block for correctness: must be properly aligned// and must not overlap any currently allocated block.if (!verify_block(p, requested_size, script, script->ops[req].lineno))return false;// Fill new block with the low-order byte of new id// can be used later to verify data copied when realloc'ingmemset(p, id & 0xFF, requested_size);script->blocks[id] = (block_t){.ptr = p, .size = requested_size};break;case REALLOC:if (!verify_payload(oldp, old_size, id, script, script->ops[req].lineno, "realloc-ing"))return false;if ((newp = myrealloc(oldp, requested_size)) == NULL && requested_size != 0) {allocator_error(script, script->ops[req].lineno, "heap exhausted, realloc returned NULL");return false;}old_size = script->blocks[id].size;script->blocks[id].size = 0;if (!verify_block(newp, requested_size, script, script->ops[req].lineno))return false;// Verify new block contains the data from the old blockfor (size_t j = 0; j < (old_size < requested_size ? old_size : requested_size); j++) {if (*((unsigned char *)newp + j) != (id & 0xFF)) {allocator_error(script, script->ops[req].lineno, "realloc did not preserve the data from old block");return false;}}// Fill new block with the low-order byte of new idmemset(newp, id & 0xFF, requested_size);script->blocks[id] = (block_t){.ptr = newp, .size = requested_size};break;case FREE:old_size = script->blocks[id].size;p = script->blocks[id].ptr;// verify payload intact before freeif (!verify_payload(p, old_size, id, script, script->ops[req].lineno, "freeing"))return false;script->blocks[id] = (block_t){.ptr = NULL, .size = 0};myfree(p);break;}if (!validate_heap()) { // check heap consistency after each requestallocator_error(script, script->ops[req].lineno, "validate_heap() returned false, called in-between requests");return false; // stop at first sign of error}}// verify payload is still intact for any block still allocatedfor (int id = 0; id < script->num_ids; id++)if (!verify_payload(script->blocks[id].ptr, script->blocks[id].size, id, script, -1, "at exit"))return false;return true;}
fprintf
C 库函数 int fprintf(FILE stream, const char format, …) 发送格式化输出到流 stream 中。
memset
2) Code study: bump allocator
/** File: bump.c* ------------* A very simple "bump" allocator.* An allocation request is serviced by tacking on the requested* space to the end of the heap thus far.* Free is a no-op: blocks are never coalesced or reused.* Realloc is implemented using malloc/memcpy/free. Operations* are fast, but utilization is terrible.** Shows the very simplest of approaches; there are better options!*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include "allocator.h"#define ALIGNMENT 8static void *next_avail, *heap_max;// Efficient bitwise round up to nearest multiple (you saw this code in lab1)// NOTE: mult has to be power of 2 for the bitwise trick to work!size_t roundup(size_t sz, size_t mult){return (sz + mult-1) & ~(mult-1);}// initialize global variables based on segment boundariesbool myinit(void *segment_start, size_t segment_size){next_avail = segment_start;heap_max = (char *)segment_start + segment_size;return true;}// place block at end of heap// no search means fast but no recycle makes for terrible utilizationvoid *mymalloc(size_t requestedsz){size_t needed = roundup(requestedsz, ALIGNMENT);if ((char *)next_avail + needed > (char *)heap_max)return NULL;void *alloc = next_avail;next_avail = (char *)next_avail + needed;return alloc;}// free does nothing. fast!... but lame :(void myfree(void *ptr){}// realloc built on malloc/memcpy/free is easy to write but not particularly efficientvoid *myrealloc(void *oldptr, size_t newsz){void *newptr = mymalloc(newsz);if (!newptr) return NULL;memcpy(newptr, oldptr, newsz);myfree(oldptr);return newptr;}// debugging routine to detect/report inconsistencies in heap data structuresbool validate_heap(){if (next_avail > heap_max) {printf("Oops! Next available spot is beyond heap end!!\n");return false;}return true;}
3) Implement implicit free list
#include "allocator.h"#include <stdint.h>#include <stdlib.h>#include <string.h>#include <stdio.h>#define ALIGNMENT 8#define SIZE_T 8#define MINBLK 24#define MINBLK_NOHEADFOOT 8#define HEADFOOT_NOCONTENT 16#define ONE 0x0000000000000001#define MULT8 0xFFFFFFFFFFFFFFF8#define NOT_ONE 0xFFFFFFFFFFFFFFFE//min acceptable ptr: seg min rounded upstatic char *heap_min;//max acceptable ptr: (seg min + seg sz) rounded down - min blk szstatic char *heap_max;/*assumptions- when given a block pointer char*ptr, it's ok to access its header and footer*/size_t rounddown(size_t, size_t);inline size_t rounddown(size_t sz, size_t mult){return ~(mult-1) & sz;}size_t roundup(size_t, size_t);inline size_t roundup(size_t sz, size_t mult){return (sz + mult-1) & ~(mult-1);}char *getsizeptr1(char *);inline char *getsizeptr1(char *ptr){return ptr;}size_t ptr2size(char *);inline size_t ptr2size(char *ptr){return *(size_t*)ptr & MULT8;}size_t getsize(char *);inline size_t getsize(char *ptr){return ptr2size(getsizeptr1(ptr));}char *getsizeptr2(char *);inline char *getsizeptr2(char *ptr){ptr += getsize(ptr) - SIZE_T;return ptr;}void setsize_setfree(char *, size_t);inline void setsize_setfree(char *ptr, size_t sz){*(size_t*)ptr = sz;ptr += sz - SIZE_T;*(size_t*)ptr = sz;}void setsize_setalloc(char *, size_t);inline void setsize_setalloc(char *ptr, size_t sz){*(size_t*)ptr = sz | ONE;ptr += sz - SIZE_T;*(size_t*)ptr = sz | ONE;}bool isalloc(char *);inline bool isalloc(char *ptr){return *getsizeptr1(ptr) & 0x01;}bool setalloc(char *);inline bool setalloc(char *ptr){char *sizeptr1 = getsizeptr1(ptr);char *sizeptr2 = getsizeptr2(ptr);bool orig = *sizeptr1 & 0x01;*sizeptr1 = *sizeptr1 | 0x01;*sizeptr2 = *sizeptr1;return orig;}bool setfree(char *);inline bool setfree(char *ptr){char *sizeptr1 = getsizeptr1(ptr);char *sizeptr2 = getsizeptr2(ptr);bool orig = *sizeptr1 & 0x01;*sizeptr1 = *sizeptr1 & 0xFE;*sizeptr2 = *sizeptr1;return orig;}//sz must be getsize(ptr)char *upstairs2(char *, size_t);inline char *upstairs2(char *ptr, size_t sz){ptr += sz;if (ptr > heap_max)return NULL;return ptr;}char *upstairs1(char *);inline char *upstairs1(char *ptr){return upstairs2(ptr, getsize(ptr));}char *downstairs(char *);inline char *downstairs(char *ptr){if (ptr < heap_min + MINBLK)return NULL;return ptr - ptr2size(ptr - SIZE_T);}//how about a while loop//sz must be &(getsize(ptr))void check_up(char *, size_t *);inline void check_up(char *ptr, size_t *sz){ptr = upstairs2(ptr, *sz);if (ptr != NULL && !isalloc(ptr)){*sz += getsize(ptr);}}void check_down(char **, size_t *);inline void check_down(char **ptr, size_t *sz){char *down = downstairs(*ptr);if (down != NULL && !isalloc(down)){*sz += getsize(down);*ptr = down;}}//given ptr and sz of a blk, initialize blk to free//attach blk to front of free listvoid initutil(char *, size_t);inline void initutil(char *ptr, size_t sz){check_up(ptr, &sz);check_down(&ptr, &sz);setsize_setfree(ptr, sz);}//input requested size//output aligned block sizesize_t pumpsz(size_t);inline size_t pumpsz(size_t sz){if (sz <= MINBLK_NOHEADFOOT)return MINBLK;sz = roundup(sz, ALIGNMENT);return sz + HEADFOOT_NOCONTENT;}////////////////////////////////////////bool myinit(void *, size_t);inline bool myinit(void *reqstart, size_t reqsz){if (reqstart == NULL)return false;char *reqend = (char *)reqstart + reqsz;// are these aligned already?char *start = (char*)roundup((size_t)reqstart, ALIGNMENT);char *end = (char*)rounddown((size_t)reqend, ALIGNMENT);size_t sz = end - start;heap_min = (char*)start;heap_max = (char*)start + sz - MINBLK;initutil(start, sz);return true;}void *mymalloc(size_t sz){sz = pumpsz(sz);char *ptr = heap_min;//first fitwhile (ptr <= heap_max){if (isalloc(ptr)){ptr = upstairs1(ptr);continue;}size_t blocksz = getsize(ptr);//has needed space + min free block in bytes. splitif (blocksz >= sz + MINBLK){setsize_setalloc(ptr, sz);initutil(ptr + sz, blocksz - sz);return ptr + SIZE_T;//internal -> client ptr}//not enough to split. allocate wholeif (blocksz >= sz){setalloc(ptr);return ptr + SIZE_T;}ptr = upstairs2(ptr, blocksz);}return NULL;}void myfree(void *);inline void myfree(void *ptrv){char *ptr = (char *)ptrv - SIZE_T;//client -> internal ptrif (ptr < heap_min ||ptr > heap_max ||!isalloc(ptr)){//printf("\ninvalid free\nheap_min %lx\nheap_max %lx\nptr %lx\n",// (size_t)heap_min, (size_t)heap_max, (size_t)ptr);//exit(1346347);}else{initutil(ptr, getsize(ptr));}}void *myrealloc(void *oldptrv, size_t newsz){char *oldptr = (char *)oldptrv - SIZE_T;//client -> internal ptrnewsz = pumpsz(newsz);size_t oldsz = getsize(oldptr);if (oldsz >= newsz + MINBLK){setsize_setalloc(oldptr, newsz);initutil(oldptr + newsz, oldsz - newsz);return oldptrv;//client ptr}if (oldsz >= newsz)return oldptrv;//client ptrchar *up = upstairs2(oldptr, oldsz);char *down = downstairs(oldptr);size_t szup = (up != NULL && !isalloc(up))?getsize(up):0;size_t szdown = (down != NULL && !isalloc(down))?getsize(down):0;if (oldsz + szup >= newsz + MINBLK){setsize_setalloc(oldptr, newsz);initutil(oldptr + newsz, oldsz + szup - newsz);return oldptr + SIZE_T;//internal -> client ptr}if (oldsz + szup >= newsz){setsize_setalloc(oldptr, oldsz + szup);return oldptr + SIZE_T;//internal -> client ptr}if (oldsz + szdown >= newsz + MINBLK){char *newptr = oldptr + oldsz - newsz;memmove(newptr, oldptr, oldsz);setsize_setalloc(newptr, newsz);initutil(down, oldsz + szdown - newsz);return newptr + SIZE_T;//internal -> client ptr}if (oldsz + szdown >= newsz){memmove(down, oldptr, oldsz);setsize_setalloc(down, oldsz + szdown);return down + SIZE_T;//internal -> client ptr}if (oldsz + szdown + szup >= newsz + MINBLK){char *newptr = oldptr + oldsz + szup - newsz;memmove(newptr, oldptr, oldsz);setsize_setalloc(newptr, newsz);initutil(down, oldsz + szup + szdown - newsz);return newptr + SIZE_T;//internal -> client ptr}if (oldsz + szdown + szup >= newsz){memmove(down, oldptr, oldsz);setsize_setalloc(down, oldsz + szdown + szup);return down + SIZE_T;//internal -> client ptr}char *ptr = heap_min;while (ptr <= heap_max){if (isalloc(ptr)){ptr = upstairs1(ptr);continue;}size_t ptrsz = getsize(ptr);if (ptrsz >= newsz + MINBLK){memcpy(ptr, oldptr, oldsz);//what if newsz real small? no way. newsz > oldsz heresetsize_setalloc(ptr, newsz);initutil(ptr + newsz, ptrsz - newsz);initutil(oldptr, oldsz);return ptr + SIZE_T;//internal -> client ptr}if (ptrsz >= newsz){memcpy(ptr, oldptr, oldsz);setsize_setalloc(ptr, ptrsz);initutil(oldptr, oldsz);return ptr + SIZE_T;//internal -> client ptr}ptr = upstairs2(ptr, ptrsz);}return NULL;}bool validate_heap(){return true;}
4) Implement explicit free list
#include "allocator.h"#include <stdint.h>#include <stdlib.h>#include <string.h>#include <stdio.h>#define ALIGNMENT 8#define SIZE_T 8#define MINBLK 32#define PTRSZ 16#define HEADFOOT_NOPTR 16#define ONE 0x0000000000000001#define MULT8 0xFFFFFFFFFFFFFFF8#define NOT_ONE 0xFFFFFFFFFFFFFFFE//head of free liststatic char *head;//min acceptable ptr: seg min rounded upstatic char *heap_min;//max acceptable ptr: (seg min + seg sz) rounded down - min blk szstatic char *heap_max;/*assumptions- when given a block pointer char*ptr, it's ok to access its header and footer*/size_t rounddown(size_t, size_t);inline size_t rounddown(size_t sz, size_t mult){return ~(mult-1) & sz;}size_t roundup(size_t, size_t);inline size_t roundup(size_t sz, size_t mult){return (sz + mult-1) & ~(mult-1);}char *getsizeptr1(char *);inline char *getsizeptr1(char *ptr){return ptr;}size_t ptr2size(char *);inline size_t ptr2size(char *ptr){return *(size_t*)ptr & MULT8;}size_t getsize(char *);inline size_t getsize(char *ptr){return ptr2size(getsizeptr1(ptr));}char *getsizeptr2(char *);inline char *getsizeptr2(char *ptr){ptr += getsize(ptr) - SIZE_T;return ptr;}void setsize_setfree(char *, size_t);inline void setsize_setfree(char *ptr, size_t sz){*(size_t*)ptr = sz;ptr += sz - SIZE_T;*(size_t*)ptr = sz;}void setsize_setalloc(char *, size_t);inline void setsize_setalloc(char *ptr, size_t sz){*(size_t*)ptr = sz | ONE;ptr += sz - SIZE_T;*(size_t*)ptr = sz | ONE;}bool isalloc(char *);inline bool isalloc(char *ptr){return *getsizeptr1(ptr) & 0x01;}bool setalloc(char *);inline bool setalloc(char *ptr){char *sizeptr1 = getsizeptr1(ptr);char *sizeptr2 = getsizeptr2(ptr);bool orig = *sizeptr1 & 0x01;*sizeptr1 = *sizeptr1 | 0x01;*sizeptr2 = *sizeptr1;return orig;}bool setfree(char *);inline bool setfree(char *ptr){char *sizeptr1 = getsizeptr1(ptr);char *sizeptr2 = getsizeptr2(ptr);bool orig = *sizeptr1 & 0x01;*sizeptr1 = *sizeptr1 & 0xFE;*sizeptr2 = *sizeptr1;return orig;}char *getprevptr(char *ptr);inline char *getprevptr(char *ptr){return (char *)*(size_t*)(ptr + SIZE_T);}void setprevptr(char *, char *);inline void setprevptr(char *ptr, char *prev){ptr += SIZE_T;*(size_t*)ptr = (size_t)prev;}char *getnextptr(char *ptr);inline char *getnextptr(char *ptr){return (char *)*(size_t*)(ptr + 2*SIZE_T);;}void setnextptr(char *, char *);inline void setnextptr(char *ptr, char *next){ptr += 2*SIZE_T;*(size_t*)ptr = (size_t)next;}//given ptr of a free blk, remove blk from free listvoid bypasslist(char *);inline void bypasslist(char *ptr){char *prev = getprevptr(ptr);char *next = getnextptr(ptr);if (prev != NULL)setnextptr(prev, next);if (next != NULL)setprevptr(next, prev);if (head == ptr)head = next;}//sz must be getsize(ptr)char *upstairs2(char *, size_t);inline char *upstairs2(char *ptr, size_t sz){ptr += sz;if (ptr > heap_max)return NULL;return ptr;}char *upstairs1(char *);inline char *upstairs1(char *ptr){return upstairs2(ptr, getsize(ptr));}char *downstairs(char *);inline char *downstairs(char *ptr){if (ptr < heap_min + MINBLK)return NULL;return ptr - ptr2size(ptr - SIZE_T);}//how about a while loop//sz must be &(getsize(ptr))void check_bypass_up(char *, size_t *);inline void check_bypass_up(char *ptr, size_t *sz){ptr = upstairs2(ptr, *sz);if (ptr != NULL && !isalloc(ptr)){*sz += getsize(ptr);bypasslist(ptr);}}void check_bypass_down(char **, size_t *);inline void check_bypass_down(char **ptr, size_t *sz){char *down = downstairs(*ptr);if (down != NULL && !isalloc(down)){*sz += getsize(down);bypasslist(down);*ptr = down;}}//given ptr and sz of a blk, initialize blk to free//attach blk to front of free listvoid initutil(char *, size_t);inline void initutil(char *ptr, size_t sz){check_bypass_up(ptr, &sz);check_bypass_down(&ptr, &sz);if (head != NULL){setprevptr(head, ptr);}setnextptr(ptr, head);setprevptr(ptr, NULL);setsize_setfree(ptr, sz);head = ptr;}//input requested size//output aligned block sizesize_t pumpsz(size_t);inline size_t pumpsz(size_t sz){if (sz < PTRSZ)return MINBLK;sz = roundup(sz, ALIGNMENT);return sz + HEADFOOT_NOPTR;}////////////////////////////////////////bool myinit(void *, size_t);inline bool myinit(void *reqstart, size_t reqsz){if (reqstart == NULL)return false;char *reqend = (char *)reqstart + reqsz;// are these aligned already?char *start = (char*)roundup((size_t)reqstart, ALIGNMENT);char *end = (char*)rounddown((size_t)reqend, ALIGNMENT);size_t sz = end - start;heap_min = (char*)start;heap_max = (char*)start + sz - MINBLK;head = NULL;initutil(start, sz);return true;}void *mymalloc(size_t sz){sz = pumpsz(sz);char *ptr = head;//first fitwhile (ptr != NULL){size_t blocksz = getsize(ptr);//has needed space + min free block in bytes. splitif (blocksz >= sz + MINBLK){bypasslist(ptr);setsize_setalloc(ptr, sz);initutil(ptr + sz, blocksz - sz);return ptr + SIZE_T;//internal -> client ptr}//not enough to split. allocate wholeif (blocksz >= sz){bypasslist(ptr);setalloc(ptr);return ptr + SIZE_T;}ptr = getnextptr(ptr);}return NULL;}void myfree(void *);inline void myfree(void *ptrv){char *ptr = (char *)ptrv - SIZE_T;//client -> internal ptrif (ptr < heap_min ||ptr > heap_max ||!isalloc(ptr)){//printf("\ninvalid free\nheap_min %lx\nheap_max %lx\nptr %lx\n",// (size_t)heap_min, (size_t)heap_max, (size_t)ptr);//exit(1346347);}else{initutil(ptr, getsize(ptr));}}void *myrealloc(void *oldptrv, size_t newsz){char *oldptr = (char *)oldptrv - SIZE_T;//client -> internal ptrnewsz = pumpsz(newsz);size_t oldsz = getsize(oldptr);if (oldsz >= newsz + MINBLK){setsize_setalloc(oldptr, newsz);initutil(oldptr + newsz, oldsz - newsz);return oldptrv;//client ptr}if (oldsz >= newsz)return oldptrv;//client ptrchar *up = upstairs2(oldptr, oldsz);char *down = downstairs(oldptr);size_t szup = (up != NULL && !isalloc(up))?getsize(up):0;size_t szdown = (down != NULL && !isalloc(down))?getsize(down):0;if (oldsz + szup >= newsz + MINBLK){bypasslist(up);setsize_setalloc(oldptr, newsz);initutil(oldptr + newsz, oldsz + szup - newsz);return oldptr + SIZE_T;//internal -> client ptr}if (oldsz + szup >= newsz){bypasslist(up);setsize_setalloc(oldptr, oldsz + szup);return oldptr + SIZE_T;//internal -> client ptr}if (oldsz + szdown >= newsz + MINBLK){bypasslist(down);char *newptr = oldptr + oldsz - newsz;memmove(newptr, oldptr, oldsz);setsize_setalloc(newptr, newsz);initutil(down, oldsz + szdown - newsz);return newptr + SIZE_T;//internal -> client ptr}if (oldsz + szdown >= newsz){bypasslist(down);memmove(down, oldptr, oldsz);setsize_setalloc(down, oldsz + szdown);return down + SIZE_T;//internal -> client ptr}if (oldsz + szdown + szup >= newsz + MINBLK){bypasslist(up);bypasslist(down);char *newptr = oldptr + oldsz + szup - newsz;memmove(newptr, oldptr, oldsz);setsize_setalloc(newptr, newsz);initutil(down, oldsz + szup + szdown - newsz);return newptr + SIZE_T;//internal -> client ptr}if (oldsz + szdown + szup >= newsz){bypasslist(up);bypasslist(down);memmove(down, oldptr, oldsz);setsize_setalloc(down, oldsz + szdown + szup);return down + SIZE_T;//internal -> client ptr}char *ptr = head;while (ptr != NULL){size_t ptrsz = getsize(ptr);if (ptrsz >= newsz + MINBLK){bypasslist(ptr);memcpy(ptr, oldptr, oldsz);//what if newsz real small? no way. newsz > oldsz heresetsize_setalloc(ptr, newsz);initutil(ptr + newsz, ptrsz - newsz);initutil(oldptr, oldsz);return ptr + SIZE_T;//internal -> client ptr}if (ptrsz >= newsz){bypasslist(ptr);memcpy(ptr, oldptr, oldsz);setsize_setalloc(ptr, ptrsz);initutil(oldptr, oldsz);return ptr + SIZE_T;//internal -> client ptr}ptr = getnextptr(ptr);}return NULL;}bool validate_heap(){return true;}
