我正在尝试制作一个可以添加玩家信息的程序。我可以运行该程序,但是当选择“查看玩家记录”时,昵称被省略。有人能看出这里的问题吗?
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
struct Player {
string nickname;
int age;
int bps1;
int bps2;
};
void addRecord(Player& record);
void viewPlayers(const Player playerArr[], int numPlayers);
double computeAve(const Player playerArr[], int numPlayers);
void showMax(const Player playerArr[], int numPlayers);
void showMin(const Player playerArr[], int numPlayers);
int main() {
start:
cout << "==============================================" << endl;
cout << " MENU " << endl;
cout << "==============================================" << endl;
cout << "1. Add record" << endl;
cout << "2. View players records" << endl;
cout << "3. Compute for the average" << endl;
cout << "4. Show the player(s) who get the max average." << endl;
cout << "5. Show the player(s) who get the min average." << endl;
cout << "6. Exit" << endl;
const int numPlayers = 5;
Player playerArr[numPlayers];
int op;
cout << "\nEnter your choice: ";
cin >> op;
switch (op) {
case 1:
for (int i = 0; i < numPlayers; i++) {
cout << endl;
cout << "ENTER DETAILS FOR PLAYER " << i + 1 << ":\n";
addRecord(playerArr[i]);
cout << endl;
}
goto start;
break;
case 2:
viewPlayers(playerArr, numPlayers);
goto start;
break;
case 3:
for (int i = 0; i < numPlayers; i++) {
cout << "Player " << i + 1 << " average: " << fixed << setprecision(2) << computeAve(playerArr, numPlayers) << endl;
}
goto start;
break;
case 4:
showMax(playerArr, numPlayers);
goto start;
break;
case 5:
showMin(playerArr, numPlayers);
goto start;
break;
case 6:
cout << "Exiting program." << endl;
return 0;
break;
default:
cout << "Invalid choice. Please select a valid option." << endl;
}
return 0;
}
void addRecord(Player& record) {
cout << "Enter player nickname: ";
cin.ignore();
getline(cin, record.nickname);
cout << "Enter player age: ";
cin >> record.age;
cout << "Enter best played score 1: ";
cin >> record.bps1;
cout << "Enter best played score 2: ";
cin >> record.bps2;
}
void viewPlayers(const Player playerArr[], int numPlayers) {
cout << "============================================================================================" << endl;
cout << " Nickname Age Best Played Score 1 Best Played Score 2 " << endl;
cout << "============================================================================================" << endl;
for (int i = 0; i < numPlayers; i++) {
cout << setw(28) << left << playerArr[i].nickname;
cout << setw(29) << right << playerArr[i].age;
cout << setw(18) << right << playerArr[i].bps1;
cout << setw(29) << right << playerArr[i].bps2 << endl;
}
}
double computeAve(const Player playerArr[], int numPlayers) {
double totalAverage = 0.0;
for (int i = 0; i < numPlayers; i++) {
totalAverage += static_cast<double>(playerArr[i].bps1 + playerArr[i].bps2) / 2.0;
}
return totalAverage / numPlayers;
}
void showMax(const Player playerArr[], int numPlayers) {
double maxAverage = 0.0;
for (int i = 0; i < numPlayers; i++) {
double average = computeAve(playerArr, numPlayers);
if (average > maxAverage) {
maxAverage = average;
}
}
cout << "Player(s) with the maximum average score: " << fixed << setprecision(2);
for (int i = 0; i < numPlayers; i++) {
double average = computeAve(playerArr, numPlayers);
if (average == maxAverage) {
cout << playerArr[i].nickname << " ";
}
}
cout << "(Average: " << maxAverage << ")" << endl;
}
void showMin(const Player playerArr[], int numPlayers) {
double minAverage = 100.0; // Initialize with a high value
for (int i = 0; i < numPlayers; i++) {
double average = computeAve(playerArr, numPlayers);
if (average < minAverage) {
minAverage = average;
}
}
cout << "Player(s) with the minimum average score: " << fixed << setprecision(2);
for (int i = 0; i < numPlayers; i++) {
double average = computeAve(playerArr, numPlayers);
if (average == minAverage) {
cout << playerArr[i].nickname << " ";
}
}
cout << "(Average: " << minAverage << ")" << endl;
}
我已经尝试将字符输入更改为 getline() 来获取字符串,但它仍然不起作用。我还隔离了这两个功能(添加和查看),并尝试在没有 switch-case 的情况下,仅使用 main 中的两个功能,并且它确实有效。但我需要那个开关盒,以便用户可以从选项中进行选择。我做的另一件事是,我没有创建一个用于查看的函数,而是直接将其写在开关内的情况下,但它也不起作用。有人可以帮忙吗?
您描述的行为是流上混合输入样式的常见症状。
在您的情况下,您的代码执行
cin >> op
(面向流的输入)来读取 int
,然后使用 getline(cin, record.nickname);
(面向行的输入)从 cin
读取数据。
这两种输入方式(面向流与面向行)在一个流上同时使用时,会以意想不到的方式交互,因为它们处理换行符 (
'\n'
) 的方式不同 - >>
在遇到 '\n'
时停止) AND 将该字符保留在流缓冲区中,而 getline(cin, ...)
(默认情况下)将数据读取到字符串中,直到遇到该 '\n'
,将其从流缓冲区中删除,丢弃它,然后立即返回。如果换行符是流缓冲区中的第一个字符,则意味着不会尝试(直到后续输入操作)读取预期数据。
看来您已经尝试过(或被错误地建议使用)
cin.ignore()
。由于各种原因,这并不总是有效。
可行的解决方案是在任何地方使用来自
cin
的相同样式的输入(例如,使用 cin.getline()
读取来自 cin
的所有输入,然后根据需要解析字符串以获取值,这意味着您的程序将接收输入一一次一行)。通过解析字符串,您的程序还可以更好地应对意外输入(例如,如果用户输入错误数据)。
问题是您在标签
playerArr
之后声明了 start
。因此,当运行 goto start
时,会调用析构函数,它可能会清除字符串 nickname
并且不会清除原始数据类型的其他变量。因此,跳转后,当您尝试查看详细信息时,它会显示空字符串和其他变量的剩余值。这个代码说明了我的意思:
#include <string>
#include <iostream>
struct A
{
std::string s;
int k;
friend std::ostream& operator<<(std::ostream& os, const A& a)
{
os << '[' << a.s << ' ' << a.k << ']';
return os;
}
~A() { std::cout << "\ndestructor called"; }
};
int main()
{
int i = 0;
label1:
A arr[2];
if (i == 0)
{
std::cin >> arr[0].s >> arr[0].k;
std::cin >> arr[1].s >> arr[1].k;
}
std::cout << '\n';
for (int j = 0; j < 2; j++)
std::cout << arr[j] << ' ';
++i;
if (i == 10)
return 0;
goto label1;
}
解决方案是将
playerArr
移到 start
标签之前。
const int numPlayers = 5;
Player playerArr[numPlayers];
start:
...