CSC 076

Programming in C++

Summary of 2/5 Lecture

We took a look at C++'s unique ternary (as opposed to binary) operator, the ? : conditional operator.  The following example illustrates quite well.

The challenge is to write code which calculates the maximum of two integers.  Following are two solutions:

Solution 1                                          Solution 2

if (x > y)                                             max = (x>y) ? x : y;
    max = x;
else
  
max = y;

The while Loop

Tonight, we considered loops in more detail.  In particular, the while loop has the following syntax:

while (boolean expression)
        statement;

Example.  Write a program that takes a sequence of numbers from the keyboard and averages them.

//File:    while.cpp
#include
<iostream.h>
int main()
{
    cout << "How many items would you like to average? " << endl;

    int     number_of_items;
    cin >> number_of_items;

    cout << number_of_items << "\n\n";      // echo input

    int     k = 0, sum = 0;                   // initialize counter and sum variables
    while (k < number_of_items)
   {
           int      number;                     // declare local variable, number   
            k++;                                    // increment counter
            cin >> number;                     // input next number
            cout << number << endl;     // echo input

            sum += number;                   // add to accumulating sum
    }

// NOTE:  The variable 'number' is unknown outside its scope,
// so, cout << number << endl; would give error message here.

    int average = 0;
    if (k > 0)
        average = sum / k;

    cout << "average = " << average << endl;

    return 0;
}


//    ALTERNATIVE (to output "real" average)
//    float average = 0.0f;
//    if (k > 0)
//        average = static_cast<float> (sum) / k;

NOTE:    Remember that "real" constants are by default of type double, so    float x = 1.2;    instead of     float x = 1.2f;    would generate the following warning:

'initializing' : truncation from 'const double' to 'float'

The for Loop

We introduced the for loop which, as usual, makes counter-controlled loops somewhat easier to code.  For example, the problem of averaging a list integers reduces to:

//File:    for.cpp
#include
<iostream.h>
int main()
{
    cout << "How many items would you like to average? " << endl;

    int     number_of_items;
    cin >> number_of_items;

    cout << number_of_items << "\n\n"; // echo input

    for (int k=0, sum=0;  k<number_of_items;   k++)
   {
            int number; // Local variable; undefined outside loop!

            cin >> number;
            cout << number << endl; // echo input

            sum += number;
   }

   int     average = 0;
   if (k >0)
        average = sum / k;

//NOTE:    The C++ standard states that since both k and sum were
//defined in the for loop, they are undefined outside the loop.

    cout << "average = " << average << endl;

   return 0;
}

To summarize, the syntax for the for loop is:

for (initialization; test condition; incrementation)
        statement;

This might lend itself nicely to the numerical calculation of integrals, for example, with intervals of width deltax_x; e.g.,

for (x = 0.0;  x <= 12.5;  x+=deltax)
{
        ....
}

As a final note, it is also possible to construct very strange looking for loops with nothing in the 3 categories:

//File:    nulloop.cpp
#include
<iostream.h>
#include <stdlib.h>
int main()
{
    int k=0;
   
    for (;;)
    {
        cout << k << endl;
        k++;
       if (k > 10) exit(EXIT_SUCCESS);
    }
   
   return 0;
}

Remember, though, that just because something is possible doesn't make it good programming practice!


Lab Exercise.  Write a program that approximates the integral of 'x squared' between 0 and 1.  (Answer:  1/3)  Try it yourself, but you can then check my solution, integral.cpp if you like.


 

Functions

Example 1.  Function int sum (int, int) takes two numbers and returns their sum as follows

//File:  sum.cpp
#include
<iostream.h>
int sum (int a, int b)
{
    return (a + b);
}
int main ()
{
   int x = 3, y = 7;

    cout << "The sum of " << x << " and " << y << " is: " << sum(x,y) << endl;

    return 0;
}

The parameters a and b are called formal parameters while the variables x and y are called actual parameters.  The formal parameters are stand-in's for the actual parameters of the calling function.  Furthermore, in this example, the formal parameters are value parameters; i.e., the actual parameters, x and y, provide values (3 and 7 respectively) to initialize the newly created memory locations, a and b.  The RAM locations a and b are discarded when execution exits the function sum.   Note that a and b occupy memory locations distinct from those of x and y; hence, operations within the function involving those two parameters can have no effect on the variables x and y in main().

Of course, there are times when it is desirable for the executing function to affect changes in the calling function.  Indeed, since C and C++ do not provide facilities for creating procedures, the only alternative is to have provision for creating reference parameters.  In Pascal, these are the VAR parameters or in/out parameters.  Suppose we consider the following function designed to swap the two values passed to it.  Note here the use of & to denote reference parameters.  The formal parameters a and b take as values the addresses of the variables x and y respectively.  So, when values are given to a and b within swap(), they are in effect simultaneously given to the variables x and y.  Indeed, you could think of a and b as aliases for x and y within the function swap().  Using the language of pointers, a and b are pointers to x and y.  Fortunately, we do not have to perform the pointer arithmetic directly; it is done for us.

Example 2.  Write a function that takes two values and swaps them.

//File:    swap.cpp
#include <iostream.h>
void swap (int &a, int &b)
{
    int temp = a;
    a          = b;
    b          = temp;
}
int main()
{
    int     x=15, y=25;
    cout << "The numbers x and y are: "
            <<  x << " and " <<  y << " respectively." << endl;
    swap (x, y);
    cout << "After the swap, the numbers x and y are: "
             <<  x << " and " <<  y << " respectively." << endl;

    return 0;
}

If you're interested in playing with the C version, just download cswap.cpp

Arrays

Example 1.  Write a program which creates an array called 'list', initializes it, and outputs it.

//File:    array.cpp
#include <iostream.h>
int main()
{
    int    list[10]={10, 20, 30, 40, 50, 60, 70, 80, 90, 100},
            k;

    for (k=0; k<10; k++)
        cout << list[k] << endl;

    return 0;
}

Unlike Pascal, which asks the programmer to set the indexing, a C++ array, list[n] defaults to  subscripts from 0 to n-1.   So the above program establishes memory locations labeled list[0], list[1], ... list[9].  The for loop reflects this in the range of the counter, k; i.e., k begins at 0 and continues while k is less than 10.  Note that several possible variations are acceptable.  For example,

    int    list[10]={0}     // initializes list[0]=0, list[1]=0, list[2]=0, ..., list[9]=0

    int     list[]={10, 20, 30, 40};     // establishes array of size 4

C and C++ arrays do not routinely perform range checking so that changing the for loop to read

for (k=0; k<=10; k++)    // goes too far
        cout << list[k] << endl;

compiles and runs but produces absurd results for list[10] (6618680 in my attempt).

Before moving on, it's probably wise to discuss the connection between arrays and pointers.  First, note that arrays are always passed by reference, even without adding the & to the formal parameter.  For example,

void sort (int a[], int n);
int main()
{
   int    list[10];
    ...........
    sort (list, 10);
    ......
    return 0;
}

does not copy the actual parameter, 'list', to the corresponding formal parameter, 'a'.   Instead, 'a' references the 'list' array.  In this case, the array, 'list', in main() is returned from function 'sort' in sorted order.  I recommend that you save the following code to try on your own.

//File:    pointers.cpp  (For variations involving formatting of output, look at pointers2.cpp and pointers3.cpp
#include <iostream.h>
#include <iomanip.h>
int main()
{
    int    list[4]={10, 20, 30, 40},
            *p,
            k;

    p    =    list;     //NOTE:  list is a constant pointer to list[0]

    for (k=0; k<4; k++)
    {
        cout << setw(5) << list[k] << endl;    //NOTE:  setw(k) sets the field width to k columns
        cout << setw(5) << *(p+k) << endl;    //             This stream manipulator is defined in the iomanip.h header file
        cout << setw(5) << p[k] << '\n\n";
    }

    return 0;
}

Note that the identifier 'list' in the above program is a constant pointer to list[0].  So making the assignment p=list makes p point to list[0].   This initializes the pointer p so that, in the loop, the pointer p  is advanced to point to successive elements of the array 'list'.  Note that the connection between pointers and arrays is so close that the notations *(p+k) and p[k] are synonymous!   By the way, if you want to see how to format double's check double.cpp.

Is it clear why the following assignment is illegal?

int    list[4]={10, 20, 30, 40},
        otherlist[4];

otherlist = list;    <------------- WHY IS THIS ILLEGAL?
.....

That assignment is illegal because otherlist is a constant pointer.   It cannot be the left hand side of an assignment statement.

Finally, to conclude our discussion of the pointer-array connection, note that the prototype of the sort function given above has two equivalent forms:

void sort (int a[], int n);

void sort (int *p, int n);

Of course, your choice of forms will determine the appropriate notation in each implementation.

Back to CSC 076 Home Page