Two Same Strings Don't Equal Each Other?

Pages: 12
By “synchronizing inputs” is meant that you are keeping track of where you are in your input stream by some semaphore — in our case, the newlines.

We do this because we know that certain inputs should have an newline after them. For example:

1
2
3
4
5
6
7
8
9
10
11
12
std::string name;
std::cout << "What is your name? ";
getline( std::cin, name );

std::string quest;
std::cout << "What is your quest? ";
getline( std::cin, quest );

double speed;
std::cout << "What is the air-speed velocity of an unladen swallow? ";
std::cin >> speed;
std::cin.ignore( std::numeric_limits <std::streamsize> ::max(), '\n' );

In each of these cases we know the user will press Enter after answering the question. So we make sure to leave the input stream in a common state: having read the last newline and ready to begin reading a new line. This allows us to program future inputs without having to worry whether the last input has left an extra newline lying around.

That last line tells the input to read and discard all input until it reads and discards a newline. When in doubt, read the documentation.

Others have picked up here as well, so I’ll leave it at that.

:O)
Last edited on
Again, thanks everyone who has replied!

Furry guy wrote:
If you are passing an object into a function, either as a copy or as itself by pointer/reference, and you want to indicate the function is not supposed to alter the object, declare the parameter const.

You are setting a contract for you, the programmer, the compiler and other users of your function the object should not be modified.

What went in should come out the same, which doesn't matter much if the object was copied locally.

A devious programmer could get around the request by casting away the constness.

Think "SHOULD NOT" instead of "CAN NOT" be changed.

Dammit, would you stop asking such good questions that make me actually have to work to explain them? :Þ

(No, not really. You asking questions actually is fun for me to try to dig down and dredge up a worthwhile and meaty answer.)

Ahh okay, thanks. Lol
-------------------------------------------
Duthomhas wrote:
Re: OS vs Command Prompt

When you have the VM up and running, you are running two operating systems at the same time. That has less to do with it than the newline conventions expected by the C library.
The Wikipedia article on Newline is a good read.
https://en.wikipedia.org/wiki/Newline

Er... my head is really fuzzy and I am tired right now. I’ll respond to your other questions sometime tomorrow... Sorry.

Ah okay thanks, yeah that wiki link was informative, especially for the graph: https://gyazo.com/b637bab85fa74746f44c06321f252e2c

And no problem. :P
--------------------------------------------
Enoizat wrote:
Please note my English is poor, so I’m never sure I’ve clarified what I meant to say - that’s why I’m so verbose. But, despite the number of rows, the underlying idea is pretty simple.

No worries!

Enoizat wrote:
In C++ a std::fstream is a stream.
In C++ std::cin is a stream.
In C++ a std::stringstream is a stream.

std::getline extracts the ‘\n’ character, but then discards it:
https://en.cppreference.com/w/cpp/string/basic_string/getline

So, if we read a ‘line’ of any stream by std::getline (with the default settings), we ‘clean’ the stream from the final '\n', without taking it along.
Later, we can use that std::string to initialize another stream, like a std::istringstream, and use it exactly the same way we could use std::cin.

.. <Rest of your msg>

Okay, so to clarify, basically stringstream will:
1. Take all user input
2. Store it into a string data type, but with the \r(?) and \n stripped (not stored in string)
3. Then you can take parts of that string and assign it to other data types (like int and double) through iss >> newVarNme?

If that's what you meant, I understand now and I agree that is very useful!

However, I can't seem to get it to work.. I created an example program to test it and and store as notes for later, but it doesn't work properly. What am I doing wrong?
Code (Please note this is a completely separate program):
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
/*
1. Program will ask for the user to input 2 player's data.
2. Then will store player's data into vector of objects (using struct)

It goes about this by using getline() for all input, then using stringstream
to get parts of that line and store it into the different struct variables.

However, it currently does not work like it should for outputting second
player's data.
*/
#include <iostream>
#include <string>
#include <vector>
#include <sstream>

struct playerData {
    std::string pName;
    int points;
    double health;
};


int main() {
	const int LEN = 2;
    // declares objects (players):
    playerData p0, p1, p2, p3;
	std::vector<playerData> players = {p0, p1, p2, p3};
    // Asks for user input for each of the player's data:
    for (int i = 0; i < LEN; i++) {
        /*
			This method will use getline() to add all input to a
			single string. Then will use stringstream to take parts
			from that string (similar to how cin >> does for input)
			and store those parts into different variables of different
			data types (like string, int, and double).
		*/
		// Declares string that all user input will be stored in:
		std::string fullInput;

		// Asks for user input:
		std::cout << "Please input player name (can have spaces): ";
        std::getline(std::cin, fullInput);
        
		std::cout << "Please input player's points (int): ";
        std::getline(std::cin, fullInput); // adds to fullInput string.
        
        std::cout << "Please input player's health (double): ";
        std::getline(std::cin, fullInput); // adds to fullInput string.
		
		std::stringstream iss { fullInput };
		iss >> players[i].pName; // Takes first part from fullInput string and stores it as a string in struct.
		iss >> players[i].points; // Takes second part of fullInput string (acts like cin) and stores it as an int in struct.
		iss >> players[i].health; // Takes third part of fullInput string and stores it as a double in struct.
    }

	// Prints Player Info:
	for (int i = 0; i < LEN; i++) {
    	std::cout << players[i].pName << '\n'
				  << players[i].points << '\n'
				  << players[i].health << "\n\n";
	}
}


Input / Output Result:
1
2
3
4
5
6
7
8
9
10
11
12
13
Please input player name (can have spaces): Jack Jackson
Please input player's points (int): 6
Please input player's health (double): 10.3
Please input player name (can have spaces): Jessie Lenox
Please input player's points (int): 4
Please input player's health (double): 5.6
10.3
807
0

5.6
-2129701632
6.36344e-310

----------------------

Enoizat wrote:
- - -
Yes, this is definitely too long. My bad.

Haha, no worries. I am quite verbose myself a lot of the time. Perhaps not when asking questions, but I am when I try to explain something. Plus your response wasn't all that long. :P
--------------------------------------------
ne555 wrote:
consistency with `getline()', whose prototype is istream& getline (istream& is, string& str);
note that you may use the return value like this
1
2
3
while(getline(input, line)){
	//process the whole file line by line
}

Ahh okay, thanks. Good example.

ne555 wrote:

and as you see it (again), printing debugging have its shortcomings, so I'll suggest you to use a debugger to watch your variables.

I've never used a debugger, but good idea. I'll add it to my things to do list (as stuff to learn), thanks!
--------------------------------------------
Duthomhas wrote:
By “synchronizing inputs” is meant that you are keeping track of where you are in your input stream by some semaphore — in our case, the newlines.

We do this because we know that certain inputs should have an newline after them. For example:
...

In each of these cases we know the user will press Enter after answering the question. So we make sure to leave the input stream in a common state: having read the last newline and ready to begin reading a new line. This allows us to program future inputs without having to worry whether the last input has left an extra newline lying around.

That last line tells the input to read and discard all input until it reads and discards a newline. When in doubt, read the documentation.

Ah okay, thank you!

Last edited on
Okay, so to clarify, basically stringstream will:
1. Take all user input
2. Store it into a string data type, but with the \r(?) and \n stripped (not stored in string)

Well, not exactly... You need to change the subject:
std::getline takes the user input, normally untill the first ’\n’ is met, discards the ’\n’ and store the rest into a std::string.

Later, you can use that std::string to initialize a std::stringstream (usually a std::istringstream).

The ‘\r\n’ issue, to my knowledge, is not something that refers to C++ itself: it depends on how the library has been implemented.
Since in Linux the EOL (end of line) character is just ‘\n’, the (most popular) Linux compiler, GCC, doesn’t take care about the ‘\r’. So the ‘\r\n’ EOL is not properly managed.
Please note years ago the Macintosh EOL was ‘\r’ :-) I’ve no idea if the std::getline version who come along with GCC was able to manage correctly that EOL.

3. Then you can take parts of that string and assign it to other data types (like int and double) through iss >> newVarNme?

You can use the std::stringstream (not the std::string!) as if it were std::cin, yes.

What am I doing wrong?

1) You assume that std::getline appends at the end of a std::string, while it overwrites the std::string.
2) You seem to believe that a std::stringstream which has been initialized by a std::string is somehow ‘connected’ with that std::string.
If you use a std::string to initalize a std::stringstream, the data inside the std::string are just copied into the std::stringstream.

Example (very poor!):
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/*
1. Program will ask for the user to input 2 player's data.
2. Then will store player's data into vector of objects (using struct)

It goes about this by using getline() for all input, then using stringstream
to get parts of that line and store it into the different struct variables.

However, it currently does not work like it should for outputting second
player's data.
*/
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

struct PlayerData {
    std::string p_name;
    int points {};
    double health {};
};


int main() {
    constexpr int LEN { 4 };    // If there are 4 elements in the std::vector,
                                // you need to loop 4 times, not 2.

    // Initialize a std::vector with 4 PalyerData:
    std::vector<PlayerData> players { PlayerData {},
                                      PlayerData {},
                                      PlayerData {},
                                      PlayerData {} };

    // Asks for user input for each of the player's data:
    for (int i {}; i < LEN; ++i) {
        /*
            This method will use getline() to add all input to a
            single string.

            Then will use that std::string to initialize a std::istringstream.

            Than will use that std::istringstream to assign values to the
            objects stored inside the std::vector as if it were std::cin >>.
        */
        // Declares string that all user input will be stored in:
        std::string full_input;

        // Asks for user input:
        std::cout << "Please input player's name (can have spaces): ";
        std::getline(std::cin, full_input);
        // Let's say now full_input contains "John Doe".
        
        std::stringstream iss { full_input };
        // Now iss contains "John Doe".

        iss >> players.at(i).p_name;
        // Now players.at(i).p_name contains "Joe".

        iss >> full_input;
        // Now full_input contains "Doe".
        
        // iss now is set to EOF.
        // If you want to reuse it, you need to clear() it (see below).

        players.at(i).p_name += ' ' + full_input;
        // Now players.at(i).p_name contains "Joe Doe".
        
        std::cout << "Please input player's points (int): ";
        std::getline(std::cin, full_input);
        // Let's say now full_input contains "13".

        iss.str(full_input);
        // Now iss contains "13" (but is still in a EOF state).

        iss.clear();
        // Now iss is in good state.

        iss >> players.at(i).points;
        // Now players.at(i).points contains "13".
        // iss is in a EOF state.


        std::cout << "Please input player's health (double): ";
        std::getline(std::cin, full_input);
        // Let's say now full_input contains "66.6".

        iss.str(full_input);
        // Now iss contains "66.6" (but is still in a EOF state).

        iss.clear();
        // Now iss is in good state.

        iss >> players.at(i).health;
        // Now players.at(i).health contains "66.6".
    }

    // Prints Player Info:
    for (int i {}; i < LEN; ++i) {
        std::cout << players[i].p_name << '\n'
                  << players[i].points << '\n'
                  << players[i].health << "\n\n";
    }
}


Output:
Please input player's name (can have spaces): John Doe
Please input player's points (int): 13
Please input player's health (double): 66.6
Please input player's name (can have spaces): Ann Smith
Please input player's points (int): 14
Please input player's health (double): 77.7
Please input player's name (can have spaces): Barbara Williams
Please input player's points (int): 15
Please input player's health (double): 88.8
Please input player's name (can have spaces): Cindy Jones
Please input player's points (int): 16
Please input player's health (double): 99.9
John Doe
13
66.6

Ann Smith
14
77.7

Barbara Williams
15
88.8

Cindy Jones
16
99.9


Actually objects should be initialized by their constructors, not this way.
Enoizat wrote:
Well, not exactly... You need to change the subject:
std::getline takes the user input, normally untill the first ’\n’ is met, discards the ’\n’ and store the rest into a std::string.


.... <rest of message> ...

Ahh okay, thank you! Sorry for late reply.

Took me a few rereads and thinking about it for a while.. But I kind of understand it now. Thanks! :)

All questions have been answered now I think so I'll mark it as solved. :D

Again, thank you to everyone who responded! I really appreciate it!

Edit: I was able to get my example to work for the string stream based off your explanation & example so I have a better understanding of how it works now. :)
Last edited on
Topic archived. No new replies allowed.
Pages: 12