🎳

Dynamic Allocation

TypeQuiz 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 heap

malloc()

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);

Realloc

ptr = realloc(ptr, num_bytes);

Realloc does:

Realloc may return:

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

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

Malloc Implementations

Outline

K&R Malloc Implementation