-1

I am new to C++ and I have some trouble preventing getline to read the new line character at the end of my text file. I tried truncating it using a newline character and then passing to a delimiter with ',' but it just doesnt work. Can you please help me understand what is going on and why I am not able to achieve what i intended to do?

I have edited this post to correct the mistake of getline() more than what is available. However I dont know how to transfer this getline() string to prevent taking the'\n' character

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
static int Ncol = 5;
int main()
{
    int ctr=0,Nrow;
    std::string line,line1;
    std::ifstream myFile1;

    Nrow = 4;
    std::cout.precision(15);
    std::fixed;

    double* input = new double[Nrow*Ncol];
    double* ftrue = new double[Nrow];

    myFile1.open("./Data_codelink_test/test.txt");
    
    while(ctr<Nrow)
    {   
        std::getline(myFile1,line1,','); // This gives me line1 with the new line character
        std::cout<<"Read "<<line1<<std::endl;
        input[ctr] = std::stold(line1);
        std::cout<<"Stored "<<input[ctr]<<std::endl;
        ctr++;  
    }
    myFile1.close();

My test.txt looks like this

1,2,3,4,5
1,2,3,4,5
1,2,3,4,5
1,2,3,4,5

I would like to have a vector of size 20 to have values stored in this manner

1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
Jason
  • 36,170
  • 5
  • 26
  • 60
  • 2
    When `getline` fails, it returns `false`. This code isn't checking for that, so it then continues on its merry way. – Eljay Nov 16 '21 at 04:04
  • [How to debug small programs](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/) – Eljay Nov 16 '21 at 04:12
  • @RemyLebeau Thanks for pointing that out. But even if I restrict the getline() to the proper amount in the while loop, it does not solve my main problem. I cannot see a way how I can prevent std::getline(myFile1,line,',') from taking the '\n' value at the end of each line. Any advice on that would be appreciated. Thank you – readysetcode Nov 16 '21 at 04:30
  • @readysetcode "*it does not solve my main problem*" - which is WHAT exactly? You haven't explained that clearly. "*I cannot see a way how I can prevent std::getline(myFile1,line,',') from taking the '\n' value at the end of each line*" - that is EXACTLY what it does. It stops only when the *specified* delimiter is read. If it is not working for you, then there is something else wrong. "It doesn't work" is not a helpful description. WHY do you think it is not working? Please elaborate. – Remy Lebeau Nov 16 '21 at 04:36
  • @readysetcode Now you have altered your code to use 1 `getline()` instead of 2. That fundamentally changes the behavior of the code (and invalidates my answer). The previous code actually does a better job of solving your problem, this new code introduces the very problem you are asking about. Please revert the code, and then explain why the ORIGINAL code does not work for you. – Remy Lebeau Nov 16 '21 at 04:39

2 Answers2

0

The only problem I see (UPDATE: with the original code before your edit) is you are calling std::getline('\n') more times (25) than you have actual lines in the file (4). You are not terminating your loop when EOF is reached. Use this loop condition instead:

while ((ctr < (Nrow*Ncol)) && std::getline(myFile1, line))

This will end the loop when EITHER Nrow*Ncol items have been stored in the array OR std::getline() fails to read the next line in the file.

That being said, consider using a std::vector instead of new[]. Let the vector grow dynamically with each line that is successfully read, eg:

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

int main()
{
    std::ifstream myFile1("./Data_codelink_test/test.txt");

    std::vector<double> input;
    std::string str;

    std::cout << std::fixed << std::setprecision(15);

    while (std::getline(myFile1, str))
    {
        std::istringstream iss(str);
        std::getline(iss, str, ',');
        std::cout << "Read " << str << std::endl;
        input.push_back(std::stold(str));
        std::cout << "Stored " << input.back() << std::endl; 
    }
    myFile1.close();

    ...
}

UPDATE: the result you want can't be achieved using either code snippet you have presented. In the original code, you were reading the lines fine, but then you were extracting only the 1st number in each line. In your edited code, you are reading comma-separated numbers without any regard to lines at all, so periodically you will read in a string that has a line break in the middle of it.

std::getline() can only handle 1 delimiter at a time. So, to parse the kind of data you have with std::getline(), you need 2 loops - one loop to read each line, and one loop to split up each line, eg:

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

static int Ncol = 5;

int main()
{
    std::ifstream myFile1("./Data_codelink_test/test.txt");

    int ctr = 0, Nrow = 4, maxElems = Nrow*Ncol;
    std::string str;

    double* input = new double[maxElems];

    std::cout << std::fixed << std::setprecision(15);

    while ((ctr < maxElems) && std::getline(myFile1, str))
    {
        std::istringstream iss(str);
        while ((ctr < maxElems) && std::getline(iss, str, ',')) {
            std::cout << "Read " << str << std::endl;
            input[ctr] = std::stold(str);
            std::cout << "Stored " << input[ctr] << std::endl;
            ++ctr;
        }
    }
    myFile1.close();

    ...
}

Alternatively, using std::vector:

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

int main()
{
    std::ifstream myFile1("./Data_codelink_test/test.txt");

    std::vector<double> input;
    std::string str;

    std::cout << std::fixed << std::setprecision(15);

    while (std::getline(myFile1, str))
    {
        std::istringstream iss(str);
        while (std::getline(iss, str, ',')) {
            std::cout << "Read " << str << std::endl;
            input.push_back(std::stold(str));
            std::cout << "Stored " << input.back() << std::endl;
        }
    }
    myFile1.close();

    ...
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • The purpose of this program is to store each integer of the text file into a vector element. However I do not see this program storing each value. From what I ran using this code, it just stores the first value. I need the vector input to store the 20 numbers sequentially and this code doesn't do that. Can you elaborate if Im missing something? (I fixed std::precision(15) to std::cout.precision(15) so that it doesnt throw an error) – readysetcode Nov 16 '21 at 04:50
  • @readysetcode your code doesn't work because you are not processing the file data correctly. I have updated my answer. – Remy Lebeau Nov 16 '21 at 05:21
0

std::getline only accepts a single character as delimiter:

Can I use 2 or more delimiters in C++ function getline?

It's more clear to use two loops to read data as below:

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
static int Ncol = 5;
int main()
{
    int column=0,Nrow;
    std::string line,field;
    std::ifstream myFile1;

    Nrow = 5;
    std::cout.precision(15);
    std::fixed;

    double* input = new double[Nrow*Ncol];
    double* ftrue = new double[Nrow];

    myFile1.open("./Data_codelink_test/test.txt");

    int row = 0;
    while (std::getline(myFile1, line))
    {
        std::stringstream stream(line);
        int column = 0;
        while(column < Ncol)
        {   
            std::getline(stream,field,','); // This gives me line1 with the new line character
            std::cout<<"Read "<<field<<std::endl;
            input[row *  Ncol + column] = std::stold(field);
            std::cout<<"Stored "<<input[row *  Ncol + column]<<std::endl;
            column++;  
        }
        row++;
    }
    myFile1.close();
}

The result is:

The result

cg-zhou
  • 528
  • 3
  • 6