C ++ 2D Struct Array数据

时间:2016-03-19 00:45:32

标签: c++ arrays struct

我希望能够将文件中的值存储到用户定义的结构中。我想拥有包含不同类型数据的列,例如:字符名称的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数组。这会是最好的选择吗?

3 个答案:

答案 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;    
}