Reading strings into struct causes extra new lines



I'm having a hard time with reading data from keyboard and storing it in a struct variable, on a C++ console program.
My struct contains data about a book (name, genre and isbn) and looks like this:

1
2
3
4
5
6
struct libro
{
	string nombre;
	string genero;
	long isbn;
};


Now I'm trying to fill in that info from keyboard, in this function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void agregar_libro()
{
	libro un_libro;
	cout << "\n\n\nAGREGAR LIBRO \n" << endl;
	cout << "Nombre: ";
	getline(cin, un_libro.nombre);
	cin.ignore();
	cout << "Genero: ";
	getline(cin, un_libro.genero);
	cin.ignore();
	cout << "ISBN: ";
	cin >> un_libro.isbn;
	cin.ignore();
}


When running in debug mode I can see the info being correctly stored in the corresponding struct members. However, I also get an extra new line after each entry. So, whenever I enter data, I have to press Return twice: once for the info to be entered and once again to dismiss a new line that is generated and get the next prompt. So I get something like this:

Nombre: example name

Genero: example genre

ISBN: 12345

And if I use cin.ignore(INT_MAX, '\n'); I get the exact same result.
I've also tried using just cin.ignore(INT_MAX); but then I get the first prompt ("Nombre; "), I'm able to enter the data and after I press Return I never get the next prompt (I can keep pressing Return and generating new lines but nothing else happens).
So how exactly should I load those strings into my struct? I then need to write the struct members into a text file, but that's a different topic :)
Thanks!
What do you think cin.ignore(); does? You use it after getline and then complain about it?

std::getline consumes the newline character and discards it for you, no need to call ignore() like with formatted extraction operator >> (which you should never use directly anyway).

http://www.LB-Stuff.com/user-input
Last edited on
Are you by any chance using Mac OS? I think the end of line character on Macs is '\r' and not '\n'. If you are using Mac OS, try removing your calls to cin.ignore and also specify a delimiter of '\r' as a third parameter to getline.

getline stops reading at '\n' and removes the '\n' from input. cin.ignore potentially removes a lot of characters from input and stops after the count is satisfied or it removes a '\n'. So you are telling your program to read a line until the user sends '\n', and immediately following that the program waits again for another '\n'. The user would have to press enter twice at the end of every string input. This would be annoying. Furthermore, after the first enter press they would be allowed to type more characters which to the user would seem like they are adding more to their string before they press enter again.
Oh, thanks!
I've read a few times that ignore had to be called after using getline to read a string variable, so I was doing just that :)

Edit: I'm using Win 7 on an intel machine, so no mac.
But I just removed the calls to cin.ignore() after each string read and that did the trick.
Last edited on
@kevinkjt2000: C++ normalizes \r\n to \n and vice versa, so your program only ever sees \n

anarelle wrote:
I've read a few times that ignore had to be called after using getline to read a string variable, so I was doing just that :)
Could you tell me where you read that? I'd like to speak to the person who said that.
Last edited on
LB wrote:
C++ normalizes \r\n to \n and vice versa, so your program only ever sees \n

You must be thinking of how std::endl normalizes line endings during output. Aside from that, I can't think of anything else in C++ that normalizes line endings off the top of my head.
http://ideone.com/5m6R3B
If the text file was written using the same operating system the line endings should not matter. But if you are trying to use a text file that was written on another operating system you may have a problem. While the "runtime" modules translate the system end lines to '\n' automatically it expects the line endings to be correct for the current system. For example if you write a text file on a Windows machine you will have a carriage return linefeed pair as the line ending ("\r\n"), if you try to read this file on Linux the operating system will only recognize the line feed character ('\n') as the end of line character leaving the carriage return character '\r' in the stream.

Last edited on
@kevinkjt: the only time C++ streams do not normalize line endings is if you open the stream in binary mode. When opened in text mode, streams always normalize line endings.
So stringstreams default to binary mode?
Edit: Just noticed that jlb agrees with me that input is not modified.
Last edited on
I don't know how I am reading jib's post differently from you, because the way I read it jib and I are saying the same thing.
... leaving the carriage return character '\r' in the stream.

Also I gave code that proves my point... '\r' is not normalized away from the input.
kevinkjt2000 wrote:
Also I gave code that proves my point... '\r' is not normalized away from the input.
The system that code ran on is a unix system which doesn't use \r so of course it didn't get removed from the stream. Jib already explained this.
C++ normalizes \r\n to \n and vice versa, so your program only ever sees \n
of course it didn't get removed from the stream

Do you see the contradiction?

I compiled and executed my example on my windows 7 machine with TDM-GCC and Visual Studio 2013:
TDM-GCC: http://postimg.org/image/ae0g3bl51/
VS2013: http://postimg.org/image/eklainkqt/

http://www.cplusplus.com/reference/istream/istream/getline/
getline wrote:
Extracts characters from the stream as unformatted input

Unformatted tells me that there is no modification of the input. Is that wrong?

me wrote:
So stringstreams default to binary mode?

I was ignored :( *cries in a corner for a few minutes*
Even if stringstreams default to binary, I know that ifstreams do not. So I also compiled an example with some input text files that I created with Haskell using the same inputs as the stringstreams.
http://postimg.org/image/pv337fav1/

Side note: I found a bug in Notepad++, when saving a file as Windows EOL it used \n on my system instead of \r\n. This could be intended, as I discovered that Windows Notepad uses \n line endings as well. I was trolled at home.
Last edited on
To whoever reported my posts: the report but is not an "I think you made a mistake" button, it's an "I think you violated the forum rules or guidelines" button.
kevinkjt2000 wrote:
Do you see the contradiction?
No I do not. The first quote is relevant to Windows, the second quote is relevant to Unix.
kevinkjt2000 wrote:
http://www.cplusplus.com/reference/istream/istream/getline/
> Extracts characters from the stream as unformatted input
Unformatted tells me that there is no modification of the input. Is that wrong?
Yes, this is the code I am using to test in Visual Studio 2015:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <fstream>
#include <string>

int main()
{
	if(std::ifstream in {"in.txt"})
	{
		std::string a, b, c;
		if(std::getline(in, a) && std::getline(in, b) && std::getline(in, c))
		{
			std::cout << a.size() << std::endl;
			std::cout << b.size() << std::endl;
			std::cout << c.size() << std::endl;
		}
	}
}
The in.txt file is 9 bytes and contains the letters a, b, and c on separate lines. Since I used Windows Notepad, the line endings are \r\n. The output of the program is all 1s because getline is only reading the letters and not the carriage returns.
kevinkjt2000 wrote:
So stringstreams default to binary mode?
kevinkjt2000 wrote:
I was ignored :( *cries in a corner for a few minutes*
I do not know the answer, because as you demonstrated stringstream seems to have different behavior than file stream.
Last edited on
No I do not. The first quote is relevant to Windows, the second quote is relevant to Unix.

Sorry, I had assumed the first quote was about C++ in general based on how the statement is worded.

I took another look at my last example using VS2013 and sure enough the Microsoft compiler behaves no different. I also ran the example you just gave with a, b, and c on separate lines each ending with \r\n. I see three 2s because getline does fetch \r. Maybe they deviated from normal in VS2015? Unfortunately, I have not taken the time yet to install VS2015 so I cannot test with that version. But I did run Windows Notepad typing a<enter>b<enter>c<enter>, saved that file, and then I peeked at it with a hex editor. Turns out the line endings are \n!!! Microsoft sure knows how to confuse us!
Turns out my roommate was trolling me the whole time with a background executable that was placed earlier in the day after he saw this forum page on my screen... LOL Now the output I see is 0, 1, 0 from my example, and all 1s for the example you just posted.
Last edited on
Well it wasn't me :)
Looks like one of mine was reported too... :(
Last edited on
Dear whoever is reporting my posts, you're not accomplishing anything because I am not violating any forum rules. The forum admin is a real human and isn't stupid ;)

kevinkjt2000 wrote:
Turns out my roommate was trolling me the whole time with a background executable that was placed earlier in the day after he saw this forum page on my screen... LOL Now the output I see is 0, 1, 0 from my example, and all 1s for the example you just posted.
Ouch - my dorm has individual locking doors to prevent this sort of thing.
Topic archived. No new replies allowed.