c++ if(cin>>input) doesn't work properly in while loop - c++

I'm new to c++ and I'm trying to solve the exercise 6 from chapter 4 out of Bjarne Stroustrups book "Programming Principles and Practise Using C++ and don't understand why my code doesn't work.
The exercise:
Make a vector holding the ten string values "zero", "one", ...,
"nine". Use that in a program that converts a digit to its
corresponding spelled-out value: e.g., the input 7 gives the output
seven. Have the same program, using the same input loop, convert
spelled-out numbers into their digit form; e.g., the input seven gives
the output 7.
My loop only executes one time for a string and one time for an int, the loop seems to continue but it doesn't matter which input I'm giving, it doesn't do what it's supposed to do.
One time it worked for multiple int inputs, but only every second time. It's really weird and I don't know how to solve this in a different way.
It would be awesome if someone could help me out.
(I'm also not a native speaker, so sorry, if there are some mistakes)
The library in this code is a library provided with the book, to make the beginning easier for us noobies I guess.
#include "std_lib_facilities.h"
int main()
{
vector<string>s = {"zero","one","two","three","four","five","six","seven","eight","nine"};
string input_string;
int input_int;
while(true)
{
if(cin>>input_string)
{
for(int i = 0; i<s.size(); i++)
{
if(input_string == s[i])
{
cout<<input_string<<" = "<<i<<"\n";
}
}
}
if(cin>>input_int)
{
cout<<input_int<<" = "<<s[input_int]<<"\n";
}
}
return 0;
}

When you (successfully) read input from std::cin, the input is extracted from the buffer. The input in the buffer is removed and can not be read again.
And when you first read as a string, that will read any possible integer input as a string as well.
There are two ways of solving this:
Attempt to read as int first. And if that fails clear the errors and read as a string.
Read as a string, and try to convert to an int. If the conversion fails you have a string.

if(cin >> input) doesn't work properly in while loop?
A possible implementation of the input of your program would look something like:
std::string sentinel = "|";
std::string input;
// read whole line, then check if exit command
while (getline(std::cin, input) && input != sentinel)
{
// use string stream to check whether input digit or string
std::stringstream ss(input);
// if string, convert to digit
// else if digit, convert to string
// else clause containing a check for invalid input
}
To discriminate between int and string value you could use peek(), for example.
Preferably the last two actions of conversion (between int and string) are done by separate functions.
Assuming the inclusion of the headers:
#include <iostream>
#include <sstream>

Related

How Do I use input to pass a string into a char array from a Text File

Hey I know I can just use a string to read from a text file. However I need to use a char array. Like If I was using a string I would do this
while (!input.eof()){
input >> s;
}
I am unsure how I would go about this if I don't know the length of the string. I know I can use getLine, but I'll prefer to use input.
I'm thinking that maybe I can use a loop to check until it reaches "\0"?
Anyway I have a feeling this question has been asked before, but if it has I can't find it. So sorry if that is the case.
You can consider istream::getline. Note that it can be use for C++ string and it must have a length limit for C string.
I think you should avoid check eof directly in while condition. It only returns true it reach end-of-file. So if you have multiple line, you read it, then do some calculate, the consequence can be unexpected when it reach the end-of-file right at reading step. So the check of EOF should be placed right after reading from stream like my example.
int main()
{
ifstream input("filename.txt");
const int MAX = 10000;
char characters[MAX];
while (true) {
input.getline(characters, MAX - 1, '\n');
if (input.eof())
break;
}
}

String Management C/C++ & Writing and Reading From txt File

I am facing a problem with reading and writing a string from and to a file respectively.
Purpose:
To enter a string into a text file as a complete sentence, read the string from the text file and separate all words that start from a vowel using a function and display them as a sentence. (The sentence just needs to consist of the words from the string that start with a vowel.)
Problem:
The code is working as intended but as i have used the getline() function to obtain the string from the txt file when i withdraw a substring from it, it includes the entire file after the vowel instead of just the word. I cannot understand how to make the substring only include words.
Code:
#include <fstream>
#include <string>
#include <iostream>
#include <cstring>
using namespace std;
string vowels(string a)
{
int c=sizeof(a);
string b[c];
string d;
static int n;
for(int i=1;i<=c;i++)
{
if (a.find("a")!=-1)
{
b[i]=a.substr(a.find("a",n));
d+=b[i];
n=a.find("a")+1;
}
else if (a.find("e")!=-1)
{
b[i]=a.substr(a.find("e",n));
d+=b[i];
n=a.find("e")+1;
}
else if (a.find("i")!=-1)
{
b[i]=a.substr(a.find("i",n));
d+=b[i];
n=a.find("i")+1;
}
else if (a.find("o")!=-1)
{
b[i]=a.substr(a.find("o",n));
d+=b[i];
n=a.find("o")+1;
}
else if (a.find("u")!=-1)
{
b[i]=a.substr(a.find("u",n));
d+=b[i];
n=a.find("u")+1;
}
}
return d;
}
int main()
{
string input,lne,e;
ofstream file("output.txt", ios::app);
cout<<"Please input text for text file input: ";
getline(cin,input);
file << input;
file.close();
ifstream myfile("output.txt");
getline(myfile,lne);
e=vowels(lne);
cout<<endl<<"Text inside file reads: ";
cout<<lne;
cout<<endl;
cout<<e<<endl;
system("pause");
myfile.close();
return 0;
}
I haven't read your code VERY carefully, but several things stand out:
Look up find_first_of - it'll simplify your code A LOT.
sizeof(a) certainly doesn't do what you think it does [unless you think it gives you the size of the std::string class type - which makes it rather strange as a use-case, why not use either 12 or 24?]
find (and find_first_of), technically speaking, doesn't return -1 when the function isn't finding what you want. It returns std::string::npos [which may appear to be -1, but a) is not guaranteed to be, and b) is unsingned so can't be negative].
Your program only reads one line.
x.substr(n) will give you the string of x from position n - is that what you want?
Don't repeat find, use p = x.find("X"); and then do x.substr(p) [assuming that is what you want].
There are various problems with your code.
int c = sizeof( a );
This is the number of bytes that a string takes up in memory. And you certainly don't want to create an array of this many strings as it makes no sense for what you're trying to achieve. Don't do this to yourself. You're only copying one string inside the loop, all you need is one string and you already have string d.
To get the actual size of a string, you have to call
str.size()
The string.substr(..) has a couple overloads, one of them takes only one argument, an index. This will return sub string starting at that index in the original string. (The string starting at the vowel all the way through to the end of the string)
What you are maybe looking for is the overload that takes two arguments, the start index (beginning of the word and the end of the word).
The string input will not take the newline that you enter to flush cin. And then you add it to the file in append mode, so after running the program a few times your file is a huge one-liner. Did you really intend to do this?
Maybe you should explicitly add a new line to the file after entering the input. Something like file << std::endl;
Also, the conditions in the ifs
if (a.find("a")!=-1)
Don't match what you do next,
b[i]=a.substr(a.find("a",n));
Then you use a static int,
static int n;
This is bad, because this function will only work once. You're lucky that static initializes its values to zero, but you should always initialize explicitly. In your case, you don't need this to be static.
Finally: "so i was unsure of how many loops to run"
When you don't know how many loops you have to run, then a for loop is not adequate.
You should use a while loop or a do while.
You shouldn't try to learn C++ by guessing, because that's what it looks like you're doing. You're trying to do more than you know and making some very silly mistakes. Find a good book to learn from, or at the very least google the functions you're using to see what they do and how to use them properly. (ie: http://www.cplusplus.com/reference/string/string/substr/ )
Here's a list of books from stackoverflow's FAQ: The Definitive C++ Book Guide and List
The last thing is about finding vowels. When you find a vowel, you have to make sure it's at the beginning of a word. Then you want to read it until the word ends, that is when you find a character that is not part of a word. (a whitespace, certain punctuation, ... ) This should mark the beginning and end of the word.

Query regarding SPOJ TEST

I might be wrong in asking an SPOJ problem on this forum but I wanted to understand one mechanism which I wanted to know from the enriched community here.
Your program is to use the brute-force approach in order to find the Answer to Life, the Universe, and Everything. More precisely... rewrite small numbers from input to output. Stop processing input after reading in the number 42. All numbers at input are integers of one or two digits.
Example
Input:
1
2
88
42
99
Output:
1
2
88
My Solution:
#include <iostream>
using namespace std;
int main()
{
int n,i=0;
int a[100] = {0};
while((cin>>n))
{
a[i] = n;
i++;
continue;
}
for(int j = 0;a[j]!=42;j++)
cout<<a[j]<<endl;
return 0;
}
Good Solution:
#include <iostream>
using namespace std;
int main()
{
int n;
while(true)
{
cin>>n;
if(n == 42)
break;
cout<<n<<endl;
}
return 0;
}
My query is what happens to the input in the good solution?We would be running the loop only till the number is not 42.How does Good solution handle the remaining input?I got some hint that it is somewhat related to buffering and all.Please provide me some explanation or links or study material or at least some keyword to google etc to get clarity on this.
Remaining input in good solution will be ignored by "good solution".
If you need more info read:
object
std::cin
extern istream cin;
Standard input stream
Object of class istream that represents the standard input stream oriented to narrow characters (of type char). It corresponds to the C stream stdin.
The standard input stream is a source of characters determined by the environment. It is generally assumed to be input from an external source, such as the keyboard or a file.
object
stdin
FILE * stdin;
Standard input stream
The standard input stream is the default source of data for applications. In most systems, it is usually directed by default to the keyboard.
stdin can be used as an argument for any function that expects an input stream (FILE*) as one of its parameters, like fgets or fscanf.

getline to split string manipulation error

Hey guys so I have an assignment for class where I have to split a string and manipulate it. However, when I try to split the string and assign it to an array only the first element comes and the other two don't. Please help.
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
int main()
{
string str;
cout<<"Enter a first name, middle initial, last name: ";
cin>> str;
string word;
string array[3];
stringstream stream(str);
int counter = 0;
while( getline(stream, word, ' ') )
{
cout<<word;
array[counter] = word;
counter++;
}
cout<<"The "<<array[0].length()<<" characters of the first name are: "<<array[0]<<endl;
cout<<"The "<<array[2].length()<<" characters of the last name are: "<<array[2]<<endl;
string newstring = array[2]+", "+array[0]+" "+array[1];
cout<<"In the phone book, the name would be: "<<newstring<<endl;
cout<<"The length of the name is: "<<newstring.length()<<endl;
cout<<"The comma is at position: "<<newstring.find(",")<<endl;
array[0].swap(array[2]);
cout<<"After the swap, the last name is "<<array[2]<<" and the first name is "<<array[0];
system("pause");
return 0;
}
There are a few blatant errors in your code:
You need to always check your input after trying to read! You do that using the while-loop but you also need to verify that you actually successfully read the string first.
It seems you are mixing the what the input operator for std::string and std::getline() are doing: the input operator reads the first word after skipping leading spaces while std::getline() read, well, a line (whether the line terminator can be specified as third argument).
When reading fixed sized array you always need to make sure you do not read more than fits into this array! You may have heart about hackers exploiting software by using buffer overruns: assuming you'd actually indeed read a line first followed by splitting it into words you'd have created one of those exploitable programs! If you don't want to check before each word if there is enough space in the array, you'd use, e.g., a std::vector<std::string> (doing so also has a problem with hackers, namely that it opens up the program for a Denial of Service attack but although this is still a problem it is a somewhat lesser problem).
There are also a few smaller issues with your program, too:
If you are only reading from a string stream, you should use std::istringstream as there is no need to also set up the writing part of the std::stringstream.
The programs asks for "first name, middle name, and last name". I would read that specification to use, e.g., "John, F., Kennedy" but it seems you'd expect "John F. Kennedy". One reason I would expect that commas are to be used is that I don't have a middle name, i.e., I would enter "Dietmar, , Kühl".

Reading/parsing multiple INTs from a String

I've been reading about converting strings to integers, the "atoi" and "strol" C standard library functions, and a few other things I just can't seem to get my head around.
What I'm initially trying to do, is to get a series of numbers from a string and put them into an int array. Here is snippet of the string (there are multiple lines in the single string):
getldsscan
AngleInDegrees,DistInMM,Intensity,ErrorCodeHEX
0,0,0,8035
1,0,0,8035
2,1228,9,0
3,4560,5,0
...
230,1587,80,0
231,0,0,8035
232,1653,89,0
233,1690,105,0
234,0,0,8035
...
358,0,0,8035
359,0,0,8035
ROTATION_SPEED,4.99
The output is from my vacuum robot, a "Neato XV-21". I've gotten the output above from over a COM port connection and I've got it stored in a string currently. (As the robot can output various different things). In this example, I'm reading from a string neatoOutput which houses the output from the robot after I've requested an update from its laser scanner.
The "getldsscan" is the command I sent the robot, it's just being read back when I get the COM output so we skip over that. The next line is just helpful information about each of the values that is output, can skip over that. From then on the interesting data is output.
I'm trying to get the value of the Second number in each line of data. That number is the distance from the scanner to an obstacle. I want to have a nice tidy int distanceArray[360] which houses all the distance values that are reported back from the robot. The robot will output 360 values of distance.
I'm not fussed with error checking or reading the other values from each line of data yet, as I'll get them later once I've got my head around how to extract the current basic data I want. So far I could use something like:
int startIndex = 2 + neatoOutput.find("X",0); //Step past end of line character
So startIndex should give me the character index of where the data starts, but as you can see by the example above, the values of each number range in size from a single character up to 4 characters. So simply stepping forward through the string a set amount won't work.
What I'm thinking of doing is something like...
neatoOutput.find("\n",startIndex );
Which with a bit more code I should be able to parse one line at a time. But I'm still confused as to how I extract that second number in the line which is what I want.
If anyone is interested in about hacking/coding the robot, you can goto:-
http://www.neatorobotics.com/programmers-manual/
http://xv11hacking.wikispaces.com/
UPDATE: Resolved
Thanks for your help everyone, here is the code I'm going to work with in the near term. You'll notice I didn't end up needing to know the int startIndex variable I thought I would need to use.
//This is to check that we got data back
signed int dataValidCheck = neatoOutput.find("AngleInDegrees",0);
if (dataValidCheck == -1)
return;
istringstream iss(neatoOutput);
int angle, distance, intensity, errorCode;
string line;
//Read each line one by one, check to see if its a line that contains distance data
while (getline(iss,line))
{
if (line == "getldsscan\r")
continue;
if (line == "AngleInDegrees,DistInMM,Intensity,ErrorCodeHEX\r")
continue;
sscanf(line.c_str(),"%d,%d,%d,%d",&angle,&distance,&intensity,&errorCode); //TODO: Add error checking!
distanceArray[angle] = distance;
}
Try this (untested, so maybe minor bugs):
#include <iostream>
#include <sstream>
#include <string>
#include <cstdio>
using namespace std;
int main()
{
string s("3,2,6,4\n2,3,4,5\n");
istringstream iss(s);
int a, b, c, d;
string line;
while (getline(iss,line))
{
// Method 1: Using C
sscanf(line.c_str(),"%d,%d,%d,%d",&a,&b,&c,&d);
// Method 2: Using C++
std::stringstream lineStream(line);
char comma;
lineStream >> a >> comma >> b >> comma >> c >> comma >> d;
// do whatever
}
}
You may parse the string yourself. It's simple.
code:
int ParseResult(const char *in, int *out)
{
int next;
const char *p;
p = in;
next = 0;
while (1)
{
/* seek for next number */
for (; !*p && !isdigit(*p); ++p);
if (!*p)
break; /* we're done */
out[next++] = atoi(p); /* store the number */
/* looking for next non-digit char */
for (; !*p && isdigit(*p); ++p);
}
return next; /* return num numbers we found */
}