0

I'm a student and this c++ subject is really hard for me . I learned a topic about file and were given a file that has 50 rows with 4 columns. I try to display the file using my lecturer notes . This is what i try :

#include < iostream >    
using namespace std;  
int main()  {

 FILE* stream = fopen("student.csv", "r");

 char line[1024];

 while (fgets(line, 1024, stream))

{
    
     printf(" %s ",line);

}

}

i managed to display the file eventhough i can't really understand it. Can someone explain to me what is the char line for ? Is it represent the 50 rows ? and if i want to find the smallest value for one column , i have to declare a new variables ?

kimsjk
  • 5
  • 3
  • 1
    The code as posted doesn't deal with columns. It reads (correctly) and prints (incorrectly) entire lines (rows), one line (row) at at time. `char line[1024];` stores that one line. If you need to break up the line into columns, you need more code. – n. m. could be an AI Jul 04 '21 at 08:48
  • Small note: `< iostream >` is wrong. It should be `` or else a preprocessor may search for a file starting and ending with space characters. – Ted Lyngmo Jul 04 '21 at 08:48
  • 1
    Learning what each of those functions does (`fopen`, `fgets`, `printf`) would be important to understand what this program does. That said, if the line `char line[1024];` is confusing you, you need to review much more remedial instruction, and I would suggest a [decent book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). Finally, for what it is worth, C++ programmers wouldn't do this as-shown anyway; they would likely use `std::getline` and `std::string`. What you show here is how a basic C engineer would likely read a file line by line. – WhozCraig Jul 04 '21 at 08:49
  • how I can break the line into columns ? – kimsjk Jul 04 '21 at 08:54
  • For a teacher of a C++ class to teach the old C I/O functions seems odd. The teacher should teach you the standard C++ streams instead. This class will likely not be very good. – Some programmer dude Jul 04 '21 at 16:12

1 Answers1

0

In C++, you would normally use a std::string to read a file and split it into columns.

I am sorry, I cannot "downgrade" to use char arrays in C++. So, I will assume that you open a file using a std::ifstream and the read line by line with std::getline in a loop. Then you have each line in a std::string

Then:

Splitting a string into parts is a very old task. There are many many solutions available. All have different properties. Some are difficult to understand, some are hard to develop, some are more complex, slower or faster or more flexible or not.

Alternatives

  1. Handcrafted, many variants, using pointers or iterators, maybe hard to develop and error prone.
  2. Using old style std::strtok function. Maybe unsafe. Maybe should not be used any longer
  3. std::getline. Most used implementation. But actually a "misuse" and not so flexible
  4. Using dedicated modern function, specifically developed for this purpose, most flexible and good fitting into the STL environment and algortithm landscape. But slower.

Please see 4 examples in one piece of code.

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <regex>
#include <algorithm>
#include <iterator>
#include <cstring>
#include <forward_list>
#include <deque>

using Container = std::vector<std::string>;
std::regex delimiter{ "," };


int main() {

    // Some function to print the contents of an STL container
    auto print = [](const auto& container) -> void { std::copy(container.begin(), container.end(),
        std::ostream_iterator<std::decay<decltype(*container.begin())>::type>(std::cout, " ")); std::cout << '\n'; };

    // Example 1:   Handcrafted -------------------------------------------------------------------------
    {
        // Our string that we want to split
        std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
        Container c{};

        // Search for comma, then take the part and add to the result
        for (size_t i{ 0U }, startpos{ 0U }; i <= stringToSplit.size(); ++i) {

            // So, if there is a comma or the end of the string
            if ((stringToSplit[i] == ',') || (i == (stringToSplit.size()))) {

                // Copy substring
                c.push_back(stringToSplit.substr(startpos, i - startpos));
                startpos = i + 1;
            }
        }
        print(c);
    }

    // Example 2:   Using very old strtok function ----------------------------------------------------------
    {
        // Our string that we want to split
        std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
        Container c{};

        // Split string into parts in a simple for loop
#pragma warning(suppress : 4996)
        for (char* token = std::strtok(const_cast<char*>(stringToSplit.data()), ","); token != nullptr; token = std::strtok(nullptr, ",")) {
            c.push_back(token);
        }

        print(c);
    }

    // Example 3:   Very often used std::getline with additional istringstream ------------------------------------------------
    {
        // Our string that we want to split
        std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
        Container c{};

        // Put string in an std::istringstream
        std::istringstream iss{ stringToSplit };

        // Extract string parts in simple for loop
        for (std::string part{}; std::getline(iss, part, ','); c.push_back(part))
            ;

        print(c);
    }

    // Example 4:   Most flexible iterator solution  ------------------------------------------------

    {
        // Our string that we want to split
        std::string stringToSplit{ "aaa,bbb,ccc,ddd" };


        Container c(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {});
        //
        // Everything done already with range constructor. No additional code needed.
        //

        print(c);


        // Works also with other containers in the same way
        std::forward_list<std::string> c2(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {});

        print(c2);

        // And works with algorithms
        std::deque<std::string> c3{};
        std::copy(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {}, std::back_inserter(c3));

        print(c3);
    }
    return 0;
}
A M
  • 14,694
  • 5
  • 19
  • 44