Thread: Reading in File Help

  1. #1
    Registered User
    Join Date
    Jan 2005
    Posts
    16

    Reading in File Help

    Hi, I'm trying to read from a file and I'm getting a segmentation fault, can someone help me with what I'm doing wrong:

    My .txt file looks exactly like this:
    Code:
    -CD-
    Artist: Outkast
    Title: Stankonia
    Year: 1997
    
    -CD-
    Artist: Jay Z
    Title: Reasonable Doubt
    Year: 1993
    
    -CD-
    Artist: Atmosphere
    Title: Overcast
    Year: 1995
    Those years might not be right but whatever, its a test

    Now this is my code:
    Code:
    #include <iostream.h>
    #include <fstream.h>
    
    
    int main()
    {
      ifstream infile;
      char* line = new char[512];
      char* temp = new char[100];
      char* garbage = new char[50];
      char* artist = new char[50];
      char* title = new char[50];
      char* year = new char[50];
    
      infile.open("databaseFile.txt");
    
      while ( infile.peek() != EOF )
        {
    
          infile.getline(garbage,100);
    
          infile.getline(line,512);
    
          temp = strtok(line, " ");
          strcpy(garbage,temp);
    
          temp = strtok(NULL, "\n");
          strcpy(artist, temp);
    
          temp = strtok(NULL, " ");
          strcpy(garbage,temp);
    
          temp = strtok(NULL, "\n");
          strcpy(title,temp);
    
          temp = strtok(NULL, " ");
          strcpy(garbage,temp);
    
          temp = strtok(NULL, "\n");
          strcpy(year,temp);
    
          infile.getline(garbage,100);
    
        }
    
    }
    The first part should ignore the first line because that just says "-CD-". Then I tried to strtok with the delimeter of " " and ignore that part because thats the part that says "Artist:", "Title: ", and "Year: ". Then I try to strtok with "\n" and save that as the actual artist, title, and year. I strtok'ed with "\n" because artists and titles could have a space in their name so if I strtok with the " " it will break it up. But I'm getting a segmentation fault and I put some cout's in there to find out how far it got and it dumps the core right after it strtok's the artist.

    Can someone please Help!

  2. #2
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    you're not checking the return value of strtok - you're probably passing a NULL pointer to strcpy.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  3. #3
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Boy you sure like overcomplicating things. For starters, why aren't you just using arrays? I mean, it's not like you're resizing anything anyway. Next, you can do all of this with one single buffer. This is what you should be doing:
    Code:
    while not at the end of the file
        read a line
        if line == only whitespace
            continue
        if line == CD
            begin a new record
        if line == artist
            stick artist info into record
        if line == title
            ...
        if line == year
            ...
    It can even be simpler than that if you're sure they'll always have the same format. If you want it to be safe, you do the above with a few variables to track what you've already got in the record.

    You then decide what you do with info that isn't right:
    -CD-
    Artist: Jay Z
    Title: Reasonable Doubt
    Title: Reasonable Foo
    Year: 1993
    Now here we have two title lines. One of these shouldn't be there. You have to account for something like this.

    At any rate, you're overcomplicating this. You don't need strtok at all. You should however use something like this strstr, because it'll be much simpler that way. I'll do this in C, because it seems you like C strings anyway...
    Code:
    while( fgets( buf, BUFSIZ, file ) != NULL )
    {
        if( strstr( buf, "-CD-" ) )
        {
            //we've found the CD line, so just skip it or make a new record
            //or whatever it is you've decided to do. I'll skip it.
            continue;
        }
         if( strstr( buf, "Artist:" ) )
        {
            //Ok, we've got a line starting (or at least containing) "Artist:"
            //Do something with it...
        }
        ...
    }
    And so on. You can even simplify it further if you know your data won't be screwed up.
    Code:
    while( fgets( buf, BUFSIZ, file ) != NULL )
    {
        if( !strstr( buf, "-CD-" ) )
            continue; // It's NOT found, so keep looking...
    
        fgets( artistbuffer, BUFSIZ, file );
        fgets( titlebuffer, BUFSIZ, file );
        fgets( yearbuffer, BUFSIZ, file );
        //now peel off the first part of each and copy them where you want
    }
    But again, this works if you're using records which won't ever be "broken" or incorrect. You could of course skip those three fgets lines and use something like fscanf to read past the "tag"/prefix, and then use fgets to pick up from there.

    Or you could use some of the *stream functions instead of C sytle functions to read your file.

    At any rate, I'd suggest rethinking how you're doing it, because as I've stated, you're overcomplicating the issue.

    Quzah.
    Hope is the first step on the road to disappointment.

  4. #4
    UT2004 Addict Kleid-0's Avatar
    Join Date
    Dec 2004
    Posts
    656
    Check this out swayp, you shall be brought to shore once again:
    Code:
    /*
      WARNING: I used goto, goto is bad.  I used goto because I was too lazy
      to understand the logicalness of the while() loop
    */
    
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <vector>
    
    using std::cout;
    using std::endl;
    using std::ifstream;
    using std::string;
    using std::vector;
    
    // Extract tags from text file
    string extractTag( ifstream * in, string startAfter, string endWhen );
    
    
    int main( )
    {
      // sz = the temperary string that gets extracted from the stream
      // szT = the temperary string that works with the tag innards
    
      string sz;
      string szT;
    
      // Create and open an input stream to the CD database
    
      ifstream in;
      in.open( "CDdb.txt" );
    
      // Make sure the CD database opened successfully
    
      if( !in.is_open( ) )
      {
          cout << "Could not open file" << endl;
          return 1;
      }
    
      // Prepare all of the information for the database
      // A = Artists
      // T = Title of CD
      // Y = Year of CD
    
      vector<string> A;
      vector<string> T;
      vector<string> Y;
    
      // Read all of the information from the CD database:
    
      while( !in.eof( ) )
      {
          // Extract Artist tag
    
          sz = extractTag( &in, "Artist:", "Title:" );
          if( sz.empty( ) )
            break;
          A.push_back( sz );
    
          // Extract Title tag:
    
          sz = extractTag( &in, "", "Year:" );
          if( sz.empty( ) )
            break;
          T.push_back( sz );
    
          // Extract Year tag:
    
          sz = extractTag( &in, "", "-CD-" );
          if( sz.empty( ) )
            break;
          Y.push_back( sz );
      }
    
      // Close the file stream
    
      in.close( );
    
      // Output all of the artists, titles, and years
    
      cout << "Artists: " << endl;
      for( size_t i = 0; i < A.size( ); i++ )
        cout << A[i] << endl;
    
      cout << "------------\nTitles: " << endl;
      for( size_t i = 0; i < T.size( ); i++ )
        cout << T[i] << endl;
    
      cout << "------------\nYears: " << endl;
      for( size_t i = 0; i < Y.size( ); i++ )
        cout << Y[i] << endl;
    
      // Return successfully
    
      return 0;
    }
    
    
    // Extract tags from text file
    string
    extractTag ( ifstream * in, // The stream we're extracting data from
                string s,       // Start extracting data after this string
                string e )      // Stop extracting data once we hit this "other" tag
    {
      // sz = Create a string for comparing when we need to start extracting
      // szM = The master string that we return back as the tag's innards
    
      string sz;
      string szM;
    
      // Start extracting until we hit the start extracting string
      // Make sure the starting isn't empty though, that means we
      // just start scanning for tag innards immediately
    
      if( s.empty( ) )
        goto SkipThisBS;
      while( ( *in ) >> sz )
      {
          if( !sz.compare( s ) )
            break;
      }
    SkipThisBS:
    
      // Make sure the stream is not empty
    
      if( ( *in ).eof ( ) )
        return "";
    
      // Start extracting the real stuff until we hit the ending tag
    
      while( ( *in ) >> sz && sz != e )
        szM += sz;
    
      // Return the innards of the tag
    
      return szM;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. opening empty file causes access violation
    By trevordunstan in forum C Programming
    Replies: 10
    Last Post: 10-21-2008, 11:19 PM
  2. Formatting the contents of a text file
    By dagorsul in forum C++ Programming
    Replies: 2
    Last Post: 04-29-2008, 12:36 PM
  3. Replies: 3
    Last Post: 03-04-2005, 02:46 PM
  4. Possible circular definition with singleton objects
    By techrolla in forum C++ Programming
    Replies: 3
    Last Post: 12-26-2004, 10:46 AM
  5. System
    By drdroid in forum C++ Programming
    Replies: 3
    Last Post: 06-28-2002, 10:12 PM