简体   繁体   English

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

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

I am doing a project where I am writing automated billing system for a fake restaurant. 我正在做一个项目,正在为一家假餐厅编写自动计费系统。 The program is supposed to take a text file containing the menu, put it into a array or vector of structs, show the menu, let the customer order, and print a receipt. 该程序应该获取包含菜单的文本文件,将其放入结构的数组或向量中,显示菜单,让客户订购并打印收据。 I am using a global vector of structs for the menu. 我在菜单中使用结构的全局向量。

This block of code is everything related to the problem. 此代码块是与问题相关的所有内容。

` `

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

` `

I have tried debugging and have determined that the segmentation fault is not specific to the line commented in the code snippet. 我尝试调试,并确定分段错误不是特定于代码片段中注释的行。 The fault seems to occur whenever I try to input to a member of a struct inside the vector. 每当我尝试输入向量内部结构的成员时,似乎都会发生错误。 I've tried using cin as well so I don't believe the text file stream is the problem. 我也尝试过使用cin ,所以我不认为文本文件流是问题。 The text file looks like this: 文本文件如下所示:

Bacon and eggs 1.00 Muffin 0.50 Coffee 0.90

Specifically, my question is: Why does trying to input to a member of a struct inside the vector cause a segmentation error and how can I fix it. 具体来说,我的问题是:为什么尝试在向量内部输入结构的成员会导致分割错误,以及如何解决该错误。

Sorry for the long explanation and awkward formatting. 抱歉,冗长的解释和笨拙的格式。 I am fairly new to both stack overflow, and c++. 我对堆栈溢出和c ++还是相当陌生。

When retrieving data from a file; 从文件中检索数据时; I tend to prefer to retrieve the contents of a single line and store that to some string, stream or buffer and parse it later, or I'll retrieve the entire contents of a file and do the same. 我倾向于检索单行的内容并将其存储到某个字符串,流或缓冲区中,然后在以后进行解析,或者我将检索文件的全部内容并执行相同的操作。 I find it easier to parse a string after you have extracted the data from the file and closed its handle. 从文件中提取数据并关闭其句柄之后,我发现解析字符串更容易。 I do not like using global variables that are NOT CONST. 我不喜欢使用不是CONST的全局变量。 Also the way you are using your for loop when reading from a file while( file.eof() ) or while ( !file.eof() ) is bad practice and can lead to many errors, crashes and headaches later on. 同样,当从文件while( file.eof() )while ( !file.eof() )读取文件时,使用for循环的方式也是不好的做法,以后可能会导致许多错误,崩溃和头痛。 If you look at my function below all it does is it takes a filename and tries to open it if it exists. 如果您从下面查看我的函数,它会使用一个文件名并尝试打开它(如果存在)。 Once it opens, then it will get a line save it to a string and push that string into a vector until there is nothing else to read. 一旦打开,它将得到一条线,将其保存到字符串中并将该字符串推入向量中,直到没有其他要读取的内容为止。 Then it closes the file handle and returns. 然后,它关闭文件句柄并返回。 This fits the concept of a function having a single responsibility. 这符合具有单一职责的功能的概念。

If you have a function where you open a file, read in a line, parse the data, read a line, parse the data etc. then close it; 如果您具有打开文件,读一行,解析数据,读一行,解析数据等功能,然后关闭它; this kind of function is considered to take on multiple tasks which can be a bad thing. 这种功能被认为可以承担多项任务,这可能是一件坏事。 First there are performance reasons. 首先是性能原因。 Opening and reading from a file itself is a computationally expensive task so to speak. 可以这么说,打开和读取文件本身是一项计算量很大的任务。 You are also trying to create objects on the fly and this can be bad if you never checked to validate the values you received from the file. 您还尝试动态创建对象,如果您从未检查过从文件中接收到的值,这可能会很糟糕。 Take a look at my code below and you will see the design pattern that I'm referring to where each function has its own responsibility. 在下面查看我的代码,您将看到我所指的设计模式,其中每个功能都有自己的职责。 This also helps to prevent file corruption . 这也有助于防止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;
}

As for your error or crash, you were probably either accessing an index that is past the end of the vector, or you were trying to use contents from the vector that had invalid data. 至于您的错误或崩溃,您可能是访问了超出向量结尾的索引,或者您尝试使用向量中包含无效数据的内容。

If you look at the operator[] of a vector and then check on the exception section, it will tell you that if n is superior than the size of the vector, it's actually undefined behavior. 如果查看向量operator [],然后检查异常部分,它将告诉您,如果n大于向量的大小,则实际上是未定义的行为。 You probably want to push back an item you've created beforehand. 您可能想要回退事先创建的项目。

I usually prefer vector::at as it is bound-checked and signals if the requested position is out of range by throwing an out_of_range exception. 我通常更喜欢vector :: at,因为它经过边界检查,并通过引发out_of_range异常来发出信号,指示所请求的位置是否超出范围。

First remove "$" from inData.txt then I suggest to use while(getline(input, item)) like this way: 首先从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