C++ (The Book)

As the title indicates, this is all about C++.

Items (chapters and pages) will be added in no particular order though will be placed in logical sections.

This is a dynamic document (book), will be changing all the time. The pages of this book may not necessarily themselves make the front page of this site. In order to keep abreast of newly created or updated articles/pages in this book (or anywhere) merely check Recent Posts which is an item in the top menu of the site.

The chapters/pages of this book are listed below and also contained in the left sidebar when this book (or any other book) is being viewed.

Basic cin operations

The following attempts to explain the peculiarities of the cin object. Why it does, what it does.

cin >> getdata;

cin >> getdata;

This is the basic form of retrieving characters from the keyboard. The characters typed at the keyboard are sent to the input stream terminated by the 'ENTER' key. Once in the input stream they are allocated or assigned to the receiving variable, from the above example, getdata. What this means is that prior to the 'ENTER' key being pressed there is no control or checking of the characters typed.

So far, so good but there is a catch, well quite a few actually and we'll ease into them.

Firstly, this form only reads alphanumeric characters up until the first white space, tab, null or newline ('ENTER' key) character. (I'm not too sure how to type in a 'null' character, maybe leave that one for later)

Lets assume a user typed, this is really awkward stuff [ENTER]

From our example at the top of the page cin >> getdata; only the word this would be assigned (or attempted to be assigned/allocated) to getdata. This is because cin only accepted characters up until the first whitespace or only retrieves a series of characters (words) not containing spaces. The remaining words is really awkward stuff [ENTER] are left in the input stream. This is the source of many problems as the very next cin >> getwhatever; will retrieve the next word from the input stream, in our case, is. Still, the input stream now contains really awkward stuff [ENTER]

In general, if a line of text, which includes spaces and/or tabs, needs to be input, do not use this form of the cin object. Yes, there are other ways and there are ways to deal with this problem if using this form of the cin object and they will be the subject of another entry.

Returning to our example at hand cin >> getdata; there are other factors that come into play. The main 'other factor' is the data type of the variable getdata. To this point that hasn't been considered but as you'll soon see it plays an important and significant part of this whole cin >> getdata; saga.

Here is a more complete snippet of code in how a basic 'get data from the keyboard' is implemented.

char getdata[20];
cout << "Please enter your name? ";
cin >> getdata;

The above code snippet, if applied to our example above, would not throw any errors as the variable getdata is actually a char array having the ability to store 20 characters (enough for our purposes). Those characters being alphanumeric, which means numbers or letters or both. We still have the same issue that only the first word is received and assigned to the variable getdata.

Now the fun starts. Let's change the data type of the variable getdata from being an array to just a plain old char variable. Our snippet of code becomes:

char getdata;
cout << "Please enter your name? ";
cin >> getdata;

A line of text, including spaces and/or tabs, can still be entered, ending up in the input stream. The result is that only the first character of the input stream will be assigned to the variable getdata. The input stream still contains the user entered text, minus the first character. This behaviour occurred as the data type of the receiving variable getdata is of type char. This means it can only hold or store a single character (digit or letter).

Whether we need to receive only a single character or a word, if the input stream still contains characters then the next cin >> getwhatever; operation will retrieve them. This might not be the expected or intended result.

Now the real fun starts. What if the data type of the receiving variable is of type integer. It's only expecting numbers not letters. Here's our snippet of code:

int getdata;
cout << "Please enter your age? ";
cin >> getdata;

If a user types in abc where is that to be stored? The variable getdata can't receive it as it can only hold an integer (a number). What occurs is that the cin object throws an error and sets it's failbit to 'true'. The other error bit of the cin object is the eofbit which is an 'End of File' (EOF) error. In the context of this discussion the eofbit is not relevant.

The consequences of the cin object throwing an error (failbit or eofbit) is that no further calls to the cin object has any effect, they are ignored. This means if your program does in fact make use of the cin object after an error, it simply won't work as intended.

To clear the error state of the cin object issue this command:

cin.clear();

This clears the error state and further processing of cin object is allowed.

As you've probably guessed there may still be characters remaining in the input stream which need to be dealt with as well. On this point, the newline (\n) character 'ENTER' remains in the input queue/stream even upon successful keyboard data input. For this discussion that's not overly relevant as the very next cin object disregards any newline character if it's the first in the input queue/stream. This aspect becomes relevant when other forms of the cin object follow the basic form of cin >> getdata;. This will be the subject of another article.

How do we trap for incorrect data input? How do we know when to clear the cin object's error state? How do we know....? Well these are all valid questions and will be answered in the next article.

Related article : Asterisk Triangle Program in which trapping incorrect data input and restricting input to a valid numeric range is discussed.

cin.getline (arrayname, size);

So you want to read an entire line from the keyboard and not be bothered with cin >> getdata; only reading the first word. Then this form of the cin object is for you.

cin.getline(arrayname, size);

This form accepts an entire line entered from the keyboard terminated by the 'ENTER' key. The newline character created by the 'ENTER' key is replaced by a null '\0' character (which is the terminating character required for character arrays). As you can guess from the code snippet, the line of text is ultimately assigned to arrayname variable, a character array, and only receives the number of characters specified by the second parameter, size.

If the number of characters entered is greater than the number specified by the second parameter size the left-over characters remain in the input queue/stream. Remember, the next cin operation will retrieve either some or all of these characters depending upon the type of cin operation that's applied. If the number of characters is less than the parameter size then the input queue is effectively flushed and will not be a problem for the next cin operation.

cin.getline(arrayname,size) also has a third parameter which isn't used here. Well, to be correct, it is used here but not explicitly expressed. The third parameter is a delimiter character and by default the newline '\n' character is the delimiter if not specified as a parameter. It's possible to speicify a character other than the newline '\n' character as the delimiter.

If you remember from Part 1 of this article there is a possibility that this form may appear not to work. That is, it may appear that the character array is receiving a blank line or incorrect characters. If cin.getline(arrayname, size) is preceded by cin >> getdata code then at the very least a newline '\n' character is left in the input queue. Our getline(...) operation receives characters until a newline is encountered and in this example, it just happens to be the very first character. Is this a problem, well not really, but not understanding it, is. We need to make sure that prior to getline(...) operation occurring that the input queue has been flushed of errant characters.

In order to flush out errant characters or at the very least a newline '\n' character issue this code cin.get(); immediately after the cin >> getdata; line. We'll discuss this form in a separate topic but for now just accept that it clears or flushes the very next character from the input queue.

To better explain the whole process copy and paste the following short code snippet and check for yourself.

#include <iostream>
using namespace std;
int main()
{
    char getdata;
    cout << "Enter one character: ";
    cin >> getdata;
    //cin.get();
    char line[20];
    cout << "\nEnter a line of text 20 characters max: ";
    cin.getline(line,20);
    cout << "\nLine of text entered : " << line;
    cout << "\n\nNow at the end of the program";
    cout << "\nFirst character of line[20] " << (int)line[0] << endl;
    // exit routine
    while (cin.get() != '\n')
        continue;
    cin.get();
    return 0;
}

Firstly, the exit routine will be explained in it's own topic and just accept that it's sole purpose is to pause the program so as you can check your results (usually a problem for Windows users executing the program directly from a compiler).

Running the program as is you will never get a chance to enter a line of text. The reason being is that the newline character entered from the cin >> getdata; line is picked up by the cin.getline(line,20) line and assigned to the character array line. You will note that the first character code of the character array line is 0 (null character).

Uncomment the cin.get() line and the program will behave nearly as intended. The cin.get() will flush the newline '\n' character and thus will allow the cin.getline(line,20) to do it's thing. If you type ABC DEF the cout line towards the end of the program will indicate the character code of the first character of the character array line. In this case being 65.

With the cin.get() line uncommented, now run the program again. This time at the first prompt, rather than enter a single character enter a series of characters ie ABCDEF. You will note that 'A' is correctly assigned to it's variable getdata but you never have a chance to enter a line of text and yet the character array line contains BCDEF. You will also note that the character code of the first character of the array is 66 (code for 'B').

At this point we are therefore still left with the problem of a user entering more than a single character for getdata which adversely affects cin.getline(...). I'll address that soon but in the interim the exit routine should be a clue as to how to address it.

cin.get (arrayname, size)

Here is another form of the cin use. This form, cin.get(arrayname, size) is similar to cin.getline(arrayname, size) discussed previously. This form cin.get(arrayname, size) reads an entire line from the keyboard terminated by the 'ENTER' key BUT leaves the newline '\n' character in the input queue. Why it does this I'm not sure and why have such a function which for all intents and purposes is the same as the cin.getline(...) method, I'm not sure either.

Some things to be aware of

If there is an existing newline in the input buffer prior to calling cin.get(arrayname,20);, this form will not accept it, remember it leaves the newline character in the input buffer. The point here is that an error state is created in the cin object; the failbit flag is set to true. No further cin operations are permitted whilst the error flag is set to true. In order to remove the error flag this command cin.clear(); is required. It resets the cin error state back to false.

The above is not applicable if the input buffer contains normal characters ending with a newline character prior to calling the cin.get(arrayname, 20);. What occurs in this instance is that the errant characters or characters already in the input buffer as a result of a previous cin operation are assigned or allocated to the character array arrayname. The newline character is left in the input buffer.

Another situation arises whereby the user types in more characters than is specified by the size parameter of the cin function. No error state is recorded and the character array arrayname only receives the number of specified characters. The remaining characters are left in the input buffer.

The following code snippet should explain the various workings of this topic. The code, as is, will create an error state, simply uncomment the line after cin.get(line, 20);.

// File : testcin3.cpp
// Author : Steven Taylor
// Date : 23 Apr 2008
#include <iostream>
using namespace std;
int main()
{
    char getdata;
    cout << "Enter one character: ";
    cin >> getdata;
    cin.get();   // clear out very next character (newline)
   
    char line[20];
    cout << "\nEnter a line of text 20 characters max: ";
    cin.get(line,20);
    cout << "\nLine of text entered : " << line;
    //cin.get();      // flush out the newline character
   
    char line2[20];
    cout << "\nEnter another line of text 20 characters max: ";
    cin.get(line2,20);
    cout << "\nSecond line of text entered : " << line2;
   
    cout << "\n\nNow at the end of the program" << endl;
    cout << "First character of line[20]  : " << line[0] << " character code is : " << (int)line[0] << endl;
    cout << "First character of line2[20] : " << line2[0] << " character code is : " << (int)line2[0]<< endl;
   
    if (cin.eof())
        cout << "\n cin.eof() == true";
    else
        cout << "\n cin.eof() == false";
    if (cin.fail())
        cout << "\n cin.fail() == true";
    else
        cout << "\n cin.fail() == false";
   
    // exit routine
    cin.clear(); // only use this if there is potential for an error state.
    while (cin.get() != '\n')
        continue;
    cin.get();
    return 0;
}

As an aside, if there is no error state, issuing the command cin.clear(); has no side effects, that is, errors are not reported simply because no error exists to start with. It's harmless.

Play with the program. You will note that if you input more than a single character for the first input, that it adversely affects the following cin methods. I'll deal with flushing the input stream/buffer/queue in a separate article but in the interim the exit routine should be a clue as to how to flush the input buffer.

Short Programs

Short example programs.

Create a triangle type pattern

Write a C++ program that asks the user to enter a number of rows to be printed. It should then display for the first row one asterisk preceded by periods. The second row should display two asterisks preceded by periods and so on until all the rows have been printed as entered by the user.

A sample run would be like so:

Enter number of rows: 5
....*
...**
..***
.****
*****

I've seen many varied questions surrounding this particular problem.

Here's a solution, firstly, just the logic of the code for clarity, not concerning ourselves with error trapping incorrect keyboard input. The object is to understand the reasoning of the logic of addressing the problem at hand.

// nestedloop.cpp
// 29 Nov, 2007.

#include <iostream>
using namespace std;

int main()
{
    int rows, c;
    cout << "Enter the number of rows: ";
    cin >> rows;
    cin.get();
    for (int r = 1; r <= rows; r++)
    {
        for (c = 1; c <= rows - r; c++)
            cout << ".";

        for (; c <= rows; c++)
            cout << "*";
        cout << endl;
    }
    // exit routine
    cout << "\n\n...Press 'ENTER' key to EXIT...\n";
    cin.get();
    return 0;
}

Copy and paste the above into your compiler of choice, compile and run it. As you can see, it works.

The guts of the solution is that an outer loop is first created, that relating to the rows. Within this loop the columns are accounted for and for this particular problem the columns loop is split into two, one dealing with the periods and the other dealing with the asterisks. Now trying to explain the sequence of the variables concerned will take forever. I reckon the code alone should clearly explain what is happening.

I mentioned earlier that this code doesn't account for incorrect data input, try it, enter a non numeric for the number of rows. The program doesn't work.

The following pages discuss enhancements to the program.

Enhancement # 1 - Trap non numeric input

Okay, lets enhance the asterisk triangle program so that it only accepts numeric input. That is, if a user types in a non numeric then the program should re-request correct input until a number is entered.

Remove these lines:

cin >> rows;
cin.get();

and replace with:

while (!(cin >> rows) ) // checking against cin fail state
{
    cout << "Must enter an integer: ";
    cin.clear();        // reset error state back to false
    cin.get();          // flush out next character
}

An understanding of the cin object is required for this snippet. As the variable rows is defined as an integer type, attempting to assign a non integer to this type will set the cin objects error flag to true. The expression (cin >> rows) returns a boolean value (true or false) relating to the error state of the expression. We can include this error state as a conditional part of a while loop. while loops only continue whilst a condition is true and therefore in this instance we need to check for when not true which means false. Confusing, I know.

Compile and run the program. Enter a single non numeric character. You'll now note that the program asks you to input only an integer. Entering an integer is the only way to exit the loop and continue through to the end.

We're not done yet. There's still a problem or two. Enter as input a multiple non numeric characters, ie 'steve'. Rediculous, I know, as it's not in context but then are users ever in context. You'll note that the loop cycles five times, each time displaying the same message like so:

Enter the number of rows: steve
Must enter an integer: Must enter an integer: Must enter an
integer: Must enter an integer: Must enter an integer:

Not very pretty but this can be cleaned up. What happened? After hitting the 'ENTER' key inputting 'steve' each character was processed by the while loop as each character created an error state in the cin object.

Enter as input 'steve10'. The same effect as above but this time 10 rows are also printed. As soon as the while loop arrived at the digit one (1), it correctly established the integer number ten (10), which no longer did an error state exist and the rows were printed. This obviously is not a desired implementation. It can be fixed.

Replace the while loop with the following snippet.

   while (!(cin >> rows))
    {
        cout << "Must enter an integer: ";
        cin.clear();              // clear cin error state
        while (cin.get() != '\n') // clear out non newline characters
            continue;
    }

As you can see we've added another while loop. This effectively removes all characters left in the input buffer, including numbers if present. At the end of this process the newline character still remains in the buffer. Remember though, that basic cin >> rows skips over newline characters, so is not an issue in our example.

As the code stands now, it still doesn't account for incorrect data entry as regards entries like '50prime'. The number 50 is considered valid input and the remaining 'prime' is ignored. Again, this should not be allowed. We'll address that component a little later.

Enhancement # 2 - Valid Input Range

To further enhance the asterisk triangle program the numeric input needs to be restricted to a certain value range. Such a valid range would be 1 through 79. Entering anything greater than 79 and all the visuals go out the window.

Replace the entire while loop with the following while snippet.

   while (!(cin >> rows) or (rows < 1 or rows > 79))
    {
        cout << "Must enter an integer (1 - 79): ";
        cin.clear();              // clear cin error state, if exists
        while (cin.get() != '\n') // clear out non newline characters
            continue;
    }

In reality, only the while statement needed to be replaced as the nothing drastically needed to be changed in the body of the loop. As you can see I did change the cout statement to better inform a user of what is required, a number between 1 - 79.

The while statement could have been written like so:

while (!(cin >> rows) || (rows < 1 || rows > 79))

The || is the same as or and, though not used in this example, && is the same as and.

You will note that the program now detects incorrect data entry, that is any data entry commencing with a non numeric and any numeric entry not falling within the range of 1 through 79.

As the code stands now, what keyboard input doesn't it correctly trap? Entries such as '5prime' or '5.5' are not processed. Both of these entries are considered valid input as the first character is a numeric. Enter as input '80prime' or '80.5' and both are considered outside the valid value range. I'll discuss this in the next article.

Enhancement # 3 - Trap number followed by non numeric

As you know, the Asterisk Triangle Program has one remaining flaw and it's a flaw that should be addressed.

Presently, if a user enters as input 50prime the number '50' is accepted as valid and the remaining 'prime' is ignored. If a user enters as input 50.5 the number '50' is accepted and the remaining '.5' is ignored. Ideally we need to trap this and force a true integer to be entered.

Replace this line of code

while (!(cin >> rows) or (rows < 1 or rows > 79))

with this

while (!(cin >> rows) or (rows < 1 or rows > 79 or cin.peek() != '\n'))

You'll note that a third condition has been added to the while statement. That being cin.peek() != '\n'. What this is saying is,

"if the next character in the input buffer is not a newline character".

We know that after the execution of cin >> rows that if a true number was entered then all that is left in the input buffer is a newline ('\n') character. The peek() function merely checks for the next character in the input buffer. It doesn't remove the character from the input buffer. An entry such as '50prime' will cause the expression cin.peek() != '/n' to evaluate to true, as it detects the letter 'p', which in turn the body of the while loop is entered.

Here is the complete program code.

// trianglerows-5.cpp
// 30 Apr, 2008.

#include <iostream>
using namespace std;

int main()
{
    int rows, c;
    cout << "Enter the number of rows (1 - 79): ";
    while (!(cin >> rows) or (rows < 1 or rows > 79 or cin.peek() != '\n'))
    {
        cout << "Must enter an integer (1 - 79): ";
        cin.clear();              // clear cin error state, if exists
        while (cin.get() != '\n') // clear out non newline characters
            continue;
    }
    for (int r = 1; r <= rows; r++)
    {
        for (c = 1; c <= rows - r; c++)
            cout << ".";

        for (; c <= rows; c++)
            cout << "*";
        cout << endl;
    }
    // exit routine
    cout << "\n\n...Press 'ENTER' key to EXIT...\n";
    while (cin.get() != '\n')
        continue;                   // clear out non newline characters
    cin.get();                      // user to hit 'ENTER' key
    return 0;
}

I think I've covered all aspects of validating against incorrect data input.

Please note that there are other ways to accept keyboard input and different methods to validate against incorrect keyboard input. Feel free to make suggestions.

Array Solution - Half and half, 10 per line

Problem : Declare and initialize an integer array having 50 elements. The value of the first 25 elements to be the square of the index element and the remaining 25 elements, the values to be treble the index element. Further, the results are to be printed 10 per line.

This was a problem put forward from this thread.

My solution.

// array-fifty.cpp  --  Assign elements, print 10 per line.
// http://www.daniweb.com/forums/thread102743.html
// Steven Taylor
// 30 Dec, 2007.

#include <iostream>
using namespace std;

int main()
{
    int alpha[50];
    for (int i=0;i<50;i++)
    {
        if (i<25)
            alpha[i] = i * i;
        else
            alpha[i] = i * 3;
        if (i % 10 == 0)
            cout << "\n" << alpha[i] << "\t";
        else
            cout << alpha[i] << "\t";
    }

    // exit routine
    cout << "\n\n...Press ENTER to Exit System...";
    cin.get();
    return 0;
}

As can be seen the code is relatively simple. The difficult part was working out how to print 10 per line. In the end, the modulus function was the only way I could think of to achieve this requirement. If there's another way, I'm open to suggestions.

As I write this another suggestion popped up suggesting that a condition is not necessary regarding the first 25 and second 25 elements. Suggestion as follows:

for(int i =0; i<25; i++) {
   alpha[i] = i * i;
   alpha[49-i] = (49-i) * 3;
}

Clever. I wonder how long it would have taken me to think of this approach. It's all a part of the learning experience.

Calculate Pace (Running Program)

During week 5 of study, learning functions and in particular references passed to and from functions. The following program, in a way, cemented some of the stuff studied. It wasn't a part of the book but since I'm interested in running, I thought I'd write a little program that calculates the average pace of a run given the distance (km) and duration (time) of the run.

// pace-2.cpp  --  To calculate pace of a run
// author : Steven Taylor
// 21 Dec, 2007.

#include <iostream>
using namespace std;
const int SECS_IN_MIN = 60;
const int MINS_IN_HOUR = 60;
const int SECS_IN_HOUR = 3600;

struct hms
{
    int hour;
    int min;
    int sec;
};
const hms & pace_is(double distance, hms  & duration, hms & rate);

int main()
{
    double distance;
    hms duration;
    hms perkm = {0,0,0};
   
    cout << "Enter distance (km's) run: ";
    while (!(cin >> distance))
    {
        cout << "\nMust enter a number - re-enter: ";
        cin.clear();
        while (cin.get() != '\n')
            continue;
    }
    cout << "\nEnter duration of run - firstly - hours: ";
    while (!(cin >> duration.hour))
    {
       cout << "\nMust be an integer number - re-enter - hours: ";
       cin.clear();
       while (cin.get() != '\n')
           ;
    }
    cout << "\nEnter minutes (0-59): ";
    while (!(cin >> duration.min) || duration.min >= MINS_IN_HOUR)
    {
        cout << "\nMinutes must be 0 - 59, re-enter - minutes: ";
        cin.clear();
        while (cin.get() != '\n')
            ;
    }
    cout << "\nEnter seconds (0 - 59): ";
    while (!(cin >> duration.sec) || duration.sec >= SECS_IN_MIN)
    {
        cout << "\nSeconds must be 0 - 59, re-enter - seconds: ";
        cin.clear();
        while (cin.get() != '\n')
            ;
    }

    perkm = pace_is(distance,duration,perkm);
   
    cout << "\nThe pace per km is : ";
    if (perkm.hour > 0)
        cout << perkm.hour << ":";
    cout << perkm.min << ":" << perkm.sec << endl;
   
    // exit routine
    cout << "\n\n...Press ENTER to Exit System...";
    cin.clear();
    while (cin.get() != '\n')
        continue;
    cin.get();
    return 0;
}

And now the function pace_is()

const hms & pace_is(double distance, hms & d, hms & rate)
{
       
    int total_secs = (d.hour * SECS_IN_HOUR) + (d.min * SECS_IN_MIN) + d.sec;
    double secs_per_km = total_secs / distance;
       
 
    if (secs_per_km > SECS_IN_HOUR)
    {
        rate.hour = secs_per_km / SECS_IN_HOUR;
        secs_per_km = (int)secs_per_km % SECS_IN_HOUR;
    }
    if (secs_per_km > 0)
    {
        rate.min = secs_per_km / MINS_IN_HOUR;
        rate.sec = (int)secs_per_km % MINS_IN_HOUR;
    }
        return rate;
}

It works but I'm not overly happy with the fact of the function pace_is returns a reference to a structure and yet that same structure is passed as a reference to the function; what's the point, no real need to have the function return a reference, it might as well be void.

The above file is listed in the attachment, feel free to download.

AttachmentSize
pace-2.zip902 bytes

Calculate Pace (Running Program) - # 2

I'm now into week # 14 of study, in which Classes and Objects have been introduced. (Studying from the book, C++ Primer Plus Fifth Edition, by Stephen Prata - about to commence chapter 12). In order to cement knowledge learned to date I decided to modify a program I wrote back in week 5. That program written calculates the pace of a run which is outputted as minutes per kilometre. It is only a one source code file program containing a few functions.

I've modified it, maybe modify is the wrong word, completely re-written it. This time basing the functionality upon Classes and Objects and purposely including multiple source code files (headers and definitions). Also in the process including a user decision as to the base unit (kilometres or miles).

The concept of Classes and Objects, though I understand them, opened my eyes more so towards the end of this little project. Originally, I only planned to report the pace in the units as given by user input, ie either 'mins per mile' or 'mins per km'. As I was finishing up I thought I might as well display the opposite or converted value. To my surprise, very few lines of code were required, the main bit being just another constructor passing in a reference of the user inputted details.

Without further ado, here's the code. I'll start with the main() program, hopefully you'll note that it's clean and easy to read, that's because all the work is done via the other files.

I'm open to any constructive criticism or suggestions and without further ado (again), here's the code.

/*
  Name: main.cpp
  Copyright:
  Author: Steven Taylor
  Date: 21/02/08 21:25
  Description: Main program calling classes to work out pace of a run
*/

#include <iostream>
#include "run01.h"
#include "functions.h"

using std::cout;
using std::cin;

int main()
{
    char active = 'y';
    run session;
    cout << "Enter details (q to quit):\n";
    while (active == 'y' || active == 'Y')
    {
        cin >> session;
        run convert(session);
        cout << "\n" << session << " or " << convert << "\n\n";
        cout << "Another session (y or n) ";
        cin >> active;
        // anything but Y or y assumes NO
    }
     // exit routine
    cout << "\n\n...Press ENTER to Exit System...";
    clear_buffer();
    cin.get();
    return 0;
}

File # 2

/*
  Name: run01.h
  Copyright:
  Author: Steven Taylor
  Date: 21/02/08 14:10
  Description: Header file for a run
*/

#ifndef RUN01_H_
#define RUN01_H_

class run
{
    private:
        static const int SECS_IN_MIN = 60;
        static const int MINS_IN_HOUR = 60;
        static const int SECS_IN_HOUR = 3600;
        static const double KM_PER_MILE = 1.60934;
        static const double MILES_PER_KM = 0.621371;
       
        // inputted values
        double dd;               // distance (km or miles)
        int hh;                  // hour component of time duration
        int mm;                  // minutes component of time duration
        int ss;                 // seconds component of time duration
        char unit;              // k = kilometre (default), m = miles
        // calculated values
        int mins;
        int secs;
    public:
        run();                  // default constructor
        run(double d, int h, int m, int s, char u = 'k');
        run(double d, int m, int s, char u = 'k');
        ~run();
        run(const run &r);      // converts to other unit of distance
               
        void set_run(double d, int h, int m, int s, char u = 'm');
        void set_run(double d, int m, int s, char u = 'k');
       
        void calculate_pace();
       
        void show_values();
             
       
        friend std::ostream & operator<<(std::ostream &os, const run &r);
        friend std::istream & operator>>(std::istream & is, run &r);
};
#endif

File # 3

/*
  Name: run01.cpp - definition file
  Copyright:
  Author: Steven Taylor
  Date: 21/02/08 14:56
  Description:
*/

#include <iostream>
#include "run01.h"
#include <fstream>
#include "functions.h"

run::run()
{
    dd = 0.0;
    hh = mm = ss = mins = secs = 0;
    unit = 'k';
}
run::run(double d, int h, int m, int s, char u)
{
    dd = d;
    hh = h;
    mm = m;
    ss = s;
    unit = u;
    calculate_pace();
}
run::run(double d, int m, int s, char u)
{
    dd = d;
    hh = 0;
    mm = m;
    ss = s;
    unit = u;
    calculate_pace();
}
run::run(const run &r)
{
    if (r.unit == 'k')
    {
        unit = 'm';
        dd = r.dd / KM_PER_MILE;
    }
    else
    {
        unit = 'k';
        dd = r.dd / MILES_PER_KM;
    }
    hh = r.hh;
    mm = r.mm;
    ss = r.ss;
    calculate_pace();
}
run::~run()
{}
void run::set_run(double d, int h, int m, int s, char u)
{
    dd = d;
    hh = h;
    mm = m;
    ss = s;
    unit = u;
    calculate_pace();
}
void run::set_run(double d, int m, int s, char u)
{
    dd = d;
    hh = 0;
    mm = m;
    ss = s;
    unit = u;
    calculate_pace();
}

void run::calculate_pace()
{
    int total_secs = (hh * SECS_IN_HOUR) + (mm * SECS_IN_MIN) + ss;
    int secs_per_unit = ((double(total_secs) / dd) + 0.5);
     
    if (secs_per_unit > 0)
    {
        mins = secs_per_unit / MINS_IN_HOUR;
        secs = secs_per_unit % MINS_IN_HOUR;
    }
}
void run::show_values()
{
    std::ofstream fout;
    fout.open("debug.txt");
    fout << "hh = " << hh << " mm = " << mm << " ss = " << ss << " unit = " << unit << "\n";
    fout << "mins = " << mins << " secs = " << secs << "\n";
}
   
std::ostream & operator<<(std::ostream &os, const run &r)
{
    os << "Pace : ";
    os << r.mins << ":";
    if (r.secs < 10)
        os << "0";
    os << r.secs;
    if (r.unit == 'k')
        os << " min/km";
    else
        os << " min/mile";
    return os;
}
   
std::istream & operator>>(std::istream & is, run &r)
{
    std::cout << "Unit of distance <k>ilometres or <m>iles: ";
    if (is >> r.unit)
    {
        switch (r.unit)
        {
            case 'M':
            case 'm':
                r.unit = 'm';
                break;
            default :
                r.unit = 'k';
         }
    }
   
    std::cout << "Distance ";
    if (r.unit == 'k')
        std::cout << "(km): ";
    else
        std::cout << "(miles): ";
   
    while (!(is >> r.dd))
    {
        std::cout << "-Distance : ";
        clear_buffer();
    }
         
    std::cout << "Hours:   ";
    while (!(is >> r.hh))
    {
        std::cout << "\n-Hours: ";
        clear_buffer();
    }
   
    std::cout << "Minutes: (0 to 59): ";
    while (!(is >> r.mm) || r.mm >= r.MINS_IN_HOUR)
    {
        std::cout << "\n-Minutes: (0 to 59): ";
        clear_buffer();
    }
     
    std::cout << "Seconds: (0 to 59): ";
    while (!(is >> r.ss) || r.ss >= r.SECS_IN_MIN)
    {
        std::cout << "\n-Seconds: (0 to 59): ";
        clear_buffer();
    }
   
    r.calculate_pace();

    return is;
}

File # 4

/*
  Name: functions.h
  Copyright:
  Author: Steven Taylor
  Date: 22/02/08 16:21
  Description: General functions file
*/

#ifndef FUNCTIONS_H_
#define FUNCTIONS_H_

void clear_buffer();
#endif

File # 5

/*
  Name: functions.cpp
  Copyright:
  Author: Steven Taylor
  Date: 22/02/08 16:24
  Description: General function(s) definitions
*/

#include <iostream>
#include "functions.h"
using std::cin;

void clear_buffer()
{
    cin.clear();
    while (cin.get() != '\n')
        continue;
}

So that's it, what do you think?

AttachmentSize
Pace-Class-Run.zip2.76 KB

Remove Vowels

Perusing the forums I came across this thread a question relating to inputting a string and then redisplaying the string without the vowels. What I failed to notice was that the thread was a C thread (not C++) and so my C++ solution, not precisely addressing the original posters question. This, not such a problem for me, as it helped cement my learning to date.

This took me about 15 or 20 minutes to nut out the basic solution and then another 40 or 50 minutes to re-visit passing and returning of arrays from functions. In essence, this little routine re-enforced the fact that arrays are passed by reference and in effect are pointers. Therefore returning an array is merely a matter of modifying an argument parameter.

A particular enhancement would be to also account for capital vowels, which I see would be easy to incorporate. The main thrust of the problem was how to strip characters from a string and display them to the user. This, I've achieved.

There's room for enhancement to this solution and I'm open to any suggestions or recommendations. I know in time I'll probably revisit this and post a comment with updated or improved coding technique.

Remember, I've written this whilst into my 6th week of self-study (haven't touched on classes yet).

// RemoveVowels-2.cpp  --  Remove vowels from an inputted string
// http://www.gidforums.com/t-16756.html
// Steven Taylor
// 29 Dec, 2007.

#include <iostream>
using namespace std;
const char VOWEL_IS[] = "aeiou";  // consider including CAPS

void strip(const char *str, int length, char *newstring);
bool isvowel(const char c);

int main()
{
    char str[80];
    cout << "Enter a string, any old string of words:\n";
    cin.get(str,80);
    char withoutvowels[80];
    strip(str,80, withoutvowels);
    cout << "\n\nThe user input without vowels :\n" << withoutvowels << endl;

    // exit routine
    cout << "\n\n...Press ENTER to Exit System...";
    cin.clear();
    while (cin.get() != '\n')
        continue;
    cin.get();
    return 0;
}

And now the functions.

void strip(const char str[], int length, char *newstring)
{
    int index = 0;
    for (int i = 0; i < length; i++)
    {
        if (!(isvowel(str[i])))
        {
            newstring[index] = str[i];
            index++;
        }
    }
    newstring[index] = '\0';
}
bool isvowel(const char c)
{
    for (int j=0; j < 5; j++)
    {
        if (c == VOWEL_IS[j])
            return true;
    }
    return false;
}

So, that's it. The above is a file, for download, in the attachments.

AttachmentSize
RemoveVowels-2.zip724 bytes

Remove Vowels - # 2 - String version

I've modified the Remove Vowels program to now account for string use instead of straight out C-style string. The purpose of the program hasn't changed and that is to accept user input of a few words and strip out all the vowels. Real earth shattering stuff.

Additional to the previous version is that both upper and lowercase characters are now accounted for.

In order to reduce clutter at the end of the main() function, I reduced the exiting procedure to a function 'keep_window_open()'. On some Windows setup, it's a real pain that when running the program from the IDE the command prompt window closes automatically at the conclusion of the program. This function addresses that. If it's not needed simply comment it out.

Here's the code:

// RemoveVowels-4.cpp  --  Remove vowels from an inputted string
// Steven Taylor
// 16 Jan, 2008.
// 3 Mar, 2008 : demonstrate using type string

#include <iostream>
#include <string>
#include <cctype> // tolower() function

using namespace std;
const string VOWEL_IS = "aeiou";
        // for caps - see use of tolower() function below.
string strip(const string &str);
bool isvowel(const char c);
void keep_window_open();

int main()
{
    string str;
    cout << "Enter a string, any old string of words:\n";
    getline(cin, str);
    cout << "\n\nThe user input without vowels :\n" << strip(str) << endl;
    keep_window_open();  // less clutter.
    return 0;
}

As you can see the main() function is clutter free and very simple. It does rely upon the following functions.

string strip(const string &str)
{
    int index = 0;
    int length = str.size();
    char temp[length];
    for (int i = 0; i < length; i++)
    {
        if (!(isvowel(tolower(str[i]))))
        {
             temp[index] = str[i];
            index++;
        }
    }
    temp[index] = '\0';
    return (string)temp;        // return temp;  also works.
}
bool isvowel(const char c)
{
    for (int j=0; j < 5; j++)
    {
        if (c == VOWEL_IS[j])
            return true;
    }
    return false;
}
void keep_window_open()
{
    // only needed if the command prompt window doesn't
    // stay open.   Using a function - assists
    // with readability of the main() program
    // that is, less clutter.
    cout << "\n\n...Press ENTER to Exit System...";
    cin.clear();
    while (cin.get() != '\n')
        continue;
    cin.get();
}

I'm open to suggestions, good, bad or indifferent. Are there any other ways to achieve the purpose of this program? I'm sure there are. Whether they are more efficient or not is not the point. The point is that it gets the mind ticking considering options and alternatives. I know for one thing, I haven't explored all the std::string functions.

Consider this. If you're next assignment is along the lines of, 'check a user inputted string and remove all the characters from that string that are a part of a secondary user inputted string', that shou