Getline skipping third line?

Hi!

I have a task where I must get the data from a simple .txt file. It works perfectly until the third line must be used. It's a program where I must count the price of a train trip based on the kilometers the user types in. However, when the user gives the program a km between 75 and 100, the program just doesn't want to work.

What can the problem be?

Thanks for the help in advance!

My code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include<iostream>
#include<fstream>
#include<string>

int findNthOccur(std::string str, char ch, int N);
void ticket(std::string filename, int km);

int main(){

	int km = 0;

	std::cout << "Counting price of train trip. Give me a distance in km and I'll return the price of its ticket.\n\n";

	do{
		
		std::cout << "Distance (km): ";
		std::cin >> km;
		
		ticket("prices.txt", km);
		
		if(km < 0){
			break;
			
		}
		
	}while(km > 0);
	
	if(km < 0){
		std::cout << "Quitting.";
		
	}
	
	return 0;
}

void ticket(std::string filename, int km){
	
	// int start, end, price;
	std::string str, s, e, p;
	
	std::ifstream file(filename);
	
	if(file.is_open()){
		
		std::getline(file, str);
		
		while(!file.eof()){
			
			std::getline(file, str);
			std::cout << str << '\n';
			
			if(str != ""){
				
				s = str.substr(0, findNthOccur(str, '\t', 1));
				e = str.substr(findNthOccur(str, '\t', 1)+1, findNthOccur(str, '\t', 2)-findNthOccur(str, '\t', 1)-1);
				p = str.substr(findNthOccur(str, '\t', 2)+1, findNthOccur(str, '\n', 1)-findNthOccur(str, '\t', 2)-1);
				
				std::cout << "s is: " << s << ", e is: " << e << ", p is: " << p << '\n';
				
				if(std::to_string(km) >= s && std::to_string(km) <= e){
					
					std::cout << "Price of ticket: " << p << '\n';
					
				}
				
			}
			
			}
			
		}
	
	
	
}

int findNthOccur(std::string str, char ch, int N){
    
	int occur = 0;
 
    for (unsigned int i = 0; i < str.length(); i++) {
        if (str[i] == ch) {
            occur += 1;
        }
        if (occur == N)
            return i;
    }
    return -1;
}


prices.txt:

Prices list
1 25 840
25 50 860
50 75 900
75 100 930
Last edited on
Hello vboro,

As a start and untested this may work better than what you have which is over done for the file that you need to read.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
void ticket(const std::string& filename, int km)
{
    std::ifstream file(filename);

    if (!file)
    {
        std::cerr << "\n File \"" << filename << "\" did not open\n";

        return;
    }

    int start{}, end{}, price{};  // <--- ALWAYS initialize all your variables.
    //std::string str, s, e, p;

    std::getline(file, str);  // <--- I take it that this eats the first line?

    while (file >> start >> end >> price)
    {

        //std::getline(file, str);
        //std::cout << str << '\n';

        //if (str != "")
        //{

        //    s = str.substr(0, findNthOccur(str, '\t', 1));
        //    e = str.substr(findNthOccur(str, '\t', 1) + 1, findNthOccur(str, '\t', 2) - findNthOccur(str, '\t', 1) - 1);
        //    p = str.substr(findNthOccur(str, '\t', 2) + 1, findNthOccur(str, '\n', 1) - findNthOccur(str, '\t', 2) - 1);

        //    std::cout << "s is: " << s << ", e is: " << e << ", p is: " << p << '\n';

        //    if (std::to_string(km) >= s && std::to_string(km) <= e)
        //    {

        //        std::cout << "Price of ticket: " << p << '\n';

        //    }

        //}

    }
}

You are going to extra work to break up a string into numeric variables to do any calculations. Start with numeric variables and then change them to a string if you need to. You may also want to consider making "price" a "double".

Andy
Hello vboro,


It works perfectly until the third line must be used.

No it does not.

I first found that the text I copied for the input file has a space between the numbers not a (\t).

So when you get to your lines 54 to 56 calling the function looking for (\t) always returns a (-1) and the string does not break up into the 3 variables. When I changed all the (\t)s to a space then it did work. Now maybe your input file uses the (\t) to separate the numbers and if so it did not display in the post properly or you typed it in and could not use the tab key to separate the numbers.

the output looks like this:

Counting price of train trip.
Give me a distance in km and I'll return the price of its ticket.


Distance (km): 81
1 25 840
s is: 1 25 840, e is: 1 25 840, p is: 1 25 840

25 50 860
s is: 25 50 860, e is: 25 50 860, p is: 25 50 860

50 75 900
s is: 50 75 900, e is: 50 75 900, p is: 50 75 900

75 100 930
s is: 75 100 930, e is: 75 100 930, p is: 75 100 930


Distance (km):

No what you need.

Changing the (\t)s to spaces:

Counting price of train trip.
Give me a distance in km and I'll return the price of its ticket.


Distance (km): 80
1 25 840
s is: 1, e is: 25, p is: 840

25 50 860
s is: 25, e is: 50, p is: 860

50 75 900
s is: 50, e is: 75, p is: 900

75 100 930
s is: 75, e is: 100, p is: 930


Distance (km):



Your if statement on line 60 does not work at all. You are converting (km) to a string and trying to do a string compare of numbers. This does not work the same as comparing actual numbers.

Changing the numeric value to a string gives you "80", that is a 2 element string where element (0)zero is '8' and element (1) is (0)zero. When comparing the 2 strings, 1 character at a time, the ASCII value of '7' is 55 and the ASCII value of '8' is 56. So far it is true until you compare the 2nd element where the ASCII value of '5' is > the ASCII value of (0)zero.

Changing the if statement to: if (km >= std::stoi(s) && km <= std::stoi(e)) I get this:

Counting price of train trip.
Give me a distance in km and I'll return the price of its ticket.


Distance (km): 80
1 25 840
s is: 1, e is: 25, p is: 840

25 50 860
s is: 25, e is: 50, p is: 860

50 75 900
s is: 50, e is: 75, p is: 900

75 100 930
s is: 75, e is: 100, p is: 930

    Price of ticket: 930


Distance (km):



This bit of code:
21
22
23
24
if (km < 0)
{
    break;
}

Is unnecessary because the while condition takes care of this.

This code:
28
29
30
31
if (km < 0)
{
    std::cout << "Quitting.";
}

The if is not necessary because you do/while loop is finished and the only part left is to end the program. Also since (0)zero ends the do/while loop checking for (< 0) would never be true.

Just some notes:
line 43 if(file.is_open()). Not the best way to code the function and you are missing the else statement should th if statement be false.

What would work better for you is:
1
2
3
4
5
6
7
8
const std::string inFileName{ "prices.txt" };

std::ifstream inFile(inFileName);

if (!inFile)
{
    return std::cerr << "\n File \"" << inFileName << "\" did not open\n", 1;
}

I also changed the function from returning "void" to returning an "int". Doing this you first define and open the file then check before you continue with the program. This eliminates the need for if(file.is_open()).

The while loop: while(!file.eof()) does not work the way that you think it does.

salem c once wrote:

eof() is a state (the result of a past event), not a prediction (of a future).
If you have a 10 line file, then calling getline 10 times does NOT make eof() true. You have to try and read the file for the 11th time to make eof() become true. That's why you have the i-- "oops, one too many" bodge.

This is in http://www.cplusplus.com/forum/beginner/278122/ if you want to read about it.

Although this seems to work it is not right. Usually the extra loop causes a problem. Try while (std::getline(file, str)). Now when the read sets the (eof) bit the while loop fails.

Andy
Registered users can post here. Sign in or register to post.