Thread: Reading Strings from a file.

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

    Reading Strings from a file.

    Hi all, I'm pretty new at programming and have some big troubles with the following program. I hope someone can give me some tips so I can continue.


    First of all I made a class URL_Keyword_Mapping, which has 3 private arguments: an url (string), a keyword (string) and a weight (int).

    Code:
    class URL_Keyword_Mapping{
    private:
    	std::string url;
    	std::string keyword;
    	int weight;
    }
    Now I am receiving a certain .txt file and I need to read the arguments and put them in an array of URL_Keyword_Mapping objects.

    Here is an example of the structure of the given file:

    http://www.youtube.com youtube 90000 videos 80000
    http://www.google.com cars 20000 dogs 30000 cats 25000

    The url is only used only once, so actually there are 5 objects up there:
    - http://www.youtube.com, youtube, 90000
    - http://www.youtube.com, videos, 80000
    - http://www.google.com cars 20000
    - http://www.google.com dogs 30000
    - http://www.google.com cats 25000


    Here is my method:

    Code:
    URL_Keyword_Mapping* read(std::ifstream& ifile, int& length) {
    
    URL_Keyword_Mapping Array[50]; 
    int i = 0;
    std::string test;      
    	
    while (ifile.eof()) { 
    
         ifile >> Array[i].url >> Array[i].keyword >> Array[i].weight; // Reading first 3 arguments
         ifile >> test; 
    		
         while (test != '\n') {   // Check if you reached end of the line or not
              Array[i+1].url = Array[i].url;
              Array[i+1].keyword = test;  
              ifile >> Array[i+1].weight;
              ifile >> test;        		
              i++;
    	  }
         i++; 
    }
    return Array;
    }
    Short explanation: First we read the first 3 arguments and put them in our first array object. We read the next argument, but don't know sure if there are any. But, if there are, it will only be a new keyword + weight, because the URL is only placed once at the beginning of each line.

    If there are still strings to come, we put them in the next array object and repeat the process. As soon as we meet a newline character, we go out of the loop and repeat the process for the next line.

    Problems: I'm getting like 20 errors about the test = '\n' comparation. I don't really know how to solve the problem =/.
    Last edited by RealLife; 05-12-2007 at 01:33 PM.

  2. #2
    Registered User
    Join Date
    May 2007
    Posts
    88
    Code:
    //This
    while (ifile.eof()) { 
    //Should probably be this
    while ( !  ifile.eof()) {
    Also, you'll want to restructure your loop like this, otherwise you'll do an extra read
    Code:
    ifile >>test;
    while (!ifile.eof()) {
        //Do whatever with test
        ifile >>test;
    }
    Also,
    Code:
    while (test != '\n')
    Assuming that your stream is set up to ignore whitespace, this will always be true. You're going to need a new plan. My suggestion would be to devise a special character/string that signifies that what you're about to read is a URL and not weight/keyword, and then test for that instead of '\n'.
    Last edited by UMR_Student; 05-12-2007 at 01:46 PM.

  3. #3
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    Damn. More !feof() people. !feof() doesn't work all the time, and when it doesn't work, it blows up in a big way. feof() and its C++ stream equivalent eof() only return true after EOF has been encountered - this results in extra iterations that can cause problems, and that's why it's still in the FAQ.

    It is better to let the input fetching routine fail and stop the loop cause it will always do so in a prompt manner.

    Consider using
    Code:
    while ( std::getline( stream, input_str, '\n' ) )
    {
      // parse the line here.   
    }
    Once you grab a whole line of input you can break it up into parts and find what you need to use or store away.

  4. #4
    Registered User
    Join Date
    May 2007
    Posts
    88
    > Damn. More !feof() people.

    It's not that big of a deal. Although checking read returns is generally a better practice, in years past I have written tons of loops with feof and processed all types of different files of different sizes, and I've never had a problem. Perhaps it's poorly implemented on other compilers/architectures...

  5. #5
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    It only "works" because you have the read in two places, one outside the loop and one inside.

    But that breeds more problems, because you end up with the same line of code in two different places.
    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.

  6. #6
    Registered User
    Join Date
    May 2007
    Posts
    88
    I understand that, which is why I apparently wasted the necessary time to say "...checking read returns is generally a better practice."

  7. #7
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    Quote Originally Posted by UMR_Student View Post
    I understand that, which is why I apparently wasted the necessary time to say "...checking read returns is generally a better practice."
    Good! I'm glad that you do, and what I said has nothing to do with you personally. But the person you were trying to help probably doesn't know that, which makes it rather important. Eventually, he's going to have to understand why certain functions can make things easy but shouldn't be used in unintended situations. The type of situations that they weren't programmed for.

    There's all sorts of things the unaware can do if they relied on something they misunderstood, like feof(). It doesn't work if you depend on that loop to also count an index to an array. Indeed, you could also seg fault because the while loop iterated one too many times.

  8. #8
    Registered User
    Join Date
    May 2007
    Posts
    5
    Thanks a lot for all the feedback. I didn't know \n was seen as a whitespace, which kinda ruins my whole plan

    Quote Originally Posted by citizen View Post
    Once you grab a whole line of input you can break it up into parts and find what you need to use or store away.
    Well I thought about that but I don't know how =|. There could be 3 words, or 100... How can i make a loop if I don't know how many words I'm looking for

  9. #9
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    Well I thought about that but I don't know how =|. There could be 3 words, or 100... How can i make a loop if I don't know how many words I'm looking for
    We're only dealing with one line at a time. If you want to separate a string by words, then look for whitespace and when you find it, end the string (the string library should have something like a splice() function) and save that part somewhere, like an array of strings.

    You might just want to practice tokenizing a sample string, and printing out what you find. After you can do it with a normal string that you make up, then incorporating the file streams part should be easy. All you'd have to do then is read the file and store the information in an array of your class.

    Observe how Noir breaks down his overall goal into smaller goals, and compiles the program often. https://cboard.cprogramming.com/showthread.php?t=88495 You get less confused if you slow down. Being able to do bigger projects faster comes with experience.

  10. #10
    Registered User
    Join Date
    May 2007
    Posts
    88
    > Thanks a lot for all the feedback.
    You're welcome.

    >How can i make a loop if I don't know how many words I'm looking for
    One solution is to make use of istringstream, then you can parse each line out of a string buffer just like you would directly out of the file.

  11. #11
    Registered User
    Join Date
    May 2007
    Posts
    5
    I managed to fix it with the sstream library, so at least I'm getting somewhere now . I can compile all the code, but the program gave me an error when executing. So I set some breakpoints and followed everything step by step, and something really weird happens.

    Code:
    URL_Keyword_Mapping* read(std::ifstream& ifile, int& length) {
    
    	URL_Keyword_Mapping ukm_array[50];
    
             // some other code, not important here I think 
    
    	return ukm_array;
    }
    I'm working with Visual C++ Express Edition and at the bottom left I have a screen where I can follow all the objects with their values.

    Right before I call the return function, ukm_array points to the correct first object (I opened a test.txt file in my main function to work with)
    But after I return the pointer, the url and keyword string suddenly become empty "" strings. The weight still stays the same...

    I'm pretty confused..

  12. #12
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    That's a local array. When the function ends, it is destroyed. You are returning a pointer to it, so when the function ends the pointer points at invalid memory.

    It would probably be better to pass the array in as a function parameter and fill it rather than return it. If the calling code doesn't know the size beforehand, you'll probably need dynamic memory, in which case I would use a vector rather than an array.

  13. #13
    Registered User
    Join Date
    May 2007
    Posts
    5
    Thanks for clearing that up, quite a stupid mistake I made there! :/

    The problem is that I cannot change the function parameters, it's a project for school and I need to work with the function prototypes in the given header file.

    I'll try to figure out what vectors are, thanks .

  14. #14
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    If you can't change the function parameters then you probably can't change the function return type. That means you can't use a vector, even though it is the better choice (unfortunately many course/books/tutorials don't teach vectors until the very end if at all).

    You'll probably have to use new to allocate your dynamic array and return a pointer to it. Since you would be using new, the memory for the array would last forever until you call delete to free it. That means it is ok to return a pointer to the array from the function, because when the function ends the memory will still be valid.

  15. #15
    Registered User
    Join Date
    May 2007
    Posts
    5
    Okay so I used a vector instead of an array. I read somewhere that you can just return the vector pointer when the function is expecting an array pointer.

    However, I still encounter the same problem . I'm still getting an empty pointer out of that function =/
    Last edited by RealLife; 05-12-2007 at 07:38 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Help with reading strings from a file
    By ldcel in forum C Programming
    Replies: 3
    Last Post: 12-01-2007, 01:31 AM
  2. Dikumud
    By maxorator in forum C++ Programming
    Replies: 1
    Last Post: 10-01-2005, 06:39 AM
  3. Simple File encryption
    By caroundw5h in forum C Programming
    Replies: 2
    Last Post: 10-13-2004, 10:51 PM
  4. Unknown Memory Leak in Init() Function
    By CodeHacker in forum Windows Programming
    Replies: 3
    Last Post: 07-09-2004, 09:54 AM
  5. simulate Grep command in Unix using C
    By laxmi in forum C Programming
    Replies: 6
    Last Post: 05-10-2002, 04:10 PM