无法填充结构数组
Posted
技术标签:
【中文标题】无法填充结构数组【英文标题】:Unable to populate array of structures 【发布时间】:2019-10-17 22:40:55 【问题描述】:我的程序应该解析文件中的字符串并存储在结构数组中。
示例:Skyfall, 1.109, Sam Mendes, 11/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;
感谢任何帮助
【问题讨论】:
似乎没有正确存储它?这是什么意思?您的程序是否正常运行和退出?如果您的程序意外终止,这不是一件好事,您可以忘记程序是如何存储数据的。你说一个错误,这意味着你的代码是crashing
。你的代码在哪一行失败了?
【参考方案1】:
问题是:
在您的“saveToFile”函数中,您打开了一个 ofstream,但不要使用它。相反,您写入 std::cout。因此,您不存储数据。
此外,您正在调用 new 但从不删除。这样你就会造成内存泄漏。
那么,您仍然在 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;
【讨论】:
以上是关于无法填充结构数组的主要内容,如果未能解决你的问题,请参考以下文章
在检查新行时使用 fscanf 从文件中填充结构数组(反馈)