Lecture File
mutation.pdf
Data & Memory
Returning multiple values via mutation and resizing arrays with double pointers.
File/lecture name: mutation.pdf
Main theme: Techniques for returning multiple values in C/C++ using mutation and managing dynamic array state using double pointers.
Prereqs assumed by slides: C/C++ syntax, basic pointer arithmetic, malloc/free, array indexing, and understanding of pass-by-value vs pass-by-reference.
What this lecture enables you to do:
return (a, b) is invalid).maxInfo Example: Walks through evolving a function to return both a maximum value and its index.push function for a dynamic array that needs to grow when capacity is reached.size_t *len works but passing int *arr alone does not update the caller's array pointer.int **) is required.push, once in main) due to pointer mutation failure.arr, len, cap) is cumbersome and suggests encapsulation (though not fully implemented).pop function using mutation principles.Mutation
*ptr = val) with mutation of the pointer (ptr = new_ptr).void set(int *x, int v) { *x = v; } mutates the integer at x.Double Pointer
int **arr). Used to modify the address stored in the caller's pointer variable.int ** is a 2D array. It is a pointer to a pointer.push(int **arr, ...) allows *arr = newArr; to update the caller's arr.Dangling Pointer
free()).free(arr); arr = newArr; makes the old arr dangling.Memory Leak
free() is optional if the program ends.arr = newArr; without updating the caller's pointer leaks the old arr.How to return multiple values in C
float max, size_t index).float *max, size_t *ind).*max = maxSoFar;).How to resize a dynamic array safely
len == cap.malloc).free(*arr)).*arr = newArr).*cap = *cap * 2).&arr), not the pointer itself.How to choose between single vs double pointer
int *arr): Use if you only need to read the array or update the contents (e.g., arr[i] = val).int **arr): Use if you need to change where the array is stored (e.g., reallocation).Pattern: Mutation via Pointer
void setMax(float *max, float val) {
*max = val;
}
* when writing (max = val instead of *max = val).* means "write to the memory at this address".Pattern: Double Pointer Reallocation
void push(int **arr, size_t *len, size_t *cap) {
if (*len == *cap) {
// ... allocate newArr ...
free(*arr);
*cap = *cap * 2;
*arr = newArr; // Update caller's pointer
}
(*arr)[*len] = val;
++*len;
}
arr instead of *arr (arr = newArr vs *arr = newArr).*arr) when modifying the caller's pointer.Pattern: Caller Responsibility
int main() {
int *arr = malloc(...);
push(&arr, ...); // Pass address of arr
// ... use arr ...
free(arr); // Caller frees
}
free(arr) inside push and then free(arr) in main.push frees memory, it must update the pointer so main knows not to free the old one.free(): double free detected in tcachepush freed the old array and updated its local pointer, but main still holds the old pointer and frees it later.&arr (double pointer) so push can update main's pointer to the new allocation.push.arr in main is dangling (points to freed memory) because push reallocated but didn't update main's pointer.int **arr) and dereference (*arr) inside push.printArray prints nothing or wrong values.len was updated locally in push but not passed by address (&len).&len to push and dereference (*len) inside.push, but the new pointer was lost (leaked) because main's pointer wasn't updated.*arr = newArr updates the caller's pointer.scanf or printf behaves unexpectedly.len is 0 because it wasn't mutated in push.&len to push.arr (int *) to a function expecting int **.&arr in main.assert(len > 0) fails immediately.len was not initialized or not updated correctly in main.len is initialized to 0 in main and passed by address.malloc returns NULL but code proceeds.malloc.free() called on uninitialized pointer.arr was never allocated before push tried to free it.malloc is called before push or handle len == 0 case.cap variable is not updated in main.cap was passed by value, not by address.&cap to push and dereference (*cap) inside.push function signature has too many parameters.arr, len, cap).main crashes before EOF.push crashed due to double free or invalid pointer access.printf shows garbage values.maxInd or max not initialized or not mutated correctly.maxInd and max are passed and dereferenced.free() called on arr in main after push reallocated.push updated *arr but main still thinks arr points to old memory.push must update *arr so main's arr points to new memory.push function compiles but logic is wrong.arr (local) and *arr (caller's).*arr is the caller's pointer.return (a, b)?
A: No. C functions return a single value. Use mutation (pointers) to return multiple values.maxInfo if it returns the max value and writes the index to a variable provided by the caller?
A: float maxInfo(float *arr, size_t len, size_t *ind);push(int *arr, ...) fail to update the caller's array pointer after reallocation?
A: Because arr is passed by value. Changes to arr inside push do not affect the caller's arr.push if it takes a double pointer?
A: push(&arr, val, &len, &cap);push frees the old array but does not update the caller's pointer?
A: The caller's pointer becomes dangling. Accessing it causes undefined behavior.*arr = newArr and arr = newArr inside a function taking int **arr?
A: *arr = newArr updates the caller's pointer. arr = newArr only updates the local pointer.free(arr) dangerous if push already freed the old array?
A: It causes a double free error because the same memory block is freed twice.assert(len > 0) in maxInfo?
A: To ensure the array is not empty before accessing arr[0].push reallocates memory, what must happen to the cap variable?
A: It must be updated (*cap = *cap * 2) so the caller knows the new capacity.maxInfo if it uses mutation for both values?
A: void (since all values are returned via mutation).&cap to push?
A: The caller's cap variable remains unchanged, leading to incorrect logic in subsequent calls.push example?
A: Pass &arr (double pointer) so push can update the caller's pointer to the new allocation.Rules for Mutation:
Type *ptr) and dereference it (*ptr = val).Type **ptr) and dereference it (*ptr = new_ptr).Type *ptr) and dereference it (*ptr = val).Memory Management:
malloc: Allocates memory. Returns void*.free: Frees memory. Must be called exactly once per malloc.sizeof: Returns size in bytes.sizeof(int): Size of an integer (usually 4 bytes).Double Pointer Syntax:
int **arr;int *arr = malloc(...); then int **ptr = &arr;*ptr = newArr;(*ptr)[i] or (*ptr)[i]Common Errors:
Type **).malloc).*ptr).&var).unsigned long).std::unique_ptr, std::shared_ptr, or std::vector are not covered.try/catch blocks are not covered.push/pop is not discussed.alignof or padding is not covered.int ***) are not covered.*ind = maxInd; return maxSoFar;void push(int **arr, ...)push(&arr, x, &len, &cap);Manually curated from summaries/mutation.txt. Use this page as a study aid and cross-check official slides for grading-critical details.