Home > OS >  reading a txt file separated by commas into arrays C cpp
reading a txt file separated by commas into arrays C cpp

Time:11-18

C question! I have a .txt file with this info:

james, watson
brittany,blake
roger,tra4@pos
jonathan, pote5
amber,Trisa123!

where the first columnn is name and the second one is the Id of website users.

I need to read this file and then sotre the informations into 2 arrays: name[] user_Id [] could you please help me? I found the solution for saving it into a 2d vector but I prefer to save it as arrays since I need to compare the string values with another string (received by uer to check if her name/user Id is already in the system or not)

I found the solution for saving it into a 2d vector but not for arrays.

CodePudding user response:

I will show you your requested solution, but I am sorry to inform you that the solution approach is wrong. For various reasons. First, and most important: In C C-Style arrays should in general not not be used.

C-Style arrays have fixed size and are not dyanmic. So, you will always come up with a magic number of an estimated max size. The correct approach would be to use a dynamic container. And for your solution, the std::vector is most appropriate.

Then, it is a very bad idea to have to separate arrays for related data. The correct approach is to put related data in a struct and then create a std::vector of this struct. Otherwise you will have always to maintain and handle always 2 arrays, and you may even lose the sync between related data.

Anyway, I will first show you a solution following your idea:

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

const unsigned int MagicNumberForMaxArraySize = 42;

int main() {

    // Define Arrays to hold the user and their IDs
    string user[MagicNumberForMaxArraySize]{};
    string user_ID[MagicNumberForMaxArraySize]{};

    // Open the file and check, if it could be opened
    ifstream ifs("test.txt");
    if (ifs.is_open()) {

        unsigned int index = 0;
        // Read all lines and put result into arrays
        while ((index < MagicNumberForMaxArraySize) and 
            (getline(getline(ifs, user[index], ',') >> ws, user_ID[index]))) {
            // Now we have read a comlete line. Goto next index
              index;
        }
        // Show debug output
        for (unsigned int i = 0; i < index;   i)
            cout << "User: " << user[i] << "\tID: " << user_ID[i] << '\n';
    }
    else
        cout << "\n\n*** Error: Could not open source file\n\n";
}

But I would not recommend to go on with that. The next improvement would be to use a struct and then an array of struct. Additionaly, I will get rid of using namespace std; which should never be used. And, I initialize varaibles with the universal initializer.

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


const unsigned int MagicNumberForMaxArraySize = 42;

struct Data {
    std::string user{};
    std::string ID{};
};

int main() {

    // Define array for our needed data
    Data data[MagicNumberForMaxArraySize];

    // Open the file and check, if it could be opened
    std::ifstream ifs("test.txt");
    if (ifs.is_open()) {

        unsigned int index = 0;
        // Read all lines and put result into arrays
        while ((index < MagicNumberForMaxArraySize) and 
            (std::getline(std::getline(ifs, data[index].user, ',') >> std::ws, data[index].ID))) {
            // Now we have read a comlete line. Goto next index
              index;
        }
        // Show debug output
        for (unsigned int i = 0; i < index;   i)
            std::cout << "User: " << data[i].user << "\tID: " << data[i].ID<< '\n';
    }
    else
        std::cout << "\n\n*** Error: Could not open source file\n\n";
}

Evolution:

We will now introduce an object oriented principle . Data and methods operating on this data shall be in one class or struct. Hence, we will add IO methods to the struct, and add an aditional struct for holding all users. Also, the new if-statement with initializer can be used. And of course the std::vector.

Please see:

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

// Struct to hold properties for one user
struct User {
    std::string name{};
    std::string ID{};

    // Simple extraction
    friend std::istream& operator >> (std::istream& is, User& user) {
        std::getline(std::getline(is, user.name, ',') >> std::ws, user.ID);
        return is;
    }
    // Simple inserter
    friend std::ostream& operator << (std::ostream& os, const User& user) {
        return os << "User: " << user.name << "\tID: " << user.ID;
    }
};
// This class will contain all users
struct Data {
    std::vector<User> users{};
    // Simple extraction
    friend std::istream& operator >> (std::istream& is, Data& d) {
        // Delete potential existing old data
        d.users.clear();
        // Now read all users
        for (User temp{}; is >> temp; d.users.push_back(std::move(temp)));
        return is;
    }
    // Simple inserter
    friend std::ostream& operator << (std::ostream& os, const Data& d) {
        for (const User& u : d.users) os << u << '\n';
        return os;
    }
};

int main() {
    // Open the file and check, if it could be opened
    if (std::ifstream ifs("test.txt");ifs) {

        // Read all data and show result
        if (Data data{}; not (ifs >> data).bad())
            std::cout << data;
    }
    else
        std::cout << "\n\n*** Error: Could not open source file\n\n";
}

CodePudding user response:

You can also use strtok() from cstring library to split string into tokens: Split string in C/C

  • Related