繁体   English   中英

尝试输入到结构向量内的结构成员会导致分段错误

[英]Trying to Input to a member of a struct inside a vector of structs causes segmentation fault

我正在做一个项目,正在为一家假餐厅编写自动计费系统。 该程序应该获取包含菜单的文本文件,将其放入结构的数组或向量中,显示菜单,让客户订购并打印收据。 我在菜单中使用结构的全局向量。

此代码块是与问题相关的所有内容。

`

#include <iostream>
#include <fstream>
#include <vector>
//there is more code to this program, but the fault occurs very soon in the program
//and none of the rest of the code has any relevance.
//also, I don't really think that the problem is with trying to input, but I don't have enough experience to rule it out.
using namespace std;

struct menuItemType
{
  string menuItem; //this is the name of the item
  double menuPrice; // this is the price of the item
  int menuCount;
};

vector<menuItemType> menuList; //the menu can be any size so I don't know how big it will be at this point. I'm using a vector to avoid having to declare a size
// I also have 2 other functions and some extra code in main that all need to access this vector. That is why I made it global

void getData() //this function opens the text file containing the menu and tries to read in each line.
{
    ifstream input;
    input.open("inData.txt");

    input.peek();
    int i = 0;
    string item;
    double price;

    while(!input.eof())
    {
        getline(input,menuList[i].menuItem); //This is the line creating the fault.
        input >> menuList[i].menuPrice;

        i++;
        input.peek();
    }
}
int main()
{
    getData();
    return 0;
}

`

我尝试调试,并确定分段错误不是特定于代码片段中注释的行。 每当我尝试输入向量内部结构的成员时,似乎都会发生错误。 我也尝试过使用cin ,所以我不认为文本文件流是问题。 文本文件如下所示:

Bacon and eggs 1.00 Muffin 0.50 Coffee 0.90

具体来说,我的问题是:为什么尝试在向量内部输入结构的成员会导致分割错误,以及如何解决该错误。

抱歉,冗长的解释和笨拙的格式。 我对堆栈溢出和c ++还是相当陌生。

从文件中检索数据时; 我倾向于检索单行的内容并将其存储到某个字符串,流或缓冲区中,然后在以后进行解析,或者我将检索文件的全部内容并执行相同的操作。 从文件中提取数据并关闭其句柄之后,我发现解析字符串更容易。 我不喜欢使用不是CONST的全局变量。 同样,当从文件while( file.eof() )while ( !file.eof() )读取文件时,使用for循环的方式也是不好的做法,以后可能会导致许多错误,崩溃和头痛。 如果您从下面查看我的函数,它会使用一个文件名并尝试打开它(如果存在)。 一旦打开,它将得到一条线,将其保存到字符串中并将该字符串推入向量中,直到没有其他要读取的内容为止。 然后,它关闭文件句柄并返回。 这符合具有单一职责的功能的概念。

如果您具有打开文件,读一行,解析数据,读一行,解析数据等功能,然后关闭它; 这种功能被认为可以承担多项任务,这可能是一件坏事。 首先是性能原因。 可以这么说,打开和读取文件本身是一项计算量很大的任务。 您还尝试动态创建对象,如果您从未检查过从文件中接收到的值,这可能会很糟糕。 在下面查看我的代码,您将看到我所指的设计模式,其中每个功能都有自己的职责。 这也有助于防止file corruption

#include <vector>
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <exception>

struct MenuItem {
  string menuItem; 
  double menuPrice; 
  int menuCount;
};

// This function is not used in this case but is a very helpful function
// for splitting a string into a vector of strings based on a common delimiter
// This is handy when parsing CSV files {Comma Separated Values}.
std::vector<std::string> splitString( const std::string& s, char delimiter ) {
    std::vector<std::string> tokens;
    std::string token;
    std::istringstream tokenStream( s );
    while( std::getline( tokenStream, token, delimiter ) ) {
        tokens.push_back( token );
    }

    return tokens;
}

void getDataFromFile( const char* filename, std::vector<std::string>& output ) {
    std::ifstream file( filename );
    if( !file ) {
        std::stringstream stream;
        stream << "failed to open file " << filename << '\n';
        throw std::runtime_error( stream.str() );
    }

    std::string line;
    while( std::getline( file, line ) ) {
        if ( line.size() > 0 ) 
            output.push_back( line );
    }
    file.close();
}

void parseFileData( const std::vector<std::string>& fileContents, std::vector<MenuItem> menuItems ) {
    // The first param is the contents of the file where each line
    // from the file is stored as a string and pushed into a vector.

    // Here you need to parse this data. The second parameter is the
    // vector of menu items that is being passed by reference.

    // You can not modify the fileContents directly as it is const and read only
    // however the menuItems is passed by reference only so you can update that

    // This is where you will need to go through some kind of loop and get string
    // of text that will stored in your MenuItem::menuItem variable.
    // then the next string will have your price. Here you showed that your
    // text file has `$` in front of the value. You will then have to strip this out 
    // leaving you with just the value itself. 
    // Then you can use `std::stod( stringValue ) to convert to value, 
    // then you can save that to MenuTiem::menuPrice variable.

    // After you have the values you need then you can push back this temp MenuItem
    // Into the vector of MenuItems that was passed in. This is one iteration of
    // your loop. You continue this until you are done traversing through the fileContents vector.


    // This function I'll leave for you to try and write.        
}

int main() {
    try {
        std::vector<std::string> fileConents;
        getDataFromFile( "test.txt", fileConents );
        std::vector<MenuItem> data; // here is the menu list from your example
        generateVectors( fileConents, data );

        // test to see if info is correct
        for( auto& d : data ) {
            std::cout << data.menuItem << " " << data.menuPrice << '\n';
        }

    } catch( const std::runtime_error& e ) {
        std::cerr << e.what() << '\n';
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

至于您的错误或崩溃,您可能是访问了超出向量结尾的索引,或者您尝试使用向量中包含无效数据的内容。

如果查看向量operator [],然后检查异常部分,它将告诉您,如果n大于向量的大小,则实际上是未定义的行为。 您可能想要回退事先创建的项目。

我通常更喜欢vector :: at,因为它经过边界检查,并通过引发out_of_range异常来发出信号,指示所请求的位置是否超出范围。

首先从inData.txt中删除“ $”,然后建议像这样使用while(getline(input,item)):

#include <iostream>
#include <fstream>
#include <vector>
#include <math.h>
//there is more code to this program, but the fault occurs very soon in the program
//and none of the rest of the code has any relevance.
//also, I don't really think that the problem is with trying to input, but I don't have enough experience to rule it out.
using namespace std;

struct menuItemType
{
  string menuItem; //this is the name of the item
  double menuPrice; // this is the price of the item
  int menuCount;
};

vector<menuItemType*> menuList; //the menu can be any size so I don't know how big it will be at this point. I'm using a vector to avoid having to declare a size
// I also have 2 other functions and some extra code in main that all need to access this vector. That is why I made it global

void getData() //this function opens the text file containing the menu and tries to read in each line.
{
    ifstream input;
    input.open("inData.txt");

    int i = 0;
    string item;
    double price;

    while(getline(input, item))
    {
        menuList.push_back(new menuItemType);
        menuList[i]->menuItem = item;
        getline(input,item);
        menuList[i]->menuPrice = atof((char*)item.c_str()); //math.h
        i++;
    }
}
int main()
{
    getData();
    for(menu : menuList)
    {
        cout << menu->menuItem << ": " << menu->menuPrice << endl;
        delete menu; //cleaning memory
    }
    return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM