gpt4 book ai didi

c++ - 在 0x5914F3BE (ucrtbased.dll) 抛出异常

转载 作者:行者123 更新时间:2023-11-30 04:43:52 27 4
gpt4 key购买 nike

我有一些代码从 .txt 文件中获取名称列表 + double 值,并在命令提示符中显示这些。为此,动态分配了一个结构数组。代码应该根据 .txt 文件中的第一个值知道数组的大小,然后是名称和关联值。然后它应该将列表分为两部分显示,首先列出的是关联 double 值大于或等于 10.000 的名称。如果没有任何值符合条件,它会在前半部分显示“无”。

程序执行了,但是调试器报了异常,输出不符合预期。

#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
using namespace std;

struct donor
{
string name;
double contribution = 0;
};

int main()
{
string filename;
ifstream inFile;

cout << "Enter name of data file: ";
cin >> filename;

inFile.open(filename);
cin.clear();

if(!inFile.is_open())
{
cout << "Could not open the file " << filename << endl;
cout << "Program terminating.\n";

exit(EXIT_FAILURE);
}

int amount;
inFile >> amount;

cin.clear();

donor* dlist = new donor[amount];
int i;

while(inFile.good())
{
for(i = 0; i < amount; i++)
{
getline(inFile, dlist[i].name);
cin.clear();

inFile >> dlist[i].contribution;
cin.clear();
}
}

cout << "Here's the list of Grand Patrons:\n";
bool grandpatrons = false;
for(i = 0; i < amount; i++)
{
if(dlist[i].contribution >= 10000)
{
grandpatrons = true;

cout << dlist[i].name << endl;
cout << dlist[i].contribution << endl;
}
}

if(grandpatrons == false)
{
cout << "None" << endl;
}

cout << "Here's the list of Patrons:\n";
for (i = 0; 1 < amount; i++)
{
if (dlist[i].contribution < 10000)
{
cout << dlist[i].name << endl;
cout << dlist[i].contribution << endl;
}
}

delete[] dlist;
return 0;
}

donorlist.txt 文件如下所示:

4

Bob

400

Alice

11000

但是输出看起来是这样的:

Enter name of data file: donorlist.txt

Here's the list of Grand Patrons:

None

Here's the list of Patrons:

0

0

0

0

调试器给我的异常是:

Exception thrown at 0x5914F3BE (ucrtbased.dll) in 6_9.exe: 0xC0000005: Access violation reading location 0xA519E363.

现在我假设从动态分配的内存中读取有问题。也许是什么东西导致我从分配的数组之外的内存中读取?我无法准确找到错误所在。

最佳答案

你的问题开始于错误的amount写在你的数据文件中。修复它:

2
Bob
400
Alice
11000

然后他们继续说你错误地阅读了文件。
记住:混合 operator>>getline()并不像看起来那么简单。
你看,operator>>忽略 newlinespace字符,直到找到任何其他字符。
然后它读取即将到来的字符,直到遇到下一个 newline。或 space字符,但不丢弃它。

这就是 getline 的问题所在进来。 getline读取所有内容,直到遇到 newline或指定的 delim特点。意思是,如果你的 operator>>遇到newline后停止, getline将读取 NOTHING 因为它立即遇到 newline .

要解决此问题,您需要处理 newline特点。您可以通过首先检查流中的下一个字符是否确实是 newline 来做到这一点。然后使用 istream::ignore()在上面;

int next_char = stream.peek();
if(next_char == '\n'){
stream.ignore();
}

您的代码的一个工作示例是:

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

//Suggestion: class/struct names should start with a capital letter.
struct Donor{
//Suggestion: Use member initializer lists to specify default values.
Donor() : name(), contribution(0){}

string name;
double contribution;
};

int main(){
cout << "Enter the filename: ";

string filename;
cin >> filename;

//Suggestion: Open the file immediately with the filename and use `operator bool` to check if it opened.
ifstream inFile(filename);
if(!inFile){
cout << "Could not open the file " << filename << '\n';
cout << "Program terminating.\n";

exit(EXIT_FAILURE);
}

int amount;
inFile >> amount; //! Leaves '\n'

Donor* donors = new Donor[amount];

for(int i = 0; i < amount; ++i){
switch(inFile.peek()){
case '\n': inFile.ignore();
break;

case EOF: cout << "Donor amount too big!\n";
exit(EXIT_FAILURE);
}

getline(inFile, donors[i].name);
inFile >> donors[i].contribution;
}

cout << "Here's the list of Grand Patrons:\n";
bool grandpatrons_exist = false;
for(int i = 0; i < amount; ++i){
if(donors[i].contribution >= 10000){
grandpatrons_exist = true;

cout << donors[i].name << '\n';
cout << donors[i].contribution << '\n';
}
}

if(!grandpatrons_exist){
cout << "None\n";
}

cout << "Here's the list of Patrons:\n";
for(int i = 0; 1 < amount; ++i){
if(donors[i].contribution < 10000){
cout << donors[i].name << '\n';
cout << donors[i].contribution << '\n';
}
}

delete[] donors;
return 0;
}

现在,更好的解决方案是使用 vector 而不是原始指针并实现 operator>>operator<<这将大大简化对象的读取和打印。

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

class Donor{
public:
Donor() noexcept: name(), contribution(0){}

friend istream& operator>>(istream& stream, Donor& donor){
switch(stream.peek()){
case EOF: return stream;
case '\n': stream.ignore();
}

getline(stream, donor.name);
stream >> donor.contribution;

return stream;
}
friend ostream& operator<<(ostream& stream, const Donor& donor){
stream << donor.name << ' ' << donor.contribution;

return stream;
}

const string& get_name() const noexcept{
return name;
}
const double& get_contribution() const noexcept{
return contribution;
}

private:
string name;
double contribution;
};

int main(){
cout << "Enter the filename: ";

string filename;
cin >> filename;

ifstream inFile(filename);
if(!inFile){
cout << "Could not open the file " << filename << '\n';
cout << "Program terminating.\n";

exit(EXIT_FAILURE);
}

int amount;
inFile >> amount;

vector<Donor> donors(amount);
//Read it as `for donor in donors`
for(Donor& donor : donors){
inFile >> donor;
}

//An STL function that takes a lambda as the thirs argument. You should read up on them if you haven't.
//I would prefer using this since it greatly improves readability.
//This isn't mandatory, your implementation of this part is good enough.
bool grandpatrons_exist = any_of(begin(donors), end(donors), [](const Donor& donor){ return donor.get_contribution() >= 10000; });

cout << "Here's the list of Grand Patrons:\n";
if(grandpatrons_exist){
for(const Donor& donor : donors){
if(donor.get_contribution() >= 10000){
cout << donor << '\n';
}
}
}
else{
cout << "None\n";
}

cout << "\nHere's the list of Patrons:\n";
for(const Donor& donor : donors){
if(donor.get_contribution() < 10000){
cout << donor << '\n';
}
}

return 0;
}

其他一些重大改进包括:

  • 使用partition将优质顾客与普通顾客区分开来。
  • 使用流迭代器将对象读入 vector 。
int main(){
cout << "Enter the filename: ";

string filename;
cin >> filename;

ifstream inFile(filename);
if(!inFile){
cout << "Could not open the file " << filename << '\n';
cout << "Program terminating.\n";

exit(EXIT_FAILURE);
}

//Ignore the first line completely
inFile.ignore(numeric_limits<streamsize>::max(), '\n');
//Calls `operator>>` internally
vector<Donor> donors(istream_iterator<Donor>{inFile}, istream_iterator<Donor>{});

auto first_grand_patron = partition(begin(donors), end(donors), [](const Donor& donor){ return donor.get_contribution() >= 10000; });

cout << "Here's the list of Grand Patrons:\n";
if(first_grand_patron == begin(donors)){
cout << "None!\n";
}
for(auto patron = begin(donors); patron != first_grand_patron; ++patron){
cout << *patron << '\n';
}

cout << "\nHere's the list of Patrons:\n";
for(auto patron = first_grand_patron; patron != end(donors); ++patron){
cout << *patron << '\n';
}

return 0;
}

现在是一些一般提示:

  • 结构/类名称应以大写字母开头。
  • Stop Using std::endl.
  • 不需要 cin.clear() . Cin 只用一次,绝不会再用。
  • 使用成员初始化列表。
  • 可选择使用 ++i而不是 i++for循环以习惯递增变量的正确方法,除非另有需要。
  • bool grandpatrons对于旗帜而言,抽象名称过于抽象。
  • donors是一个主观上比捐助者名单简称更好的名字。

关于c++ - 在 0x5914F3BE (ucrtbased.dll) 抛出异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57988946/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com