Thread: Reading string from outside data file

  1. #1
    Registered User
    Join Date
    Oct 2007
    Posts
    5

    Unhappy Reading string from outside data file

    Hi everyone,
    I'm trying to read data from a text file, which looks like this:

    Toots Sweet 87 76 90 -1
    Willy Nilly 73 63 74 70 -1
    Phil O'Sophy -88
    Jill Quirk 84 73 83 -3

    I delcare first name and last name as string, and score as double.
    By using the code below, I cannot read all the data in the file but only the first record. If I take out system("pause"), the program will go crazy with endless line of record.

    Code:
    while (!in.eof())
    {
    in >> fname >> lname >> score;
    cout << fname << lname << score << endl; 
    system("pause");
    }
    I'm new with programming, can anyone give me some advice please?

  2. #2
    Software Developer jverkoey's Avatar
    Join Date
    Feb 2003
    Location
    New York
    Posts
    1,905
    Try this:

    Code:
    #include <iostream>
    using namespace std;
    
    int main()
    {
      double input;
      cin >> input;
      cout << input;
    
      double input2;
      cin >> input2;
      cout << input2;
      return 0;
    }
    Try typing in any string for the first input. This program will fail the same way on the next input as in your program. This is because when you attempt to read in a string ("Willy") as a double (some numerical value), cin fails.

    Code:
    in >> fname >> lname >> score;
          string  string  double   <- Expected
          Toots   Sweet     87   <- First iteration
          76       90       -1   <- Second iteration
    I'll leave it up to your creative intellect to figure out how to avoid reading in a string as a double in your case.
    Last edited by jverkoey; 10-29-2007 at 10:49 PM.

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Is the last number on each line always negative?
    Can you use that to determine where one record ends and another begins?
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Registered User
    Join Date
    Oct 2007
    Posts
    5
    Salem, you're absolutely right, but what code do I have to use to use the negative a "break" for each record?

  5. #5
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    For each line of data, first you read in the two names. Then you start a loop and read in scores as doubles one at a time. Check each score to see if it is negative, and break the loop when you find a negative one.

    That whole process handles one line, so you'll have to put that into its own loop to handle all the lines. When you do that, don't use eof() to control the outer loop. Put the code that reads in the first name in the loop control like this:
    Code:
    while (in >> fname)
    If you loop while !eof(), then you end up running the loop one extra time because the eofbit won't be set until after you try to read past the end of the file and your code checks for it before it does the read.

  6. #6
    Registered User
    Join Date
    Oct 2007
    Posts
    5
    Daved,
    I tried as you suggested, but doesn't seem to work out. Can anyone tell me what's wrong with my code here:
    Code:
    in >> fname >> lname; 
    			
    	while (in >> fname)
                    {
    	      while (score>0)
    	           {
    		in >> score;
    	           }
                     }
    	cout << fname << lname << score << endl;
    It seems to override the previous score and view only the latest score.
    How can I avoid this?
    Do I have to declare more than one scores?
    Is there a way to declare only one variable and read all the scores?
    Please advice....

  7. #7
    Registered User mikeman118's Avatar
    Join Date
    Aug 2007
    Posts
    183
    You could have an array:
    Code:
    double score[10]
    int x = -1
    ...
    x++;
    in >> score[x];
    That's probably not the best way, but it works.

  8. #8
    Registered User
    Join Date
    May 2007
    Posts
    77
    Yes, you could use an array, put a variable in there, and have it increment it until it gets to the end of the record with the negative number, perhaps like this:
    Code:
    while (cin >> fname >> lname) {
    
            double score[6];
            int w=0,s=0;
            while (cin >> score[w])
            {
                if (score[w] <= 0)
                {
                    break;
                }
                ++w;
            }
    The way I did that in there with the if instead of the while, is I did exactly the opposite of what you had. If you have a "cin" in a while parentheses, it's going to ask for input for that. If you ask for input again, it will get a second input before going back to the beginning of the loop. And, this particular loop assumes that you are not wanting to include the negative numbers as part of the scores.

    I'm assuming, of course, that you have that whole code segment on a loop as well, considering there is more than one record in the file. And you'll have to declare score outside of the inner loop, and make sure to allocate it enough element slots so that you can accommodate however many scores there are.

    With arrays, in order to display the values, you have to have an actual index in the brackets. You can't just say "cout << score" if it's an array, because it will give you the memory address of the array, not the values in it. So you'll have to have a loop (I would suggest a do...while) to increment a second integer variable, separate from "w" that I used above, and increment that and display the related score, as long as "s != w".

    Another good thing to do is to have the spaces and line endings in there in between the outputs so that you can actually read what the program is printing.

    Now, you'll also have to put an "eof()" parameter in the first "while" settings to allow for the end of the file you have the program reading, so it stops when it needs to, and doesn't go on an error loop.
    Last edited by Molokai; 11-04-2007 at 12:24 PM.

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Now, you'll also have to put an "eof()" parameter in the first "while" settings to allow for the end of the file you have the program reading, so it stops when it needs to, and doesn't go on an error loop.
    That is not necessary in your example since it tests cin directly. What may be necessary is a cin.clear() and cin.ignore() to stop the "error loop" you speak of.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Registered User
    Join Date
    Oct 2007
    Posts
    5
    Molokai,

    I tried your code, but it doesn't work.
    I partly understand your code, but ...
    What is the "s" for in your case?
    After "while(cin >> score[w])" why not "cin << score;" to input the next score in the record, instead you have "if (score[w])....."?
    After "if (score[w] <= 0)" you have "break;", what does "break" mean?

    My final purpose is to read all the score from the input text file and then calculate average score and view it on the screen. And if the record has no valid score, there will be an error message on screen.

    What do you mean below?

    Another good thing to do is to have the spaces and line endings in there in between the outputs so that you can actually read what the program is printing.
    Sorry for my dullness, but I'm trying hard to learn this language. Your help and advice are truly appreciated.

  11. #11
    Registered User
    Join Date
    May 2007
    Posts
    77
    That was only a very small section of the code I had come up with to basically be a mirror of what you were trying to do with files (I don't have a file, so I used user input. I guess I should probably try to work that out.)

    After "if (score[w] <= 0)" you have "break;", what does "break" mean?
    Anyway, I am correct in assuming then that you do not want to count the negative numbers at the end of each line? Because that's what the "if" statement does. "if (score[w] <=0)" checks whether or not the (double) integer being read is less than or equal to 0, which is the first score you do not want, as far as I know. If the number is less than or equal to 0 (or in other words, 0 or a negative number), then it goes to break, which kicks it out of the while loop. It then proceeds to print the full name and list of positive integers it read into the array (score[]), which is something I had later in my full code.

    Looking at the file stream operators, it gets a lot more complicated than using user input, because you have to open the file, make sure it reads everything into the right spots, and knows to skip to the next variable at each space, and/or ignore the spaces. However, that loop remains essentially the same.

    What is the "s" for in your case?
    The s, however, was for the display loop, because as you put each number into an element, w is incremented. Therefore, w already tells you the limit of the integers to read. So, you have s compare to w, and increment s as you output the integers, and it does that as long as s is less than w (the reason for this is because even when you input the negative number, it increments w. However, that provides for the possibility to include the negative number. All you have to do is make s compare to w through <=, instead of "<" or "!="). Once it is equal to w, the loop stops, and moves on to the next set of info, starting with the next first name. Here is what I mean:
    Code:
    #include "stdafx.h"
    #include <cstdlib>
    #include <string>
    #include <iostream>
    
    using namespace std;
    
    int main(){
        string fname,lname;//declares the two strings for the input loop
    	cout << "Type \"eof\" as first name to end program."//tells user how to stop the program
        while (cin >> fname) {//input loop
            if (fname == "eof")//test for end program
    		{
    			break;
    		}
    	cin >> lname;//input last name if first name is not "eof"
    	int score[10];//declare score array with enough elements to accommodate total number of scores for each line
            int w=0;//declare element call variable for score input loop
            while (cin >> score[w])//score input loop
            {
                if (score[w] <= 0)//test for stop at negative number
                {
                    break;
                }
    			++w;
            }
            int s=0;//declare element call variable for output loop
        	cout << fname << " " << lname;
            do {//score output loop
                cout << "  " << score[s];
                ++s;
            } while (s < w);
            cout << endl;
        }
        system ("pause");
        return 0;
    }
    Now, notice in the output portion of it (cout << fname, etc.), I put parenthesis surrounding a single space. That's what I meant by "spaces and line endings" (line endings can be coded by either "cout << endl" or "cout << "\n"", whichever is easier given the context). You have to format your output to be readable. Otherwise, if it got your first line in the file (Toots Sweet 87 76 90 -1) it would display the output as TootsSweet877690. You'd much rather read the original, wouldn't you?

    And as a final note:
    After "while(cin >> score[w])" why not "cin << score;" to input the next score in the record, instead you have "if (score[w])....."?
    The reason why is because that's exactly what I'm doing with "cin >> score[w]". If you don't give it a specific element to put the integer to, it will give you an error message in the compiling process. And, as previously explained, the "if" part of that loop stops the loop when it reaches the negative number.

    Feel free to play with that as it is, to get a feel for the user input side of it, and then tweak it to your file input needs. It still requires a bit of work, but I think with that guide, it will be a lot easier.

    Edit: Man, I am completely lost in the file input process. I just spent the last 3 hours trying to adapt my previous code to an "fstream" capable code, and I just can't get it to read the names. It's a lot more difficult than I thought it would be. But, I think I'm on to something...
    Last edited by Molokai; 11-04-2007 at 11:43 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Inheritance Hierarchy for a Package class
    By twickre in forum C++ Programming
    Replies: 7
    Last Post: 12-08-2007, 04:13 PM
  2. Please Help Reading Data From A File
    By NickHolmes in forum C Programming
    Replies: 5
    Last Post: 05-29-2005, 11:24 PM
  3. Editing a data file
    By Strait in forum C++ Programming
    Replies: 7
    Last Post: 02-05-2005, 04:21 PM
  4. File Database & Data Structure :: C++
    By kuphryn in forum C++ Programming
    Replies: 0
    Last Post: 02-24-2002, 11:47 AM
  5. what does this mean to you?
    By pkananen in forum C++ Programming
    Replies: 8
    Last Post: 02-04-2002, 03:58 PM