简体   繁体   English

C ++ 2D结构数组数据

[英]C++ 2D Struct Array data

I want to be able to store values from a file into a user defined struct. 我希望能够将文件中的值存储到用户定义的结构中。 I want to have columns that hold different types of data such as: a std::string for Character names, a float for Character health and an int for Character experience. 我想拥有保存不同类型数据的列,例如:std :: string代表角色名称,float代表角色状态,int代表角色体验。

My desired output is to have a 6 by 3 array as shown below 我想要的输出是具有6 x 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

Here is what I have tried so far: 到目前为止,这是我尝试过的:

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

I am also planning on to allow the user to sort the data by each column type. 我还计划允许用户按每种列类型对数据进行排序。 To sort names alphabetically, sort by health and or experience: I am thinking of using a 2D array. 要按字母顺序对名称进行排序,按健康状况或经验进行排序:我正在考虑使用2D数组。 Would this be the best option? 这是最好的选择吗?

I think you are confusing the number of fields in your structure with the number of columns of data. 我认为您将结构中的字段数与数据的列数混淆了。 You show data for only 6 records of 3 fields each. 您仅显示3条字段的6条记录的数据。 Try setting NUM_COLS to 1 and see if it works any better for you. 尝试将NUM_COLS设置为1,看看是否对您更好。

Or, get rid of the second dimension (j) of your array entirely. 或者,完全摆脱数组的第二维(j)。

I don't know if you are reading your file as binary or as a text; 我不知道您是以二进制文件还是文本文件形式读取文件; but within my answer I'm reading from a text file where each field on a line of text is separated by a space character. 但是在我的回答中,我正在从一个文本文件中读取,其中一行文本中的每个字段都由一个空格字符分隔。 I will include all files necessary to compile and build a proper working program of what you are looking for. 我将包括所有必要的文件,这些文件可用来编译和构建您所寻找的正确的工作程序。 Some of these includes may not be needed but are within my solution for I have larger project that depends on these to properly build. 其中一些可能不需要使用,但在我的解决方案中,因为我有一个较大的项目,需要依靠这些项目才能正确构建。

stdafx.h 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 stdafx.cpp

#include "stdafx.h" #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 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 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 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 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 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 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

Just make sure that you are calling the file from the correct path, also when using the Utility::splitString() method make sure the second parameter or the delimiter matches what you have in your stored file. 只要确保您从正确的路径调用文件,就在使用Utility :: splitString()方法时,请确保第二个参数或分隔符与您存储的文件中的内容匹配。 The splitString() method will divide the string from each line of the file every time it sees that character. 每次看到该字符时,splitString()方法都会将字符串从文件的每一行中分开。 If you happen to have multiple names such as a first & last name that you want stored to a single string then a little more care needs to be taken. 如果您碰巧要将多个名称(例如名字和姓氏)存储到单个字符串中,则需要多加注意。

for sorting on the basis of any col you can use sort() in algorithm header with your own compare function. 要基于任何col进行排序,您可以在algorithm标头中将sort()与您自己的compare函数一起使用。
Define your compare function like this: 定义您的比较函数,如下所示:

on the basis of Health: 在健康的基础上:

bool MyCompHealth(struct charData a,struct charData b) 
{ 
    return (a.charHealth>b.charHealth);
}

on the basis of Exp: 根据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);
}

code: 码:

#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;    
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM