I'm struggling with my If-statement using Atoi - c++

I'm trying to make a ticket customer code, and I'm currently working with displaying my "customers". I want it to be like, if i type "blank, like nothing then enter" I want all of my customers in my own DTA file to be on my output. In other words displayed, to see which customers are registered.
void Customer::DisplayCustomer() {
cin.getline(buffer, MAXTEXT)
buffernr = atoi(buffer) //I need to convert text to numbers.
if (buffer[0]=='A' && buffer[1] == '\0')
// (Here I have a function which displays everything) don't focus on this one
}
What I'm asking is, what do i have to type, in order for my code to understand that I want to have a if statement for someone who presses Enter without typing anything my display customer function will run. I've also tried (If buffer[0]=='\n') but that won't work either.

It seems you want to use std::getline() rather than std::istream::getline() for your use case:
void Customer::DisplayCustomer() {
std::string buffer;
std::getline(std:cin,buffer);
std::istringstream iss(buffer);
int buffernr;
if(!(iss >> buffernr)) { // This condition would be false if there's no numeric value
// has been entered from the standard input
// including a simple ENTER (i.e. buffer was empty)
// (Here i have a function which displays everything) don't focus on this
// one
}
else {
// Use buffernr as it was parsed correctly from input
}
}

This code checks if the buffer is empty
#include <iostream>
int MAXTEXT{300};
int main() {
char buffer[MAXTEXT];
std::cin.getline(buffer, MAXTEXT);
if (buffer[0] == '\0') {
std::cout << "Empty" << std::endl;
}
return 0;
}
A better solutions with std::string is
#include <string>
#include <iostream>
int main() {
std::string buffer;
std::getline(std::cin, buffer);
if (buffer.empty()) {
std::cout << "Empty" << std::endl;
}
return 0;
}

Related

How to replace Hi with Bye in a file

I want to replace hi with a bye by reading a file and outputting another file with the replaced letters.
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ifstream myfile;
ofstream output;
output.open("outputfile.txt");
myfile.open("infile.txt");
char letter;
myfile.get(letter);
while (!myfile.eof()) {
if (letter == 'H') {
char z = letter++;
if (z == 'i')
output << "BYE";
}
else output << letter;
}
output.close();
myfile.close();
return 0;
}
My outputs are repeated capital I's that is repeated infinity times.
Here is my input file
Hi
a Hi Hi a
Hi a a Hi
Don't check eof
The eof method is returning the location of the input stream read pointer, and not the status of the get. It is more like telling you whether or not get will succeed, so you could write something like:
while (!myfile.eof()) {
char letter;
myfile.get(letter);
//...
}
In this way, you would at least be getting a new letter at each iteration, and the loop ends when the read pointer reaches the end of the input.
But, there are other cases that might cause the get to not succeed. Fortunately, these are captured by the stream itself, which is returned by get. Testing the status of the stream is as easy as treating the stream as a boolean. So, a more idiomatic way to write the loop is:
char letter;
while (myfile.get(letter)) {
//...
}
Peek at the next letter
When you want to look at the next letter in the input following the detected 'H', you perform an increment.
char z = letter++;
But, this does not achieve the desired result. Instead, it just sets both letter and z variables to the numerical successor of 'H' ('H' + 1), and does not observe the next letter in the input stream.
There is another method you can use that is like get, but leaves the input in the input stream. It is called peek.
char z;
auto peek = [&]() -> decltype(myfile) {
if (myfile) z = myfile.peek();
return myfile;
};
if (peek()) {
//...
}
And now, you can check the value of z, but it is still considered input for the next get on letter.
Close to what you implemented
So, the complete loop could look like:
char letter;
while (myfile.get(letter)) {
if (letter == 'H') {
char z;
auto peek = [&]() -> decltype(myfile) {
if (myfile) z = myfile.peek();
return myfile;
};
if (peek() && z == 'i') {
myfile.get(z);
output << "BYE";
continue;
}
}
output << letter;
}
With this approach, you will be able to correctly handle troublesome cases like HHi as input, or the last letter in the input being an H.
Your two lines:
myfile.get(letter);
while (!myfile.eof()) {
are wrong.
First off you only read letter once, hence your infinite loop.
Secondly you don't use eof in a while loop.
You want something more like:
while (myfile.get(letter)) {
Also:
char z = letter++;
is wrong, you want to read another letter:
myfile.get(z);
but you have to be careful that you get something, so
if(!myfile.get(z)) {
output << letter;
break;
}
So finally:
char letter;
while (myfile.get(letter)) {
if (letter == 'H') {
char z;
if(!myfile.get(z)) {
output << letter;
break;
}
if (z == 'i') {
output << "BYE";
}
else output << letter << z;
}
else output << letter;
}
But now we are consuming the character after any H which may not be desirable.
See #jxh's answer for a way to do this with look ahead.
There is a dedicated function to replace patterns in strings. For example, you could use std::regex_replace. That is very simple. We define, what should be searched for and with what that would be replaced.
Some comments. On StackOverflow, I cannot use files. So in my example program, I use a std::istringstream instead. But this is also an std::istream. You can use any other std::istream as well. So if you define an std::ifstream to read from a file, then it will work in the same way as the std::istringstream. You can simply replace it. For the output I use the same mechanism to show the result on the console.
Please see the simple solution:
#include <iostream>
#include <sstream>
#include <regex>
// The source file
std::istringstream myfile{ R"(Hi
a Hi Hi a
Hi a a Hi)" };
// The destination file
std::ostream& output{ std::cout };
int main() {
// Temporary string, to hold one line that was read from a file
std::string line{};
// Read all lines from the file
while (std::getline(myfile, line)) {
// Replace the sub-string and write to output file
output << std::regex_replace(line, std::regex("Hi"), "Bye") << "\n";
}
return 0;
}

Incorrect addition from a file

if (infile.is_open())
{
int count = 0;
while (infile)
{
string author, ratings;
getline(infile, author);
if (author != "")
{
getline(infile, ratings);
// TODO: Create new User object
User newuser(author, ratings);
// TODO: Add new User object to vector
userList.push_back(newuser);
count++;
}
}
cout << count << " users read in. Closing user file." << endl;
The output for this that I am getting is that 86 users were read in from the text file. the correct output is supposed to be 32. I think that it is because I am using a while loop but I am not fully sure.
Your condition should be something like
while (getline(author, infile) && getline(ratings, infile)) {
// validate input, then process it
}
Then the if (infile.open()) becomes trivial. There is a '}' missing in the code you posted, which makes it hard to really tell where your counting error is coming from, or maybe that's just the reason, incrementing your count in the wrong place. Please make sure your examples are complete and possibly even compile.
A little tip, you can just write
userList.push_back(User(author, ratings));
EDIT:
I created this minimal test code (for you) and tested it on the following file, resulting in the following output. Can you confirm? Please note: The current program doesn't accept newlines in your file, e.g. for grouping various users, however, this is a feature easily added, once the basic program works.
Code:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
struct User {
string author, ratings;
User(string auth, string rat)
: author(auth), ratings(rat) {}
};
int main()
{
ifstream ist("test.txt");
if (!ist) {
cout << "Could not open file test.txt\n";
return 1;
}
vector<User> userList;
string author, ratings;
size_t count = 0;
while (getline(ist, author) && getline(ist, ratings)) {
if (author != "" && ratings != "") {
userList.push_back(User(author, ratings));
++count; // in this case, count++ is equivalent
}
}
cout << count << " users read in. Closing user file.\n";
}
The file test.txt
foo
bar
foobar
lalilu
myTotalUsersAre
3
Output:
3 users read in. Closing user file.

How to stop recursion if nothing is inputed in cin?

I am writing a program that must print numbers at first which was entered at last.
So here is my code:
#include <iostream>
using namespace std;
void recursive()
{
long long n;
if((cin>>n)&&(!cin.eof())) // Dont work because enter is ignored in cmd window os
recursive();
cout<<n<<endl;
return;
}
int main()
{
recursive();
return 0;
}
Any idea how to stop function when nothing is input? Or how to solve problem in another way?
Thanks
As your program is right now it will read the long long's until cin's operator void* indicates that the value read was not compatible (but still prints the n , filled with garbage,that it failed to read), as you notice it ignores the blank lines.
If I understand correctly, what you want is that when the user inputs a blank line the program should output the numbers read, a simple way to do this would be to read the input as a string, then check the string's length, and use a stringstream to convert it to the appropriate type.
#include <iostream>
#include <sstream>
#include <string>
void recursive()
{
std::string input;
long long n;
if ( std::getline(std::cin,input) && input.length() > 0 )
{
std::istringstream ss(input);
if (ss >> n)
{
recursive();
std::cout << n << std::endl;
}
}
}
int main ()
{
recursive();
return 0;
}
edit
Here's another way, if your input comes in the form 46 798 4163 4654 32132, it uses std::cin.peek() that returns the next character in the input without extracting it, the result of peek() is compared to '\n' to test if the user pressed enter, and if that's the case it prints the number it just read without waiting for the next number
#include <iostream>
#include <sstream>
#include <string>
void recursive_in_a_line ()
{
long long n;
if (std::cin >> n)
{
if (std::cin.peek() != '\n')
{
recursive();
}
std::cout<< n << std::endl;
}
}
int main ()
{
recursive_in_a_line();
return 0;
}
Do you have to implement the program in a recursive way?
An alternative solution that does not use recursion would be to read the numbers in a while loop and add them to a container (a list or a vector), then display the content of the container.

checking input using a do-while loop with c, c++

Hello i'm trying to use a do-while loop to check the input and repeat the prompt until the user types in a correct integer. So that's my code:
#include <iostream>
#include <stdio.h>
#include <ctype.h>
int main ()
{
int a;
do
{
printf("Please type in your number: ");
}while(scanf_s("%d", &a) == 0);
std::cin.get();
std::cin.get();
return 0;
}
Well it seems to work. When I type in a number the program runs correctly. But when I type in a letter an infinite loop starts. Sincerly I don't know where the problem is.
Again, I suggest reading a line into a string and then trying to parse that string according to your needs. If the parse fails, simply prompt the user again. You can bury the messy details in a function template:
#include <iostream>
#include <sstream>
#include <string>
template <typename T>
T read(std::string prompt)
{
for (; ;)
{
std::cout << prompt;
std::string line;
getline(std::cin, line);
std::istringstream ss(line);
T x;
if ((ss >> x) && (ss >> std::ws).eof()) return x;
}
}
int main ()
{
int a = read<int>("Please type in your number: ");
std::cout << "You entered " << a << '\n';
}
Here's what's going on -- I'll go through step by step. Starting from the do:
output: Please type in your number:
call to scanf Scanf finds that stdin is empty, and therefore waits for a line to be typed in.
input : letter (note that the input buffer now contains "letter")
scanf attempts to parse the string as an integer. Parsing fails before it consumes any characters. Therefore the buffer still contains "letter"
scanf returns EOF (error)
output: Please type in your number:
call to scanf -- scanf sees that there's already waiting input in stdin
scanf attempts to parse the buffer as an integer.....
This will go on forever because scanf will never consume the characters from the buffer. You can solve the problem by correctly checking for an error return code from scanf.
First of all never ever use scanf as its one hell of a dangerous function.
If you want to stick with C you should use fgets to read the input from the user to a buffer and then atoi to convert the input from the user to an integer.
Note: fgets always adds the 'enter' in to the buffer so you want to strip it off before converting the content of the buffer.
this could be easily done as follow:
_buffer[strlen(_buffer)-1] = '\0';
I have modified my code so that it works now. But sincerly it just works for numbers and letters. I want it to work with every char. For example "!?%". I have already tried to change the "isalnum" by "isascii" but that does not work.
#include <stdio.h>
#include <ctype.h>
int main ()
{
int a;
int b = 1;
char c ;
do
{
printf("Please type in a number: ");
if (scanf("%d", &a) == 0)
{
printf("Your input is not correct\n");
do
{
c = getchar();
}
while (isalnum(c));
ungetc(c, stdin);
}
else
{
printf("Thank you! ");
b--;
}
}
while(b != 0);
getchar();
getchar();
return 0;
}
# ordo
Blockquote
I have modified my code so that it works now. But sincerly it just works for numbers and letters. I want it to work with every char. For example "!?%". I have already tried to change the "isalnum" by "isascii" but that does not work.
Blockquote
You can use
if(userInput>='!'&& userInput<= '~') // refer ASCII chart between !and ~.
{ exit=0; }
http://www.cdrummond.qc.ca/cegep/informat/professeurs/alain/images/ASCII1.GIF
int main ()
{
int a;
char userInput,exit=1;
do
{
printf("Please type in your number: ");
userInput=getch();
if(userInput=='1') // suppose the correct input is 1.
{ exit=0; }
}while(exit);
std::cin.get();
std::cin.get();
return 0;
}
If the input is between 0 and 9...
if(userInput>='0'&& userInput<= '9') // suppose the correct input is 1.
{ exit=0; }
Note that we have to use ' ' signs
You can use getchar() function
do
{
printf("Please type in your number: ");
}while((getchar() - '0') == 0);

How to validate numeric input in C++

I'd like to know how to limit an input value to signed decimals using std::cin.
double i;
//Reading the value
cin >> i;
//Numeric input validation
if(!cin.eof())
{
peeked = cin.peek();
if(peeked == 10 && cin.good())
{
//Good!
count << "i is a decimal";
}
else
{
count << "i is not a decimal";
cin.clear();
cin >> discard;
}
}
This also gives an error message with the input -1a2.0 avoiding the assignation of just -1 to i.
If the backing variable of the cin is a number, and the string provided is not a number, the return value is false, so you need a loop:
int someVal;
while(!(cin >> someVal)) {
cin.reset();
cout << "Invalid value, try again.";
}
Combining the techniques from the top answer here and this website, I get
input.h
#include <ios> // Provides ios_base::failure
#include <iostream> // Provides cin
template <typename T>
T getValidatedInput()
{
// Get input of type T
T result;
cin >> result;
// Check if the failbit has been set, meaning the beginning of the input
// was not type T. Also make sure the result is the only thing in the input
// stream, otherwise things like 2b would be a valid int.
if (cin.fail() || cin.get() != '\n')
{
// Set the error state flag back to goodbit. If you need to get the input
// again (e.g. this is in a while loop), this is essential. Otherwise, the
// failbit will stay set.
cin.clear();
// Clear the input stream using and empty while loop.
while (cin.get() != '\n')
;
// Throw an exception. Allows the caller to handle it any way you see fit
// (exit, ask for input again, etc.)
throw ios_base::failure("Invalid input.");
}
return result;
}
Usage
inputtest.cpp
#include <cstdlib> // Provides EXIT_SUCCESS
#include <iostream> // Provides cout, cerr, endl
#include "input.h" // Provides getValidatedInput<T>()
int main()
{
using namespace std;
int input;
while (true)
{
cout << "Enter an integer: ";
try
{
input = getValidatedInput<int>();
}
catch (exception e)
{
cerr << e.what() << endl;
continue;
}
break;
}
cout << "You entered: " << input << endl;
return EXIT_SUCCESS;
}
Sample run
Enter an integer: a
Invalid input.
Enter an integer: 2b
Invalid input.
Enter an integer: 3
You entered: 3.
cin's >> operator works by reading one character at a time until it hits whitespace. That will slurp the whole string -1a2.0, which is obviously not a number so the operation fails. It looks like you actually have three fields there, -1, a, and 2.0. If you separate the data by whitespace, cin will be able to read each one without problem. Just remember to read a char for the second field.
I tried many techniques for reading integer input from the user using the >> operator, but in a way or another all my experiments have failed.
Now I think that getline() function (not the method with the same name on std::istream) and the strtol() function from the include cstdlib is the only predictable consistent solution for this problem. I would appreciate if someone proved me wrong. Here is something like the one I use:
#include <iostream>
#include <cstdlib>
// #arg prompt The question to ask. Will be used again on failure.
int GetInt(const char* prompt = "? ")
{
using namespace std; // *1
while(true)
{
cout << prompt;
string s;
getline(cin,s);
char *endp = 0;
int ret = strtol(s.c_str(),&endp,10);
if(endp!=s.c_str() && !*endp)
return ret;
}
}
*1: Placing using namespace whatever; to the global scope may lead to broken "unity builds" (google!) on larger projects, so should be avoided. Practice to not use that way, even on smaller projects!
Reading integers from files is a very different matter. Raúl Roa's approach can be good for that if properly worked out. I also suggest that wrong input files should not be tolerated, but it really depends on the application.
Be warned that using >> and getline() in the same program on cin will lead to some problems. Use one of them only, or google to know how to handle the issue (not too hard).
Something like:
double a;
cin >> a;
Should read your signed "decimal" fine.
You'll need a loop and some code to make sure it handles invalid input in a sensible way.
Good luck!