2.11. Exercises

Exercises for 2.3: Pointers and Functions

  1. Consider the following program:

    #include <stdio.h>
    
    int arg_modifier(int x, int *y);
    
    int main() {
        int val1, val2, ret;
    
        printf("Enter a value: ");
        scanf("%d", &val1);
        printf("Enter another value: ");
        scanf("%d", &val2);
    
        // pass val1 by value and val2 by pointer:
        printf("before call: val1 = %d val2 = %d\n", val1, val2);
        ret = arg_modifier(val1, &val2);
        printf("after call:  val1 = %d val2 = %d ret = %d\n", val1, val2, ret);
    
        /*
         * uncomment to test passing val2 by value and val1 by pointer
         */
        //printf("before 2nd call: val1 = %d val2 = %d\n", val1, val2);
        //ret = arg_modifier(val2, &val1);
        //printf("after 2nd call: val1 = %d val2 = %d\n", val1, val2);
    
        return 0;
    }
    
    /*
     * This function illustrates C-style pass by pointer semantics, the
     * argument pointed to by the second parameter, y, will be modified
     * after the call, the value of the first argument, x, will not.
     */
    int arg_modifier(int x, int *y) {
    
        printf("  in arg_modifier:      x = %d *y = %d\n", x, *y);
    
        /* the location y points to gets (value of what y points to + x) */
        *y = *y + x;
    
        x = x + 5;
    
        printf("  leaving arg_modifier: x = %d *y = %d\n", x, *y);
    
        return x;
    }

    Here’s the output from an example run:

    Enter a value: 100
    Enter another value: 200
    before call: val1 = 100 val2 = 200
      in arg_modifier:      x = 100 *y = 200
      leaving arg_modifier: x = 105 *y = 300
    after call:  val1 = 100 val2 = 300 ret = 105

    Copy this program (ex_passbypointer.c), compile and run it a few times to understand its behavior and the semantics of pass-by-pointer. You can uncomment the second call in main that passes the local variables in different order as arguments to the function.

    Then draw the stack for a call to the arg_modifier function, entering the values 5 and 2. Draw the stack at the point in the execution right before the return from the arg_modifier function, and consider the following questions:

    1. Where are variables val1 and val2 located on the stack?

    2. Where are the parameter values located?

    3. What value does each parameter get?

    4. How does the value of the parameter affect the value of each argument after the call?

  1. Implement a C program with a swap function that swaps the values stored in its two arguments. Make some calls to it in main to test it out.

Solutions

If your browser supports hidden solutions, click here to reveal them.
Main’s stack frame contains two variables, val1 (5) and val2(7).  The arg_modifier stack frame also contains two variables, x (10) and y (the address of val2 in main).
Figure 1. Stack diagram just before returning from arg_modifier when given 5 and 2 as user input.

Figure 1 shows a snapshot of the stack before arg_modifier returns. Parameter y receives the value of the address of val2 (y points to val2). By dereferencing y, it accesses the value stored in val2 — the statement *y = *y + x; changes the value pointed to by y from 2 to 7.

  1. val1 and val2 are located in main’s stack frame

  2. in arg_modifier’s stack frame

  3. y gets the value of the second argument (the address of val2), x gets the value of the first argument (the int value stored in val1)

  4. the value of the first argument cannot be modified by the function. the value of the second argument can be modified by the function by dereferencing the pointer parameter.

Here’s a swap function. Try it out if you do not understand how it works:

#include <stdio.h>

// do you understand why swap is a void function?
void swap(int *v1, int *v2) {
    int temp;      // do you understand why temp is an int and not int*?
    temp = *v1;
    *v1 = *v2;
    *v2 = temp;
}

int main() {
    int x, y;
    x = 10;
    y = 50;
    printf("x = %d y = %d\n", x, y);  // prints x = 10 y = 50
    swap(&x, &y);
    printf("x = %d y = %d\n", x, y);  // prints x = 50 y = 10
    return 0;
}

Exercises for 2.4 Dynamic Memory Allocation

#include <stdio.h>
#include <stdlib.h>

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

int main() {
    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
}
  1. Step through the execution and list the program’s output.

  2. List the values of the array’s elements after the call to foo returns.

  3. Draw the contents of the stack and the heap at the point of execution immediately before the blah function returns.

Solutions

If your browser supports hidden solutions, click here to reveal them.

The program’s output is:

x = 10 y = 20
x = 3 y = 20 arr[0] = 13 arr[3] = 5

The array contents are:

13, 3, 4, 5, 6
The stack frames, starting from the bottom: main, foo, and blah.  Main contains x (3), y (20), and arr (a pointer to an array on the heap containing 13, 3, 4, 5, and 6).  Foo contains i (5), n (5), arr (a pointer to the same array on the heap), c (2), and b (a pointer to x in main’s stack frame).  Blah contains s (4), and r (another pointer to x in main’s stack frame).
Figure 2. The execution stack drawn at the point shown in function blah.