Learn C++ STL

Lesson 1 of 9 · From C to Just-Enough C++

Module 1 · From C to Just-Enough C++

Hello, C++: The Same Program in Both Languages

FreeReading

In this lesson

  • Write and run a C++ program that reads two numbers with std::cin and prints their sum with std::cout.
  • Explain what #include <iostream>, std::, std::cout, <<, std::cin and >> each do.
  • Recognise the three places where a C program stops being a C++ program on day one, by GCC 12's message or output.

Bob writes C every day, and he is in a hurry to reach the STL. He copies his sum program into a file called sum.cpp and compiles it as C++. It compiles, and for the input 3 4 it prints 7. "So what changed?" he asks. Nothing yet. That is the first fact of this track: most C is already C++.

Bob's C program is already C++

Here is Bob's program, as he wrote it for the C track.

#include <stdio.h>

int main(void)
{
    int a = 0;
    int b = 0;

    scanf("%d %d", &a, &b);
    printf("%d\n", a + b);
    return 0;
}
7

That output is for the input 3 4. Bob saved the same text as sum.cpp and compiled it with g++, the C++ compiler of the GCC family that also gives you gcc. GCC 12 compiled it with no message, both at the Playground's command line and at -Wall -Wextra. It printed the same 7.

This is no accident. Bjarne Stroustrup started C++ in 1979 at Bell Labs as "C with Classes", and he kept C inside it on purpose. Your loops, arrays, functions, pointers and structs all carry over. So a C program is very nearly a C++ program. Later in this lesson you will see exactly where the "nearly" bites.

The same program in C++ words

Now the same program written the way C++ programmers write it. It reads with std::cin and prints with std::cout.

#include <iostream>

int main()
{
    int a = 0;
    int b = 0;

    std::cin >> a >> b;
    std::cout << a + b << '\n';
    return 0;
}
7

Same input, same output. Put the two programs side by side, line by line, and only four lines differ.

In CIn C++What changed
#include <stdio.h>#include <iostream>the header for C++ input and output streams; C++'s own headers have no .h
int main(void)int main()in C++, empty brackets already mean "no parameters"
scanf("%d %d", &a, &b);std::cin >> a >> b;no format string, and no &
printf("%d\n", a + b);std::cout << a + b << '\n';no %d; the newline is sent like any other value

Reading and printing with streams

std::cin >> variable >> variable ... ;
std::cout << value << value ... ;
  • std::cin is the standard input stream, the C++ partner of scanf.
  • >> reads one value out of the stream into the variable on its right.
  • std::cout is the standard output stream, the C++ partner of printf.
  • << sends the value on its right into the stream. A chain of them runs left to right.

The line ends with '\n', a char that holds the newline. You will also meet std::endl in other people's code. It ends a line too, and does one more thing that costs time; lesson 02 measures it. So the C++ program prints the same 7, and only the words for reading and printing changed.

Streams: << sends, >> reads

A stream is a line of characters that flows one way, like water in a pipe. Your program has one stream coming in, standard input or stdin. It also has one going out, standard output or stdout. Stdin may be your keyboard, a file, or the Playground's input box; stdout may be the screen, a file, or a judge.

The stream picture: std::cin is a tap on stdin, std::cout is a pipe to stdout One stream comes in, one goes out stdin 3 4 \n keyboard, file, input box std::cin the tap: >> reads int a 3 int b 4 a + b 7 std::cout the pipe: << sends stdout 7 \n screen, file, judge Your program sits in the middle: it draws values from the tap and pushes values into the pipe.

std::cin is a tap on stdin. Each >> draws the next value out of it and stores it in a variable. std::cout is a pipe into stdout, and each << pushes one value in. The arrows point the way the data flows: out of std::cin, into std::cout.

Three things that cost Bob time in C are gone. First, there is no format string. The compiler knows a is an int, so >> reads an int; make it a double and the same line reads a double. Bob's old %d against %lf mix-ups cannot happen.

Second, there is no &. std::cin receives the variable itself, not its address. The C++ feature that makes this work is the reference, and lesson 03 is about it. Third, >> skips spaces and newlines before a number, as scanf's %d does, so 3 4 on one line or on two reads the same.

The chain std::cin >> a >> b reads a first, then b. Each >> hands the stream on to the next one. << chains the same way, left to right.

Text needs one more tool. std::string is a text variable that grows by itself, from the header <string>; Module 3 teaches it properly. >> reads one word into it, up to the first space.

#include <iostream>
#include <string>

int main()
{
    std::string name;

    std::cin >> name;
    std::cout << "Hello, " << name << '\n';
    return 0;
}
Hello, Maria

That output is for the input Maria Lopez: the word stopped at the space, and Lopez stayed in the stream. So the variable's type decides what >> reads, and a word ends at a space.

std:: and using namespace std

Every name the C++ standard library gives you lives inside a namespace, a named box of names. The standard library's box is called std. So std::cout means "the cout that lives in std", and :: is the operator that looks inside a box. C has no namespaces: every name in stdio.h is simply global.

Typing std:: again and again is why much contest code starts with one extra line. Here is Bob's program with it.

#include <iostream>

using namespace std;

int main()
{
    int a = 0;
    int b = 0;

    cin >> a >> b;
    cout << a + b << '\n';
    return 0;
}
7

That output is for the input 3 4 again. using namespace std; pours every name in the box into your program. That is hundreds of names you never see, such as count, max, sort and size. Name one of your own variables the same way, and the compiler may not know which one you mean. Lesson 07 shows the message you get.

So this track has one rule. The line is fine in a short, one-file contest program, which is why you see it in so much contest code. It never goes in a header, a .h file that other files include, because then it pours std into every one of them. In this module we write std:: on every standard name, so you always see where a name comes from.

So cout after using namespace std; is the same std::cout. The only difference is how many names you let into your program.

Where C and C++ part ways on day one

Most C compiles as C++, but not all of it. Three differences meet a C programmer in the first week. Each one is shown with GCC 12's real message or output.

1. A void* does not turn into another pointer by itself. In C, malloc returns a void*, and C converts it to int* silently. This C program compiles with no message at either command line.

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int *marks = malloc(3 * sizeof(int));

    marks[0] = 72;
    printf("%d\n", marks[0]);
    free(marks);
    return 0;
}
72

Compile the same line as C++, with <cstdlib> in place of <stdlib.h>, and GCC 12 refuses it at the Playground's flags and at -Wall -Wextra.

int* marks = malloc(3 * sizeof(int));

The message is error: invalid conversion from 'void*' to 'int*' [-fpermissive]. C++ wants you to say the conversion out loud with a cast: (int*)malloc(3 * sizeof(int)). The [-fpermissive] names a flag that would turn the error back into a warning; do not use it. In practice you will rarely call malloc in C++, because Module 2's std::vector manages its own memory.

2. bool is built in. In C17, bool, true and false come from <stdbool.h>. Forget the header, and GCC 12 at -std=c17 stops.

bool passed = true;

The C compiler says error: unknown type name 'bool', then error: 'true' undeclared (first use in this function), each with a note suggesting <stdbool.h>. In C++, bool is a type of the language itself, and no header is needed.

#include <iostream>

int main()
{
    bool passed = true;

    std::cout << passed << '\n';
    return 0;
}
1

std::cout prints a bool as 1 or 0. C23 also made bool a keyword, but GCC 12's C is not C23.

3. A character literal is a char. In C, 'a' has type int. In C++, it has type char. Ask sizeof, and the two languages give different answers. Here is C.

#include <stdio.h>

int main(void)
{
    printf("%zu\n", sizeof('a'));
    return 0;
}
4

And here is C++, with one more line that shows why it matters.

#include <iostream>

int main()
{
    std::cout << sizeof('a') << '\n';
    std::cout << 'a' << ' ' << 'a' + 1 << '\n';
    return 0;
}
1
a 98

std::cout prints by type. 'a' is a char, so it prints the letter. 'a' + 1 is arithmetic, which turns the char into an int first, so it prints 98, the ASCII code of b. So in C++ a character stays a character until you do arithmetic with it.

Compiling with g++ -std=c++17

A C++ file ends in .cpp. On your own machine, compile it with g++ and name the standard: g++ -std=c++17 -Wall -Wextra sum.cpp -o sum. Then run ./sum and type the input. This track teaches C++17, the 2017 edition of the C++ standard.

On the Playground, pick C++ and the version id c++17, which is the default. The other ids are c++14 and c++20. The runner compiles with g++ -O2 -std=c++17 on GCC 12, and with no -Wall. So a warning that needs -Wall never shows up there. That is why this track always says which command line printed a message.

One newer tool is missing from our compiler. C++20's std::format builds text from a format string, like printf, but checks the types; it needs GCC 13, so not on our compiler yet. So the same .cpp file compiles on your machine and on the Playground; only the warnings you see can differ.

Example 1: the smallest C++ program

One include, one main, one line of output.

#include <iostream>

int main()
{
    std::cout << "Hello, C++\n";
    return 0;
}
Hello, C++

A string literal can carry its own \n, exactly as in C. std::cout sends the characters as they are.

Run in Compiler
Example 2: Alice's shop, two types and no format string

Alice sells notebooks. She reads a quantity, an int, and a price, a double, and prints the bill.

#include <iostream>

int main()
{
    int quantity = 0;
    double price = 0.0;

    std::cin >> quantity >> price;
    std::cout << quantity << " x " << price << " = " << quantity * price << '\n';
    return 0;
}
3 x 2.5 = 7.5

That output is for the input 3 2.50. The same >> read an int and then a double. std::cout printed 2.50 as 2.5: by default it shows up to six significant digits and drops trailing zeros.

Run in Compiler
Example 3: Amara's three marks

Amara reads three marks and prints their total and their average. This is the program a C programmer writes on their first C++ day.

#include <iostream>

int main()
{
    int m1 = 0;
    int m2 = 0;
    int m3 = 0;

    std::cin >> m1 >> m2 >> m3;
    int total = m1 + m2 + m3;
    std::cout << "total: " << total << '\n';
    std::cout << "average: " << total / 3.0 << '\n';
    return 0;
}
total: 217
average: 72.3333

That output is for the input 72 65 80. Dividing by 3.0 rather than 3 keeps the fraction, as in C. Zara runs it with an empty input first, as always. It prints total: 0 and average: 0, because the reads found nothing and every variable started at 0.

Run in Compiler

Where this is used

  • LLVM. The LLVM compiler project's coding standards forbid #include <iostream> in its library code, because it adds start-up work to every file. LLVM prints through its own stream, raw_ostream, which keeps the << shape you learned here.
  • Unreal Engine. Its logging macro, UE_LOG, takes a printf-style format string such as "Score: %d". Game code still writes format strings every day.
  • {fmt} and std::format. The open-source {fmt} library joined printf's short format strings with the type checks of streams. It became C++20's std::format, which is why both styles exist.

Common mistakes

1. Forgetting std::.

cout << "hello\n";

An error at both command lines, the Playground included: error: 'cout' was not declared in this scope; did you mean 'std::cout'?. GCC 12 even names the fix. Write std::cout. You will forget it because in C every library name is global.

2. The arrows pointing the wrong way.

int a = 0;

std::cin << a;

An error at both command lines: error: no match for 'operator<<' (operand types are 'std::istream' {aka 'std::basic_istream<char>'} and 'int'). On Compiler Explorer the full message ran to 119 lines, 43 of them notes listing what << can do. Read the first line only: an input stream cannot take <<. Write std::cin >> a;. You will flip them until the picture sticks: data flows out of std::cin and into std::cout.

3. Bob's & from scanf.

int a = 0;

std::cin >> &a;

An error at both command lines: error: no match for 'operator>>' (operand types are 'std::istream' {aka 'std::basic_istream<char>'} and 'int*'). At -Wall -Wextra GCC 12 also warns warning: the address of 'a' will never be NULL [-Waddress]. &a is a pointer, and >> has no way to read into a pointer. Drop the &. Bob will type it for weeks, because scanf trained his fingers.

Brain teaser

Kenji wants to print the sum of 1 and 2, and he likes short code.

#include <iostream>

int main()
{
    std::cout << 1 << 2 << '\n';
    return 0;
}

It compiles with no message at either command line. It does not print 3. What does it print, and why? And what would it print with brackets, std::cout << (1 << 2) << '\n';?

Read every << after std::cout as "send this", left to right. Then remember what << meant between two numbers in C.

Exercise 1Easy

Bob noted three lap times in the order he ran them. He wants them from the last lap back to the first.

Input. One line with three integers.

Output. The three integers in reverse order, on one line, separated by single spaces.

Constraints. Each integer is between -1000000000 and 1000000000.

Sample. Input 4 9 2 gives 2 9 4.

#include <iostream>

int main()
{
    int a = 0;
    int b = 0;
    int c = 0;

    // Read the three integers with std::cin, then print them
    // in reverse order with std::cout, separated by single spaces.

    return 0;
}

Not graded on its own. Exercise 3 grades reading with std::cin.

Run in Compiler
Exercise 2Easy

The school library prints a welcome line on each new card. Read a first name and an age, and print one sentence.

Input. One line with a first name (one word, letters only) and an integer age.

Output. One line: the name, then is, the age and years old., separated by single spaces.

Constraints. The name has 1 to 20 letters. 1 <= age <= 120.

Sample. Input Maria 15 gives Maria is 15 years old.

#include <iostream>
#include <string>

int main()
{
    std::string name;
    int age = 0;

    // Read the name and the age with one std::cin line.
    // Print the sentence with one std::cout line.

    return 0;
}

Not graded on its own. It practises std::string and a mixed chain of <<.

Run in Compiler
Exercise 3Easy

Kenji logs the score of every game he plays in a tournament. He wants the best score and which game it came from. Games are counted from 1, the way people count them.

Input. The first line holds one integer n. The second line holds n integers, the scores in the order the games were played.

Output. One line with two integers separated by one space: the largest score, then its position (the first score is position 1). If the largest score appears more than once, print the first position where it appears.

Constraints. 1 <= n <= 80000. Each score is between -1000000000 and 1000000000. Time limit: 1 second per test.

Sample. Input 5 and 4 9 2 9 1 gives 9 2. The largest score is 9; it appears at positions 2 and 4, and the first of them is 2.

#include <iostream>

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int n = 0;
    std::cin >> n;

    // Read the n integers. Print the largest one and its position
    // (the first integer is position 1), separated by one space.
    // If the largest appears more than once, print its first position.

    return 0;
}

The two lines at the top of main belong to lesson 02; leave them in, they do not change what the program prints. Graded as max-and-position. The hidden tests include n = 1, scores that are all equal, scores that are all negative, and n = 80000.

Run in Compiler

Common doubts

  • Can I keep writing scanf and printf in C++?

    Yes. Include <cstdio> and they work, and they are fast. Bob may keep them. Two limits: they cannot read or print a std::string directly, and lesson 02 shows why one program must not mix them with std::cin and std::cout.

  • Why does <iostream> have no .h?

    The C++ standard's own headers have no .h. Old books wrote <iostream.h>, and GCC 12 refuses it: fatal error: iostream.h: No such file or directory. C's headers come in a C++ form too, such as <cstdio> and <cmath>, with a c in front and no .h.

  • Why did std::cout print 2.50 as 2.5?

    By default it prints up to six significant digits and drops trailing zeros. On Compiler Explorer, 1234567.0 printed as 1.23457e+06 for the same reason. When a problem wants exact decimals, std::fixed and std::setprecision(2) from <iomanip> give them.

  • Are there other C programs that are not C++ programs?

    A few. C++ has more keywords than C, such as new, class and delete. int new = 5; is fine C, but GCC 12 says error: expected unqualified-id before 'new' in C++. Rename the variable and move on.

Key takeaways

  • Most C compiles as C++ unchanged; Bob's sum program did, with the same output.
  • std::cin >> a >> b; reads and std::cout << a + b << '\n'; prints, with no format string and no &.
  • std::cin is a tap on stdin and std::cout a pipe into stdout; the arrows show the flow.
  • std:: names the standard library's namespace; using namespace std; is for short contest programs, never for a header.
  • Day one in C++: a void* needs a cast, bool needs no header, and 'a' is a char.
  • Compile with g++ -std=c++17; the Playground's c++17 runs g++ -O2 -std=c++17 on GCC 12, without -Wall.

Next, Kenji's correct program runs out of time on a million numbers, and lesson 02 measures the two lines that fix it.

End of lesson 1

Mark it done, and your progress moves with you.

Next: Fast Input and Output: Why Contest Code Starts the Same Way