Dynamic Allocation
| Type | Quiz 4 Material |
|---|
Pointer video: https://www.youtube.com/watch?v=5VnDaHBi8dM
Helpful reading: https://jraleman.medium.com/c-programming-language-functions-malloc-calloc-realloc-and-free-61cfc3e45da7
Three memory allocation functions
void *malloc(size_t n);
//Allocates (at least) n bytes of memory on the heap,
//returns a pointer to it
//Assume memory contains garbage values
void *calloc(size_t num, size_t size);
//Allocates (at least) num*size bytes of memory on the heap,
//returns a pointer to it
//Memory will be zero’ed out.
void *realloc(void *ptr, size_t n);
//Reallocates (at least) n bytes of memory on the heap,
//returns a pointer to it
//Copies the data starting at ptr that was previously allocated
//Often used to expand the memory size for an existing object on the heapmalloc()
- malloc() returns a pointer to at least as many bytes as we requested
- malloc() is declared as “void *malloc(unsigned long)”
- C uses the idiom “pointer to void” for a generic pointer
- To be safe, you should cast this pointer into the correct type to type-check
int *ip; ip = (int *) malloc(sizeof int);
struct r {
char name[40];
double gpa;
struct r *next;
};
struct r *rp;
rp = malloc(sizeof(struct r));
//Find memory in heap and returns a pointer
if (rp == NULL) {
/*HANDLE ERROR*/
}
/*
option for handling error
- ABORT
- ASK AGAIN
- SAVE USER DATA
- ASK FOR LESS
- FREE UP SOMETHING
*/
//Idiomatic but safe way of implementing malloc
if ((rp == malloc(sizeof struct r)) == NULL) {
/* HANDLE ERROR HERE*/
}
ALTERNATIVE SYNTAX
if (!(rp = malloc(sizeof struct r))) {
/* HANDLE ERROR HERE*/
}NEVER USE RP BEFORE CHECKING FOR NULL
free()
Use free() to make storage available for reuse
free(rp);
/*returns the memory back to the heap for re-use*/MUST NOT use the value in rp after the call to free()
MUST NOT dereference the memory it points to
free(NULL) does nothing but is not an error
Variable rp still exists (a pointer to struct r), but what it points to is now garbage data. Should never dereference rp(*rp), but we CAN assign a new value to rp(make it point somewhere else)
Persistent Data
char *foo(void)
{
static char ca[10];
return ca;
}
//Anyone calling this function now has access to ca in this block. Could be dangerous.
//Since ca was allocated on stack during function call
//pointer returned is now pointing to who-knows-what
//this approach is not dynamic
char *foo(void)
{
char *ca = malloc(...);
/* error checking but no free */
return ca;
}
//This actually works, but the caller needs to know that they’re responsible for the free()
char *strFromUnsigned(unsigned u)
{
static char strDigits[] = “?????”;
char *pch;
pch = &strDigits[5];
do
*--pch = (u % 10) + '0';
while((u /= 10) > 0);
return pch;
}
//Problems
//strHighScore = strFromUnsigned(HighScore);
//strThisScore = strFromUnsigned(ThisScore);Memory Leaks
Memory leaks occur when the programmer loses track of memory allocated by malloc or other functions that call malloc
void foo(void)
{
char *ca = malloc(...);
/* no free */
return;
}
Calloc
void *calloc(size_t num, size_t size);- Call malloc() to find space for num new allocations
- Initialize the space to zero (0)
Realloc
ptr = realloc(ptr, num_bytes);Realloc does:
- Find space for new allocation
- Copy original data into new space
- Free old space
- Return pointer to new space
Realloc may return:
- same pointer
- different pointer
- NULL
Always assign the result of realloc to a new pointer!
cp = realloc(cp, n);
//If realloc returns NULL cp is lost --> Memory Leak!
//Correct way:
void *tmp;
if((tmp = realloc(cp,...)) == NULL)
{
/* realloc error */
} else {
cp = tmp;
//free(temp); NOOOO, cp and tmp points to the same mem
}
Edge cases
- realloc(NULL, n) = malloc(n);
- realloc(cp, 0) = free(cp); // only on some compilers
- These can be used to make realloc work in a single loop design to build a dynamic structure such as a linked list.
int size = 0; /* Size of "array" */
int *ip = NULL; /* Pointer to "array" */
int *temp;
int i;
char buffer[80];
while(fgets(buffer, 80, stdin) != NULL) {
size++;
if((temp = realloc(ip, size*sizeof(*temp))) == NULL){
fprintf(stderr, "Realloc failure\n");
exit(EXIT_FAILURE);
}
ip = temp;
ip[size-1] = strtol(buffer, NULL, 10);
}Dynamically Allocate a 2-D array
int grid[3][3]
int *grid2 = (int*) malloc(3 * 3 * sizeof(int))Dynamic Allocation: Pitfalls
- Allocate a block and lose it by losing the value of the pointer
- Allocate a block of memory and use the contents without initialization
- Read or write beyond the boundaries of the block
- Free a block but continue to use the contents
- Call realloc to expand a block of memory and then – once moved – keep using the old address
- FAIL TO NOTICE ERROR RETURNS
Malloc Implementations
Outline
K&R Malloc Implementation
- Headers
- Heap Layout
- Allocating the Correct Amount of Memory
- malloc(): Getting the memory for work
- free(): Recycling the memory when done
- morecore(): OS requests for real memory



