Skip to main content
Logo image

Dive Into Systems: Exercises

Section 2.3 Pointers and Functions

Checkpoint 2.3.1. Pointers.

Consider the following snippet of code:
int x, y, *z;

x = 1;
y = x * 2;
z = &x;
x = y * 2;
List the values of the following expressions after executing the statements above.
x is
y is
*z is
Hint.
Draw pictures of variables and their values as you trace through the execution of each statement.

Checkpoint 2.3.2. Pass by Pointer vs Pass by Value.

    Consider the following code snippet:
    int mystery(int y) {
        y = 6;
        return y*y;
    }
    
    int main(void) {
        int x, ret, *ptr;
    
        ptr = &x;
        x = 34;
        ret = mystery(x);
        
        return 0;
    }
    
    What is the value of x after the call to mystery?
  • 34
  • Correct! The value of x in the main function remains unchanged.
  • 36
  • Incorrect. That is the value of ret not x!
  • 6
  • Incorrect. Trace through the program carefully again.
  • None of the above
  • Incorrect. It is one of the options above!

Checkpoint 2.3.3. Pass by Pointer vs Pass by Value.

    Consider the following code snippet:
    int mystery2(int *p) {
        *p = 13;
        return (*p + 6);
    }
    
    int main(void) {
        int x, ret, *ptr;
    
        ptr = &x;
        x = 34;
        ret = mystery2(ptr);
    
        return 0;
    }
    
    What is the value of x after the call to mystery2?
  • 19
  • Close, but incorrect! Read through the code carefully. Did you capture all options?
  • 13
  • Correct! Since p is a pointer to x, it modifies the value of x in main’s stack frame.
  • 34
  • Incorrect. Trace through the program carefully again -- how does dereferencing a pointer affect the value of x?
  • None of these choices.
  • Incorrect. It is one of the options above!

Checkpoint 2.3.4. Multiple-Choice.

    Consider the following code.
    #include <stdio.h>
    
    int change_string(char *a, char *b);
    
    int main(void) {
        char alpha, beta;
    
        alpha = 'a';
        beta = 'b';
        
        change_string(&alpha, &beta);
        printf("alpha: %c beta: %c\n", alpha, beta);
    
        return 0;
    }
    
    int change_string(char *a, char *b) {
        b = a;
        // draw the stack here
        return 0;
    }
    
    PART A: Draw the stack as it appears immediately before change_string returns (at the // draw the stack here point). Answer appears in the "Answer" box below.
    PART B: What is printed when the code is compiled and run?
  • alpha: a; beta: a
  • Try again!
  • alpha: a; beta: b
  • Great work!
  • alpha: b; beta: a
  • Try again!
  • alpha: b; beta: b
  • Try again!
Answer.
A stack drawing is shown below. Initially, variables a and b in the change_string function contain the addresses of alpha and beta respectively. When the statement b = a executes in the change_string function, b is updated to contain the address of of alpha. However, this pointer reassignment does not actually update either the values of alpha or beta. Therefore, the values in the main function remain unchanged.

Checkpoint 2.3.5. Functions calling functions, pointers.

Complete the call to calculate in main.
Answer.
calculate(a, b, &sum, &product);

Checkpoint 2.3.6. Activecode.

Implement the function swap below that attempts to swap the values of two character variables. If either parameter to swap is NULL, the function should return 1. Otherwise, the values pointed to by a and b should be swapped and the function should return 0.
Final answer below should be:
alpha: b beta: a
The retun value is: 0
Hint.
In order to change the values stored at alpha and beta, we must dereference a and b inside of swap.

Checkpoint 2.3.7. Explore a larger program.

Consider the following program
 1 
diveintosystems.org/book/C2-C_depth/_attachments/ex_passbypointer.c
:
#include <stdio.h>

int arg_modifier(int x, int *y);

int main(void) {
    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;
}

(a)

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.
Hint.
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

(b)

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?
Answer.
Here is 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.