# Functions

## Goals

This laboratory exercise provides initial practice with functions and passing values as parameters within C programs. In many cases, the code you are given or asked to write will cause errors. This is done intentionally!!

HINT: turn statements that are correct into comments rather than deleting them. That makes it easier to restore the program when you are done experimenting.

Consider the program `quadratic.c` that solves the quadratic formula ax2 + bx + c = 0, while illustrating several common variations for simple functions.

## `void` and non-`void` Functions

Read the directions carefully; sometimes you are asked to predict what will go wrong and then test it. Sometimes, you are encouraged to fix it. Use comments to temporarily change code rather than deleting.

1. Copy `quadratic.c` to your account, compile and run it, and review the code to determine how it works.

1. Procedure `printEquation` has a `void` return type. Parameters are passed into `printEquation`, but nothing is passed back. What will happen if the statement
``return coeff2 + coeff1 + coeff0;``
is inserted at the end of this procedure?
2. Verify your prediction by making the modification and compiling the code. Explain the result.
3. Restore the program to its original state.
4. Procedure` printEquation `is called in both procedures `displayExample1` and `displayExample2` with just a simple statement, such as:
``printEquation (1.0, -3.0, 2.0);``
Predict what will happen if you try to assign the result of` printEquation` to a variable, such as
``double value = printEquation(1.0, -3.0, 2.0);``
After making your prediction, verify whether you were correct by making the change and compiling the code. Explain the results.
5. Restore the program again to its original state.
6. Procedure `computeDiscriminant` returns a `double`. Sometimes beginning coders separate the call to a function with the assignment of the return value. Here are three examples:

Attempt 1:

``````double discriminant;
computeDiscriminant (a, b, c);``````

Attempt 2:

``````computeDiscriminant (a, b, c);
double discriminant;``````

Try each of these attempts within procedure `printRoots`.

• Does the code compile?
• Does the code give the desired result?
When you are finished, restore the program to its original state.
7. Change the body of `computeDiscriminant` to the following
``````printf ("r = %lf, s = %lf, t = %lf\n", r, s, t);
return sqrt (s * s - 4 * r * t);``````
Compile and run the program.
• Describe what is printed by the overall program. What might you conclude about what happens when printing is done in the middle of a computation? For example, how does this impact the overall program's output?
• Can you identify any guidelines regarding the advisability of including print statements in functions designed for computation (e.g., `computeDiscriminant`)?
• In addition to the `printf` statement in function `computeDiscriminant`, insert the Attempt 1 code from Step 1.6 (into `printRoots`). What happens when procedure with a return value (e.g., `computeDiscriminant`) is called on a line by itself?
Restore the program to its original state.

## Writing Numeric Functions

1. Within a C program, define and use the following functions:
• Function `circum` that takes a circle's radius as parameter and returns the circumferences of the circle.
• Function `area` that takes a radius as parameter and returns the area of the circle with that radius.

## The Perils of Global Variables

Global variables are variables declared outside any particular function. In terms of our stack model of computation, they exist in a separate part of memory called the static region, which you can draw in your diagrams as a collection of variable-value pairs separate from the stack. They tend to be problematic and are generally to be avoided. Instead, you should favor explicitly passing data between function calls using parameters and return values.

1. To better understand the confusions global variables can cause, consider the following program.
``````#include <stdio.h>

int glob = 10;

void
g (void) {
// Point (B)---first call to g()
for (int i = 0; i < glob; i++) {
printf("%d ", i);
}
printf("\n");
glob += 1;
// Point (C)---final call to g()
} // g

int
f (void) {
for (int i = 0; i < glob; i += 2) {
// Point (A)---first iteration of the for-loop
g();
printf("===\n");
}
return glob;
} // f

int
main (void) {
int ret = f();
// Point (D)
} // main``````
1. Predict what the program will print.
2. Verify your prediction by compiling and running the code. If your prediction was incorrect, trace the execution of the program by recording and updating the stack (including the static region) diagram as you trace the code's execution.

## Functions, Values as Parameters, and Robot Motion

Program `yoyo.c` uses the function `yoyo` to control a Scribbler 2 robot.

1. Copy `yoyo.c` to your account, compile and run it, and review to code to determine how it works.
1. Explain what the program does.
• What movements does the robot make? Why?
• What output is printed? Why?
2. In the main program, duplicate the line
``result = yoyo (repetitions);``

(I.e., this line should appear twice in succession.)

Does making this call twice change how many times the robot yoyos in each call? Why or why not?

3. In the main program, replace the line
``result = yoyo (repetitions);``
by
``````repetitions = yoyo (repetitions);
repetitions = yoyo (repetitions);``````
Does making this call twice change how many times the robot yoyos in each call? Why or why not?
4. In C (as in Scheme), variables declared within a function are separate from variables declared elsewhere (e.g., in `main`). In the original program, change the name of the `repetitions` variable to `reps` throughout the ```main procedure```. Compile and run the program.

Does changing `yoyo`'s variable `reps` have any impact on the variable `reps` in the `main` procedure?

5. Again, return to the original program. This time nest the call to `yoyo` in the `main` procedure. That is, the call to `yoyo` will become:
``yoyo (yoyo (repetitions));``
• Make a prediction of what will happen with the above nested call.
• Test out your nested call and explain what happened.
2. Recall the reading's discussion of memory diagrams. Draw a sequence of stack diagrams for program `quadratic.c` from Step 1.

Important: To benefit from this exercise, you must actually draw these diagrams. It is not a mental exercise.

3. Consider the program `value-params.c`.
1. Copy the program to your account, compile, and run it.
2. Draw stack diagrams for the program state when each `print` statement is executed. Be sure you can explain the running of the program at each step, based upon this series of diagrams.
Exercise 3 is a derivative work of Parameters and Mental Models, by Titus Klinge and Peter-Michael Osera, used under a Creative Commons Attribution-NonCommercial 4.0 license.