Cin used on character arrays - c++

In C++ , Is this a valid/efficient way to input a series of characters ?
As in :
char abc[100];
cout<<"Enter your address:";
cin>>abc;
This says :
However, cin extraction always considers spaces (whitespaces, tabs, new-line...) as terminating the value being extracted, and thus extracting a string means to always extract a single word, not a phrase or an entire sentence.
Since the above statement is given for Strings and not character arrays , I am confused .
Will this code work properly ?
Note : I am using TurboC++

If you want to read only non-whitespace characters, you can use:
char abc[100];
cout<<"Enter your address:";
cin >> abc;
However, that is risky. If the sequence of non-whitespace characters consists of 100 or more characters, you will run into the problem of accessing memory out of bounds, which will lead to undefined behavior.
If you want to read everything up to a the newline character, you can use:
char abc[100];
cout<<"Enter your address:";
cin.getline(abc, 100);
This has the added advantage that it will not read more than 99 character, saving the last space for the null terminator.
More details on istream::getline() can be found at http://en.cppreference.com/w/cpp/io/basic_istream/getline.

Related

Getting multiline sentence input in c++

I am trying to take multiple lines of string input (may contain spaces) in c++ using 2D char array but the loop gets terminated without taking any input for n=1 in the code:
When n=2, it takes only one input and when I try to print input[0], it prints blank. But for cout<
char input[100][100];
int n,i;
cout<<"Enter no of lines : ";
cin>>n;
cout<<"Enter "<<n<<" sentences : "<<endl;
for(i=0;i<n;i++)
cin.getline(input[i],100);
This is a common problem when mixing formatted and unformatted input. After a formatted input, the internal buffer is positioned before the first blank character and before the \n. The bullet proof way would be to always use getline and then scan the first line to extract the number of lines. But for such a simple case, it is enough to use a dummy getline after reading the number of line to skip the end of line:
char input[100][100];
int n,i;
cout<<"Enter no of lines : ";
cin>>n;
cin.getline(input[0], 100); // skip the end of line
cout<<"Enter "<<n<<" sentences : "<<endl;
for(i=0;i<n;i++)
cin.getline(input[i],100);
But:
you should always test cin after a read (what if the user types erroneously e instead of 4?)
you should avoid char arrays and always use string in C++ (simpler, cleaner, less error prone)
When you enter number of lines(say 4) you press 4 and then enter key. It is stored as 4\n in stdin that is standard input. When you read using cin.getline() you are reading \n. You will have to use cin.ignore to ignore existing buffer in stdin. However using >> operator is better since it handles newlines.
For multiline input you can input a third parameter to getline(): a delimiter specifying what indicates the end of your input.

Scanf does not work as expected

I tried to compare std::cin and scanf, I expected them to have same behavior, but actually not:
#include<iostream>
using namespace std;
int main()
{
int i;
cin>>i;
return 0;
}
This receives an input from user, no problem.
But
#include<stdio.h>
int main()
{
int i;
scanf("%d\n",&i);
return 0;
}
I input a integer, program doesn't terminate even if I press "enter" multiple times, unless I enter another integer number.
Note there's an "\n" in scanf's format string.
So I tried to add one statement
printf("%d\n", i);
Well it prints out the 1st number I just input. This is correct but weird, why after scanf, the program requires me to enter any character rather then \n, to exit the program?
I tried both VC and GCC, same problem. What is that \n indicating?
scanf("%d\n",&i);
Let's read the manpage of scanf :
Whitespace character: the function will read and ignore any whitespace characters encountered before the next non-whitespace character (whitespace characters include spaces, newline and tab characters -- see isspace). A single whitespace in the format string validates any quantity of whitespace characters extracted from the stream (including none).
What it means is scanf will search for a integer followed by an optionnal whitespace. that's why he's waiting for you to use two times enter. If you used "%d\n\n", it'll have to be three times. And so on.
If you want only an interger, use scanf("%d",&i);
scanf("%d\n",&i); is equivalent to std::cin >> i >> std::ws;.
If you want the same behaviour for scanf, remove \n: scanf("%d",&i);
This is caused by the fact that any whitespace character in scanf means "skip input until non-whitespace is found"

Asking the user to input a char and then a string

I'm writing a simple program that asks a user to input a letter. And then I want him to input a phrase. When it's just a single string I don't have a problem.
char c;
string s;
cin >> c;
cin >> s;
But when I want a phrase
cin >> c;
getline(cin, s);
When I run the program after the user inputs a letter and hits enter I don't get a chance to input the phrase. Of course if I type the character and enter a phrase after a space the program works fine.
On the contrary when I input a character and then enter a single string after a space using the first method, it won't record the string.
Why does it do this?
When ever you write a character and press enter, actually 2 char are send to the buffer: the character itself and \n as the result of the enter key press. Your cin >> c; reads the first character only while \n still remains in the buffer. Since std::getline() reads everything before it encounters a \n character and since \n is the first character it encounters it doesn't read anything and the program terminates. Add a std::cin.ignore(); (to ignore the \n) before std::getline and the code will work.
Since c only takes a character, the enter key that the user presses is given to s so anything other than that is not recorded. Only press a single key and no enter for the character. Or else just use a string anyway.

How does input buffering work in C++

Here is a code snippet. I'm confused as to how the buffering internally works.
while(true)
{
cout << "Enter a character: ";
cin.ignore(3, '\n');
ch = cin.get(); // ch is char type
cout << "char: ch: " << ch << endl;
}
Actually cin.ignore(3, '\n') ignores the first three characters and then gets the next immediate character. Till that point its fine. Since, I kept this in a while loop, I was trying to check the behavior of ignore() and get(). For instance, the output for which I checked was
Enter a character: abcd
char: ch: d
Enter a character: efgh
char: ch: e
Enter a character: ijkl
char: ch: i
Enter a character: mnopq
char: ch: m
Enter a character: char: ch: q
Enter a character:
Just to check the buffering, intentionally I was give 4 characters instead of 1. In the first case, its fine and got it. From second, the ignore doesn't seem to work. When I entered 5 characters, I din't get the behavior.
Need explanation on this. :)
According to documentation of std::cin.ignore(streamsize n = 1, int delim = EOF):
Extracts characters from the input sequence and discards them, until either n characters have been extracted, or one compares equal to delim.
http://www.cplusplus.com/reference/istream/istream/ignore/
You are putting abcd\n onto stdin. Your first ignore(3,'\n') removes abc and your get() fetches d. \n remains in the buffer.
Then you add efgh\n to the buffer which now contains \nefgh\n. Your next ignore() reads either 3 characters or a newline, whatever comes first. Since your newline is first in the buffer, only the newline is ignored.
You probably want to empty the stdin buffer before asking for more input. You can achieve this either by modifying your get() call, or by adding a second ignore() call before asking for more input.
cin.ignore(3, '\n') ignores up to three characters, stopping after it finds the end of a line (i.e. a \n character).
After the first line of input, the buffer will contain 5 characters, abcd\n. So ignore ignores abc, and get gets d, leaving \n.
After the second line, it contains \nefgh\n. So ignore just ignores the end-of-line character, and get returns e.
If you want to discard the rest of line after extracting the character, then use ignore again:
cin.ignore(numeric_limits<streamsize>::max(), '\n');

Is there a better way to parse a line of text like this?

I have a text file with lines of text that have a string another string followed by up to 4 integers,
ex:
clear "clear water.png" 5 7
wet "wet water.png" 9 5 33 17
soft "soft rain falling.png"
The only way I see it is:
read until space is found
set string to wet
read until double quote
read until second double quote
set second string to wet water.png
while not end of line
read until space
put string through string stream
push resulting integer into vector of int
Is there a better way to do this?
Thanks
This is the sort of task for which scanf and company truly shine.
char first_string[33], second_string[129];
sscanf(input_string,
"%32s%*[^\"]%*c%128[^\"]%*c %d %d %d %d",
first_string,
second_string,
&first_int,
&second_int,
&third_int,
&fourth_int);
You probably want to do that in an if statement so you can test the return value, to tell you how many of those fields converted (e.g., so you know how many integers you read at the end).
Edit: perhaps some explanation would be helpful. Let's dissect that:
%32s reads a string to the first white-space (or 32 characters, whichever comes first).
%*[^\"] ignores input up to the first ".
%*c ignores one more byte of input (the quote itself)
%128[^\"] reads the string in the quote (i.e., up to the next quote character).
%*c Ignores the closing quote
%d Reads an int (which we've done four times).
The space before each %d is really unnecessary -- it'll skip whitespace, but without the space, %d will skip leading whitespace anyway. I've included them purely to make it a little more readable.
Ugly, with no error-checking, but no dependencies on any non-standard libraries:
string s;
while(getline(fin, s))
{
string word, quoted_string;
vector<int> vec;
istringstream line(s);
line >> word;
line.ignore(numeric_limits<streamsize>::max(), '"');
getline(line, quoted_string, '"');
int n;
while(line >> n) vec.push_back(n);
// do something with word, quoted_string and vec...
}
Depending on the restrictions of the input strings you could trying splitting on double-quote then splitting on space.
Yes
Use getline to read one line at a time. Parse the lines using a regular expression library.