Skip to main content
Logo image

Dive Into Systems: Exercises

Section 2.4 Dynamic Memory Allocation

Checkpoint 2.4.1. Dynamic Memory Allocation.

    What is the difference between arr1 and arr2, defined as follows?
    int arr1[10];
    int *arr2;
    
    arr2  =  (int *) malloc(sizeof(int) * 10);
    
  • They are different sizes.
  • No. Both arr1 and arr2 can hold up to 10 int elements.
  • arr1 is allocated in stack memory, while arr2 is allocated in heap memory.
  • Correct!
  • arr1 stores ints, while arr2 stores pointers to ints.
  • Incorrect. Read the code again carefully!
  • arr1 is NULL, but arr2 contains values.
  • Incorrect. Neither array contains any values.

Checkpoint 2.4.2. Dynamic Memory Allocation.

    Why might one choose to allocate an array dynamically in heap memory using malloc rather than statically in stack memory? Select all that apply.
  • You want to avoid exceeding the size of stack memory.
  • Correct! The stack is of limited size.
  • The size of the array is not known until runtime.
  • Great work!
  • You want to provide more flexibility to grow or shrink the size of the array.
  • Correct! Unlike static arrays, you can change the size of a dynamically allocated array!
  • To automatically deallocate the array when the function returns.
  • Incorrect!

Checkpoint 2.4.3. Dynamic Memory Allocation.

    Given the function prototype:
    void *test_fun(int i);
    What is the meaning of void *?
  • test_fun returns a pointer to an unspecified type
  • Correct!
  • test_fun does not return a value
  • Incorrect.
  • test_fun returns NULL
  • Incorrect.

Checkpoint 2.4.4. Dynamic Memory Allocation (Active Code).

In the main function: 1) write code to declare a static array named static_array with a fixed size of 5 integers; 2) write code to dynamically allocate an array named dynamic_array that will be used to store 5 integers; 3) initialize the values in both arrays to be the values 1 through 5; 4) print the middle value of each array.
Answer.
A sample implementation is shown below:
int static_array[5];
int *dynamic_array;
int i;

// allocate heap space for dynamic_array
dynamic_array = (int *) malloc(sizeof(int) * 5);

// Initialize arrays with values 1 to 5
for (i = 0; i < 5; i++) {
     static_array[i] = i + 1;
     dynamic_array[i] = i + 1;
}

printf("%d\n", static_array[2]);
printf("%d\n", dynamic_array[2]);

Checkpoint 2.4.5. Dynamic Memory Allocation.

    Given the following partial program, which of the calls to do_something from main are valid based on do_something’s prototype? Select all that apply.
    #include <stdlib.h>
    
    void do_something(int *array, int size);
    
    int main(void) {
        int arr1[10];
        int *arr2;
        
        arr2 = malloc(sizeof(int)*10);
        
        // assume some initialization code is here
        
        // call do_something here
    
        return 0;
    }
    
  • do_something(arr1, 10);
  • Correct!
  • do_something(arr2, 10);
  • Correct!
  • do_something(&arr1, 10);
  • Incorrect.
  • do_something(&arr2, 10);
  • Incorrect.

Checkpoint 2.4.6. Passing Dynamic Arrays to Functions.

Given the code:
#include <stdio.h>
#include <stdlib.h>

void init_array(double *array, int size);

int main(void) {
    int size;
    double *array2;

    size = 100;
    array2  = (double *) malloc(sizeof(double) * size);
    array2[0] = 2.0;
    init_array(array2, size);
    printf("%f\n", array2[0]);

    return 0;
}

void init_array(double *array, int size) { 
    array = (double *) malloc(sizeof(double) * size);
    array[0] = 3.0;
}
What will this program print when it’s executed?

Checkpoint 2.4.7. Explore a larger program.

Consider the execution of the mallocstacktrace.c program:
#include <stdio.h>
#include <stdlib.h>

void foo(int *b, int c, int *arr, int n) ;
void blah(int *r, int s);

int main(void) {
    int x, y, *arr;

    arr = (int *)malloc(sizeof(int)*5);
    if (arr == NULL) {
	exit(1);   // should print out nice error msg first
    }

    x = 10;
    y = 20;
    printf("x = %d y = %d\n", x, y);
    foo(&x, y, arr, 5);
    printf("x = %d y = %d arr[0] = %d arr[3] = %d\n",
	    x, y, arr[0],arr[3]);
    free(arr);

    return 0;
}

void foo(int *b, int c, int *arr, int n) {
    int i;
    c = 2;
    for (i=0; i<n; i++) {
	arr[i] = i + c;
    }
    *arr = 13;
    blah(b, c);
}

void blah(int *r, int s) {
    *r = 3;
    s = 4;
    // DRAW STACK HERE
}

(a)

Step through the execution of this program. What is its output?
Answer.
The program’s output is:
x = 10 y = 20
x = 3 y = 20 arr[0] = 13 arr[3] = 5

(b)

List the values of the array’s elements after the call to foo returns.
Answer.
The array contents are:
13, 3, 4, 5, 6

(c)

Draw the contents of the stack and the heap at the point of execution immediately before the blah function returns.
Answer.
Here is the execution stack drawn at the point shown in function blah: