我正在做一个项目,为一家假冒餐厅编写自动计费系统。该程序应该获取一个包含菜单的文本文件,将其放入结构的数组或向量中,显示菜单,让客户订购,并打印收据。我正在为菜单使用结构的全局向量。
这段代码是与问题有关的一切。
`
#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循环的方式也是一种糟糕的做法,可能会导致许多错误、崩溃和以后的头痛。如果你看看下面的函数,它所做的就是获取一个文件名,并尝试打开它(如果存在的话(。一旦打开,它就会得到一行,将其保存到字符串中,并将该字符串推入向量中,直到没有其他内容可读取为止。然后它关闭文件句柄并返回。这符合具有单一责任的职能的概念。
如果你有一个函数,你可以打开一个文件,读入一行,解析数据,读取一行,分析数据等等,然后关闭它;这种功能被认为承担多个任务,这可能是一件坏事。首先是性能方面的原因。可以说,打开和读取文件本身是一项计算成本高昂的任务。您还试图动态创建对象,如果您从未检查以验证从文件中收到的值,这可能会很糟糕。看看我下面的代码,你会看到我所指的设计模式,每个功能都有自己的责任。这也有助于预防CCD_ 5。
#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;
}
至于您的错误或崩溃,您可能正在访问超过向量末尾的索引,或者您试图使用向量中包含无效数据的内容。
如果你查看向量的运算符[],然后检查异常部分,它会告诉你,如果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;
}