我希望能够将文件中的值存储到用户定义的结构中。我想拥有包含不同类型数据的列,例如:字符名称的std :: string,Character运行的浮点数和Character体验的int。
我想要的输出是有一个6乘3的数组,如下所示
Alice 23.4 3210
Xander 45.3 1110
Bernard 12.9 2024
Yanni 23.7 1098
Craw 50.5 980
Zack 11.9 1024
这是我到目前为止所尝试的内容:
struct charData
{
string charName;
float charHealth;
int charExp;
};
int main() {
const int NUM_COLS = 3;
int NUM_ROWS = 6;
int charNumber = 0;
int userInput;
int loop = 0;
int i,j;
string line;
ifstream myIn; // Declare read file stream
myIn.open("party.dat"); // Open file
struct charData charArray[NUM_ROWS][NUM_COLS];
while( !myIn.eof() ) {
for ( j = 0; j < NUM_COLS ; j++) {
for ( i = 0; i < NUM_ROWS ; i++) {
myIn >> charArray[i][j].charName;
myIn >> charArray[i][j].charHealth;
myIn >> charArray[i][j].charExp;
}
}
}
return 0;
}
我还计划允许用户按每个列类型对数据进行排序。按字母顺序排序名称,按健康和/或经验排序:我正在考虑使用2D数组。这会是最好的选择吗?
答案 0 :(得分:0)
我认为您将结构中的字段数与数据列数混淆。您只显示每个3个字段的6条记录的数据。尝试将NUM_COLS设置为1并查看它是否适合您。
或者,完全摆脱阵列的第二维(j)。
答案 1 :(得分:0)
我不知道您是以二进制文本还是以文本形式阅读文件;但在我的回答中,我正在从一个文本文件中读取,其中一行文本中的每个字段由空格字符分隔。我将包含编译和构建正在寻找的正确工作程序所需的所有文件。其中一些包括可能不需要,但在我的解决方案中,我有更大的项目,依赖于这些正确构建。
<强> stdafx.h中强>
#ifndef STDAFX_H
#define STDAFX_H
#include <Windows.h>
#include <stdio.h>
#include <tchar.h>
#include <conio.h>
#include <string>
#include <sstream>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <vector>
#include <array>
#include <memory>
#include <queue>
#include <functional>
#include <algorithm>
// User Application Specific
// #include "ExceptionHandler.h" // Required For My Solution But Isn't Used In Yours
namespace util {
enum ReturnCode {
RETURN_OK = 0,
RETURN_ERROR = 1,
}; // ReturnCode
extern const unsigned INVALID_UNSIGNED;
extern const unsigned INVALID_UNSIGNED_SHORT;
} // namespace util
#endif // STDAFX_H
<强> stdafx.cpp 强>
#include“stdafx.h”
namespace util {
const unsigned INVALID_UNSIGNED = static_cast<const unsigned>( -1 );
const unsigned INVALID_UNSIGNED_SHORT = static_cast<const unsigned short>( -1 );
} // namespace util
<强> Utility.h 强>
#ifndef UTILITY_H
#define UTILITY_H
namespace util {
class Utility {
public:
static void pressAnyKeyToQuit();
static std::string toUpper(const std::string& str);
static std::string toLower(const std::string& str);
static std::string trim(const std::string& str, const std::string elementsToTrim = " \t\n\r");
static unsigned convertToUnsigned(const std::string& str);
static int convertToInt(const std::string& str);
static float convertToFloat(const std::string& str);
static std::vector<std::string> splitString(const std::string& strStringToSplit, const std::string& strDelimiter, const bool keepEmpty = true);
private:
Utility(); // Private - Not A Class Object
Utility(const Utility& c); // Not Implemented
Utility& operator=(const Utility& c); // Not Implemented
template<typename T>
static bool stringToValue(const std::string& str, T* pValue, unsigned uNumValues);
template<typename T>
static T getValue(const std::string& str, std::size_t& remainder);
}; // Utility
#include "Utility.inl"
} // namespace util
#endif // UTILITY_H
<强> Utility.inl 强>
// ----------------------------------------------------------------------------
// stringToValue()
template<typename T>
static bool Utility::stringToValue(const std::string& str, T* pValue, unsigned uNumValues) {
int numCommas = std::count(str.begin(), str.end(), ',');
if (numCommas != uNumValues - 1) {
return false;
}
std::size_t remainder;
pValue[0] = getValue<T>(str, remainder);
if (uNumValues == 1) {
if (str.size() != remainder) {
return false;
}
}
else {
std::size_t offset = remainder;
if (str.at(offset) != ',') {
return false;
}
unsigned uLastIdx = uNumValues - 1;
for (unsigned u = 1; u < uNumValues; ++u) {
pValue[u] = getValue<T>(str.substr(++offset), remainder);
offset += remainder;
if ((u < uLastIdx && str.at(offset) != ',') ||
(u == uLastIdx && offset != str.size()))
{
return false;
}
}
}
return true;
} // stringToValue
<强> Utility.cpp 强>
#include "stdafx.h"
#include "Utility.h"
namespace util {
// ----------------------------------------------------------------------------
// pressAnyKeyToQuit()
void Utility::pressAnyKeyToQuit() {
std::cout << "Press any key to quit" << std::endl;
_getch();
} // pressAnyKeyToQuit
// ----------------------------------------------------------------------------
// toUpper()
std::string Utility::toUpper( const std::string& str ) {
std::string result = str;
std::transform( str.begin(), str.end(), result.begin(), ::toupper );
return result;
} // toUpper
// ----------------------------------------------------------------------------
// toLower()
std::string Utility::toLower( const std::string& str ) {
std::string result = str;
std::transform( str.begin(), str.end(), result.begin(), ::tolower );
return result;
} // toLower
// ----------------------------------------------------------------------------
// trim()
// Removes Elements To Trim From Left And Right Side Of The str
std::string Utility::trim( const std::string& str, const std::string elementsToTrim ) {
std::basic_string<char>::size_type firstIndex = str.find_first_not_of( elementsToTrim );
if ( firstIndex == std::string::npos ) {
return std::string(); // Nothing Left
}
std::basic_string<char>::size_type lastIndex = str.find_last_not_of( elementsToTrim );
return str.substr( firstIndex, lastIndex - firstIndex + 1 );
} // trim
// ----------------------------------------------------------------------------
// getValue()
template<>
float Utility::getValue( const std::string& str, std::size_t& remainder ) {
return std::stof( str, &remainder );
} // getValue <float>
// ----------------------------------------------------------------------------
// getValue()
template<>
int Utility::getValue( const std::string& str, std::size_t& remainder ) {
return std::stoi( str, &remainder );
} // getValue <int>
// ----------------------------------------------------------------------------
// getValue()
template<>
unsigned Utility::getValue( const std::string& str, std::size_t& remainder ) {
return std::stoul( str, &remainder );
} // getValue <unsigned>
// ----------------------------------------------------------------------------
// convertToUnsigned()
unsigned Utility::convertToUnsigned( const std::string& str ) {
unsigned u = 0;
if ( !stringToValue( str, &u, 1 ) ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to unsigned";
throw strStream.str();
}
return u;
} // convertToUnsigned
// ----------------------------------------------------------------------------
// convertToInt()
int Utility::convertToInt( const std::string& str ) {
int i = 0;
if ( !stringToValue( str, &i, 1 ) ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to int";
throw strStream.str();
}
return i;
} // convertToInt
// ----------------------------------------------------------------------------
// convertToFloat()
float Utility::convertToFloat(const std::string& str) {
float f = 0;
if (!stringToValue(str, &f, 1)) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to float";
throw strStream.str();
}
return f;
} // convertToFloat
// ----------------------------------------------------------------------------
// splitString()
std::vector<std::string> Utility::splitString( const std::string& strStringToSplit, const std::string& strDelimiter, const bool keepEmpty ) {
std::vector<std::string> vResult;
if ( strDelimiter.empty() ) {
vResult.push_back( strStringToSplit );
return vResult;
}
std::string::const_iterator itSubStrStart = strStringToSplit.begin(), itSubStrEnd;
while ( true ) {
itSubStrEnd = search( itSubStrStart, strStringToSplit.end(), strDelimiter.begin(), strDelimiter.end() );
std::string strTemp( itSubStrStart, itSubStrEnd );
if ( keepEmpty || !strTemp.empty() ) {
vResult.push_back( strTemp );
}
if ( itSubStrEnd == strStringToSplit.end() ) {
break;
}
itSubStrStart = itSubStrEnd + strDelimiter.size();
}
return vResult;
} // splitString
} // namspace util
<强> CharacterData.h 强>
#ifndef CHARACTER_DATA_H
#define CHARACTER_DATA_H
class CharacterData {
private:
std::string m_name;
float m_health;
unsigned m_exp;
public:
CharacterData();
CharacterData( const std::string& name, float health, unsigned exp );
void setName( const std::string& name );
void setHealth( float health );
void setExperience( unsigned exp );
std::string getName() const;
float getHealth() const;
unsigned getExperience() const;
private:
CharacterData( const CharacterData& c ); // Not Implemented
CharacterData& operator=( const CharacterData& c ); // Not Implemented
}; // CharacterData
#endif // CHARACTER_DATA_H
<强> CharacterData.cpp 强>
#include "stdafx.h"
#include "CharacterData.h"
// ----------------------------------------------------------------------------
// CharacterData()
CharacterData::CharacterData() :
m_name( std::string() ),
m_health( 0.0f ),
m_exp( 0 ) {
} // CharacterData
// ----------------------------------------------------------------------------
// CharacterData()
CharacterData::CharacterData( const std::string& name, float health, unsigned exp ) :
m_name( name ),
m_health( health ),
m_exp( exp ) {
} // CharacterData
// ----------------------------------------------------------------------------
// setName()
void CharacterData::setName( const std::string& name ) {
m_name = name;
} // setName
// ----------------------------------------------------------------------------
// getName()
std::string CharacterData::getName() const {
return m_name;
} // getName
// ----------------------------------------------------------------------------
// setHealth()
void CharacterData::setHealth( float health ) {
m_health = health;
} // setHealth
// ----------------------------------------------------------------------------
// getHealth()
float CharacterData::getHealth() const {
return m_health;
} // getHealth
// ----------------------------------------------------------------------------
// setExperience()
void CharacterData::setExperience( unsigned exp ) {
m_exp = exp;
} // setExperience
// ----------------------------------------------------------------------------
// getExperience()
unsigned CharacterData::getExperience() const {
return m_exp;
} // getExperience
<强> CharacterDatabase.h 强>
#ifndef CHARACTER_DATABASE_H
#define CHARACTER_DATABASE_H
class CharacterData;
class CharacterDatabase {
private:
std::string m_filename;
std::vector<std::shared_ptr<CharacterData>> m_vpCharacters;
public:
explicit CharacterDatabase( const std::string& filename );
// ~CharacterDatabase(); // Default Okay
void displayByOption( unsigned option = 0 );
private:
CharacterDatabase( const CharacterDatabase& c ); // Not Implemented
CharacterDatabase& operator=( const CharacterDatabase& c ); // Not Implemented
void parseFile();
void display() const;
static bool sortByName( const std::shared_ptr<CharacterData>& d1, const std::shared_ptr<CharacterData>& d2);
static bool sortByHealth( const std::shared_ptr<CharacterData>& d1, const std::shared_ptr<CharacterData>& d2);
static bool sortByExperience(const std::shared_ptr<CharacterData>& d1, const std::shared_ptr<CharacterData>& d2);
}; // CharacterDataase
#endif // CHARACTER_DATABASE_H
<强> CharacterDatabase.cpp 强>
#include "stdafx.h"
#include "CharacterDatabase.h"
#include "CharacterData.h"
#include "Utility.h"
// ----------------------------------------------------------------------------
// CharacterDatabase()
CharacterDatabase::CharacterDatabase( const std::string& filename ) :
m_filename( filename ) {
parseFile();
} // CharacterDatabase
// ----------------------------------------------------------------------------
// parseFile()
void CharacterDatabase::parseFile() {
using namespace util;
if ( m_filename.empty() ) {
std::cout << "Missing or invalid filename." << std::endl;
return;
}
std::string line;
std::vector<std::string> results;
std::ifstream in;
// Try To Open File For Reading
in.open( m_filename.c_str(), std::ios_base::in );
if ( !in.is_open() ) {
std::cout << "Can not open file(" << m_filename << ") for reading.";
return;
}
// Read Line By Line And Store Contents Into String & Parse Each Line One At A Time.
while ( !in.eof() ) {
std::getline( in, line );
results = Utility::splitString( line, " " );
// On Each Pass We Want To Construct A CharacterData Object & Save It Into Our Container
m_vpCharacters.push_back( std::make_shared<CharacterData>( results[0], Utility::convertToFloat( results[1] ), Utility::convertToUnsigned( results[2] ) ) );
}
// Close File Pointer
in.close();
} // parseFile
// ----------------------------------------------------------------------------
// display()
void CharacterDatabase::display() const {
for (unsigned u = 0; u < m_vpCharacters.size(); u++) {
std::cout << m_vpCharacters[u]->getName() << "\t"
<< m_vpCharacters[u]->getHealth() << "\t"
<< m_vpCharacters[u]->getExperience() << std::endl;
}
std::cout << std::endl;
} // display
// ----------------------------------------------------------------------------
// displayByOption() Default 0 = Order In Which File Is Read In,
// 1 = Sorted By Name, 2 = Sorted By Health, 3 = Sorted By Experience
void CharacterDatabase::displayByOption( unsigned option ) {
switch ( option ) {
case 1: { // Sorted By Name
std::sort( m_vpCharacters.begin(), m_vpCharacters.end(), sortByName );
display();
break;
}
case 2: { // Sorted By Health
std::sort( m_vpCharacters.begin(), m_vpCharacters.end(), sortByHealth );
display();
break;
}
case 3: { // Sorted By Experience
std::sort( m_vpCharacters.begin(), m_vpCharacters.end(), sortByExperience );
display();
break;
}
default: { // Unsorted - Order Read In By File
display();
}
}
} // displayByOption
// ----------------------------------------------------------------------------
// sortByName()
bool CharacterDatabase::sortByName( const std::shared_ptr<CharacterData>& d1, const std::shared_ptr<CharacterData>& d2 ) {
return d1->getName() < d2->getName();
} // sortByName
// ----------------------------------------------------------------------------
// sortByHealth()
bool CharacterDatabase::sortByHealth( const std::shared_ptr<CharacterData>& d1, const std::shared_ptr<CharacterData>& d2 ) {
return d1->getHealth() < d2->getHealth();
} // sortByHealth
// ----------------------------------------------------------------------------
// sortByExperience()
bool CharacterDatabase::sortByExperience( const std::shared_ptr<CharacterData>& d1, const std::shared_ptr<CharacterData>& d2) {
return d1->getExperience() < d2->getExperience();
} // sortByExperience
<强> characterData.txt 强>
Alice 23.4 3210
Xander 45.3 1110
Bernard 12.9 2024
Yanni 23.7 1098
Craw 50.5 980
Zack 11.9 1024
<强>的main.cpp 强>
#include "stdafx.h"
#include "Utility.h"
#include "CharacterDatabase.h"
int main() {
using namespace util;
CharacterDatabase cd( "characterData.txt" );
cd.displayByOption();
cd.displayByOption( 1 );
cd.displayByOption( 2 );
cd.displayByOption( 3 );
Utility::pressAnyKeyToQuit();
return RETURN_OK;
} // main
确保从正确的路径调用文件,同样在使用Utility :: splitString()方法时,请确保第二个参数或分隔符与存储文件中的参数匹配。每次看到该字符时,splitString()方法都会将文件的每一行中的字符串分开。如果你碰巧有多个名字,比如第一个&amp;您想要存储到单个字符串的姓氏,然后需要更多的关注。
答案 2 :(得分:0)
根据任何col进行排序,您可以使用sort()
标题中的algorithm
和您自己的比较功能。
像这样定义比较函数:
以健康为基础:
bool MyCompHealth(struct charData a,struct charData b)
{
return (a.charHealth>b.charHealth);
}
基于Exp:
bool MyCompExp(struct charData a,struct charData b)
{
return (a.charExp > b.charExp);
}
基于姓名:
bool MyCompName(struct charData a,struct charData b)
{
int r = a.charName.compare(b.charName);
return (r > 0);
}
代码:
#include<algorithm>
#include<iostream>
#include<fstream>
using namespace std;
struct charData
{
string charName;
float charHealth;
int charExp;
};
bool MyCompHealth(struct charData a,struct charData b)
{
return (a.charHealth<b.charHealth);
}
//on the basis of Exp:
bool MyCompExp(struct charData a,struct charData b)
{
return (a.charExp < b.charExp);
}
//on the basis of Name:
bool MyCompName(struct charData a,struct charData b)
{
int r = a.charName.compare(b.charName);
return !(r > 0);
}
int main() {
const int NUM_COLS = 3;
int NUM_ROWS = 6;
int charNumber = 0;
int userInput;
int loop = 0;
int i,j;
string line;
ifstream myIn; // Declare read file stream
myIn.open("party.dat",ios::in); // Open file
struct charData charArray[NUM_ROWS];
while( !myIn.eof() ) //taking input
{
for ( i = 0; i < NUM_ROWS ; i++)
{
myIn >> charArray[i].charName;
myIn >> charArray[i].charHealth;
myIn >> charArray[i].charExp;
}
}
cout<<"How you want to sort?(1:health 2:Exp 3:Name)\n";
cin>>userInput; //input from user how he wants to sort
if(userInput==1)
{
//sorting on the basis of health
sort(charArray,charArray+NUM_ROWS,MyCompHealth);
}
else if(userInput==1)
{
//sorting on the basis of Experience
sort(charArray,charArray+NUM_ROWS,MyCompExp);
}
else
{
//sorting on the basis of Name
sort(charArray,charArray+NUM_ROWS,MyCompName);
}
//display result
for ( i = 0; i < NUM_ROWS ; i++)
{
cout<<charArray[i].charName<<" ";
cout<<charArray[i].charHealth<<" ";
cout<<charArray[i].charExp<<endl;
}
return 0;
}