我的程序应该解析文件中的字符串并存储在结构数组中。
例如:Skyfall,1.109,Sam Mendes,12/9 / 12、143。程序将解析字符串并存储标题,毛额,导演姓名等。
每当我运行代码时,它似乎都无法正确存储。
另外,我遇到此错误。 抛出'std :: logic_error'实例后终止调用 what():basic_string :: _ M_construct null无效
这是我的结构:
struct Movie
{
string Title; // Movie title
string Gross; // Gross total in billion dollars
string Director; // Director name
string Date; // Release date
string Runtime; // Runtime in minutes
};
此功能是创建对象数组并打开文件
Movie* createDatabase(int& number_Of_Lines)
{
// input file
ifstream movie_file;
string filename;
do
{
cout << "Please enter filename: " ;
getline (cin , filename);
movie_file.open(filename.c_str());
if(movie_file.fail())
cout << "Invalid file" << endl ;
}while(movie_file.fail());
// array of objects
number_Of_Lines = numberOfLines(movie_file);
Movie* ptr = new Movie [number_Of_Lines];
//Looping through array of objects
for(int i = 0 ; i < number_Of_Lines ; i++)
populateMovieFromFile(movie_file, ptr[i]);
return ptr;
}
此函数填充对象
void populateMovieFromFile(ifstream& movie_file, Movie& movies)
{
getline(movie_file, movies.Title, ',');
movie_file.ignore();
getline(movie_file, movies.Gross, ',');
movie_file.ignore();
getline(movie_file, movies.Director, ',');
movie_file.ignore();
getline(movie_file, movies.Date, ',');
movie_file.ignore();
getline(movie_file, movies.Runtime);
}
完整程序:
#include <iostream>
#include <string>
#include <fstream>
#include <iomanip>
#include <cctype>
using namespace std;
struct Movie
{
string Title; // Movie title
string Gross; // Gross total in billion dollars
string Director; // Director name
string Date; // Release date
string Runtime; // Runtime in minutes
};
int numberOfLines(ifstream&);
void populateMovieFromFile(ifstream&, Movie&);
void displayMovie(const Movie&);
Movie* createDatabase(int&);
bool caseInsensitiveCmp(string, string);
void findMovie(Movie*, int);
void saveToFile(const Movie&);
bool promptToContinue();
//void displayFavorites();
int main ()
{
int number_Of_Lines = 0;
Movie* ptr_movies = createDatabase(number_Of_Lines);
do
{
findMovie(ptr_movies , number_Of_Lines);
}while (!promptToContinue());
//displayFavorites();
return 0;
}
int numberOfLines(ifstream& movie_file)
{
int number_Of_Lines = 0;
string lines;
if(movie_file)
{
while(getline(movie_file, lines))
number_Of_Lines++ ;
}
movie_file.seekg (0, ios::beg);
return number_Of_Lines;
}
void populateMovieFromFile(ifstream& movie_file, Movie& movies)
{
getline(movie_file, movies.Title, ',');
movie_file.ignore();
getline(movie_file, movies.Gross, ',');
movie_file.ignore();
getline(movie_file, movies.Director, ',');
movie_file.ignore();
getline(movie_file, movies.Date, ',');
movie_file.ignore();
getline(movie_file, movies.Runtime);
}
void displayMovie(const Movie& movie)
{
cout << right << setw(13) << "Title: " << left << movie.Title << endl;
cout << right << setw(13) << "Gross Total: " << left << movie.Gross << " billion dollars" << endl;
cout << right << setw(13) << "Director: " << left << movie.Director << endl;
cout << right << setw(13) << "Release date: " << left << movie.Date << endl;
cout << right << setw(13) << "Runtime: " << left << movie.Runtime << " minutes" << endl;
}
Movie* createDatabase(int& number_Of_Lines)
{
// input file
ifstream movie_file;
string filename;
do
{
cout << "Please enter filename: " ;
getline (cin , filename);
movie_file.open(filename.c_str());
if(movie_file.fail())
cout << "Invalid file" << endl ;
}while(movie_file.fail());
// array of objects
number_Of_Lines = numberOfLines(movie_file);
Movie* ptr = new Movie [number_Of_Lines];
//Looping through array of objects
for(int i = 0 ; i < number_Of_Lines ; i++)
populateMovieFromFile(movie_file, ptr[i]);
return ptr;
}
bool caseInsensitiveCmp(string input, string list) //list will be from the object of array
{
int i = 0 , j = 0;
while (input[i])
{
char c = input[i];
input[i] = tolower(c);
i++;
}
while (list[j])
{
char c = list[j];
list[j] = tolower(c);
j++;
}
if (input == list)
return true;
else
return false;
}
void findMovie(Movie* ptr_movie, int number_Of_Lines)
{
cout << endl;
int i = 0;
char save;
string input_title;
bool found = false;
bool No_Match = false;
cout << "Enter a movie title to search for: ";
getline(cin , input_title);
do
{
found = caseInsensitiveCmp(ptr_movie[i].Title , input_title); //loop it
if (found == false)
i++;
if (i>=number_Of_Lines)
No_Match = true;
} while (found == false || No_Match == false);
if(found == true)
{
displayMovie(ptr_movie[i]);
cout << endl ;
cout << "Would you like to save the above movie? (Y or N)" << endl;
cin >> save;
if (save == 'y' || save == 'Y')
saveToFile(ptr_movie[i]);
}
else
cout << input_title << " not found in database. Please try again." << endl;
}
void saveToFile(const Movie& movie)
{
ofstream outfile;
outfile.open("favourites.txt", ios::app);
cout << movie.Title << "," << movie.Gross << ","
<< movie.Director << "," << movie.Date << ","
<< movie.Runtime << endl;
}
bool promptToContinue()
{
char Quit;
bool exit = false;
cout << "Would you like to exit? (Y or N): ";
cin >> Quit;
switch (Quit)
{
case 'Y':
case 'y':
exit = true;
case 'N':
case 'n':
exit = false;
}
return exit;
}
感谢您的帮助
答案 0 :(得分:0)
问题是:
在“ saveToFile”函数中,打开一个ofstream,但不要使用它。相反,您写入std :: cout。因此,您不必存储数据。
此外,您拨打的是新电话,但从未删除。这样会造成内存泄漏。
然后,您仍然在考虑C语言。您不应该使用new
或纯C样式数组。永远不会。
您应该改用STL容器和更面向对象的方法。目前,您正在使用很多全局函数来处理数据。
在C ++中,您应该使用对象以及关联的数据和方法。例如,电影知道如何读取和存储其数据。因此,将其作为一种方法来实现。
电影数据库是包含电影矢量的附加对象。
为了让您对面向对象的方法有所了解,我为您创建了一个小示例。
请查看并尝试了解。
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <regex>
#include <string>
class Movie
{
public:
// Overload Extractor Operator to read data from somewhere
friend std::istream& operator >> (std::istream& is, Movie& m);
// Overload Inserter operator. Insert data into output stream
friend std::ostream& operator << (std::ostream& os, const Movie& m);
// Show movie data on std::out
void display() const;
// Check if a movie has a certain title
bool hasTitle(const std::string& t) const { return t == title; }
private:
// Data
std::string title{}; // Movie title
std::string gross{}; // Gross total in billion dollars
std::string director{}; // Director name
std::string date{}; // Release date
std::string runtime{}; // Runtime in minutes
};
// Overload Extractor Operator to read data from somewhere
std::istream& operator >> (std::istream& is, Movie& m) {
std::vector<std::string> dataInOneLine{}; // Here we will store all data that we read in one line;
std::string wholeLine; // Temporary storage for the complete line that we will get by getline
std::regex separator(","); ; // Separator for a CSV file
std::getline(is, wholeLine); // Read one complete line
// Parse the line and split it into parts
std::copy(std::sregex_token_iterator(wholeLine.begin(), wholeLine.end(), separator, -1),
std::sregex_token_iterator(),
std::back_inserter(dataInOneLine));
// If we have read all expted strings, then store them in our struct
if (dataInOneLine.size() == 5) {
m.title = dataInOneLine[0];
m.gross = dataInOneLine[1];
m.director = dataInOneLine[2];
m.date = dataInOneLine[3];
m.runtime = dataInOneLine[4];
}
return is;
}
std::ostream& operator << (std::ostream& os, const Movie& m) {
// Copy csv data to ostream
return os << m.title << "," << m.gross << "," << m.director << "," << m.date << "," << m.runtime << "\n";
}
void Movie::display() const {
std::cout << " Title: " << title << "\n Gross Total: " << gross << " billion dollars\n Director: " << director
<< "\nRelease date: " << date << "\n Runtime: " << runtime << " minutes\n";
}
// Database for Movies
class MovieDatabase {
public:
// Constructor. Open and read the database
explicit MovieDatabase(const std::string pafn) : pathAndFileName(pafn) { open(); }
// Destructor automatically saves and closes the database
~MovieDatabase() { close(); };
// Open/close the database
bool open();
void close();
// Add a new movie
void addMovie(const Movie& m) { data.push_back(m); }
// Find and display a movie
bool findAndDisplay (const std::string& title);
private:
const std::string pathAndFileName{};
std::vector<Movie> data{};
};
// Destructor
void MovieDatabase::close() {
// Save data
std::ofstream outFileStream{ pathAndFileName, std::ios::trunc };
if (outFileStream) {
// then save all data in csv format
std::copy(data.begin(), data.end(), std::ostream_iterator<Movie>(outFileStream));
}
}
// Open database and read the data from disk
bool MovieDatabase::open() {
bool success{ false };
// Open the file
std::ifstream inFileStream{ pathAndFileName };
// If the file could be opened
if (inFileStream) {
success = true;
// Then copy all data from disk, parse the csv and store it in our data vector
std::copy(std::istream_iterator<Movie>(inFileStream), std::istream_iterator<Movie>(), std::back_inserter(data));
}
return success;
}
// Find and display a value
bool MovieDatabase::findAndDisplay (const std::string& title) {
bool found { false };
// Search for a given title
std::vector<Movie>::iterator md = std::find_if(data.begin(), data.end(), [&title](const Movie &m) { return m.hasTitle(title); });
if (data.end() != md) {
// If found, then display it
md->display();
found = true;
}
else {
std::cerr << "\n\nTitle '" << title << "' not found in database\n\n";
}
return found;
}
int main() {
// Get the name of the database
std::string pathNameDatabase{};
std::cout << "Enter the path/filename of the database:\n";
std::cin >> pathNameDatabase;
// Define database and open it
MovieDatabase md{ pathNameDatabase };
// Do some stuff
std::cout << "\n\nSearch for title. Please enter title:\n";
std::string title{};
std::cin >> title; std::cin.ignore();
// Search and display data
md.findAndDisplay(title);
// Add a new record
std::cout << "\n\nAdd new movie data\nPlease enter title, gross, director, date, runtime (in one line, seperated by comma):\n";
Movie m{};
std::cin >> m;
m.display();
md.addMovie(m);
return 0;
}