Input and Output in C++
Overview
These notes provide an overview for how to perform input and output in C++,
focused on best practices (as of C++23).
Format
What
- Create strings and output them using a syntax similar to the Python Format Specification.
- The preferred method for string formatting and output as of
C++23. - Handles output but does not handle input.
How
#include<print>(use#include<format>if only formatting strings but not outputting them).- Uses the Formatting Library, available since
C++20 std::format("Var1 = {} and var2 = {}", var1, var2)- Returns a
stringwhere each{}is replaced with a string representation of the corresponding argument - The
{}can have{arg-id (optional) : format-spec}arg-idis an optional index specifying which argument tostd::formatis substituted.std::format("var2 = {1} var1 = {0}", var1, var2)- You must either not use
arg-idfor any{}or use it for all{}.
format-specprovides options for formatting, such as printing inhexformat or how many decimal digits to include.- The Standard Format Specifiation has the details for basic types, but other types can implement custom format options
- Returns a
- In
C++23std::printandstd::printlnallow printing with format strings directly- In
C++20you can format strings withstd::formatand then output those strings - In
C++11the third-partyfmtlibrary (upon whichstd::formatis based) can be used if desired - It is possible to use
std::printandstd::printlnto output to files by
- In
File I/O
std::printandstd::printlncan output to bothC++std::ostreamobjects orCFILE*pointers.- =
#include<ostream>to use thestd::ostreamversion.
- =
- The advantage of using
FILE*is efficiency, however, you need to explicitly close theFILE*when done.- It can be wrapped using a
unique_ptrwith a custom deallocator:std::unique_ptr<std::FILE, int(*)(FILE*)>(fopen("filename", "w"), &std::fclose)
- It can be wrapped using a
- The advantage of using an
ofstreamis that it will close automatically due to it's destructor - Explicitly closing the file is needed if you want to be able respond to errors that may occur when closing the file,
regardless of whether you use a
FILE*, aunique_ptr<FILE, int(*)(FILE*)>orstd::ostream- The behavior of
std::ostreamis to fail silently if the file closure fails in the destructor - Of course there is not much that can be done on a file-close error.
- The behavior of
Why
- Safety: if the format string is specified incorrectly or the type is not
std::formattablethe compiler will catch the error - Extensibility: it is possible to enable custom types to work with
std::formatand provide custom formatting options - Readability: the
std::formatis based on syntax similar to Python f-strings and remains local to each variable you wish to output
Iostreams
What
- The original method for input and output in
C++ - Handles both input and output, so it is what you should use for input
How
Output
#include<iostream>- To output
cout << "Stuff" << myvar << " stuff" << endlendloutputs a newline and flushes the output buffer (ensuring all text is displayed on the screen)- To output a
newlinewithout flushing the buffer use"\n"in the string - Flushing the buffer takes time, so it's best to use
"\n"until you want to ensure that all the output is written to the screen. - Variables and strings can all be output together by separating with
<<
- Formatting is accomplished using
#include<iomanip>- This header contains input/output manipulators that change properties of the stream
- Using these are notoriously tricky because they change the state of the stream
- For example
cout << "Int a in hex: 0x" << std::hex << myint << endl.- After executing this line,
coutwill output integers inhexuntilstd::decis inserted into the stream
- After executing this line,
std::coutis the standard output stream. There is alsostd::cerrfor the standard error stream, and files can be opened as anstd::ofstreamand used the same way.
Input
- The global
istreamstd::cin is automatically connected to the standard input stream, allowing you to read buffered keyboard input std::cin >> varreads data from the standard input into a variable- The type of
vardetermines how the text is parsed - Spaces separate values, and
\n(the user typingEnter) causes the buffer to be read and parsed - Parsing errors set error flags on
std::cinwhich need to be checked manually - It is possible to call
std::cin.exceptions()to make errors throw exceptions, but likely not a good idea because running into an error when parsing user input is not exceptional behavior.
- The type of
- Use
std::string line; std::getline(std::cin, line)to read a whole line of text and parse it yourself.
- File Input
- Create an
std::ifstreamto read from a file - In text mode, can use the same functions as with
cin - Can also open in
binarymode and usereadto read bytes The
eofflag on anifstreamis not set until after a read fails, therefore the following code is incorrectifstream mystream("hello.txt") int x = 0; while(mystream) { mystream >> x; // this read could result in the end of file print("X is {}", x) }
The correct pattern is
ifstream mystream("hello.txt") int x = 0; while(mystream >> x) { print("X is {}", x) }
- The key point here is the read is in the loop condition, so if the read fails (e.g., due to reaching the end-of-file) the loop is not entered.
- Also works with
std::getline
- Create an
Why
- Safety: only types that have
operator>>implemented can be used without creating a compiler error - Extensibility: it is possible to enable custom types to work with
input streamsand create custom stream manipulators for formatting options
C-Style
What
Using the input/output facilities that are available in the C standard library. These are here for completeness but should not be used in this class.
How
#include<cstdio>(C++standard library equivalent of<stdio.h>)- For output:
printfandfprintfprintf("The output is %d\n" 12)printftakes a Format String that tells it how to format it's arguments
- For input
scanfandfgetscan be usedscanfhas many dangerous pitfallsfgets
Why
- Faster
Why Not?
- Dangerous: incorrect format strings can still compile and cause bugs
- Modern compilers allow warning about the format strings and can catch many errors
- Dangerous: it is possible to get buffer overflows with
scanfif proper precautions are not taken- Even most basic usages such as
scanf("%s", mystring)can cause a buffer overflow.
- Even most basic usages such as