Programming Forums

Programming Forums (http://www.programmingforums.org/forumindex.php)
-   C++ (http://www.programmingforums.org/forum15.html)
-   -   Have A Problem With Cout (http://www.programmingforums.org/showthread.php?t=1272)

sys0p Nov 25th, 2004 12:55 AM

Hi,
Long time since I've been here :) I have a problem with this code I'm writing :( I was hoping that someone could help me out :)

I'm writing a simple address book to test structures and functions, and I want to allow the user to enter their details, and have the option whether to continue or exit the loop.

I get this error, at the end of the loop, if I continue it prints out the First name: Last name: together, as you can see at the bottom of the text below -

First name: rich
Last name: morton
Address1: 39 bay mews
Address2: hout bay
City: cape town
Province: western cape
Country: south africa
ZIP: 8000
Continue? Quit?
1
First name: Last name:

I can't figure out why this is happening?!? <annoyed> I tried moving the int cin to the last line, and also tried putting another cout but didn't work :(

The code is below. I hope someone can help me :) I would really appreciate any help :)

Cheers :)

:

#include <iostream.h>

struct mailing {
char firstname[100];
char lastname[100];
char address1[100];
char address2[100];
char city[100];
char province[100];
long int zip;
char country[100];
};

//our mailing list
#define MAX_ENTRIES 3

struct mailing mailing_list[MAX_ENTRIES];

main()
{
int userOp; //quit/continue bool variable
//add people into address book
for( int i = 0; i < MAX_ENTRIES; ++i )
        {
        cout << "First name: ";
        cin.getline (mailing_list[i].firstname, sizeof(mailing_list[i].firstname));

        cout << "Last name: ";
        cin.getline (mailing_list[i].lastname, sizeof(mailing_list[i].lastname));

        cout << "Address1: ";
        cin.getline (mailing_list[i].address1, sizeof(mailing_list[i].address1));

        cout << "Address2: ";
        cin.getline (mailing_list[i].address2, sizeof(mailing_list[i].address2));

        cout << "City: ";
        cin.getline (mailing_list[i].city, sizeof(mailing_list[i].city));

        cout << "Province: ";
        cin.getline (mailing_list[i].province,        sizeof(mailing_list[i].province));

        cout << "Country: ";
        cin.getline (mailing_list[i].country, sizeof(mailing_list[i].country));

        cout << "ZIP: ";
        cin >> mailing_list[i].zip;

        cout << "Continue? Quit?" << '\n';
        cin >> userOp;
 if( userOp == 1 )
 continue;
 else
 break;        //quit if 0
        };

        //print our address book contents
        for( int j = 0; j < MAX_ENTRIES; ++j )
        {
        cout << "Entry " << (j + 1)  << '\n';
        cout << "Name: "        << '\t'        << '\t' << mailing_list[j].firstname        << " "        << mailing_list[j].lastname << '\n';
        cout << "Address1: "        << '\t'        << '\t' << mailing_list[j].address1        << '\n';
        cout << "Address2: "        << '\t'        << '\t' << mailing_list[j].address2        << '\n';
        cout << "City: "        << '\t'        << '\t' << mailing_list[j].city << '\n';
        cout << "Province: "        << '\t'        << '\t' << mailing_list[j].province        << '\n';
        cout << "Zip: " << '\t'        << '\t' << mailing_list[j].zip << '\n';
        cout << "Country: "        << '\t'        << '\t' << mailing_list[j].country        << '\n';
        };
};


tempest Nov 25th, 2004 1:25 AM

No semicolons on the ends of for loop statements ;)

Eggbert Nov 25th, 2004 8:11 AM

>No semicolons on the ends of for loop statements
A null statement is usually harmless provided it isn't placed somewhere that changes the logic of the code, such as immediately after the condition of a loop or if:
:

for ( int i = 0; i < 10; i++ ); // A semicolon here is bad
 cout<< i <<endl;

The problem is here:
:

cout << "Continue? Quit?" << '\n';
cin >> userOp;

cin's >> operator has an annoying tendency to leave newline characters on the standard input stream. Because the next input function you call is getline (which terminates on a newline character), it will appear as if the call was skipped. This is because getline read a newline straight away and terminated successfully.

There are quite a few solutions to this problem, but the simplest is:
:

cout << "Continue? Quit?" << '\n';
cin >> userOp;
char ch;
while ( cin.get ( ch ) && ch != '\n' )
 ;

However, a shorter and more interesting solution is:
:

cout << "Continue? Quit?" << '\n';
cin >> userOp;
cin.ignore ( cin.rdbuf()->in_avail() );

or:
:

#include <ios>  // For streamsize
#include <limits> // For numeric_limits

cout << "Continue? Quit?" << '\n';
cin >> userOp;
cin.ignore ( numeric_limits<streamsize>::max(), '\n' );


sys0p Nov 25th, 2004 10:23 AM

Hey tempest, removing semi-conlons didn't work for me :(
hey Eggbert, I will have to be offline to read your reply, but when I do I will reply :)
Cheers :)
And thanks for the help guys :)

sys0p Nov 25th, 2004 11:04 AM

Hi,
Thanks Eggbert, very interesting code you put there! But unfortunately I don't really understand it :) Would you mind explaining the three sections of code you posted? I would really appreciate that :)

I did find a solution, and it seems to work without the code. It seems I was to blame for the bugs, first I was meant to put the break at the beginning of the loop:

:

if( userOp == 0 )
break;


Secondly I forgot to put in the return statement!!! I don't think that matters, cos the code compiled without it. Does it?

And, just to make sure, could you guys check the code below

:

#include <iostream.h>
#include <stdlib.h>

struct mailing {
char firstname[100];
char lastname[100];
char address1[100];
char address2[100];
char city[100];
char province[100];
long int zip;
char country[100];
};

//our mailing list
#define MAX_ENTRIES 3

struct mailing mailing_list[MAX_ENTRIES];

main()
{
int userOp;
//add people into address book
for( int i = 0; i < MAX_ENTRIES; ++i )
        {
        if( userOp == 0 )
        break;

        cout << "First name: ";
        cin.getline (mailing_list[i].firstname, sizeof(mailing_list[i].firstname));

        cout << "Last name: ";
        cin.getline (mailing_list[i].lastname, sizeof(mailing_list[i].lastname));

        cout << "Address1: ";
        cin.getline (mailing_list[i].address1, sizeof(mailing_list[i].address1));

        cout << "Address2: ";
        cin.getline (mailing_list[i].address2, sizeof(mailing_list[i].address2));

        cout << "City: ";
        cin.getline (mailing_list[i].city, sizeof(mailing_list[i].city));

        cout << "Province: ";
        cin.getline (mailing_list[i].province,        sizeof(mailing_list[i].province));

        cout << "Country: ";
        cin.getline (mailing_list[i].country, sizeof(mailing_list[i].country));

        cout << "ZIP: ";
        cin >> mailing_list[i].zip;

        cout << "Continue? Quit?" << '\n';
        cin >> userOp;
        };

        //print our address book contents
        for( int j = 0; j < MAX_ENTRIES; ++j )
        {
        cout << "Entry " << (j + 1)  << '\n';
        cout << "Name: "        << '\t'        << '\t' << mailing_list[j].firstname        << " " << mailing_list[j].lastname << '\n';
        cout << "Address1: "        << '\t'        << '\t' << mailing_list[j].address1        << '\n';
        cout << "Address2: "        << '\t'        << '\t' << mailing_list[j].address2        << '\n';
        cout << "City: "        << '\t'        << '\t' << mailing_list[j].city << '\n';
        cout << "Province: "        << '\t'        << '\t' << mailing_list[j].province        << '\n';
        cout << "Zip: " << '\t'        << '\t' << mailing_list[j].zip << '\n';
        cout << "Country: "        << '\t'        << '\t' << mailing_list[j].country        << '\n';
        };
        system("PAUSE");
        return(0);
};


Just to make sure :)

And, thanks again for your help :) Very much appreciated. To Eggbert: I hope you don't mind explaining the bits of code you posted, they certainly look useful :)
Cheers :)

Eggbert Nov 25th, 2004 12:02 PM

>Would you mind explaining the three sections of code you posted?
Happily:
:

cout << "Continue? Quit?" << '\n';
cin >> userOp;
char ch;
while ( cin.get ( ch ) && ch != '\n' )
 ;

The intention of all of the snippets is to remove extraneous characters from the input stream so that the next request for input will result in a blocking read, thus stopping execution long enough for the user to type something.

In the above code, I simply read a single character repeatedly until either end-of-file is encountered, an input error occurs, or a newline is found. The first two probably won't happen in interactive input unless you prompt for end-of-file as a terminator for input, so the real magic is happening with the test for '\n'. Because stream input in C++ is line oriented, we can guarantee that once a newline character is extracted from the stream, there will be nothing in the buffer and the next request for input will wait for the user to type something.
:

cout << "Continue? Quit?" << '\n';
cin >> userOp;
cin.ignore ( cin.rdbuf()->in_avail() );

This is a tricky piece of code. Instead of searching for a newline and removing all intervening characters as the loop did, I chose to go directly to the source: the stream input buffer (cin.rdbuf()). I then asked how many characters were in the stream buffer (in_avail()) and used cin's ignore member function to discard that many characters. The end result is that the buffer is cleared and the next request for input will cause a blocking read.
:

#include <ios>  // For streamsize
#include <limits> // For numeric_limits

cout << "Continue? Quit?" << '\n';
cin >> userOp;
cin.ignore ( numeric_limits<streamsize>::max(), '\n' );

This snippet does the same thing as the last snippet, except in a different way. cin.ignore() will read up to the limit provided as the first argument, or until the character defined by the second argument is reached. The above code says "Read characters until the maximum size for the stream is reached or a newline is found".

>I did find a solution
Notice how userOp is uninitialized on the first iteration of the loop. Accessing an uninitialized variable results in undefined behavior, so your code is broken even if it appears to work.

sys0p Nov 25th, 2004 2:40 PM

Hey Eggbert!
Thanks very much for explaining, that certainly makes more sense to me now :) I appreciate your help, and I am sure that someday that will come in very handy :)
Cheers :)
OH, and yes, I moved the userOp variable into the loop. Thanks for pointing that out :)
Btw How long have you been programming?

Eggbert Nov 25th, 2004 3:00 PM

>Btw How long have you been programming?
About 40 years.

Ooble Nov 25th, 2004 6:36 PM

Not surprised, really. Oh, and I believe you can just use cin.ignore(), but I'm probably wrong.

Eggbert Nov 25th, 2004 8:46 PM

>Oh, and I believe you can just use cin.ignore(), but I'm probably wrong.
You can, but that will only discard a single character. It only works if the next character on the stream is a newline.


All times are GMT -5. The time now is 1:55 AM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC