Video Coming Soon...
19: Input From a User
You are now going to create a simple program to ask the user some questions and convert their answers. C++ has multiple ways to get input from a user, and quite frankly, they're all bad. I'll be showing you a way to get input that's very simple and will work only for very simple inputs. In the next exercise you'll learn how to use another older API to read files.
This is Not "Standard" C++
The normal C++ input system looks like this:
int age = 0;
std::cin >> age;
This seems simple on the surface but explaining what is going on is here is impossible given your current point in your journey. To understand these two lines of code you need to know:
- Object Oriented Programming...all of it...and then some.
- Template Meta Programming.
- Operator Overloading.
These are all large topics that you'll have to learn later, so for this exercise I've cooked up a simple little exercise that doesn't use any of the above. My code only uses functions and a little bit of new knowledge.
The Code
I want you to do this one slowly and to think about how you might improve this given what you know. Get it to work first, but we'll soon try to "fix" it.
View Source file ex19.cpp Only
#include <iostream>
#include <fmt/core.h>
#include <limits>
using std::string, std::cin;
using namespace fmt;
int convert_number(const std::string& buffer) {
try {
int num = stoi(buffer);
return num;
} catch(...) {
return -1;
}
}
int main() {
string name;
string buffer;
int age = 0;
int height = 0;
println("What's your name?");
getline(cin, name);
println("Welcome {}. What's your age?", name);
getline(cin, buffer);
age = convert_number(buffer);
println("Nice, glad to hear you've lived {} years.", age);
println("How tall are you in inches?");
getline(cin, buffer);
height = convert_number(buffer);
println("Wow {} is pretty tall.", height);
}
Code Walkthrough
Here's what is going on in this code:
int convert_number(const std::string& buffer) {- This starts a new function that will convert
bufferto an integer. try {- This is new tech. It starts a
try/catchblock which "tries" a block of code, and if that block of code fails for any reason, "catches" the error so you can handle it. int num = stoi(buffer);- The
stoi()function converts a "string to an int." Thesstands for "string" and theistands for "int." return num;- If the conversion from
stoi()works then the result is in number, so just return it. } catch(...) {- If the conversion from
stoi()fails then your code will jump here so you can handle the error. return -1;- For now we'll do a simple error handling method of returning a -1 value. Since we're asking questions about age and height this works, but if you were to ask for arbitrary numbers it wouldn't.
int main() {- The start of your program as usual.
string name;- A place to store the user's name.
string buffer;- A place to store other data before converting it to
ageandheight. int age = 0;- Where we'll store the user's age.
int height = 0;- Where we'll store the user`s height.
println("What's your name?");- Prompt for their name.
getline(cin, name);- This function comes from
#include <string>getline. It waits for the user to type a line. When they hit enter what they type is placed in thenamevariable. Thecinis the input stream to read from. In this case it's standard input, or the "C stdin." println("Welcome {}. What's your age?", name);- This will print another prompt, but notice that it uses the name from the previous
getline()to make it more personal. getline(cin, buffer);- Another
getline()but this time we want the data to go inbufferso we can convert it to an integer. We are doing this because the prompt is asking for their age. age = convert_number(buffer);- This uses our
convert_number()function from the top of the code. If you forgot how that function works go and read it again. println("Nice, glad to hear you've lived {} years.", age);- Print something nice about being alive.
println("How tall are you in inches?");- We then askt he user's height in freedom units.
getline(cin, buffer);- And again, get that input and place it in
buffer. You should notice thatgetline()only read strings. That's why we have to convert them using ourconvert_number()function. height = convert_number(buffer);- Once again, convert that input to a
heightinteger. println("Wow {} is pretty tall.", height);- Tell them their tall. Everyone needs a lift sometimes.
Exceptions and Error Handling
In this example we have this block of code in the convert_number() function:
try {
int num = stoi(buffer);
return num;
} catch(...) {
return -1;
}
This is an Exception which allows your code to attempt something, and if it fails, report the error or attempt to recover.
The exception works like this:
- Your code is run inside the
try { ... }. - If your code has no errors then the
catch(...) { }is skipped over. In our function that means it just exits the function by the firstreturn num. - However, if your code has an error then the
try { }code is halted and your program jumps to thecatch { }block. In this case, it jumps toreturn -1. - Once the catch is done the program exits it and will continue, but in this case we're just returning to avoid it.
In this example I'm avoiding what goes in the catch (...) since that's a complicated topic we'll have to cover later. For now just do your try/catch like this, or just don't use it unless you absolutely have to. There's many C++ programmers who never use them.
Add More Error Handling
It's challenge time. You know how to use while from Exercise 14 and if-else from Exercise 12. Can you use those to make the convert_number() function repeatedly ask the user to enter a number until they get it right?
Break It
Breaking this code involves mostly throwing garbage at it. Some examples are:
- Find a file with unrelated data, like a Word document,
.csvfile, or a.zipfile. - You can "pipe" this file to your program with
cat garbage.zip | ex19and watch it burn...maybe. - Your screen might get wrecked so be ready to close your terminal and open a new one if it's messed up.
- On Unix systems you should have a
/dev/randomor/dev/urandomfile that you can use instead. - ADVANCED Write your own "fuzzer" which is a program that prints smarter garbage that you then feed into this program to break it. You'd run it the same way with
fuzzer | ex19to feed it.
A "fuzzer" is a special testing program that purposefully feeds garbage and unexpected input to a system. It's a useful testing technique for detecting unexpected input situations you need to handle, and there's some advanced fuzzing systems out there that can do very complex fuzzing.
Further Study
- Read through the
stoi()documentation and try some of the other functions. - Read the
getline()documentation and try the 3rd parameterdelim. - Try removing the
try/catchand see what happens. - Try using the
atoi()intead ofstoi(). This function doesn't throw an exception because it's older, and you need to use thebuffer.c_str()function. Read the documentation carefully and try to figure it out.
Register for Learn C++ the Hard Way
Register to gain access to additional videos which demonstrate each exercise. Videos are priced to cover the cost of hosting.