Programming in C

Chapter 3, 6/29/93

Augmenting the First Program: User Input, Monthly Deposits, New C Keywords
The first program we developed calculated compound interest on a savings account. This is rather useful, but the rate of interest, initial balance, and so on were all coded directly into the program. This meant that altering and recompiling the program was necessary in order to examine a different set of conditions.
I will now present a new, interactive version of the program which accepts input from the user and allows several different financial scenarios to be examined in the same session. This version will also allow a monthly deposit to be specified, so you may find it interesting to examine your own finances. (Of course those on the debt side of life can enter a negative number to represent payments made each month and see how long it takes for the initial balance to be reduced to zero!)
The program follows. See the previous installment for instructions on entering, compiling, and executing it, as well as the manuals for your compiler. (Enter everything between the three-dash lines; do not enter the dash lines themselves.)
---

/* This program calculates the balance of a savings or loan account after
   a number of years specified by the user, with an interest rate,
   monthly payment, initial balance and rate of compounding specified
   by the user. */

/* Get standard input and output functions */
#include < stdio.h >

/* Get standard math functions */
#include < math.h >

int main() {
  /* Initial balance (money in account). Since this value can
    have a fractional part, we declare a float (floating point)
    variable to store it. */
  float initial_balance;

  /* Rate of interest, per year (also a floating point value) */
  float interest;

  /* Number of times interest is compounded each year (interest periods)
    (thus 1.0 is annually, 365.0 is daily) */ 
  float frequency;

  /* Time in years */
  float years;

  /* Total interest periods. This cannot have a fractional part,
    so we declare an integer (no fractional part) variable to store it. */
  int interest_periods;

  /* Current balance. (We store this in a separate place form the
    initial balance, so we will still be able to tell how much money
    we started with when the calculation is finished.) */

  float balance;

  /* Counter of interest periods */
  int i;

  /* Monthly deposit (negative values are permitted) */
  float deposit;

  /* Flag: when this is set true (nonzero), the user is finished */

  int done;

  /* User input: analyze again? */

  int again; 

  /* Initially, of course, we are *not* finished. (C does NOT automatically
    set variables to zero. Making this assumption is a common mistake
    among new programmers.) */

  done = 0;

  /* Loop until done. */

  while (!done) {
    /* Fetch starting values from user */  
    printf("Initial balance: ");
    scanf("%f", &initial_balance);

    printf("Interest rate (example: .05 for 5 percent): ");
    scanf("%f", &interest);

    printf("Number of compoundings per year (12 = monthly, 365 = daily): ");
    scanf("%f", &frequency);

    printf("Monthly deposit (enter negative value for loan payment): ");
    scanf("%f", &deposit);

    printf("Number of years (examples: 1, 5, .5): ");
    scanf("%f", &years);

    /* Actual logic begins here. */

    /* Calculate number of interest periods. */
    interest_periods = frequency * years;

    /* Set working balance to begin at initial balance. */
    balance = initial_balance;

    /* Loop through interest periods, increasing balance */
    for (i=0; (i < interest_periods); i++) {
      /* Add deposit. User enters deposit in terms of a monthly
        deposit, so calculate how much this comes out to
        over a given interest period. 
        
        This isn't 100% accurate because the deposit begins 
        earning interest on the fraction of it "deposited" 
        in one interest period, when in fact the whole amount 
        should be added at the beginning of the month. Feel free 
        to try to improve on this. */  
     
      balance += deposit * ( (1.0/frequency) * 12.0);

      /* Each period, multiply balance by 1.0 plus the annual
        rate of interest divided by the number of times per year
        (frequency) with which interest is compounded. */

      balance = balance * (1.0 + (interest/frequency));
    }
    /* Print out result */
    printf("Initial balance: %f Final balance: %f\n", 
      initial_balance, balance);
  
    printf("Enter 1 for another analysis, or 0 to quit: ");
    scanf("%d", &again);

    if (again) {
      done = 0;
    } else {
      done = 1;
    }
  }
  /* Everything went fine */
  return 0;
}

---
Once again I will proceed line by line, explaining the portions of the program that have changed.
First, I added several new variables, which are reasonably well-explained by their associated comments:
float deposit;
specifies a deposit to be made on a monthly basis (a negative value can be entered in order to make a "loan payment" (reduce the balance) each month).
int done;
will be used to determine whether the program should halt.
int again;
will store the user's decision as to whether the program should be run again.
done = 0;
initializes the done flag to false. This line is VERY important! The C programming language does NOT initialize variables to zero. This means that if you do not initialize or otherwise set the value of a variable, its value is undefined; it can be anything, and it can be different from one run to the next.
Some (faulty) compilers do in fact set all variables to zero. Others have an option to do so. DON'T trust this. If you do, you will be unable to move your program to a different compiler or computer without significant changes. This is one of the most common errors in C programming.
The line:
  while (!done) {
begins a while loop.
While loops are similar to the for loops discussed in the previous chapter, in that they continue until a condition ceases to be true. But they are simpler in that they consist only of the while keyword, a conditional expression in parentheses, and the following statement, which is executed until the condition ceases to be true. The condition is tested each time the loop returns to the top. If the condition is false at the very beginning, the loop will never execute.
Recall that "!" is the "NOT" operator in C. So "while (!done)" means "while done is not true." Since done is initially zero, which is false in C, "NOT false" yields true, and the statement after the condition executes.
(Recall also that a statement can be either a simple statement ending in a semicolon, such as "i = 0;" , or a compound statement, which is a series of simple statements inside "{" and "}" characters. while loops and for loops themselves are also statements, and can appear inside each other. A compound statement follows the condition in this while loop, and happens to consist of the majority of the program.)
Now consider the following lines, which gather input from the user:
printf("Initial balance: ");
scanf("%f", &initial_balance);
The first line is simple; it prints a message to the user, prompting for an initial balance.
The second line calls scanf(), a function which can be used to gather user input. scanf is analogous to printf(), and is used in a similar fashion: a series of % sequences between double-quotes specify the types of values to be input (%f for floating-point values here, just as for printing such values), and the variables to be input follow the quoted string.
"Fine. But what's that & in front of initial_balance for?"
When you call a function in C, the function receives the *values* of the variables you pass. This may seem obvious, but in fact it's an important issue.
In some languages, such as Microsoft QuickBASIC and QBASIC, a function can change the variables that are passed to it, and those values are *changed in the function that called it.*
In C, this isn't the case. When you pass a variable to a function, the function receives the value, but stored in a different place. So while the function is permitted to change the value, that change won't be reflected in the calling function.
"I still don't see what all this has to do with ampersands. "&"'s, even."
Since a function can't change the values passed to it, in order for scanf() to let the user set the variables you pass, it must be given the *location* of the variables, instead of the *value* stored at them. The "&" operator returns the *location* of a variable.
scanf(), in turn, uses another special operator to access the values stored at that location. This operator, and how to use it in your own functions, will be discussed later.
If all this isn't entirely clear just yet, relax; it'll be explained in more detail in a future chapter. But for now, keep the following simplified explanation in mind:
"A function cannot normally change the variables passed to it. In order to 'grant permission' for variables to be changed, they must be passed with the "&" operator preceding them. Functions must be specifically designed to work this way, and scanf() is one of those functions."
Now consider the subsequent lines, which also use printf()/scanf() pairs to prompt the user and gather input.
Note that the sequence "\n" does not appear in the printf() calls. This is in order to keep the user's input on the same line with the prompt.
Now, turn your attention to the following line, placed inside the for loop just before the line that calculates interest (covered in the previous chapter):
balance += deposit * ( (1.0/frequency) * 12.0);
As the comment preceding this line explains, the purpose of this statement is to add the monthly deposit to the balance. As the comment also notes, it is not done perfectly (because if, for instance, compounding is daily, then the deposit is actually added in small daily pieces, and so the entire deposit does not begin earning interest from the beginning of the month, as it would in reality). Feel free to attempt to improve on this. (Hint: you'll want to keep track of how many interest periods have passed and whether enough time has now passed for a deposit to be made.)
Note the use of parentheses to make the order of operations clear. Also note the use of the += operator to simplify the statement.
Now consider the following lines, placed after the final "}" of the for loop:
printf("Enter 1 for another analysis, or 0 to quit: ");
scanf("%d", &again);
The first statement prompts the user; the second stores the user's input into the variable "again" by calling the scanf() function. Note the use of the "%d" sequence to read an integer, just as "%d" is used to print an integer in printf(). It is crucial to use the correct sequence for the correct type.
Finally, consider the following lines:
if (again) {
  done = 0;
} else {
  done = 1;
}
Here we use the "if" keyword for the first time.
An "if" statement consists of "if", followed by a conditional expression in parentheses, followed by a statement which is executed only if the conditional expression is true (not zero).
In *addition,* the "else" keyword may appear next, in which case the statement following "else" is executed only if the condition is *not* true (zero).
In this case, we test the variable "again"; if it is not zero, then the user has opted to run another analysis, so we set the value of "done" to zero. If it *is* zero, the user wants to halt the program, so we set the value of "done" to 1.
Immediately after the if statement, the closing "}" of the while loop appears. (Note that the closing "}" is indented by the same number of spaces as the word "while". This helps to prevent confusion as a function grows in length. Your editor may have keys which assist in moving blocks of code left and right; these can be of great help in indenting.) When this closing "}" is encountered, the running program jumps back to the top of the while loop and tests the condition. If "done" is now true (nonzero, 1 in this case), the while loop exits. Once it does exit, the statement "return 0;" returns from the main() function, ending the program.
Now, if you have not already done so, compile and run the program. (See chapter 2, and the manuals of your compiler, for assistance in doing so.) Note that you must press RETURN (or ENTER, depending on your keyboard) after typing each value the program prompts for. Also note that negative values can be entered by prefacing them with a "-", just as in regular algebra.
Again, if you encounter errors, check your code carefully against what I have provided, since it has been tested against a standard compiler. If you're sure there's a problem and can't resolve it yourself, feel free to contact me for assistance, giving a *specific* description of the error message you received. "It gives an error" will *not* help. I also need to know what make of computer you are using and, if possible, what brand and version of compiler.
When you run the program, be sure to try entering various combinations of values. Again, you may wish to try inserting a line which prints out the balance at each interest period, as suggested in chapter 2.

<< Previous || Next >>