Topic(s)   Book Reference   Location Below or Elsewhere
Preparatory Materials   N/A   Color and Typography Legend
Introductory Materials   N/A   Educational and Course Information
Introduction to Programming   Chapter 1   Programming Background
Fundamental Data Types   Chapter 2   C++ Startup
Objects   Chapter 3
  Output and Input via Streams
Introductory strings
Ensuring Line Entry
Fool-Proofing Data Entry
Intermediate strings
Basic Control Flow   Chapter 4   Ensuring Line Entry
Fool-Proofing Data Entry
Repeat as Desired
Nesting — Console Graphics
Nesting — Menus
Making Your Program SEEM Intelligent
Accumulation and Counting
Functions   Chapter 5   Modularization of Code
classes   Chapter 6   Data Abstraction
Advanced Control Flow   Chapter 7   Flow Control Gone Extra-Strictly Structured
Testing and Debugging   Chapter 8   Covered throughout the semester as necessary...
For instance:
Ensuring Line Entry
Fool-Proofing Data Entry
Repeat as Desired
vectors and Arrays   Chapter 9.1-4   Containing More Than Just characters
Multidimensional Containers: vectors   Chapter ??   Multiple Dimensions

Legend

The following display styles were designed with the intention of helping you distinguish one new concept from another while still capitalizing on similarities to help you put them together in your head. (I am NOT, however, a professional designer. See below.)

First on the normal background:

Now on a 'sample' background:

Holy Cow but that's ugly!?

Beauty is in the eye of the beholder...if s/he can actually behold the thing, that is. Visually impaired readers and color-blind readers might have difficulty with some of the displays in these pages. If you ever have trouble reading anything here, let me know — whether it is a matter of color, spacing, or even actually figuring out what I was trying to say. (I had to rewrite that previous sentence, in fact. It once said, "no matter if it is a matter of...". *shakes head* *shrug*)

A possible fix for this is the Content Preferences extension. It is available at the Firefox Addons site. Although not perfect, it is a wonderful improvement!

There are two color schemes available to you. Internet Exploder will only allow you to use the 'visually impaired' one. (That is, it uses light text on a darker background for higher contrast.) Any Mozilla-based browser I know of (Firefox, Seamonkey, Mozilla Suite, or even Netscrape) as well as Opera will offer you a choice of which style to use under the View menu. Just select one from the Use Style or Page Style drop-down. (Unfortunately, the Mozilla-based browsers don't [yet?] 'stick' the style — you have to re-select it as you navigate each page..!)

I've no [known] personal experience with the Safari or Opera browsers, but Opera is known as a leader in the user customization area. They were the first browser to support user-selectable style sheets like these, in fact. Safari I merely know exists...I'm not even sure what platform it is on/for...Mac, maybe?

General Educational & Course Information

The Learning Process and You

How You Understand Something

Knowledge
  • Acknowledgment — trust that there is something there to know
  • Identification — be able to pick something out from alternatives
  • Description — briefly, yet accurately describe the concept
  • Explanation — more detailed level of knowledge of concept
Application

Note here that we rarely need to go through the 'acknowledgment' phase. Most likely this is do to the fact that we've seen the instructor do it already.

  • Identification — be able to pick something out from alternatives
  • Direction — following explicit directions, have something happen
  • Selection — choosing from among given tools, perform task
  • Implementation — perform task with little/no direction or guidance

For Each Topic within the Subject...

Sadly, each of these phases (as applicable) must be repeated for each topic within the subject under study...

Blending Two or More Topics

The real goal is to not only go through the above steps for each topic in the subject area, but to then be able to blend two or more topics together at the same time. Be careful, though, as it is sometimes difficult to blend one topic with others before we've reached a particular level of ability/understanding with it (or even them).

Specific Background Information for Computer Programming

Programming, Computers, etc.

What's Programming?

Putting together the instructions for a task in a simple and logical way to ensure correct reproduction of the desired actions by a computer.

So what's a computer?

A computer is an electro-mechanical computation device. The ones we typically use are composed of several smaller parts both inside and outside the main case that most people call 'the computer'. Outside are display devices such as screens and/or printers. Also on the outside are devices to gather input for use within the computer such as keyboards, mice, and drawing pads.

Inside the case resides a network of chips and devices to store, process, and retrieve the gathered information and send the properly processed form to the display devices. Among these pieces are the RAM (Random Access Memory) for storage of information while the computer is on, disk drives for storing data in a more permanent fashion, the CPU (Central Processing Unit) for arithmetic and logic operations as well as central control of the other devices both inside and outside the case, and various information BUSses — connections between devices that transfer data to/from/between them (they really are called that!).

And what's a language?

Why are we using C++?

C++ is a popular language with the object-oriented features desirable in today's marketplace.

Also, once you learn a language from the procedural or object-oriented family, learning others from any family (except perhaps 'symbolic') is greatly simplified. Since C++ has both a procedural ancestry and object-oriented extensions to that history, it is an excellent 'stepping off' point.

Um...What did you mean by 'compiler'?

A compiler translates a high-level language (like C++) to a lower-level one (typically Assembly language or machine language) for use inside the computer's CPU.

C++ Specifics

C++ Startup

A VERY minimalist program...

    int main( )
    {
        return 0;
    }

This program does just one thing: it thanks the Operating System for the great time it had while staying at its CPU.

The Standard Library's Libraries and Their Symbols' namespace

The C++ language has features that are both part of the language itself and those which one must take in from 'outside'. Much like the content of a course textbook is core to the course subject. However, by following the references at the textbook's end (or the ends of its chapters), one can find out more detailed knowledge about the subject. Of course, in order to do that, you'd have to find those references at the library, most likely.

Many 'topics' or features of the C++ language are considered part of the core language: keywords, built-in types, operators, how functions work, the concept of the main func...er, program.

Others are prescribed by the C++ standard, but are considered more auxiliary and were therefore placed in files programmers call libraries. The whole collection of libraries prescribed by the C++ standard is known as the Standard Library. (Although this is mildly confusing, have no fear — it gets worse.)

To avoid name conflicts when a programmer using C++ or a company (aka third-party) wishing to supply a non-standard library, all of the names/symbols in the Standard Library are placed together in a single space of names (or namespace): std. (No, it's short for standard...silly.) One possible way to visualize this is to picture the names/symbols from the Standard Library as the main ideas of a chapter. These are normally not only displayed in some sort of bold or italics, but also form the main portion of the book's index. So then the namespace std is like the index.

Note: Core Language vs. Library Features

Although not strictly necessary, it can be quite helpful to note what is a core language feature as compared to a library feature. That's why I've tried to note in these pages what is a keyword or operator symbol vs. what is a library identifier.

Note that technically pre-processor commands like #include are neither — they are part of a second language which helps the compiler pull in the library files...among other duties.

Similarly, the language does specify how to define new variables and such, but these symbols are the programmers own. Programmer defined symbols are noted in this font highlight. Likewise, the language specifies that comments come after a // pair through to the end of that line or between /* and */ no matter how many/few lines intervene. However, it is the programmer her/himself that actually comes up with the commentary and so these portions of discussions are highlighted like this.

Finally, the language also specifies how numeric values are formed, but the actual values are typed by either a programmer or a user. Such values are denoted with this font change where the user is considered to be typing them in or with this font change once they've been stored in a memory location. (The same goes for character, string, or boolean values.)

Output

The object-oriented concepts start early on in C++. Our main program is structured very much from our procedural ancestry, but our system for handling both output and input is heavily reliant on object-oriented views.

Bjarne conceived of the output of a C++ program as a sequence of characters generated from inside the program and then flowing out to the display device (the screen or monitor) for the user's perusal. This flow of information forms a 'stream' that carries the information from your program to the screen. Here's a truly horrid rendering (perhaps worse than the one I drew during lecture):

      +----------+
      |  ~~~~~~  |
      | (      ) |
      | (      ) |
      | (      ) |~~~,      <<
      |  ~~~~~~  |    \                 +------+
      |       @ @|~~,  `~~~~~~,         |      |
      +----------+   \         \        | C++  |
        screen        `~~~~~~,  `~~~~~~~|      |
                              \         | pro- |
                               `~~~~~~~~|      |
                                        | gram |
                                        |      |
                                        |      |
                                        +------+

Notice that the informations direction of travel is given by the double-headed arrow above the 'stream'. This pair of less-than symbols is the operator C++ uses for displaying output to the screen, in fact. When we use it this way, we call it the insertion operator — since it is inserting data onto the screen. (*shrug* So it shoulda' been 'into'...big deal...*phbbt*)

The stream leading to the screen (and therefore, pretty much, the screen itself) is called cout. This is not short for C++ output, as many new programmers think. It is actually a contracted form of Console OUTput. (The screen is one part of a historical device known as a console. The other part was the keyboard. Such consoles — or dumb terminals — would be used by most people connected to a large central computer over a local network.)

In order to use this object-oriented concept in our programs, we'll have to actually tell the compiler we'd like to perform output with this stream. It seems so obvious that a program which produces no output isn't of much use, but there are other ways to display information to a user. C++ doesn't want to lock you in to a single kind of display mechanism, so they placed the stream routines for console output in a separate 'package'. The term used in C++ for a module or package of extra-lingual routines is 'library'. The C++ standard specifies a large number of libraries which are to come with a standards-compliant compiler. The group of them together is known as the Standard Library... (*shakes head* I know...I didn't name it, I'm just telling you what it is called...)

Specifically, for console output on the cout stream, we'll want to pull in the iostream library. To do this, the compiler has a helper called the pre-processor which does a few things to your source program before the compiler actually begins translation. One of these helpful tasks is to pull in or include any libraries the programmer specifies. Here is one way to accomplish this task:

    #include <iostream>

    int main( )
    {
        std::cout << "\n\tHello World!\n\n";
        return 0;
    }

The #include directive to the preprocessor tells it to find the library known as iostream which is located in the Standard Library installation (denoted by the use of angle-brackets — < > around the library's name).

Next we find inside the main program's body a new statement: an output or cout statement. Here we are printing the message "\n\tHello World!\n\n" onto the user's screen. (The use of this phrase or a variation thereon is a time-honored tradition amongst programmers. Whenever you write your first program in a new programming language, it should do the local equivalent of displaying 'Hello World'. *shrug* I didn't say it was deep, just honored.)

Notice that we use the insertion operator (<<) to point the data toward the cout stream. It is supposed to resemble an arrow [-head] to remind you of which direction the information/data is going.

There is that one other odd bit, though. What's that std:: bit in front of cout there? Well, that's a longer story, but perhaps worth a short detour. Since the symbols (like cout) from the standard library are all wrapped up in that namespacestd, we have a choice. Either we have to place the syntax std:: in front of every one of them we use; or we can place a single line after we've #included the individual libraries from which we want to use symbols. This line will tell the compiler that we'll be using symbols from the namespace called std. After that, any symbol we use that the compiler doesn't see defined in our code will be sought in the std namespace [portions] that we've #included at the top of our code.

    #include <iostream>

    using namespace std;

    int main( )
    {
        cout << "\n\tHello World!\n\n";
        return 0;
    }

If it doesn't look simpler, trust me — it is in the long run. (Later we'll find places where we have to use the std:: syntax and you'll look back to these simpler days and *sigh*. *smile*)

Data Types and Declaring Variables

double is a built-in type that can contain a subset of math's real numbers.

    double var;

Multiple variables of type double can be declared at the same time, as well.

    double var_1, var_2, var_3;

Input

The keyboard is known as cin and it uses the extraction operator (two greater-than symbols right next to one another: >>) to take data from the keyboard stream and translate it into a variable:

    cin >> var;

For instance, you may have this code fragment in your program:

    double var;
    cout << "Enter your number:  ";
    cin >> var;

Which, when executed, would result in this display on-screen:

Enter your number:  _

At this stage, the program waits for the user to type the requested number. Perhaps they type thusly:

Enter your number:  420E-1_

If they left it like that, we'd not soon get anywhere. The user must hit the Enter (sometimes called the Return) key before cin gets to process their typed characters to translate them into the requested double-typed variable's value!

Enter your number:  420E-1
_

Now the extraction operator (>>) goes to work on the cargo of characters to transform it into a double value and store it in your program's variable:

   cin's buffer                      actions taken
    420E-1\n                  cargo received; accumulating double --> 0.0

    420E-1\n                  '4' --> 4; accumulating double --> 4.0

    420E-1\n                  '2' --> 2; accumulating double --> 42.0

    420E-1\n                  '0' --> 0; accumulating double --> 420.0

    420E-1\n                  'E' --> scientific notation; accumulating exponent --> 0
                                                                       accumulating double --> 420.0 (holding)

    420E-1\n                  '-' --> negative exponent; accumulating exponent --> 0 (neg)
                                                                       accumulating double --> 420.0 (holding)

    420E-1\n                  '1' --> 1; accumulating exponent --> 1 (neg)
                                                                       accumulating double --> 420.0 (holding)

    420E-1\n                  '\n' --> whitespace ends translation; accumulating exponent --> -1 (exponent)
                                                                       accumulating double --> 42.0 (scientific notation applied)

So, at this point, your variable is given the 42.0 to hold onto and cin's buffer essentially holds merely \n (from when they hit Enter).

The values for multiple variables can be read in (or extracted from cin) at the same time, as well.

    cin >> var_1 >> var_2 >> var_3;

In this case, cin's >> operator uses the presence of either spacing characters or characters which are invalid for the type of data being requested (which it can tell from the variable used on its right side — as its right operand) to separate the values for the variables.

Simple Calculations and Storing Results

The operator symbol + is used to add two double values together. The result is another double.

    double_var + other_double_var

    4.2 + 5.0

    5.0 + double_var

    double_var + 4.2

The operator symbol = is used to assign a variable a new value. This works because it has lower precedence than the arithmetic operators — aka +.

    var = new_value

    var_1 = 4.2 + var_2

    var = var + 5.0

Note that in this last sample, it is the relative precedence of = compared to + which makes this mean that the current value of var will have 5.0 added to it and this result will then be stored into the variable var.

Literal vs. Variable vs. constant
Any sufficiently advanced technology is indistinguishable from magic. -- Arthur C. Clarke "Profiles of The Future" 1961

A numeric literal in a program might be called a magic number if its meaning is not obvious to the 'casual' reader of the program's source. Literals used in an obvious context such as the 2 in:

    (a + b) / 2

would not be considered magical. Numeric literals which come from a cultural perspective, a company's internal policy decisions, etc. could all be considered magical.

To avoid magic numbers in your code, you can make all non-obvious literals into named constants. By giving these constants a clear and meaningful identifier, you remove their 'magic' — their power over the uninitiated mind, as it were.

A variable is a named memory location declared to hold a value which may change during the program's execution.

A constant is a named memory location declared and initialized to a particular value and which is not allowed to change during the program's execution. When you use the const keyword to change an initialized variable declaration into a constant declaration, you are making a promise to not change that memory location for the rest of the program. The compiler not being a trusting soul, always checks that such promises are being kept. This helps us to avoid accidental changes to the values of things like π or g (the acceleration due to gravity):

const double pi = atan2(0.0, -1.0);

const double g = 9.8; // m/(s^2)
 

A literal is a value that is:

  1. just literally sitting there in the source code
  2. literally typed into the source code by the programmer
  3. 'what it is' — i.e. self-representing

For example, here are literals of each of the most useful types (see also below):

Data
Type
int
short
long double char string bool
Example
Literal(s)
5 5L 5.
5.0
'5' "5" true
false

(Note that there is no way to type a short literal, so we'll just use the means to type an int literal, since we won't be using int for variables, constants, etc. in our code...er...yeah...)

Putting It All Together

Putting together all we've just learned can write a lame program like this one:

    #include <iostream>

    using namespace std;

    int main( )
    {
        double x;

        cout << "\n\tWelcome!\n\n";

        cout << "Please enter value:  ";
        cin >> x;

        x = x + 5;

        cout << "Five more would get you " << x << ".\n";

        return 0;
    }

But don't worry as...

It IS only the beginning..!

More Arithmetic Operators

    ( )
    - * / % +
    + -

The ( ) can be used to change the order of operations from that of standard convention. (i.e. Parentheses can [temporarily] alter the precedence of enclosed operations.)

- can be used in unary fashion for 'negation' or taking the opposite.

+ can also be used in a unary fashion. It does nothing — at all.

% is used to determine the remainder during integer division (see below).

More Data Types

  • Numeric?
    • Need fractional parts? double
    • No decimal places, eh? Then how large is the value?
      • [magnitude] less than ~32k, short
      • more, long
  • Not a number, eh? Is it purely logical in nature? bool
  • Not numeric or logical, eh? char

Now that you've chosen a data type, tell the compiler what kind of variables you'll be using:

    data_type var_name;

    // or if you have more than one of a single type:

    data_type var_name_1, var_name_2, ...;
One's from a library...

string is a class data type for storing a sequence of characters all at once. (This can be handy since a single char variable can only hold a single character at a time — new values obliterate old ones!) It is located in the string library. (Don't forget to #include it if you want to declare string variables!)

The string has taught = how to assign it new values from both literal strings and literal chars. It has also taught cout's insertion operator (<<) to display all of its component characters in proper sequence. And, it even taught cin's extraction operator (>>) how to store a new sequence of characters — terminated by any spacing! — into it.

If you need to read strings that contain spaces from a user, you may use the getline function. It is conveniently located with the string class in the string library. It has the strange syntax of:

    getline(cin, string_var);

The parentheses (( )) are acting just as they do in algebra to evaluate the function. If you haven't already, you'll most likely soon find out that even in math, functions can have more than a single input. (In fact, we took that trick from the mathematicians. *grin*)

Just be aware that getline can be slightly unsafe in the 'hands' of unwitting users. It will happily tell you that they entered an empty string!

Not All Arithmetic was Created Equal

When you divide floating point types (purely or mixed with an integer partner), you receive a floating point result as expected:

    7.0 / 5.0 --> 1.4
      7 / 5.0 --> 1.4
    7.0 / 5   --> 1.4

However, when only integers are involved in a division operation, the computer feels that you must only want the integer portion of the result and so:

    7   / 5   --> 1

Where'd the .4 go?! Well, first off, let's recall that the .4 is really a 2 — out of 5:

         1  R 2
      ------
    5 )  7
       - 5
        ---
         2

So, we aren't really looking for a .4, but rather a 2. And, as it happens, it is calculated by the computer at the same time as the 1 — it just didn't tell us about it. So, C++ allows us to use the math concept of 'modulo' to access it. ('modulo' is a fancy Latin for "where's the left-overs?"...essentially...*shrug*)

Unfortunately, our C ancestors chose the % symbol to use for this operation. (No, it has nothing to do with percentages!!! *sigh* *shakes head* *light moaning*)

So, if we divide pure integers, we get just the integer quotient. And the remainder is found with the modulo operator (%):

    7   / 5   --> 1
    7   % 5   --> 2

This amazingly tricky bit of weirdness comes in quite handy for many things, the most obvious of them being converting units within a single system — most especially the old English systems of measure. Whenever you start with a [large] measurement in a smaller unit, you can use integer division and modulo (%) to convert that single value into a set of equivalents which are [typically] each smaller values. For instance, if you knew that you were going to receive 231 cents in change, what bills and coins would you expect? I doubt you'd want or expect the 231 pennies, right? But, using integer division and modulo, we can group the 231 cents into fewer sub-groups and find the proper bills/coins to use:

    231 / 100   --> 2     (100 pennies in a dollar; so 2 dollars)
    231 % 100   --> 31    (taking out the 2 dollars, there are 31 cents left)

     31 /  25   --> 1     (25 pennies in a quarter; so 1 quarter)
     31 %  25   --> 6     (taking out the quarter, there are 6 cents left)

      6 /  10   --> 0     (10 pennies in a dime; we have no dimes)
      6 %  10   --> 6     (taking out nothing, we still have 6 cents left)

      6 /   5   --> 1     (5 pennies in a nickel; we have 1 nickel)
      6 %   5   --> 1     (taking out the nickel, we have 1 cent left)

There are other uses for modulo besides unit conversion, but they can be less obvious and often are more intimidating...so we'll look at them as they come up.

Type-casting...

C++ has three forms of type-casting (i.e. casting one type into the form of another; like a shadow casts from a real object or like a cast is made in the form of a limb or model). One was inherited from our ancestor language, C:

    (desired_data_type)value

For instance:

    (double)long_var / short_const   // produces a double result

    (long)(long_var * double_var)    // produces a long result

This variation, however, will do things to your data that just plain shouldn't be done to data. It is twisted and sick and should be left back in the C language where it belongs!

The second is a C++ core feature:

    static_cast<desired_data_type>(value)

For instance:

    static_cast<double>(long_var) / short_const   // produces a double result

    static_cast<long>(long_var * double_var)      // produces a long result

This is our preferred method of temporarily changing one data type to look like another during a calculation.

The third was a pre-standardization C++ feature which was removed before the final standard was finished, but it was in use for several years before the removal was done and so still creeps up from time-to-time. Please do NOT use this version!!! (I'm only telling it to you so you can realize what it is and fix it to use the above form instead...)

    desired_data_type(value)

For instance:

    double(long_var) / short_const   // produces a double result

    long(long_var * double_var)      // produces a long result

Its primary deficiency is that it cannot be used with types like long double or unsigned short which are formed with two words. All data types work with both the C type-casting form and the C++ static_cast technique.

Unfortunately, the C form will do things to the underlying bits that just should not be done under normal circumstances. I'll spare you the gory details, but trust me that you don't want to use a C-style type-cast any more than you want to use the old C++ style. Basically we are left with the static_cast option.

Oh, yeah, "libraries"...

characters of strings and Calling Functions

Other Math Operations?

To do other mathematical operations like powers/exponents, absolute values, logarithms, or trigonometric functions we need to bring in the cmath library:

  • pow(base,exponent) results in the base raised to the exponentth power.
  • sqrt(x) is a more specialized way to calculate the square root of x. (It is more efficient than calling pow with a 0.5 for the exponent.)
  • fabs(x) is a faster way to take an absolute value than taking the square root of a square of x.
  • exp(x) is also a specialized function for calculating the mathematical constant e to the xth power.
  • log(x) is the poorly-named natural logarithm function.
  • log10(x) is the slightly less-poorly-named common logarithm function.
  • sin(x), cos(x), and tan(x) are the trigonometric functions. All arguments must be given in radians.
  • asin(x), acos(x), and atan(x) are the inverse trigonometric functions. All results are given in radians.
  • atan2(y, x) is a special inverse tangent function designed to have an output range of [-π, π] rather than the standard (-π/2, π/2). By selecting particular y and x values, it will give an angle in a particular quadrant. For instance, atan2(0.0, -1.0) will result in the value of π...better than you could type in by hand, anyway.
  • floor(x) is known in maths as the greatest integer function. More wordily, it results in the greatest integer value (represented as a double, though) which is less than or equal to x. Um...it truncates more cleanly than type-casting does — working on values that wouldn't actually fit in an integral type: floor(1234567890123.45) gives 1234567890123 rather than the slightly less useful 2147483647.
  • ceil(x) is known in maths as the least integer function. More wordily, it results in the least integer value (represented as a double) which is greater than or equal to x. Um...it...er...forces the value up if it isn't already 'whole'.
Round and Round We Go!

Note that there is no rounding function provided. However, we can build one by simply using the floor function and a little algebraic fun! If we were to graph the floor function and our concept of rounding (to the nearest whole number), we'd find that the two looked almost identical except for their horizontal placement. They are offset from one another by 0.5 in the x direction. Thus, to build a rounding expression/formula from our given floor function, we'll need to shift it 0.5 to the left. As algebra goes, this means adding 0.5 to the floor function's input (x): floor(x+0.5).

To generalize slightly, though, we don't always want to round to the nearest whole number. Sometimes we want to round to the nearest hundredths, the nearest thousands, or maybe even the nearest multiple of three or 25 or 4.032. (*shrug*) For this kind of trickery, we can actually simply use our desired 'place' (or our target multiple base) as a scaling factor and transform the original value to a base of 1.0 and then scale the rounded value back out to the original multiple base. Um...like this: floor(x/place+0.5)*place. (Yeah, I know...just trust me, won'cha?)

Making Our Displays Pretty

cout.setf(flag); can set a flag (like a flag-person on a highway work crew or a dude with the light sticks on an airport runway or a boyscout with a set of semaphore flags...) so that cout's insertion (<<) operator will know how we'd like certain data displayed.

Chief among these is floating-point data types. Much like a scientific calculator you'd use for maths, << will determine at times that displaying a value would take too many characters on the screen because the number is too small or too large. In these situations, the value will instead be shown in scientific notation (although it may very well display e instead of E as mathematicians and lab scientists are accustomed).

To have << not do this, we need to fly (aka set up) a flag to catch its attention. Then, when it is displaying floating-point data, it will notice the flag and not even worry about the value being too small or too large. In <<'s view of things, it is leaving the decimal point fixed in place — right there behind the ones' position. In fact, it has a constant for this concept stored in a class shared by lots of input and output folk: ios_base.

Of course, since the constant is inside of the class ios_base, we can't just say 'fixed', or the compiler wouldn't know what we were talking about! Instead, we have to use the syntax 'ios_base::fixed' (without the ticks, of course) to denote the constant named fixed from inside of (::) the class named ios_base. (This is similar to our earliest program with library support where we could have used 'std::cout' to refer to the screen object — since cout is declared inside of (::) the namespace std. The only difference is that here we are referring to a constant rather than a variable/object and it is inside a class rather than a namespace.)

Putting it all together, we'd want:

    cout.setf(ios_base::fixed);

Placed somewhere in our program before we began to insert (<<) floating-point values into cout. (If we don't fly/set the flag until after we print, how would << know what we wanted it to do?)

Unfortunately, making sure cout always inserts floating-point values in a fixed or 'normal' notation isn't quite enough. We also need to make sure that we're getting the proper number of decimal places on those floating-points. This will require two steps. The first is to tell cout how many decimal places we'd like to see. We do this with the slightly misnamed precision function:

    cout.precision(2);

Again, this can be placed in your code anywhere before you begin to insert (<<) floating-point values for screen (cout) display.

You'd normally think that we'd be done with that task, but cout is a little too self-assured for that. It is absolutely certain that any decimal places which are merely 0 would be useless to display — even if we just asked it for those positions! To prod it into doing what we want, we'll have to fly/set another flag: ios_base::showpoint. This flag tells it to display all requested decimal positions — even if they appear insignificant!

    cout.setf(ios_base::showpoint);

So, to sum up, there would be three lines of code to set up beautiful output of floating-point values. Make sure to place these before your code to actually display the floating-point values!

    cout.setf(ios_base::fixed);
    cout.precision(2);
    cout.setf(ios_base::showpoint);

time to Make the Donuts...

If you ever need to know anything about time of day or length of time or the like, you'll want to have the time function from the ctime library handy. (Make sure to #include ctime with your other used libraries up at the top of your program's source file!)

Calling time(nullptr) will return to you the number of seconds which have passed since [the first] midnight on January first of 1970 ...GMT. This date-time is known as the 'epoch' of computer time and could be an entire lecture of its own — let's just take note of its craziness and that the units are 'seconds'.

We can use the units conversion concept from back in the modulo section:

    short hour, minute;

    hour = time(nullptr) % (60*60*24) / (60*60);
    minute = time(nullptr) % (60*60*24) % (60*60) / 60;

Of course, that's kind of ugly and less intelligible, so let's get rid of the magic and make it a bit sleeker:

    const short HRS_PER_DAY = 24,
                MIN_PER_HR  = 60,
                MIN_PER_DAY = MIN_PER_HR * HRS_PER_DAY,
                SEC_PER_MIN = 60,
                SEC_PER_HR  = SEC_PER_MIN * MIN_PER_HR;
    const long  SEC_PER_DAY = static_cast<long>(SEC_PER_HR) * HRS_PER_DAY;

    long sec_today = time(nullptr) % SEC_PER_DAY;

    short hour, minute;

    hour = sec_today / SEC_PER_HR;
    minute = sec_today % SEC_PER_HR / SEC_PER_MIN;

There, that's more manageable, readable, and handy...

Determinism Bytes

When things are always the same, it can be comforting. But the world is a dynamic, growing, shifting place. And sometimes, comforting becomes tedious instead. One of the most obvious places to note this is a game of Solitaire. If the deck couldn't be shuffled differently, and its current order dealt an un-winnable Solitaire hand...that would SUCK! Don'choo think?

So let's mix it up a bit! In math terms, we want things to be more random. In computer terms, there is no such thing as true randomness, but we have what we call 'pseudo-random'. Basically, a large segment of the whole numbers was roped off. The top of the segment can vary from compiler to compiler, but they all call it RAND_MAX. Unfortunately, they also aren't clear as to whether RAND_MAX is or is not included in the segment of numbers! That is, is the interval of pseudo-random values [0..RAND_MAX] or is it [0..RAND_MAX)? Well, since the compiler writers can't agree, we'll just have to be careful at that end. For now, though, I'll use the made up notation [0..RAND_MAX} to say that I'm not sure if the end is closed or open. (Cheap, but it works...)

Now to actually pull a pseudo-random value out of our interval, we use the function rand(). This function, kinda like the main program, needs no information before it selects the next pseudo-random value. It knows the pattern/algorithm used to select values and it knows where it last was (which is pretty cool, but a topic for another lecture). So we just need to call the function from our program:

    cout << "Random value is " << rand() << ".\n";

Well, almost. First of all, both RAND_MAX and rand() are in the old C library cstdlib. So we have to remember to #include that with our other libraries at the top of our source code file.

Next we'll notice that the value is rather awkward. Especially since we don't even know what the upper bound of the pseudo-random selection interval is! To deal with that, we can return to our friend modulo. Mathematically, you see, all modulo results are between zero and the divisor — less one! That is, all modulos by 4 result in 0, 1, 2, or 3. If 4 were a possible result, then we really could have had one more on the quotient, right? (Remember, modulo gives the left-overs or remainders. If we're dividing into groups of 4 and end up with 4 left over, we really could have made a whole other group ...which would leave none left over!)

So we modulo by the number of values we desire and then scoot these 'left-overs' to the proper starting position along the number line:

    cout << "You've drawn the " << (rand() % 52 + 1)
         << " card.\n\t(Please refer to your manual for the table of"
                  " playing card identification numbers.)\n";

Well, I suppose that last bit is a bit less than gratifying, we'll have to work on that!

But, in general, you can use the formula rand() % (max-min+1) + min to choose a uniformly-distributed, pseudo-random value from the integer range [min..max].

Note that the +1 inside the divisor for the modulo operation has nothing to do with either the minimum value or the maximum value of your desired range. It is all about the classic fence-post problem.

What do you mean you've never heard of the 'fence-post problem'? You encounter it almost daily!? Well, essentially, to build a fence requires one more post than sections of fence you desire to build. If you don't have that extra post, the last section of fence will fall down. (The other sections share a post with the following section as well as having their own. The last one has no following section.)

It is also an issue when determining how many items are in a range of discrete values (those that are set apart like the integers as opposed to those which are continuous like the reals). So, if you had an assignment to read Chapter 4 which started on page 115 and ended on page 152, you wouldn't be reading 152-115=37 pages. In fact, you'd be reading 38 pages! The subtraction removes the first 115 pages of the book from your 'total', but you actually needed to read page 115 as well. So, after the subtraction, you must add that first page back in.

It is also the reason that the short data type is lop-sided: [-32768..32767]. With 16 bits, we could store 216=65536 values. If we divide that in half, we get 32768 — the magnitude of our minimum value. So why is the maximum one off? Because the 0 takes up a bit-pattern and therefore takes up 'space' in our range of allowed values. (Okay, this one is stretching it a bit, but it is at least related!)

Ensuring we really Got a Line!

It turns out that getline won't necessarily fill your string in with a line full of data! It sees its calling as "pull characters out of cin's buffer until a '\n' is seen, storing all but that terminal '\n' into the specified string object." It sounds so complete and innocent! What could go wrong?!

Let's look at the order of inputs from our user for a second. Let's say that we read the user's name and age into a program. If we read it in that order — name followed by age — we might have this:

    string name;
    short age;

    getline(cin, name);

    cin >> age;

(I've taken out the couts for prompting to keep things more focused.)

Now a user can easily get their information to us with no problems. But if we simply reverse the order of the inputs:

    string name;
    short age;

    cin >> age;

    getline(cin, name);

Suddenly! We have a problem... Compare the two situations side-by-side to see more closely what's happening:

What... Read Name First Read Age First
Code:
    string name;
    short age;

    cout << "Prompt for name:  ";
    getline(cin, name);

    cout << "\nPrompt for age:  ";
    cin >> age;

    cout << "\nWelcome to the program " << name
         << ", let's get going!\n\n";
    string name;
    short age;

    cout << "Prompt for age:  ";
    cin >> age;

    cout << "\nPrompt for name:  ";
    getline(cin, name);

    cout << "\nWelcome to the program " << name
         << ", let's get going!\n\n";
User
Interface:
    Prompt for name:  my name is Jim

    Prompt for age:  42

    Welcome to the program my name is Jim, let's get going!

    ...
    Prompt for age:  42

    Prompt for name:   
    Welcome to the program , let's get going!

    ...
cin's
Buffer:
    my name is Jim\n         getline comes over,
                                 and uses up
                                 ~everything~:
    my name is Jim\n         it stores the
                                 "my name is Jim"
                                 in our variable
                                 name
                             with its buffer empty,
                                 cin will pause the
                                 program to refill
                                 ...if necessary...
    42\n                     >> comes along, and uses
                                 just the ~visible~
                                 characters:
    42\n                     storing 42 in our
                                 age variable, but
                                 leaving the new-line
                                 from the user's
                                 Entery behind...
    42\n                     >> comes along, and
                                 uses just the ~visible~
                                 characters:
    42\n                     storing 42 in our
                                 age variable, but
                                 leaving the new-line
                                 from the user's
                                 Entery behind...
    42\n                     getline comes over, and
                                 uses ...the only thing
                                 that's left:
    42\n                     and it stores "" in our
                                 name variable...oops!
                             (note that the program
                                 doesn't even pause to
                                 allow them to enter
                                 their name — and our
                                 line spacing is off...
                                 *bleah*)
                             and NOW cin will pause
                                 the program to refill
                                 its buffer...

Um...so how do we fix it? Well, there are two possible techniques... The easier of them is to let the problem occur and then clean up afterwards:

    getline(cin, name);
    while (name.empty())
    {
        getline(cin, name);
    }

We simply insert a while loop immediately after the getline call to repeatedly perform another getline call while the name that we just read in was empty... Yeah. Simple...

Let's dissect it a bit. First, let's agree that the English term while here means "as long as". The purpose of a while loop is to repeat the code in the following block/statement for as long as the boolean condition in its parentheses evaluates to true. Were the condition to evaluate to false, the program would jump over the body of the loop and pick up after its closing brace (}).

So, here, we have the condition name.empty(). Which we learned from our flag discussion is read from right to left as: "call the empty function with respect to the name object." Since our name object is of the string type, the compiler makes sure that strings have an empty function. They do! It takes no information (hence the empty parentheses on the call — just like with rand()) and returns true when the string in question contains nothing (i.e. an empty string"") or false when the string contains ...well, something.

The last piece of the puzzle is to note that the close brace (}) on the while loop has a wormhole connected back to the condition at the head of the loop. (Well, not really, but there's just not the right visual structure in a text file to show that that is what is meant. We do our best with indention and the braces, but it just isn't "all that". *sigh*) This keeps the loop going until the condition becomes false, at which point the computer does a little 'cliff' diving to go over the wormhole and reach the code that follows the loop's body.

Foolproof..?

Notation is Clearly in the Way

Mixing character variables amongst numeric type inputs is an easy way to pull human notation out of an input stream during data acquisition.

For instance, were the user to be entering the time [of day] that some event was to take place, our program might look something like this:

What hour will the event begin?  2

What minute will the event begin?  30

Thank you!  It is noted that the event will begin at 2:30.

By contrast, this code:

    char t;
    short hour, minute;

    cout << "What time will the event begin?  ";
    cin >> hour >> t >> minute;

    cout << "\nThank you!  It is noted that the event will begin at "
         << hour << ':' << minute << ".\n";

Can allow the user to interact more naturally:

What time will the event begin?  2:30

Thank you!  It is noted that the event will begin at 2:30.

And it can even lead us toward more interesting input processing possibilities!

What time will the event begin?  2:30 pm

Thank you!  It is noted that the event will begin at 2:30 P.M.

Or:

What time will the event begin?  14:30

Thank you!  It is noted that the event will begin at 2:30 P.M.

Or even:

What time will the event begin?  2:30

Thank you!  It is noted that the event will begin at 2:30 A.M.

Now You See It...Now You Don't!

Lazy humans seem to have an actual need to only include data when it is absolutely necessary. Note the above input samples, for instance: with 24-hour time, the 'A.M.' and 'P.M.' are not needed; the user doesn't type the periods technically supposed to be after both 'P' and 'M' (and don't bother to hit the Shift key); and when it is 'A.M.', they leave it off altogether!

But that is only the begin...er...ending? Users are also known to leave out information that might come at the beginning of a quantity if they feel it should be understood. Like for a date: 7/14 might be entered, leaving the year to be understood as 2007. Or for a phone number: 925-6697 might be entered, leaving the area code to be understood as 847 (not to mention the *glorph-mmph-urp-thbbt* HEY! STOP THAT! ...the leading 1- which we have been ordered by the phone companies must be dialed!).

For these situations, we'll need to look into the peek function for use with cin. This function returns the very next character which would be considered for input from the buffer, were we to actually try to input something — rather than just peeking ahead at it. (Come on! You've never played 'peek-a-boo' with a kid before? It's great fun!)

    cin >> ws;
    if ( 'd' == tolower(cin.peek()) )
    {
        num_dice = 1;
    }
    else
    {
        cin >> num_dice;
    }
    cin >> d_sep >> num_sides;

Here we throw out any leading white-space before peeking at the next character to see if it is a 'd'. (I'm also being helped out here by the tolower function from over in cctype, but that might be another story...) We need to throw out the white-space, however, because our eventual plan is to extract (>>) data from cin's buffer and extraction thinks all white-space is crap — leading or trailing. peek is much more open-minded and believes all characters were created equal. (Thank goodness the == operator doesn't, eh?! *grin*) So we throw out the white-spaces that might lead off our user's input sequence before we peek for the data.

In our case, we'll be either reading the number of dice the user wants to roll or setting it to the assumed/understood value of 1 die. (No, that is NOT a typo — the singular of 'dice' is 'die'.) Either way, we then read in the 'd' 'separator' and the number of sides these dice(?) will each have. (A roll consists of a single type or size of die — no mixing and matching!)

Of course, this leads us back to our original dilemma: data at the end of the sequence which might be left off. peek will once again be helpful, but ws would be a killer! If we were to use ws to get rid of those potential white-spaces, it would happily eat through even the new-line ('\n') that follows the user's input (from when they hit Enter, remember?)! Then we wouldn't realize that we'd finished their entry and were really working on data from another! In fact, the user might not know it either, because they might not see the next prompt come up! EEK!!!

To alleviate this bit of pain, we'll go with our own version of ws built from extra peeks, an ignore, and some character tests:

    while ( '\n' != cin.peek() &&       // next char is NOT end of input
            isspace(cin.peek()) )       // but it is ~some~ kind of spacing
    {
        cin.ignore();
    }

Using this loop structure before peeking for potential trailing data allows us to still skip those nasty white-spaces that extraction dislikes so much, but still not cross over the end of the user's input — and thus realize if the data was or was not there!

    // after the 'ws' loop:
    if ( '\n' != cin.peek() )
    {
        // data must be here!  read it!
    }
    else
    {
        // nope...just a new-line...we'll have to assume a value(s)
    }

failure IS an Option

They might just be truly clumsy, but man can users ever type what you ask for? *whew*

You just have to remember to ask cin if it has failed after numeric inputs you are worried about the user having screwed up. If it has, then you'll need to clear its memory of the error (it has a flag to remember when it has recently failed — much like you'd keep a bool variable to remember recent events in your program). The first thing to do after clearing out the error flag, though, is to remove the offending character(s) from the buffer! If you don't, the next extraction (>>) will fail just as spectacularly as the one that got you here!

Last piece of advice: use a loop rather than a branch to clear up users' failed inputs. If they screwed it up once already, what are the odds that they'll screw it up again? I'd say pretty good...

    cin >> numeric_variable;
    while ( cin.fail() )
    {
        cin.clear();
        cin.ignore();  // optimistic -- just one char was bad
        cin >> numeric_variable;
    }
    // by here, we really do have a number stored in the variable!

Or perhaps:

    cin >> numeric_variable;
    while ( cin.fail() )
    {
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');  // realistic -- who knows how many bad chars?!
        cerr << "\n\aInvalid data!  Numerals only, please!\n";
        cout << "\n...repeat original prompt here...";
        cin >> numeric_variable;
    }
    // by here, we really do have a number stored in the variable!

Or maybe even:

    cin >> numeric_variable;
    while ( cin.fail() )
    {
        cin.clear();
        cin.ignore();
        if ( '\n' == cin.peek() )  // if everything is gone, nudge them harder
        {
            cerr << "\n\aInvalid data!  Numerals only, please!\n";
            cout << "\n...repeat original prompt here...";
        }
        cin >> numeric_variable;
    }
    // by here, we really do have a number stored in the variable!

More about Flow Patterns

Ooooo...Do It Again!

Repeating code until the user tires of it — but no longer!

    char yesno;

    cout << "\nWould you like to begin?  ";
    cin >> yesno;
    cin.ignore(numeric_limits<streamsize>::max(), '\n');
    while ( 'Y' == toupper(yesno) )
    {
        // do stuff we want to repeat here

        cout << "\nWould you like to go again?  ";
        cin >> yesno;
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    }

Of course, the cheap route would be to merely assign a 'y' to the variable so that the loop (and the user) would be forced to 'repeat' once...but that's not very nice and might not even be good for us, either.

Branches Don't Have to Be So Controlled

    choice = rand() % number_of_choices;
    if ( 0 == choice )
    {
        // first action
    }
    else if ( 1 == choice )
    {
        // second action
    }
    // . . .
    else if ( number_of_choices - 2 == choice )
    {
        // next-to-last action
    }
    else // choice must have been number_of_choices-1
    {
        // last action
    }

Accumulators

Sometimes it is useful to accumulate a value over the course of several loop iterations. This fact occurred to mathematicians years ago and hence they developed the use of capital sigma and capital pi to accumulate over addition and multiplication, respectively.

       5
    -------
    \
     >    i  =  1 + 2 + 3 + 4 + 5  =  15
    /
    -------
     i = 1
       5
    -------
     |   |
     |   | i  =  1 * 2 * 3 * 4 * 5  =  120
     |   | 
     i = 1

For us, this is simply a properly initialized variable used through consecutive iterations of a loop:

    sum = 0;
    i = 1;
    while ( i <= 5 )
    {
        sum = sum + i;
        i = i + 1;
    }
    prod = 1;
    i = 1;
    while ( i <= 5 )
    {
        prod = prod * i;
        i = i + 1;
    }

Here i is iterating through the values 1, 2, 3, 4, and 5. When the last update of the loop takes it to 6, the loop condition fails (becomes false) and the loop ends before its body is executed another time.

Note also that the accumulator (sum and prod) is initialized with the identity for its operation — 0 for addition and 1 for multiplication. This makes the actual accumulation work on the first loop iteration. With an inappropriate (or no) initializer, the accumulator simply doesn't!

Synchronous...Asynchronous...It ALL Hurts My Head!

Nesting of flow control structures is something that makes even the strongest of folk shudder with fear ...at times. We're not talking the fear of commitment that a prospective bride or groom might feel — wrong kind of 'nest' there. We're talking about taking a branch or loop and placing it inside of another flow control structure — maybe the same kind, maybe not...

Branches in Branches
A Branch in an if

(It might be an &&...)

A Branch in an else

This type of nesting leads to a style issue. It causes hideous levels of indention for little or no reason. To fix the style problems, we developed a structural style known as the cascaded (or cascading) if.

Loops in Loops

Nesting with repetition involved can often be the worst of them. Even this first form which is still entirely synchronous (that is, it executes along an easily predicted temporal pattern — the steps of its execution are 'in sync' with one another) can be mildly nauseating at first glance.

A loop inside another loop leads to an inherently two-dimensional process, you see. Consider that the flow of a single loop — all alone — is one-dimensional. As the loop executes along, its LCV moves from one state to another:

    // LCV initialized
    while ( /* LCV is not a terminal value */ )
    {
        // body
        // LCV updated
    }

Or, more specifically:

    count = 0;
    while ( count != 5 )
    {
        cout << '-';
        count = count + 1;
    }

This loop will cause one dash ('-') to be printed right after its predecessor as count follows a predictable and prescribed path from 0 to 4. When that last dash has displayed, the while will terminate because the counter will have reached its final value of 5. Since the dashes are printed while the counter is not equal to 5, we've displayed five of them.

-----

Although this might at first sound ludicrous, it is correct because of our initial state of 0 for the counter. This all goes back to the issues we had with fences and fence posts earlier.

If I were to place this one-dimensional construct inside another, we'd necessarily get a two-dimensional result:

    row = 0;
    while ( row != 7 )
    {
        column = 0;
        while ( column != 5 )
        {
            cout << '*';
            column = column + 1;
        }
        cout << '\n';
        row = row + 1;
    }

This produces seven rows ('\n') of five stars ('*') each:

*****
*****
*****
*****
*****
*****
*****

Notice how the columns loop executes all of its iterations during each single iteration of the rows loop. We often refer to the one inside the other as the inner loop and the one it is inside as the outer loop — wild as that may seem!

Branches in Loops
Increasing the Flexibility: Default Option Values

Often used for menus...

Use a bool to keep track of whether certain events have or have not yet occurred. Since the branches do not execute in a synchronous manner (i.e. they are asynchronously executed), you cannot predict which branch has or has not been chosen by the user to execute.

Using the bool to remember if a branch has (true) or has not (false) executed yet is a simple trick that many beginning programmers forget. It can keep you from repeating lots of tests meaninglessly — like checking all of the characters that could mean the user chose to quit from the menu loop both in a branch (avoiding displaying that "\aInvalid choice!" message when they legitimately chose to quit) and again in the loop condition — only logically negated — so we can eventually stop.

This trick can also help you track whether data has been entered so that you don't allow them to operate on it/with it before it has been input. (This is kind-of like the 'grayed out' menu items in a GUI menu.)

It can also help you to implement user 'options' or 'preferences' that are on/off (yes/no, etc.). If they choose the menu option to toggle the preference, you set the bool to its logical opposite and just try to display the current state in the menu choice:

    bool pref_is_on = true;
    string pref_state = "ON";
    // . . .
        cout << // . . . display head of menu . . .
             << "#) preferenCe menu choice tExt [" << pref_state
             << "]\n"
             << // . . . display rest of menu . . .
             /* . . . and read user's choice . . .
              * cin >> choice;
              * cin.ignore(numeric_limits<streamsize>::max(), '\n');
              * choice = toupper(choice);
              */
        /* else? if ( choice == 'C' || choice == 'E' || choice == '#' ) */
        {  // preference chosen branch
            if (pref_is_on)   // it is _currently_ on
            {
                pref_is_on = false;
                pref_state = "OFF";
            }
            else              // it will _now be_ on
            {
                pref_is_on = true;
                pref_state = "ON";
            }
        }

Such an option would originally display in the menu as:

             #) preferenCe menu choice tExt [ON]

But after the user had chosen it, the menu display would change to:

             #) preferenCe menu choice tExt [OFF]

(Note how the display tells the current state of the option — not what choosing the option will change it to! It is important to keep things like this consistent across your entire application for the user's [remaining] sanity.)

More Controlled Alternation of Action

If you had a counter variable (either your LCV or just going along with the loop for the ride), you could have certain tasks within the loop alternate in some fashion. One of the most common is a 1-1 flip-flop. That is, one task is done on the first iteration and the other task is done on the second and then they repeat. Such an alteration can be controlled by checking the even/odd -ness of the counter variable.

But how can we tell if a variable is even or odd? Oh, yeah, divisibility by 2. But how can we check divisibility?! Oh, yeah, there are no left-overs — no remainder — when a value is evenly divisible.

So, then, we just set up the loop with a nested branch that checks the divisibility of the counter by 2 to decide which of our flip-flop actions to perform:

    count = 1;
    while ( /* loop condition -- true to keep going */ )
    {
        // other tasks that always happen first..?
        if ( count % 2 == 0 )
        {
            // counter is even -- task flip
        }
        else
        {
            // counter is odd -- task flop
        }
        // other tasks that always happen last..?
        count = count + 1;
    }
Loops in Branches

By this point, most folks have grown numb to the nesting madness. I've not got any special new warnings for you here. Have fun!

Loops Used to Process strings

At first, it seems that the string class is self-sufficient for any processing we'd ever need to do:

What more could we possibly want to do to/with strings?!

Repeated Substitution

    string::size_type pos, shift;
    string str, find_me, repl_with_me;
    // . . .
    if ( /* the find_me string could be created by the repl_with_me string
            abutting the original str contents -- or is simply within the
            repl_with_me string, we ~might~ want to zealously check for the
            find_me */ )
    {
        shift = 0;
    }
    else // we can be more efficient by skipping the replaced text when
    {    // looking for the next occurrence of the text to find...
        shift = repl_with_me.length();
    }
    pos = str.find( find_me );
    while ( pos != string::npos )
    {
        str.replace( pos, find_me.length(), repl_with_me );
        pos = str.find( find_me, pos+shift );
    }

Alteration of Case

    string::size_type pos;
    string str;
    // . . .
    pos = 0;
    while ( pos != str.length() )
    {
        str[pos] = to___er( str[pos] );
        pos = pos + 1;
    }

Modular Program Design with Functions

Reviewing Math and Library Functions

Layout of a Program with Its Own Functions

    #include < . . . >
    using namespace std;
    const'ants
    typedef'initions
    prototypes
    [inline function definitions — see below]
    main
    (other) function definitions
The Three Parts of a Function
  • prototype/declaration
  • call
  • definition

The Simplest Kind(s) of Function

Quick Vocabulary Lesson: Ins and Outs
Input(s) and Output
return_type function_name(arg_type arg_name)
{
    // . . .
    return return expression;
}

return_type function_name(arg_type arg_name, arg_type arg_name)
{
    // . . .
    return return expression;
}
Input(s) but NO Output
void function_name(arg_type arg_name)
{
    // . . .
    return;
}

void function_name(arg_type arg_name, arg_type arg_name)
{
    // . . .
    return;
}
NO Input(s) but Output
return_type function_name(void)
{
    // . . .
    return return expression;
}
NO Input(s) AND NO Output
void function_name(void)
{
    // . . .
    return;
}

Increasing the Power: Reference Arguments

Using const with Arguments

Increasing the Flexibility: Overloading

  • same name — why pick a different name when the one we were using is perfectly clear?!
  • similar purpose — if the task/goal of the function is much different, we'd not want to logically connect them by naming them the same way, now would we?
  • different number of arguments — the easiest way to distinguish overloaded functions is that they have a completely different number of arguments: cin.ignore(numeric_limits<streamsize>::max(), '\n') vs. cin.ignore(), for instance
  • different [data] types of arguments — slightly more difficult is when the overloaded functions merely differ in the types of their arguments; this may require typecasting at the call to help the compiler tell which version we desire to use

Increasing the Flexibility: Default Arguments

  • only at [right] end of argument list
  • simply add = and a default initialization value after the argument name
  • caller cannot skip defaulted arguments — only leave them off of the end of their actual argument list
  • rarely default non-constant reference arguments, since we have no global variables to which they might refer by default

Increasing the Speed: inline'ing

  • place inline keyword before return type in function head
  • since some compilers have trouble with prototyping inline functions, replace the prototype with the definition
  • only inline small, short, simple functions:

    • NO loops
    • five (5) or fewer branches
    • twenty (20) or fewer statements

Increasing the Power: Separate Compilation

(AKA our own libraries.)

The Typical Parts of Se-'par'-ate
What Goes Where?
Putting It All Back Together..?

Data Abstraction for Implementation

Why do we do this, again?

Abstract Data Types

The structures of C
Improvements via classes in C++

Specifying private vs. public Access

Accessors and Mutators

Constructors

Default, Copy, and ...er...'with Parameters'

Why must the copy constructor take its parameter for the original object by reference?

How does overloading apply to the constructors of a class?

Initializer Lists

Behavior of constant Objects When Calling Methods

Cascading/Chaining Method Calls

Improving the Speed: inline for class Methods

Increasing the Re-Use: Putting classes in Libraries

Flow Control Gone Extra-Strictly Structured

New Repetition/Looping Structures

do Loops
for Loops

New Decision/Selection/Branching Structures

switches
The ?: Operator

Rewritable 1-Way Branches

Nesting of ?: operations...

A Little More Depth about bool

DeMorgan's Laws

Containing More Than Just characters

The vector class

The Library, Declarations, Element Access...
Putting Elements IN the vector

General List Management

Displaying the List
Adding a New Element
Looking for an Element
Removing an Old Element
Editing an Existing Element
Sorting the Elements

Properties of sorting algorithms...

Advanced sorting techniques...

Bubble sort...

Selection sort...

Insertion sort...

Adding a New Element II
Looking for an Element II
Removing an Old Element II
Editing an Existing Element II

Multiple Dimensions

2D, We Hardly Recognized Ye'!

One of the simplest 2D structures you can create and which is QUITE useful is a vector of strings:

      vector<string> blah;  // each element of the vector is a string
                            // a string is a container/collection of chars

A vector of strings is also easier to initialize to particular values (an inner vector would need push_back's or resize'ing and future subscripting).

For instance, here's some code to fill our blah vector with a few initial strings:

    blah.push_back(" 1 | 2 | 3 ");
    blah.push_back("---+---+---");
    blah.push_back(" 4 | 5 | 6 ");
    blah.push_back("---+---+---");
    blah.push_back(" 7 | 8 | 9 ");

And then we could print them on-screen like this:

    for (vector<string>::size_type b = 0; b != blah.size(); b++)
    {
        cout << blah[b] << '\n';
    }

Of course, you could fill the strings with any text you'd like:

    blah.push_back("####E######");
    blah.push_back("#  # # @# #");
    blah.push_back("#    ## # #");
    blah.push_back("#  #      #");
    blah.push_back("###########");

Or whatever!

Other Kinds of Dimensionality
Uses of Multiple Dimensions
Declaration and Sizing Beyond the First Dimension

Consider if the heights vector we created earlier were not a collection of students' heights but rather a collection of the height measurements for a [single] grade school student's 'grow the plant' project. So we have many measures of the same plant collected over time. This provides us with a one-dimensional storage need. (Yes, a single simple variable is considered zero-dimensional — a data 'point'. I don't think it's a pun...it is just what we call it. *sigh* *shakes head*)

    vector<double> heights;  // collect plant measurements during semester

But, if we wanted to collect the plant measurements for multiple students rather than a single student, we'd need more of a two-dimensional structure: each row representing a single student's collected heights for their plant. This can actually be done! All we'd said before was that the base type of a vector couldn't be void, right? There wasn't a rule that kept it from being another vector type, even!

Here's a vector storage structure that could hold the plant measurements for a whole class-full of students' plants:

    vector<vector<double> > heights;  // collect measurements during semester
                                      // for all students in class

(Yes, the space between the two closing angle brackets (>) is required for now. The next standard will make it officially optional, but in the mean time, there are compilers which think that your are trying to extract from the double — or something...)

If we had 10 measurements each for 4 students, the data in this vector might look something like this diagram:

    +-----------------------------------------------------+
    |    0    1    2    3    4    5    6    7    8    9   |
    | +----+----+----+----+----+----+----+----+----+----+ |
    | | .4 |    |    |    |    |    |    |    |    |    | | 0
    | +----+----+----+----+----+----+----+----+----+----+ |
    +-----------------------------------------------------+
    |    0    1    2    3    4    5    6    7    8    9   |
    | +----+----+----+----+----+----+----+----+----+----+ |
    | |    |    |    |    |    |    |    |    |    |    | | 1
    | +----+----+----+----+----+----+----+----+----+----+ |
    +-----------------------------------------------------+
    |    0    1    2    3    4    5    6    7    8    9   |
    | +----+----+----+----+----+----+----+----+----+----+ |
    | |    |    |    |    |    |    | 2. |    |    |    | | 2
    | +----+----+----+----+----+----+----+----+----+----+ |
    +-----------------------------------------------------+
    |    0    1    2    3    4    5    6    7    8    9   |
    | +----+----+----+----+----+----+----+----+----+----+ |
    | |    |    |    |    |    |    |    |    |    |    | | 3
    | +----+----+----+----+----+----+----+----+----+----+ |
    +-----------------------------------------------------+

Notice how each of the four primary elements is itself a vector and each of them holds ten height measures. (Although I've only filled in a couple of them...*sigh*)

But most of the time it is simpler to envision this structure as a simple grid:

       0    1    2    3    4    5    6    7    8    9
    +----+----+----+----+----+----+----+----+----+----+
    | .4 |    |    |    |    |    |    |    |    |    | 0
    +----+----+----+----+----+----+----+----+----+----+
    |    |    |    |    |    |    |    |    |    |    | 1
    +----+----+----+----+----+----+----+----+----+----+
    |    |    |    |    |    |    | 2. |    |    |    | 2
    +----+----+----+----+----+----+----+----+----+----+
    |    |    |    |    |    |    |    |    |    |    | 3
    +----+----+----+----+----+----+----+----+----+----+
Subscripting Beyond the First Dimension

.4 is at position 0,0. But we'd actually access this with heights[0][0] in our code. The first subscript operation specifies the row (element of the outer vector) and the second subscript specifies the column (element of the inner vector). Likewise, the 2. value is at heights[2][6].

Two ideas to keep in mind as dimensionality grows (pardon the pun):

  • keep your subscript use consistent throughout the program

  • keep your inner vectors a consistent size so that the overall structure is rectangular

Extending Algorithms to Multiple Dimensions

Rows vs. Columns

New Algorithms for Multiple Dimensions