Commit 7ea3c1a8 authored by GILLES Sebastien's avatar GILLES Sebastien
Browse files

Updating and cleaning-up introduction and procedural programming part. The...

Updating and cleaning-up introduction and procedural programming part. The section introducing pointers and references has been refactored a bit.
parent 833647bd
%% Cell type:markdown id: tags:
# [Getting started in C++](/) - [Getting started with the tutorial](/notebooks/getting_started_with_tutorial.ipynb)
# [Getting started in C++](/) - [Getting started with the tutorial](./getting_started_with_tutorial.ipynb)
%% Cell type:markdown id: tags:
<h1>Table of contents<span class="tocSkip"></span></h1>
<div class="toc"><ul class="toc-item"><li><span><a href="#About-the-choice-of-a-Jupyter-notebook" data-toc-modified-id="About-the-choice-of-a-Jupyter-notebook-1">About the choice of a Jupyter notebook</a></span></li><li><span><a href="#When-the-notebook-is-not-enough..." data-toc-modified-id="When-the-notebook-is-not-enough...-2">When the notebook is not enough...</a></span></li><li><span><a href="#Few-guidelines-about-Jupyter" data-toc-modified-id="Few-guidelines-about-Jupyter-3">Few guidelines about Jupyter</a></span><ul class="toc-item"><li><span><a href="#Restarting-the-kernel" data-toc-modified-id="Restarting-the-kernel-3.1">Restarting the kernel</a></span></li></ul></li><li><span><a href="#Very-basic-C++-syntax-(in-notebook-and-in-general)" data-toc-modified-id="Very-basic-C++-syntax-(in-notebook-and-in-general)-4">Very basic C++ syntax (in notebook and in general)</a></span><ul class="toc-item"><li><span><a href="#Semicolons" data-toc-modified-id="Semicolons-4.1">Semicolons</a></span></li><li><span><a href="#Blocks" data-toc-modified-id="Blocks-4.2">Blocks</a></span></li><li><span><a href="#Input-/-output" data-toc-modified-id="Input-/-output-4.3">Input / output</a></span></li><li><span><a href="#Comments" data-toc-modified-id="Comments-4.4">Comments</a></span></li></ul></li></ul></div>
%% Cell type:markdown id: tags:
## About the choice of a Jupyter notebook
This notebook uses up [xeus-cling](https://xeus-cling.readthedocs.io/en/latest/), a special instance of Jupyter able to run C++ code based upon xeus (tool to build Jupyter kernels for any language) and cling (a creation from CERN to be able to run C++ as an interpreted language).
The reasons for these choices is to really access directly to handle C++ code without the hassle of explaining how to compile and run stuff, which is an especially cumbersome way to start with this (or any really...) language.
This is not to say this tutorial will ignore entirely these topics (see the dedicated [chapter](/notebooks/6-InRealEnvironment/0-main.ipynb), just that we will first focus on C++ code. However keep in mind that this notebook's fancy interpreter is not a typical C++ environment.
This is not to say this tutorial will ignore entirely these topics (see the dedicated [chapter](./6-InRealEnvironment/0-main.ipynb)), just that we will first focus on C++ code. However keep in mind that this notebook's fancy interpreter is not a typical C++ environment.
Jupyter Xeus-Cling is still under active development: you should really get a recent version and keep it up-to-date. Some examples in this lecture didn't work at first and were properly dealt with with a version one month later!
## When the notebook is not enough...
As we shall see repeatedly, Xeus-cling notebooks are far from being full-proof: some stuff that are perfectly acceptable C++ aren't accepted in them, and some others required work-arounds. When such an issue appears:
* It will be indicated explicitly in the notebook if a specific work around is used. We do not want you to take Jupyter work-arounds as a legit advice on how to write proper C++.
* If Jupyter can't deal with the code, we will use [Coliru](https://coliru.stacked-crooked.com/). Coliru is a C++ online compiler; others are listed [here](https://arne-mertz.de/2017/05/online-compilers/) ([Wandbox](https://wandbox.org/) deserves a shout out as it enables testing the same code with a great variety of compiler versions).
%% Cell type:markdown id: tags:
## Few guidelines about Jupyter
You might not be familiar with Jupyter notebooks, so here are few tips to run it smoothly (the _Help_ menu will help you find more if you need it).
In a Jupyter notebook the content is divided into _cells_, in our case we are using two kind of cells:
* Markdown cells, such as the ones into these very words are written.
* Code cells, which are running code. In these notebooks the chosen kernel is C++17, so the code is C++17 which is interpreted by cling.
There are two modes:
* Edit mode, in which you might change the content of a cell. In this mode the left part of the cell is in green.
* Command mode, in which you might take actions such as changing the type of a cell, create or delete a new one, etc...
To enter in edit mode, simply type on 'Enter'.
To enter in command mode, type 'Esc'.
To execute a cell, type 'Shift + Enter'. For a markdown cell it will edit nicely the content by interpreting the markdown, and for a code cell it will run the code.
In command mode, several handy shortcuts are there; I would recommend especially:
* `a` (add a cell above)
* `b` (add a cell below)
* `x` (cut a cell)
* `M` (change cell mode to Markdown)
The complete list is available in _Help_ > _Keyboard_ shortcut.
If for some reason the code in the notebook seems stuck, you might try to restart the kernel with one of the restart option in the _Kernel_ menu.
### Restarting the kernel
Sometimes something that should work doesn't... In this case try restarting the kernel: it might fix your issue!
%% Cell type:markdown id: tags:
## Very basic C++ syntax (in notebook and in general)
### Semicolons
In C++ most instructions end by a semicolon `;`. If you forget it, the underlying compiler doesn't understand the syntax.
%% Cell type:code id: tags:
``` C++17
{
int foo = 5 // COMPILATION ERROR!
}
```
%% Cell type:code id: tags:
``` C++17
{
int foo = 5; // OK
}
```
%% Cell type:markdown id: tags:
Spaces, end lines and tabulations act as word separators; utterly unreadable code as the one below is perfectly fine from the compiler standpoint:
%% Cell type:code id: tags:
``` C++17
# include <string>
{
int nombre ; nombre = 1
; std::string nom;
nom=
int number ; number = 1
; std::string name;
name=
"truc" ;
nombre = 2
number = 2
;
}
```
%% Cell type:markdown id: tags:
### Blocks
You may have notices the braces `{` and `}` in the examples above. They are here a technicality to make cling interpreter work better in a Jupyter environment, but that is also useful in a real C++ code.
What is between both braces constitute a **block**; variables that are initialized inside are destroyed once the closing brace is past (don't worry - we will come back to that [later](/notebooks/1-ProceduralProgramming/5-DynamicAllocation.ipynb#Stack)).
What is between both braces constitute a **block**; variables that are initialized inside are destroyed once the closing brace is past (don't worry - we will come back to that [later](./1-ProceduralProgramming/5-DynamicAllocation.ipynb#Stack)).
This is an incredibly useful feature: you may ensure this way that a variable is not kept any longer than necessary. We will come back to this feature (called the **locality of reference** later); let's see why they are useful in a notebook environment.
In C++, at a given scope a same variable can't be defined twice. So for instance if I defined twice a same variable, the compiler will yell about redefinition of a variable:
%% Cell type:code id: tags:
``` C++17
int i = 2; // Should be fine on the first call.
// But if you have executed it already, a new attempt will make the compiler yell.
```
%% Cell type:code id: tags:
``` C++17
int i = 1; // If the cell above was run, compilation error as `i` is already defined.
```
%% Cell type:markdown id: tags:
The only way to circumvent this is to restart the kernel... and you may then run only one of this cell, and only once.
So you might now see the usefulness of the braces: by putting them I define the variables in a cell in a block, and it is only defined inside this block. Same variable may this way be defined in different cells:
%% Cell type:code id: tags:
``` C++17
{
int i = 2; // Fine
}
```
%% Cell type:code id: tags:
``` C++17
{
int i = 1; // Also fine
}
```
%% Cell type:markdown id: tags:
### Input / output
Inputs and outputs aren't directly a part of the language itself, but are in the standard library (often abbreviated as STL for Standard Template Library even if some purist may yell and explain it's not 100 % the same thing...). You therefore need to __include__ a file named `iostream`; doing so will enable the use of the input / output facilities.
%% Cell type:code id: tags:
``` C++17
{
std::cout << "Hello world!" << std::endl; // Should fail (unless you run a cell that includes iostream before)
}
```
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
std::cout << "Hello world!" << std::endl; // Should work: std::cout and std::endl are now known.
}
```
%% Cell type:markdown id: tags:
- `std::cout` is the symbol to designate the standard output (i.e. your screen...)
- `std::endl` is the symbol to clean-up the stream and go to next line.
The operator `<<` is used to indicate what you direct toward the stream; here std::cout << "Hello world!" tells to redirect the string toward the standard output.
We will see that a bit more in detail in [a later chapter](/notebooks/1-ProceduralProgramming/6-Streams.ipynb), but printing something is really helpful early on hence this brief introduction here.
We will see that a bit more in detail in [a later chapter](./1-ProceduralProgramming/6-Streams.ipynb), but printing something is really helpful early on hence this brief introduction here.
%% Cell type:markdown id: tags:
### Comments
There are two ways to comment code in C++:
- `//` which comments all that is after this symbol on the same line
- `//` which comments all that is after this symbol on the same line.
- `/*` ... `*/` which comments everything in the between the symbols.
%% Cell type:code id: tags:
``` C++17
{
int i = 0; // Everything after // is commented until the end of the line
/*
commented...
also commented...
*/
int j = 5; // no longer commented
/*
// This type of comment might be in the other style
// This type of comment might be used inside the other style
*/
}
```
%% Cell type:markdown id: tags:
© _CNRS 2016_ - _Inria 2018-2019_
© _CNRS 2016_ - _Inria 2018-2020_
_This notebook is an adaptation of a lecture prepared by David Chamont (CNRS) under the terms of the licence [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](http://creativecommons.org/licenses/by-nc-sa/4.0/)_
_The present version has been written by Sébastien Gilles and Vincent Rouvreau (Inria)_
......
%% Cell type:markdown id: tags:
# [Getting started in C++](/) - [Procedural programming](/notebooks/1-ProceduralProgramming/0-main.ipynb)
# [Getting started in C++](/) - [Procedural programming](./0-main.ipynb)
%% Cell type:markdown id: tags:
* [Variables, initialisation, affectation](/notebooks/1-ProceduralProgramming/1-Variables.ipynb)
* [Condition and loops](/notebooks/1-ProceduralProgramming/2-Conditions-and-loops.ipynb)
* [TP 1](/notebooks/1-ProceduralProgramming/2b-TP.ipynb)
* [Predefined types](/notebooks/1-ProceduralProgramming/3-Types.ipynb)
* [Functions](/notebooks/1-ProceduralProgramming/4-Functions.ipynb)
* [TP 2](/notebooks/1-ProceduralProgramming/4b-TP.ipynb)
* [Dynamic allocation](/notebooks/1-ProceduralProgramming/5-DynamicAllocation.ipynb)
* [Input/output](/notebooks/1-ProceduralProgramming/6-Streams.ipynb)
* [TP 3](/notebooks/1-ProceduralProgramming/6b-TP.ipynb)
* [Variables, initialisation, affectation](./1-Variables.ipynb)
* [Condition and loops](./2-Conditions-and-loops.ipynb)
* [TP 1](./2b-TP.ipynb)
* [Predefined types](./3-Types.ipynb)
* [Functions](./4-Functions.ipynb)
* [TP 2](./4b-TP.ipynb)
* [Dynamic allocation](./5-DynamicAllocation.ipynb)
* [Input/output](./6-Streams.ipynb)
* [TP 3](./6b-TP.ipynb)
%% Cell type:markdown id: tags:
© _CNRS 2016_ - _Inria 2018-2019_
© _CNRS 2016_ - _Inria 2018-2020_
_This notebook is an adaptation of a lecture prepared by David Chamont (CNRS) under the terms of the licence [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](http://creativecommons.org/licenses/by-nc-sa/4.0/)_
_The present version has been written by Sébastien Gilles and Vincent Rouvreau (Inria)_
......
This diff is collapsed.
%% Cell type:markdown id: tags:
# [Getting started in C++](/) - [Procedural programming](/notebooks/1-ProceduralProgramming/0-main.ipynb) - [Conditions and loops](/notebooks/1-ProceduralProgramming/2-Conditions-and-loops.ipynb)
# [Getting started in C++](/) - [Procedural programming](./0-main.ipynb) - [Conditions and loops](./2-Conditions-and-loops.ipynb)
%% Cell type:markdown id: tags:
<h1>Table of contents<span class="tocSkip"></span></h1>
<div class="toc"><ul class="toc-item"><li><span><a href="#Conditions" data-toc-modified-id="Conditions-1">Conditions</a></span><ul class="toc-item"><li><span><a href="#if-condition-followed-by-a-single-statement" data-toc-modified-id="if-condition-followed-by-a-single-statement-1.1"><code>if</code> condition followed by a single statement</a></span></li><li><span><a href="#if-condition-followed-by-a-block" data-toc-modified-id="if-condition-followed-by-a-block-1.2"><code>if</code> condition followed by a block</a></span></li><li><span><a href="#No-semicolon-at-the-end-of-the-if-condition" data-toc-modified-id="No-semicolon-at-the-end-of-the-if-condition-1.3">No semicolon at the end of the <code>if</code> condition</a></span></li><li><span><a href="#if-...-else-if-...-else" data-toc-modified-id="if-...-else-if-...-else-1.4">if ... else if ... else</a></span></li><li><span><a href="#The-ternary-operator" data-toc-modified-id="The-ternary-operator-1.5">The ternary operator</a></span></li><li><span><a href="#switch-statement" data-toc-modified-id="switch-statement-1.6"><code>switch</code> statement</a></span></li></ul></li><li><span><a href="#Logical-operators" data-toc-modified-id="Logical-operators-2">Logical operators</a></span></li><li><span><a href="#Loops" data-toc-modified-id="Loops-3">Loops</a></span><ul class="toc-item"><li><span><a href="#while-loop" data-toc-modified-id="while-loop-3.1"><code>while</code> loop</a></span></li><li><span><a href="#do...while-loop" data-toc-modified-id="do...while-loop-3.2"><code>do</code>...<code>while</code> loop</a></span></li><li><span><a href="#for-loop" data-toc-modified-id="for-loop-3.3"><code>for</code> loop</a></span><ul class="toc-item"><li><span><a href="#Historical-for-loop" data-toc-modified-id="Historical-for-loop-3.3.1">Historical <code>for</code> loop</a></span></li><li><span><a href="#New-for-loop" data-toc-modified-id="New-for-loop-3.3.2">New <code>for</code> loop</a></span></li></ul></li><li><span><a href="#continue,-break-and-infinite-loop" data-toc-modified-id="continue,-break-and-infinite-loop-3.4">continue, break and infinite loop</a></span></li><li><span><a href="#So-which-loop-should-I-use?" data-toc-modified-id="So-which-loop-should-I-use?-3.5">So which loop should I use?</a></span></li></ul></li></ul></div>
%% Cell type:markdown id: tags:
## Conditions
%% Cell type:markdown id: tags:
### `if` condition followed by a single statement
%% Cell type:markdown id: tags:
In C++, a condition is the `if` command followed by a condition in parenthesis `()`. The single instruction (that ends at the next `;`) _or_ the block (in braces `{}`that follows is then executed only if the condition is true.
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
int a = 2;
if (a > 0)
std::cout << a << " is greater than 0" << std::endl;
if (a < 0)
std::cout << "This line won't be executed so nothing will be printed." << std::endl;
std::cout << "But this line will be printed: without braces `{}` only the first instruction depends "
"on the condition!" << std::endl;
}
```
%% Cell type:markdown id: tags:
Of course, the precedent code is embarrassing but is due to the poor indenting used: you have to remember that in C++ indenting is just for the programmer: it is much easier to read if a program is properly indented, but it doesn't matter from the compiler standpoint!
Our case above would be much clearer however with a more logical indenting and spacing:
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
int a = 2;
if (a < 0)
std::cout << "This line won't be executed so nothing will be printed." << std::endl;
std::cout << "It's much clearer now that this line is not encompassed by the condition!" << std::endl;
}
```
%% Cell type:markdown id: tags:
### `if` condition followed by a block
And if you need several lines to be encompassed by the condition, just use braces!
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
int a = 2;
if (a < 0)
{
std::cout << "Should not be printed: the condition is false!" << std::endl;
++a; // won't be executed: the condition is false
}
std::cout << "a was not modified and is still 2" << std::endl;
}
```
%% Cell type:markdown id: tags:
### No semicolon at the end of the `if` condition
__BEWARE__: do not put a `;` at the end of an `if` statement! If you do so, the statement executed if the condition is true is the empty statement `;` which does nothing... The risk is rather mitigated: any compiler worth its salt will warn you if you do this mistake.
%% Cell type:code id: tags:
``` C++17
{
int a = 2;
if (a == 0);
std::cout << "Will be printed: the statement after the condition is ';', which does nothing..." << std::endl;
}
```
%% Cell type:code id: tags:
``` C++17
{
int a = 2;
if (a == 2)
; // putting the semicolon in a different line silences the warning; there are legitimate cases in
// which it's useful to do so and the risk is
// slim that this was written by mistake.
}
```
%% Cell type:markdown id: tags:
### if ... else if ... else
It is rather usual to foreseen two (or more...) courses of action depending on the results of one or several conditions. The syntax in this case is the following:
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
int a = 2;
if (a < 0)
std::cout << a << " is negative." << std::endl;
else if (a == 0)
{
std::cout << a << " is zero." << std::endl;
}
else if (a < 10)
std::cout << a << " is positive but lower than 10." << std::endl;
else if (a < 100)
std::cout << a << " is in the interval [10, 20[." << std::endl;
else
{
std::cout << a << "is greater than 20." << std::endl;
}
}
```
%% Cell type:markdown id: tags:
Please notice that:
* `else if` and `else` syntax is the same as the one for `if` and you may choose a single statement or a block in each branch of the condition.
* As soon as one condition is fulfilled, the execution of the condition blocks ends. I therefore didn't have to spell out in the (`a < 100`) case that `a` had to be greater than 10.
%% Cell type:markdown id: tags:
### The ternary operator
%% Cell type:markdown id: tags:
C++ has inherited from C the so-called ternary operator, which is basically an if/else case packed in one line:
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
int i = 5;
std::cout << "Is " << i << " even? -> " << (i % 2 == 0 ? "true" : "false") << std::endl;
}
```
%% Cell type:markdown id: tags:
It is really the same as:
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
int i = 5;
std::cout << "Is " << i << " even? -> ";
if (i % 2 == 0)
std::cout << "true" << std::endl;
else
std::cout << "false" << std::endl;
}
```
%% Cell type:markdown id: tags:
There are nonetheless some cases in which a ternary operator performs a task that is not otherwise reachable by an if/else statement; please consider for instance the initialisation of a `const` variable:
%% Cell type:code id: tags:
``` C++17
{
int i = 5;
const int is_strictly_positive = (i > 0 ? 1 : 0);
std::cout << is_strictly_positive << std::endl;
}
```
%% Cell type:markdown id: tags:
With if/else it doesn't work: both ways to do so that might step in mind are flawed:
With if/else this doesn't work: both ways to do so that might step in mind are flawed:
%% Cell type:code id: tags:
``` C++17
{
int i = 5;
const int is_strictly_positive;
if (i > 0)
is_strictly_positive = 1; // COMPILATION ERROR: can't assign to const value!
// ...
}
```
%% Cell type:code id: tags:
``` C++17
{
int i = 5;
if (i > 0)
{
const int is_strictly_positive = 1;
}
else
const int is_strictly_positive = 0;
std::cout << is_strictly_positive << std::endl; // COMPILATION ERROR: is_strictly_positive not
// in the current scope.
}
```
%% Cell type:markdown id: tags:
### `switch` statement
Very briefly: there is also a `switch` statement that can be used when:
* The variable is an integer, an enum (see [next notebook](/notebooks/1-ProceduralProgramming/3-Types.ipynb#Enumerations)) or might be convertible into one of those.
* The variable is an integer, an enum (see [next notebook](./3-Types.ipynb#Enumerations)) or might be convertible into one of those.
* The relationship considered is an equality.
I present it quickly in [appendix](/notebooks/7-Appendix/Switch.ipynb) but we do not have yet seen all the elements needed to explain its interest.
I present it quickly in [appendix](../7-Appendix/Switch.ipynb) but we do not have yet seen all the elements needed to explain its interest.
%% Cell type:markdown id: tags:
## Logical operators
A condition might be an amalgation of several conditions. The way to glue it is to use logical operators.
The operators are:
* `&&` for the **and** operator.
* `||` for the **or** operator.
* `!` for the **not** operator.
Actually there are so-called __alternative representations__ using the english name directly for each of them but their usage is not widely spread and not advised from a stylistic standpoint (many StackOverflow threads debate on this topic...).
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
int a = 2;
int b = 3;
if (a == 2 || b == 5)
std::cout << "Ok: first condition is true." << std::endl;
if (a == 2 or b == 5)
std::cout << "Same as above illustrating the alternative representation." << std::endl;
if (a == 2 && b == 5)
std::cout << "Not printed: one condition is false." << std::endl;
if (!(a < 0))
std::cout << "Ok: a < 0 is false so the `not` operator returns true." << std::endl;
}
```
%% Cell type:markdown id: tags:
You may combine several of them in a more complex condition. `and` takes precedence over `or`, but anyway it's usually better to disambiguate using parenthesis:
%% Cell type:code id: tags:
``` C++17
{
int a = 2;
int b = 3;
if (a == 5 || a == 2 && b == 3)
std::cout << "(a == 5) and (a == 2 && b == 3) are evaluated separately and the latter is true so this text is printed" << std::endl;
if ((a == 5) || (a == 2 && b == 3))
std::cout << "Same but easier to grasp." << std::endl;
}
```
%% Cell type:markdown id: tags:
Builtin operators `&&` and `||` perform short-circuit evaluation: they do not evaluate the second operand if the result is known after evaluating the first. Please notice this means these operators aren't commutative!
%% Cell type:code id: tags:
``` C++17
{
int a = 2;
int b = 3;
if (a > 0 || ++b < 10)
std::cout << "b is still " << b << ": as the first operand was true ++b was never evaluated." << std::endl;
b = 3;
if (++b < 10 || a > 0)
std::cout << "b is now " << b << ": the first operand run is not the same..." << std::endl;
}
```
%% Cell type:markdown id: tags:
Please notice it's true only for built-in operators: later in this tutorial we will deal with operators overloading, and such operators always evaluate both operands.
%% Cell type:markdown id: tags:
## Loops
%% Cell type:markdown id: tags:
### `while` loop
%% Cell type:markdown id: tags:
The `while` instruction allows you to execute a block of instructions in a loop
as long as a condition is true. The condition is checked **before** each
iteration.
The rules about the instructions belonging to the loop are exactly the same as the ones described for `if` statements. </