0

I am reposting this with all of the code this time. I would appreciate not closing the post for at least a little while. I am obviously no expert and I have never run into anything like this before but I do think it can be useful to other members. I tried the comments and agree the error is with destruction but can't find where. I have included the location of the seg fault in comment towards the bottom. I don't have an IDE and don't know how to use the debugger surely built into xterm so I am at a loss!!

#include <iostream>
#include <fstream>
#include <string>
#include "File.h"

using namespace std;

string promptQuit()
{
    string userMode;
    cout 
    << 
    "Would you like to [q]uit?  Enter any other key to continue." 
    << 
    endl;       
    cin >> userMode;
    cin.clear();
    cin.ignore( 1000,'\n' );
    return userMode;
}
int main()
{
    /**************************************************************************/
    /* Variable Declarations and Initializations                              */ 
    /**************************************************************************/
    char fileName[256];
    char destinationFile[256];
    string userMode;
    /**************************************************************************/
    /* Begin prompting user for what they want to do, starting with           */
    /* the filename, then what they want to do with the file.  Once the user  */
    /* finishes with a particular file, they may continue with another file.  */
    /* Therefore, this loop terminates only when the user asks to quit        */
    /**************************************************************************/
    while( userMode != "q" )
    {
        cout 
        << 
            "Welcome to the file handling system. Please type the name of the "
            "file that you wish to read from, write to, or modify followed by "
            "the <return> key:" 
         << 
        endl;
        cin.getline( fileName, 256 );
        File thisFile( fileName );  
        cout 
        << 
            "Current File: " << thisFile.getFileName() << "\nWhat would you "
            "like to do?\n[r]ead, [w]rite, [m]odify, or [q]uit"
        << 
        endl;       
        cin >> userMode;        
        // Invalid entry handling: Reset the failure bit and skip past the 
        // invalid input in the stream, then notify and re-prompt the user for 
        // valid input      
        while( !( (userMode == "w") | (userMode == "r") | (userMode == "q") | 
              (userMode == "m" ) ) )
        {           
            cout 
            <<
                "Invalid entry, please try again\nWhat would you like to do?\n"
                "[r]ead, [w]rite, [m]odify, or [q]uit" 
            << 
            endl;           
            cin >> userMode;
            cin.clear();
            cin.ignore( 1000, '\n' );
        }               
        /*********************************************************************/     
        /* Write Mode: The user is prompted to enter one number at a time    */
        /* and this number is written to the chosen file.  If the user enters*/
        /* an invalid number, such as a letter, the user is notified and     */
        /* prompted to enter a valid real number                             */
        /*********************************************************************/  
        if( userMode == "w" )
            thisFile.writeTo();
        /*********************************************************************/     
        /* Read Mode: The user reads in the entire contents from the file    */
        /* they have chosen                                                  */
        /*********************************************************************/     
        if( userMode == "r" )
            thisFile.readFrom();    
        /*********************************************************************/
        /* Modify Mode: The user may either leave the old file unmodified and*/
        /* place the modified contents into a new file or actually modify the*/ 
        /* original file.                                                    */
        /* The user reads in one line from the file at a time and can either */
        /* choose to accept this number, replace it, delete it, or accept it */
        /* and insert one or more numbers after it.  At any time the user may*/
        /* also choose to accept the remainder of the numbers in the file    */
        /*********************************************************************/
        if( userMode == "m" )
        {
            cout 
            << 
                "Do you want to modify the original file?\n[y]es/[n]o?" 
            << 
            endl;           
            string modify;
            cin >> modify;
            while( !( ( modify == "y" ) | ( modify == "n" ) ) )
            {           
                cout 
                <<
                    "Invalid entry, please try again\nDo you want to modify "
                    "the original file?\n[y]es/[n]o?" 
                << 
                endl;           
                cin >> userMode;
                cin.clear();
                cin.ignore( 1000, '\n' );
            }       
            if( modify == "y" )
            {
                File tempFile;
                thisFile.modify( &tempFile );
            }
            if( modify == "n" )
            {
                cout 
                << 
                    "Please type the name of the destination file followed by "
                    "the <return> key:" 
                << 
                endl;               
                cin.getline( destinationFile, 256 );
                File newFile( destinationFile );
                thisFile.modify( &newFile );
/****************************************************************/
/****Seg fault occurs here.  Never exits this IF but above*******/ 
/*function does return.Doesn't get past close curly brace********/
/****************************************************************/
            }
        }
        userMode = promptQuit();
    }
return 0;
}

Here is the .cpp file

#include <fstream>
#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <string>
#include <math.h>
#include <iomanip>
#include "File.h"

using namespace std;

// Returns ordinal number from input integer num, e.g., 1st for 1
string ordinalString( const int num )
{
    stringstream numeric;
    numeric << num;
    string ordinalUnit;
    string ordinal = numeric.str();
    switch( num%10 )
    {
    case 1: ordinalUnit = "st"; break;
    case 2: ordinalUnit = "nd"; break;
    case 3: ordinalUnit = "rd"; break;
    default: ordinalUnit = "th"; break;
}
switch( num )
{
    case 11: ordinalUnit = "th"; break;
    case 12: ordinalUnit = "th"; break;
    case 13: ordinalUnit = "th"; break;
}
ordinal += ordinalUnit;
return ordinal;
}

float promptRealNumber()
{
float validEntry;
// Invalid entry handling: Reset the failure bit and skip past the 
// invalid input in the stream, then notify and re-prompt the user for 
// valid input
while ( !(cin >> validEntry) )
{
    cout << "Invalid Input: Entry must be a real number. Please try again:";                
    cin.clear();   
    cin.ignore( 1000, '\n' ); 
}
return validEntry;
}

File::File()
{
    fileName = "temp.txt";
    entries = 0;
}

File::File( const char * file_name )
{
entries = 0;
string currentLine;
fileName = file_name;
ifstream thisFile( file_name );
if ( thisFile.is_open() )
{
    while ( !thisFile.eof() )
    {
        getline ( thisFile, currentLine );
        entries++;
    }
thisFile.close();
}
else 
    cout << "Error opening file.  File may not exist." << endl; 
entries--;
}

File::File( const File * copyFile )
{
fileName = copyFile->fileName;
entries = copyFile->entries;
}


void File::promptNumEntries()
{
cout 
<< 
    "Please enter the number of entries you wish to input into " 
    << fileName << " followed by the '<return>' key" 
<< 
endl;

// Invalid entry handling: Reset the failure bit and skip past the invalid 
// input in the stream, then notify and re-prompt the user for valid input
while ( !(cin >> entries) || ( floor( entries ) != entries ) )
{
    cout << "Invalid Input: Entry must be an integer.  Please try again: ";         
    cin.clear(); 
    cin.ignore ( 1000, '\n' );  
}
}   

void File::readFrom()
{
string currentLine;
ifstream inFile( fileName.c_str() );    
if ( inFile.is_open() )
{
    while ( inFile.good() )
    {
        getline ( inFile, currentLine );
        cout << currentLine << endl;
    }
    inFile.close();
}
else 
    cout << "Error opening file.  File may not exist." << endl; 
}

void File::writeTo()
{
ofstream outFile( fileName.c_str() );
string ending;
promptNumEntries();
for( int entry = 1; entry <= entries; entry++ )
{       
    // Notify the user which entry they are currently entering so if they lose
    // their place, they can easily find which number they should be entering.
    cout 
    << 
        "Please enter the " << ordinalString( entry ) << " number followed "
        "by the <return> key" 
    << 
    endl;

    float entryNum = promptRealNumber();
    outFile << fixed << setprecision(1) << entryNum << endl;
}       
outFile.close();
}

void File::modify( const File * destination_file )
{
ifstream sourceFile( fileName.c_str() );
ofstream destinationFile( destination_file->fileName.c_str() );
string currentLine;
string entryAction;
string insertMore = "y";
float replacementEntry;
float insertEntry;
int entry = 0;

if ( sourceFile.is_open() )
{
    while ( !sourceFile.eof() )
    {
        getline( sourceFile, currentLine ); 
        cout 
        << 
            currentLine << endl << "Do you want to [k]eep this entry, "
            "[r]eplace it, [d]elete it, [i]nsert after it, or accept this "
            "and [a]ll remaining entries?" 
        << 
        endl;           
        cin >> entryAction;

        // Keep current entry.  Also called when inserting an entry since
        // this also requires keeping the current entry
        if( ( entryAction == "k" ) | ( entryAction == "i" ) )
            destinationFile << currentLine << endl;

        // Replace current entry
        if( entryAction == "r" )
        {
            cout 
            << 
                "Please type the new entry followed by the <return> key:" 
            << 
            endl;                               
            replacementEntry = promptRealNumber();
            destinationFile 
            << 
                fixed << setprecision(1) << replacementEntry 
            << 
            endl;
        }

        // Deleting the current entry amounts to simply ignoring it and 
        // continuing to the next entry, if it exists
        if( entryAction == "d" );

        // Insert one or more entries after current entry
        if( entryAction == "i" )
        {

            while( insertMore == "y" )
            {
                cout 
                << 
                    "Please type the entry to be inserted followed by the "
                    "<return> key:" 
                << 
                endl;                               
                insertEntry = promptRealNumber();
                destinationFile 
                << 
                    fixed << setprecision(1) << insertEntry 
                << 
                endl;                   
                cout << "Insert another number?\n[y]es/[n]o?" << endl;
                cin >> insertMore;
                while( !( (insertMore == "y") | (insertMore == "n" ) ) )
                {           
                    cout 
                    <<
                        "Invalid entry, please try again\nInsert another "
                        "number?\n[y]es/[n]o?"
                    << 
                    endl;           
                    cin >> insertMore;
                    cin.clear();
                    cin.ignore( 1000, '\n' );
                }   
            }
        }

        // Accept all remaining entries
        if( entryAction == "a" )
        {
            destinationFile << currentLine << endl;
            while ( entry < entries )
            {
                getline ( sourceFile, currentLine );
                destinationFile << currentLine << endl;
                entry++;
            }           
        }
        destinationFile.close();
        sourceFile.close(); 
    }
}
else 
    cout << "Error opening file.  File may not exist." << endl;
}

void File::copyFileContents( const File * to, const File * from )
{
ifstream fromFile( to->fileName.c_str() );
ofstream toFile( from->fileName.c_str() );
string currentLine;
while( !fromFile.fail() && !toFile.fail() )
{
    for( int line = 0; line < from->entries; line++ )
    {
        getline( fromFile, currentLine );
        toFile << currentLine;
    }
}
}

Here is the .h file

#include <string>

using namespace std;

class File
{
public:
    File();
    File( const char * );
    File( const File * copyFile );
    ~File() { delete this; }
    string getFileName() { return fileName; }
    float numEntries() { return entries; }
    void setNumEntries( const float numEntries ) { entries = numEntries; }
    void promptNumEntries();
    void readFrom();
    void writeTo();
    void modify( const File * );
    void copyFileContents( const File * , const File * );
private:
    string fileName;
    float entries;
};

I tried commenting out the sourceFile.close() statement and still nothing. I know its a lot of code but whoever can help would be my hero of the century!!

Blake
  • 75
  • 1
  • 2
  • 10
  • 1
    Try using a debugger. If you have a segfault, the debugger backtrace should be able to tell you precisely what's going wrong; come back with a more specific question. – Kerrek SB Oct 10 '11 at 15:32
  • 4
    Try reducing the code to the smallest example that still fails. There is a lot of code here (and a lot of missing code too). You may even solve the problem on your own this way! You are much more likely to get help if you present a [SSCCE](http://sscce.org/). – Mankarse Oct 10 '11 at 15:34
  • Seems like it crashes in the destractor of File? Although the crash may be a result of some other problem. – Yakov Galka Oct 10 '11 at 15:35
  • I didn't want to but it got closed after 5 min – Blake Oct 10 '11 at 16:05
  • There's a reason it got closed, Blake. – Michael Petrotta Oct 10 '11 at 16:06
  • Too narrow? Can't be that uncommon of a problem! – Blake Oct 10 '11 at 16:07
  • Don't be rude. Observe the rules and conventions of the community you're new to. If I knock on your door, and I answer and tell you to go away, do you knock again? – Michael Petrotta Oct 10 '11 at 16:09
  • 2
    `~File() { delete this; }`??? this is meaningless because: 1. you don't know where File was allocated, in your case it was allocated on stack in which case you cannot delete it. 2. calling delete on an object that is already being deleted is just recursively calls it's destructor. => remove this line. – Yakov Galka Oct 10 '11 at 16:10
  • Put the code in your original question (and improve the overall question if necessary) and then flag it for moderator attention to get it re-opened. – Paul R Oct 10 '11 at 16:13
  • Hey Michael, don't be so unfriendly. The error wasn't that difficult to spot after all. And I've seen much worse code here (ok, its a LOT of code, but at least, it's nicely formatted). I agree it should have been shortened, but sometimes that's a difficult task for unexperienced programmers (and thats the people we'd like to help here, aren't they?), especially if they have no clue where to spot for the error ... – MartinStettner Oct 10 '11 at 16:18
  • 1
    Thank you Paul, I will do that in the future. I tried to make it as short as possible and when people mentioned the missing code I tried to put it in, but it was already closed, so I reposted. My response to Michael wasn't rude at all, and frankly, I think he is the one being rude. – Blake Oct 10 '11 at 16:19
  • @Martin, Paul: my issue isn't with the original question. My issue is with this one. The community decided (for better or worse) to close the original, and Blake decided to ignore that decision and repeat himself. Quite rude. If you don't see that, I'd encourage you to spend some time here, and get a feel for the community. – Michael Petrotta Oct 10 '11 at 16:27
  • Wow. Yeah I am getting a feel for the community already! Some real cool people here so far though. Can't wait til' there is a low enough level problem for me to help out on lol. – Blake Oct 10 '11 at 16:34
  • @Michael: Oh, of course I certainly do not spend as much time here as you :) But on the other hand, it only needs 5(!) people to close a question, so I cannot always accept this to be a "community decision". Also if this happens within half an hour it can be quite discouraging (especially if all the OP gets are comments like "you didn't post enough of your code" and then "your code is too long" and he doesn't know how to do it better). Besides from the amount of code, imo the question was perfectly legal compared to other questions I spot in the scarce time I spend here ... – MartinStettner Oct 10 '11 at 16:45
  • @Martin, again, I'm not talking about the original question. I'm talking about this one. Blake might be quite right in objecting to the closure of his original question, but the right way to do that is not by reposting it (it's by improving it, commenting on it, or by appealing to [Meta](http://meta.stackoverflow.com) in egregious cases). I bring my example up again - maybe it's not right to close my front door in someone's face if I don't like them. It's not right to stand there and knock until they open again, though. – Michael Petrotta Oct 10 '11 at 16:49
  • I appreciate you sticking up for me. As discouraging as this may be to Michael, you and Paul are the only reason I won't completely abandon this forum.I am a new poster and do not know all the rules and etiquette of the forum, so when my post got closed and people had commented on missing code and the like, I thought that was why and didn't feel I was being rude by reposting. Programmers tend to be very strict rule people, syntax syntax syntax, and I can wade through his attitude to the lesson to be learned. I am a physicist/mathematician in a CSE masters, I better get used to it quickly!! – Blake Oct 10 '11 at 16:58
  • We can all come up with analogies as a basis for any opinion, doesn't mean they're valid. Constructive criticism helps, and had it been given before the thread got closed, it would have been taken. – Blake Oct 10 '11 at 17:02
  • Well, you learned something today about SO rules and etiquette! Here's one more: if you want someone to see your replies, prefix your comment with the '@' character and the user's name, like: @Blake. – Michael Petrotta Oct 10 '11 at 17:02

2 Answers2

2

Remove delete(this) from the destructor!

You aren't constructing a File with new (since you're using a static instance on the stack), but the destructor is called anyway. So the delete statement is invalid and probably causes the segfault.

MartinStettner
  • 28,719
  • 15
  • 79
  • 106
  • What should I have put there? – Blake Oct 10 '11 at 16:09
  • Thank you so much, I can't even tell you how much work I put into trying to solve this by myself, I never post on forums and everyone jumped on me for posting this so I really appreciate your help. – Blake Oct 10 '11 at 16:12
  • You're welcome :) Next time, try to reduce the code size, you could've omitted all the comments and `cout`s for example, and just have tried to only leave the `if` branch which gave you the segfault. – MartinStettner Oct 10 '11 at 16:21
  • Thanks again Martin. I knew it was something stupid but I am taking this dumb software engineering class and he flagged me for not having a default and copy constructor even though I don't need them. Every time in the past I made a destructor I had always used new to create so it didn't even occur to me that that could be the problem. Embarassing!! I'm not that unexperienced but it sure appears I have some significant gaps!! – Blake Oct 10 '11 at 16:24
  • OK thanks again. Again I have never posted before and didn't know if people needed the comments to figure out function or what I should do. I posted less on the last post and people commented it was hard with the missing code so I'll try to do better balancing that in the future. That's why I was pretty upset the post got closed so fast without even giving me these type of comments. – Blake Oct 10 '11 at 16:27
  • @Blake - Possibly he flagged you about the copy constructor because of [the rule of three](http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three), which is usually good advice. There's definitely no reason why *every* `class` needs to have any/all implemented though. – Flexo Oct 10 '11 at 19:39
0

I've once seen a SEG fault on an if statement and the cause of it (after many hours of misery) turned out to be because I was accessing a private data member of the object, but that I had already started to destroy the object.

My guess is that it might be this line as that looks to me that you are destroying a resource that you are still using.:

 sourceFile.close(); 

Try commenting that out and see how it goes.

satnhak
  • 9,407
  • 5
  • 63
  • 81
  • The destructor executes before the destructors of the members, though. – Kerrek SB Oct 10 '11 at 15:40
  • Sure, this was an MFC error - the window.close() method had been called mid-function, which had invalidated all of the data members and so when a boolean member was accessed the memory was no longer valid and it threw a seggy. This looks similar. – satnhak Oct 10 '11 at 15:44