C : ошибка Seg при выходе из оператора IF

#segmentation-fault

#c #ошибка сегментации

Вопрос:

На этот раз я перепечатываю это со всем кодом. Я был бы признателен, если бы не закрывал сообщение хотя бы на некоторое время. Я, очевидно, не эксперт, и я никогда не сталкивался ни с чем подобным раньше, но я думаю, что это может быть полезно для других участников. Я попробовал комментарии и согласен, что ошибка связана с уничтожением, но не могу найти, где. Я включил местоположение ошибки seg в комментарий внизу. У меня нет IDE, и я не знаю, как использовать отладчик, обязательно встроенный в xterm, поэтому я в недоумении!!

 #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 againnWhat 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 againnDo 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( amp;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( amp;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;
}
  

Вот файл .cpp

 #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 againnInsert 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() amp;amp; !toFile.fail() )
{
    for( int line = 0; line < from->entries; line   )
    {
        getline( fromFile, currentLine );
        toFile << currentLine;
    }
}
}
  

Вот файл .h

 #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;
};
  

Я попытался закомментировать оператор SourceFile.close() и по-прежнему ничего. Я знаю, что это много кода, но тот, кто может помочь, станет моим героем века!!

Комментарии:

1. Попробуйте использовать отладчик. Если у вас ошибка segfault, отладчик должен быть в состоянии точно сообщить вам, что происходит не так; вернитесь с более конкретным вопросом.

2. Попробуйте сократить код до наименьшего примера, который все еще терпит неудачу. Здесь много кода (и много недостающего кода тоже). Вы даже можете решить проблему самостоятельно таким образом! У вас гораздо больше шансов получить помощь, если вы представите SSCCE .

3. Похоже, что он выходит из строя в деструкторе файла? Хотя сбой может быть результатом какой-то другой проблемы.

4. ~File() { delete this; } ??? это бессмысленно, потому что: 1. вы не знаете, где был выделен файл, в вашем случае он был выделен в стеке, и в этом случае вы не можете его удалить. 2. вызов delete для объекта, который уже удаляется, просто рекурсивно вызывает его деструктор. => удалите эту строку.

5. Спасибо, Пол, я сделаю это в будущем. Я попытался сделать его как можно короче, и когда люди упомянули недостающий код, я попытался вставить его, но он уже был закрыт, поэтому я перепостил. Мой ответ Майклу совсем не был грубым, и, честно говоря, я думаю, что это он грубит.

Ответ №1:

Удалить delete(this) из деструктора!

Вы не создаете File with new (поскольку используете статический экземпляр в стеке), но деструктор вызывается в любом случае. Таким delete образом, оператор недействителен и, вероятно, вызывает ошибку segfault.

Комментарии:

1. Что я должен был туда поместить?

2. Большое вам спасибо, я даже не могу сказать вам, сколько работы я потратил, пытаясь решить это самостоятельно, я никогда не публикую сообщения на форумах, и все набросились на меня за публикацию этого, поэтому я действительно ценю вашу помощь.

3. Пожалуйста 🙂 В следующий раз попробуйте уменьшить размер кода, например, вы могли бы опустить все комментарии и cout s и просто попытаться оставить только ту if ветку, которая дала вам ошибку segfault.

4. Еще раз спасибо, Мартин. Я знал, что это что-то глупое, но я беру этот тупой класс разработки программного обеспечения, и он отметил меня за то, что у меня нет конструктора по умолчанию и копирования, хотя они мне не нужны. Каждый раз, когда в прошлом я создавал деструктор, я всегда использовал new для создания, поэтому мне даже не приходило в голову, что это может быть проблемой. Смущает!! Я не настолько неопытен, но, похоже, у меня есть некоторые существенные пробелы!!

5. Хорошо, еще раз спасибо. Опять же, я никогда не публиковал раньше и не знал, нужны ли людям комментарии, чтобы выяснить функцию или что я должен делать. Я опубликовал меньше в последнем сообщении, и люди прокомментировали, что это было сложно с отсутствующим кодом, поэтому я постараюсь лучше сбалансировать это в будущем. Вот почему я был очень расстроен, что сообщение было закрыто так быстро, даже не дав мне комментариев такого типа.

Ответ №2:

Однажды я видел ошибку SEG в операторе if, и ее причиной (после многих часов страданий) оказалось то, что я обращался к частному элементу данных объекта, но я уже начал уничтожать объект.

Я предполагаю, что это может быть эта строка, поскольку мне кажется, что вы уничтожаете ресурс, который вы все еще используете.:

  sourceFile.close(); 
  

Попробуйте прокомментировать это и посмотреть, как это происходит.

Комментарии:

1. Однако деструктор выполняется перед деструкторами членов.

2. Конечно, это была ошибка MFC — метод window.close() был вызван в середине функции, что привело к аннулированию всех элементов данных, и поэтому при обращении к логическому элементу память была недействительной, и она выдавала сегги. Это выглядит похоже.