Commit 3ab0e8b3 authored by GILLES Sebastien's avatar GILLES Sebastien
Browse files

Change year in copyright notice.

parent d1e0e20a
...@@ -316,7 +316,7 @@ ...@@ -316,7 +316,7 @@
"metadata": {}, "metadata": {},
"source": [ "source": [
"\n", "\n",
"© _CNRS 2016_ - _Inria 2018_ \n", "© _CNRS 2016_ - _Inria 2018-2019_ \n",
"_This notebook is an adaptation of a lecture prepared and redacted 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/)_ \n", "_This notebook is an adaptation of a lecture prepared and redacted 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/)_ \n",
"_The present version has been redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_" "_The present version has been redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_"
] ]
......
%% Cell type:markdown id: tags: %% 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](/notebooks/getting_started_with_tutorial.ipynb)
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
<h1>Table of contents<span class="tocSkip"></span></h1> <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></ul></li></ul></div> <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></ul></li></ul></div>
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## About the choice of a Jupyter notebook ## 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). 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. 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](/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.
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! 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... ## 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: 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++. * 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). * 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: %% Cell type:markdown id: tags:
## Few guidelines about Jupyter ## 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). 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: 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. * 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. * 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: 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. * 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... * 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 edit mode, simply type on 'Enter'.
To enter in command mode, type 'Esc'. 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. 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: In command mode, several handy shortcuts are there; I would recommend especially:
* `a` (add a cell above) * `a` (add a cell above)
* `b` (add a cell below) * `b` (add a cell below)
* `x` (cut a cell) * `x` (cut a cell)
* `M` (change cell mode to Markdown) * `M` (change cell mode to Markdown)
The complete list is available in _Help_ > _Keyboard_ shortcut. 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. 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 ### Restarting the kernel
Sometimes something that should work doesn't... In this case try restarting the kernel: it might fix your issue! Sometimes something that should work doesn't... In this case try restarting the kernel: it might fix your issue!
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## Very basic C++ syntax (in notebook and in general) ## Very basic C++ syntax (in notebook and in general)
### Semicolons ### Semicolons
In C++ most instructions end by a semicolon `;`. If you forget it, the underlying compiler doesn't understand the syntax. 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: %% Cell type:code id: tags:
``` C++17 ``` C++17
{ {
int foo = 5 // COMPILATION ERROR! int foo = 5 // COMPILATION ERROR!
} }
``` ```
%%%% Output: stream %%%% Output: stream
input_line_11:3:16: error: expected ';' at end of declaration input_line_11:3:16: error: expected ';' at end of declaration
int foo = 5 // COMPILATION ERROR! int foo = 5 // COMPILATION ERROR!
 ^  ^
 ;  ;
 
%%%% Output: error %%%% Output: error
Interpreter Error: Interpreter Error:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
{ {
int foo = 5; // OK int foo = 5; // OK
} }
``` ```
%% Cell type:markdown id: tags: %% 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: 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: %% Cell type:code id: tags:
``` C++17 ``` C++17
# include <string> # include <string>
{ {
int nombre ; nombre = 1 int nombre ; nombre = 1
; std::string nom; ; std::string nom;
nom= nom=
"truc" ; "truc" ;
nombre = 2 nombre = 2
; ;
} }
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### Blocks ### 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. 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](/notebooks/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. 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: 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: %% Cell type:code id: tags:
``` C++17 ``` C++17
int i = 2; // Should be fine on the first call. 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. // But if you have executed it already, a new attempt will make the compiler yell.
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
int i = 1; // If the cell above was run, compilation error as `i` is already defined. int i = 1; // If the cell above was run, compilation error as `i` is already defined.
``` ```
%%%% Output: stream %%%% Output: stream
input_line_17:2:6: error: redefinition of 'i' input_line_17:2:6: error: redefinition of 'i'
int i = 1; // If the cell above was run, compilation error as `i` is al... int i = 1; // If the cell above was run, compilation error as `i` is al...
 ^  ^
input_line_16:2:6: note: previous definition is here input_line_16:2:6: note: previous definition is here
int i = 2; // Should be fine on the first call. But if you have execute... int i = 2; // Should be fine on the first call. But if you have execute...
 ^  ^
 
%%%% Output: error %%%% Output: error
Interpreter Error: Interpreter Error:
%% Cell type:markdown id: tags: %% 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. 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: 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: %% Cell type:code id: tags:
``` C++17 ``` C++17
{ {
int i = 2; // Fine int i = 2; // Fine
} }
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
{ {
int i = 1; // Also fine int i = 1; // Also fine
} }
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### Input / output ### 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 well 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. 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 well 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: %% Cell type:code id: tags:
``` C++17 ``` C++17
{ {
std::cout << "Hello world!" << std::endl; // Should fail (unless you run a cell that includes iostream before) std::cout << "Hello world!" << std::endl; // Should fail (unless you run a cell that includes iostream before)
} }
``` ```
%%%% Output: stream %%%% Output: stream
input_line_26:3:10: error: no member named 'cout' in namespace 'std' input_line_26:3:10: error: no member named 'cout' in namespace 'std'
std::cout << "Hello world!" << std::endl; // Should fail (unless yo... std::cout << "Hello world!" << std::endl; // Should fail (unless yo...
 ~~~~~^  ~~~~~^
 
%%%% Output: error %%%% Output: error
Interpreter Error: Interpreter Error:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
std::cout << "Hello world!" << std::endl; // Should work: std::cout and std::endl are now known. std::cout << "Hello world!" << std::endl; // Should work: std::cout and std::endl are now known.
} }
``` ```
%%%% Output: stream %%%% Output: stream
Hello world! Hello world!
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
- `std::cout` is the symbol to designate the standard output - `std::cout` is the symbol to designate the standard output
- `std::endl` is the symbol to clean-up the stream and go to next line. - `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. 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](/notebooks/1-ProceduralProgramming/6-Streams.ipynb), but printing something is really helpful early on hence this brief introduction here.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
© _CNRS 2016_ - _Inria 2018_ © _CNRS 2016_ - _Inria 2018-2019_
_This notebook is an adaptation of a lecture prepared and redacted 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/)_ _This notebook is an adaptation of a lecture prepared and redacted 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 redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_ _The present version has been redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
"metadata": {}, "metadata": {},
"source": [ "source": [
"\n", "\n",
"© _CNRS 2016_ - _Inria 2018_ \n", "© _CNRS 2016_ - _Inria 2018-2019_ \n",
"_This notebook is an adaptation of a lecture prepared and redacted 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/)_ \n", "_This notebook is an adaptation of a lecture prepared and redacted 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/)_ \n",
"_The present version has been redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_" "_The present version has been redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_"
] ]
......
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
# [Getting started in C++](/) - [Procedural programming](/notebooks/1-ProceduralProgramming/0-main.ipynb) # [Getting started in C++](/) - [Procedural programming](/notebooks/1-ProceduralProgramming/0-main.ipynb)
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
* [Variables, initialisation, affectation](/notebooks/1-ProceduralProgramming/1-Variables.ipynb) * [Variables, initialisation, affectation](/notebooks/1-ProceduralProgramming/1-Variables.ipynb)
* [Condition and loops](/notebooks/1-ProceduralProgramming/2-Conditions-and-loops.ipynb) * [Condition and loops](/notebooks/1-ProceduralProgramming/2-Conditions-and-loops.ipynb)
* [Predefined types](/notebooks/1-ProceduralProgramming/3-Types.ipynb) * [Predefined types](/notebooks/1-ProceduralProgramming/3-Types.ipynb)
* [Functions](/notebooks/1-ProceduralProgramming/4-Functions.ipynb) * [Functions](/notebooks/1-ProceduralProgramming/4-Functions.ipynb)
* [TP 1](/notebooks/1-ProceduralProgramming/4b-TP.ipynb) * [TP 1](/notebooks/1-ProceduralProgramming/4b-TP.ipynb)
* [Dynamic allocation](/notebooks/1-ProceduralProgramming/5-DynamicAllocation.ipynb) * [Dynamic allocation](/notebooks/1-ProceduralProgramming/5-DynamicAllocation.ipynb)
* [Input/output](/notebooks/1-ProceduralProgramming/6-Streams.ipynb) * [Input/output](/notebooks/1-ProceduralProgramming/6-Streams.ipynb)
* [TP 2](/notebooks/1-ProceduralProgramming/6b-TP.ipynb) * [TP 2](/notebooks/1-ProceduralProgramming/6b-TP.ipynb)
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
© _CNRS 2016_ - _Inria 2018_ © _CNRS 2016_ - _Inria 2018-2019_
_This notebook is an adaptation of a lecture prepared and redacted 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/)_ _This notebook is an adaptation of a lecture prepared and redacted 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 redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_ _The present version has been redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_
......
...@@ -926,7 +926,7 @@ ...@@ -926,7 +926,7 @@
"metadata": {}, "metadata": {},
"source": [ "source": [
"\n", "\n",
"© _CNRS 2016_ - _Inria 2018_ \n", "© _CNRS 2016_ - _Inria 2018-2019_ \n",
"_This notebook is an adaptation of a lecture prepared and redacted 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/)_ \n", "_This notebook is an adaptation of a lecture prepared and redacted 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/)_ \n",
"_The present version has been redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_\n", "_The present version has been redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_\n",
"\n" "\n"
......
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
# [Getting started in C++](/) - [Procedural programming](/notebooks/1-ProceduralProgramming/0-main.ipynb) - [Predefined types](/notebooks/1-ProceduralProgramming/1-Variables.ipynb) # [Getting started in C++](/) - [Procedural programming](/notebooks/1-ProceduralProgramming/0-main.ipynb) - [Predefined types](/notebooks/1-ProceduralProgramming/1-Variables.ipynb)
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
<h1>Table of contents<span class="tocSkip"></span></h1> <h1>Table of contents<span class="tocSkip"></span></h1>
<div class="toc"><ul class="toc-item"><li><span><a href="#Ordinary-variables" data-toc-modified-id="Ordinary-variables-1">Ordinary variables</a></span><ul class="toc-item"><li><span><a href="#Declaration" data-toc-modified-id="Declaration-1.1">Declaration</a></span></li><li><span><a href="#Initialisation" data-toc-modified-id="Initialisation-1.2">Initialisation</a></span></li><li><span><a href="#Affectation" data-toc-modified-id="Affectation-1.3">Affectation</a></span></li><li><span><a href="#Increment-and-decrement-operators" data-toc-modified-id="Increment-and-decrement-operators-1.4">Increment and decrement operators</a></span></li><li><span><a href="#Comparing-values" data-toc-modified-id="Comparing-values-1.5">Comparing values</a></span></li></ul></li><li><span><a href="#References" data-toc-modified-id="References-2">References</a></span></li><li><span><a href="#Pointers" data-toc-modified-id="Pointers-3">Pointers</a></span><ul class="toc-item"><li><span><a href="#nullptr" data-toc-modified-id="nullptr-3.1"><code>nullptr</code></a></span></li></ul></li><li><span><a href="#Constant-variables-and-pointers" data-toc-modified-id="Constant-variables-and-pointers-4">Constant variables and pointers</a></span></li><li><span><a href="#Arrays" data-toc-modified-id="Arrays-5">Arrays</a></span><ul class="toc-item"><li><span><a href="#Arrays-and-pointers" data-toc-modified-id="Arrays-and-pointers-5.1">Arrays and pointers</a></span></li></ul></li></ul></div> <div class="toc"><ul class="toc-item"><li><span><a href="#Ordinary-variables" data-toc-modified-id="Ordinary-variables-1">Ordinary variables</a></span><ul class="toc-item"><li><span><a href="#Declaration" data-toc-modified-id="Declaration-1.1">Declaration</a></span></li><li><span><a href="#Initialisation" data-toc-modified-id="Initialisation-1.2">Initialisation</a></span></li><li><span><a href="#Affectation" data-toc-modified-id="Affectation-1.3">Affectation</a></span></li><li><span><a href="#Increment-and-decrement-operators" data-toc-modified-id="Increment-and-decrement-operators-1.4">Increment and decrement operators</a></span></li><li><span><a href="#Comparing-values" data-toc-modified-id="Comparing-values-1.5">Comparing values</a></span></li></ul></li><li><span><a href="#References" data-toc-modified-id="References-2">References</a></span></li><li><span><a href="#Pointers" data-toc-modified-id="Pointers-3">Pointers</a></span><ul class="toc-item"><li><span><a href="#nullptr" data-toc-modified-id="nullptr-3.1"><code>nullptr</code></a></span></li></ul></li><li><span><a href="#Constant-variables-and-pointers" data-toc-modified-id="Constant-variables-and-pointers-4">Constant variables and pointers</a></span></li><li><span><a href="#Arrays" data-toc-modified-id="Arrays-5">Arrays</a></span><ul class="toc-item"><li><span><a href="#Arrays-and-pointers" data-toc-modified-id="Arrays-and-pointers-5.1">Arrays and pointers</a></span></li></ul></li></ul></div>
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## Ordinary variables ## Ordinary variables
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### Declaration ### Declaration
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
To be usable in a C++ program, a variable must be declared. This declaration shall include at least the type of To be usable in a C++ program, a variable must be declared. This declaration shall include at least the type of
the variable, followed by its name and a semicolon. the variable, followed by its name and a semicolon.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int number; // integer variable int number; // integer variable
double real; // floating-point variable double real; // floating-point variable
std::cout << number << std::endl; std::cout << number << std::endl;
std::cout << real << std::endl; std::cout << real << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
32766 32766
1.37345e-70 1.37345e-70
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### Initialisation ### Initialisation
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Although not mandatory, it is strongly recommended to give a Although not mandatory, it is strongly recommended to give a
initial value to your variables, as an expression between brackets. initial value to your variables, as an expression between brackets.
Not providing an initial value may lead to unexpected behaviour. For instance you can't make hypothesis upon the values of `number` and `real` in the cell above: you might end-up with any value... and someone else might get other values on his computer! Not providing an initial value may lead to unexpected behaviour. For instance you can't make hypothesis upon the values of `number` and `real` in the cell above: you might end-up with any value... and someone else might get other values on his computer!
If you give braces without values, a predefined and associated value If you give braces without values, a predefined and associated value
to the type is used (usually a form of 0). to the type is used (usually a form of 0).
If you give nothing , the behaviour is undefined: you might end up with a 0-like value or something If you give nothing , the behaviour is undefined: you might end up with a 0-like value or something
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
{ {
int nb1 { 1 }; // integer variable set with the value 1 int nb1 { 1 }; // integer variable set with the value 1
int nb2 {}; // same as int nb2{0}; int nb2 {}; // same as int nb2{0};
double pi { 3.14 } ; // real variable double pi { 3.14 } ; // real variable
} }
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
C++ actually supports many other historical forms C++ actually supports many other historical forms
of initialization, which you will encounter everywhere, including in this tutorial, of initialization, which you will encounter everywhere, including in this tutorial,
with brackets and/or an equal sign. There are some subtile differences with brackets and/or an equal sign. There are some subtile differences
between each other... that you can ignore most of the time. between each other... that you can ignore most of the time.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
{ {
int a = 5; int a = 5;
int b(5); int b(5);
int c = { 5 }; int c = { 5 };
} }
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
In all cases, even if there is an equal sign, it is important to remember In all cases, even if there is an equal sign, it is important to remember
that it is an initialization, not an assignment (this will be that it is an initialization, not an assignment (this will be
important when we will define our own types). important when we will define our own types).
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### Affectation ### Affectation
A new value is stored in an existing variable using the operator A new value is stored in an existing variable using the operator
of assignment `=`. The name of the variable is on the left; the expression of assignment `=`. The name of the variable is on the left; the expression
on the right of the `=` sign is evaluated, and its result is assigned to the variable. on the right of the `=` sign is evaluated, and its result is assigned to the variable.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> // for std::cout and std::endl #include <iostream> // for std::cout and std::endl
{ {
int a {}, b {}, c {} ; // default initialization; set the values to 0 int a {}, b {}, c {} ; // default initialization; set the values to 0
std::cout << "Default initialization: a = " << a << ", b = " << b << " and c = " << c << std::endl; std::cout << "Default initialization: a = " << a << ", b = " << b << " and c = " << c << std::endl;
a = 4; a = 4;
b = 7; b = 7;
c = a + b; c = a + b;
std::cout << "After affectations: a = " << a << ", b = " << b << " and c = " << c << std::endl; std::cout << "After affectations: a = " << a << ", b = " << b << " and c = " << c << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
Default initialization: a = 0, b = 0 and c = 0 Default initialization: a = 0, b = 0 and c = 0
After affectations: a = 4, b = 7 and c = 11 After affectations: a = 4, b = 7 and c = 11
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
It is also possible to define (slightly) more advanced operators of assignments that modify the value currently stored by a simple operation: It is also possible to define (slightly) more advanced operators of assignments that modify the value currently stored by a simple operation:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int a {}, b {}, c {} ; // default initialization; set the values to 0 int a {}, b {}, c {} ; // default initialization; set the values to 0
a += 4; // add 4 to the current value of a a += 4; // add 4 to the current value of a
std::cout << "a = " << a << std::endl; std::cout << "a = " << a << std::endl;
a *= 7; // multiply current value of a by 3 a *= 7; // multiply current value of a by 3
std::cout << "a = " << a << std::endl; std::cout << "a = " << a << std::endl;
a /= 5; // divide a by 5 and assign the quotient to a a /= 5; // divide a by 5 and assign the quotient to a
std::cout << "a = " << a << std::endl; std::cout << "a = " << a << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
a = 4 a = 4
a = 28 a = 28
a = 5 a = 5
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### Increment and decrement operators ### Increment and decrement operators
Finally, C++ also provides a shortcut when value is either incremented or decremented by adding `++` or `--` before or after the name of the variable. Finally, C++ also provides a shortcut when value is either incremented or decremented by adding `++` or `--` before or after the name of the variable.
* If the sign is placed before the variable, it is a **pre-increment**. * If the sign is placed before the variable, it is a **pre-increment**.
* If the sign is placed after the variable, it is a **post-increment**. * If the sign is placed after the variable, it is a **post-increment**.
An example is the better way to explain the difference between both: An example is the better way to explain the difference between both:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int a = 5; int a = 5;
int b = 3; int b = 3;
a++; // increment a by 1. a++; // increment a by 1.
++a; // same, both are actually equivalents here. ++a; // same, both are actually equivalents here.
int c = a + b; int c = a + b;
std::cout << "a = " << a << ", b = " << b << " and c = " << c << std::endl; std::cout << "a = " << a << ", b = " << b << " and c = " << c << std::endl;
c = a-- + b; // first a + b is evaluated, and only then a is decremented. c = a-- + b; // first a + b is evaluated, and only then a is decremented.
std::cout << "a = " << a << ", b = " << b << " and c = " << c << std::endl; std::cout << "a = " << a << ", b = " << b << " and c = " << c << std::endl;
c = a + ++b; // first b is incremented, and only then a + b is evaluated. c = a + ++b; // first b is incremented, and only then a + b is evaluated.
std::cout << "a = " << a << ", b = " << b << " and c = " << c << std::endl; std::cout << "a = " << a << ", b = " << b << " and c = " << c << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
a = 7, b = 3 and c = 10 a = 7, b = 3 and c = 10
a = 6, b = 3 and c = 10 a = 6, b = 3 and c = 10
a = 6, b = 4 and c = 10 a = 6, b = 4 and c = 10
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Honestly it's usually better to remove any ambiguity by separating explicitly both operations: Honestly it's usually better to remove any ambiguity by separating explicitly both operations:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int a = 7; int a = 7;
int b = 3; int b = 3;
int c = a + b; int c = a + b;
std::cout << "a = " << a << ", b = " << b << " and c = " << c << std::endl; std::cout << "a = " << a << ", b = " << b << " and c = " << c << std::endl;
--a; // equivalent to a-- but for reasons related to the standard library I advise you to rather use the --a; // equivalent to a-- but for reasons related to the standard library I advise you to rather use the
// pre-increment form. // pre-increment form.
c = a + b; // first a + b is evaluated, and only then a is decremented. c = a + b; // first a + b is evaluated, and only then a is decremented.
std::cout << "a = " << a << ", b = " << b << " and c = " << c << std::endl; std::cout << "a = " << a << ", b = " << b << " and c = " << c << std::endl;
++b; // same: equivalent to b++; ++b; // same: equivalent to b++;
c = a + b; // first a is incremented, and only then a + b is evaluated. c = a + b; // first a is incremented, and only then a + b is evaluated.
std::cout << "a = " << a << ", b = " << b << " and c = " << c << std::endl; std::cout << "a = " << a << ", b = " << b << " and c = " << c << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
a = 7, b = 3 and c = 10 a = 7, b = 3 and c = 10
a = 6, b = 3 and c = 9 a = 6, b = 3 and c = 9
a = 6, b = 4 and c = 10 a = 6, b = 4 and c = 10
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### Comparing values ### Comparing values
As shown above, `=` is the affectation operator. To compare two values, the symbol to use is `==`. As shown above, `=` is the affectation operator. To compare two values, the symbol to use is `==`.
Other arithmetic operators are: Other arithmetic operators are:
| Operator | Effect | | Operator | Effect |
|:------------- |:-------------------------------------------:| |:------------- |:-------------------------------------------:|
| `a == b` | `true` if a and b are equals | | `a == b` | `true` if a and b are equals |
| `a != b` | `true` if a and b are different | | `a != b` | `true` if a and b are different |
| `a < b` | `true` if a is less than b | | `a < b` | `true` if a is less than b |
| `a > b` | `true` if a is greater than b | | `a > b` | `true` if a is greater than b |
| `a >= b` | `true` if a is greater than or equal to b | | `a >= b` | `true` if a is greater than or equal to b |
| `a <= b` | `true` if a is less than or equal to b | | `a <= b` | `true` if a is less than or equal to b |
These operators are defined for most ordinary types and may be defined for your own types (we'll see that [later](/notebooks/3-Operators/2-Comparison.ipynb)). These operators are defined for most ordinary types and may be defined for your own types (we'll see that [later](/notebooks/3-Operators/2-Comparison.ipynb)).
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## References ## References
A reference is a variable that acts as a kind of alias, and provides another name for the same value. A reference is a variable that acts as a kind of alias, and provides another name for the same value.
When defining a reference, it must be immediately initialized by When defining a reference, it must be immediately initialized by
indicating on which variable it should point; it cannot be changed after that. indicating on which variable it should point; it cannot be changed after that.
The syntax is to add a `&` character just after the type: The syntax is to add a `&` character just after the type:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int a { 2 }; int a { 2 };
int b { a }; int b { a };
b = b + 1; b = b + 1;
int& c { a }; // c is a reference to a int& c { a }; // c is a reference to a
std::cout << "Initial values : a = " << a << ", b = " << b << " and c = " << c << std::endl; std::cout << "Initial values : a = " << a << ", b = " << b << " and c = " << c << std::endl;
b = b + 5; b = b + 5;
std::cout << "After b is modified: a = " << a << ", b = " << b << " and c = " << c << std::endl; std::cout << "After b is modified: a = " << a << ", b = " << b << " and c = " << c << std::endl;
c = c + 1 ; // c = c + 1 ; //
std::cout << "After c is modified: a = " << a << ", b = " << b << " and c = " << c << std::endl; std::cout << "After c is modified: a = " << a << ", b = " << b << " and c = " << c << std::endl;
a *= 3; a *= 3;
std::cout << "After a is modified: a = " << a << ", b = " << b << " and c = " << c << std::endl; std::cout << "After a is modified: a = " << a << ", b = " << b << " and c = " << c << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
Initial values : a = 2, b = 3 and c = 2 Initial values : a = 2, b = 3 and c = 2
After b is modified: a = 2, b = 8 and c = 2 After b is modified: a = 2, b = 8 and c = 2
After c is modified: a = 3, b = 8 and c = 3 After c is modified: a = 3, b = 8 and c = 3
After a is modified: a = 9, b = 8 and c = 9 After a is modified: a = 9, b = 8 and c = 9
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Reference is a purely C++ concept that doesn't exist in C. Reference is a purely C++ concept that doesn't exist in C.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## Pointers ## Pointers
A pointer contains the address of another variable. It declares itself by slipping A pointer contains the address of another variable. It declares itself by slipping
a `*` character before the name. It can be initialized or not with the address a `*` character before the name. It can be initialized or not with the address
of another variable. To explicitly extract the address of this other variable, of another variable. To explicitly extract the address of this other variable,
we use the symbol `&`. we use the symbol `&`.
Later, either you want to modify the address stored in the pointer, to which Later, either you want to modify the address stored in the pointer, to which
in this case we use the pointer name directly, or we want to modify the variable in this case we use the pointer name directly, or we want to modify the variable
pointed, in which case the name is prefixed with `*`. pointed, in which case the name is prefixed with `*`.
We can therefore see the pointer as a kind of redefinable reference. We can therefore see the pointer as a kind of redefinable reference.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int a { 2 }, b { 10 }; int a { 2 }, b { 10 };
int* p {&a}; // define a pointer p which is initialized with the address of a int* p {&a}; // define a pointer p which is initialized with the address of a
std::cout << "Initial values: " << std::endl; std::cout << "Initial values: " << std::endl;
std::cout << "\t p: address = " << p << ", value = " << *p << std::endl; std::cout << "\t p: address = " << p << ", value = " << *p << std::endl;
std::cout << "\t a: address = " << &a << ", value = " << a << std::endl; std::cout << "\t a: address = " << &a << ", value = " << a << std::endl;
std::cout << "\t b: address = " << &b << ", value = " << b << std::endl; std::cout << "\t b: address = " << &b << ", value = " << b << std::endl;
std::cout << std::endl; std::cout << std::endl;
*p = *p + 1; // increment the integer value present at address p *p = *p + 1; // increment the integer value present at address p
std::cout << "After value pointed by p is incremented:" << std::endl; std::cout << "After value pointed by p is incremented:" << std::endl;
std::cout << "\t p: address = " << p << ", value = " << *p << std::endl; std::cout << "\t p: address = " << p << ", value = " << *p << std::endl;
std::cout << "\t a: address = " << &a << ", value = " << a << std::endl; std::cout << "\t a: address = " << &a << ", value = " << a << std::endl;
std::cout << "\t b: address = " << &b << ", value = " << b << std::endl; std::cout << "\t b: address = " << &b << ", value = " << b << std::endl;
std::cout << std::endl; std::cout << std::endl;
p = &b; // change the address pointed by p p = &b; // change the address pointed by p
std::cout << "p now points to the address of b:" << std::endl; std::cout << "p now points to the address of b:" << std::endl;
std::cout << "\t p: address = " << p << ", value = " << *p << std::endl; std::cout << "\t p: address = " << p << ", value = " << *p << std::endl;
std::cout << "\t a: address = " << &a << ", value = " << a << std::endl; std::cout << "\t a: address = " << &a << ", value = " << a << std::endl;
std::cout << "\t b: address = " << &b << ", value = " << b << std::endl; std::cout << "\t b: address = " << &b << ", value = " << b << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
Initial values: Initial values:
p: address = 0x7ffeea882974, value = 2 p: address = 0x7ffeea882974, value = 2
a: address = 0x7ffeea882974, value = 2 a: address = 0x7ffeea882974, value = 2
b: address = 0x7ffeea882970, value = 10 b: address = 0x7ffeea882970, value = 10
After value pointed by p is incremented: After value pointed by p is incremented:
p: address = 0x7ffeea882974, value = 3 p: address = 0x7ffeea882974, value = 3
a: address = 0x7ffeea882974, value = 3 a: address = 0x7ffeea882974, value = 3
b: address = 0x7ffeea882970, value = 10 b: address = 0x7ffeea882970, value = 10
p now points to the address of b: p now points to the address of b:
p: address = 0x7ffeea882970, value = 10 p: address = 0x7ffeea882970, value = 10
a: address = 0x7ffeea882974, value = 3 a: address = 0x7ffeea882974, value = 3
b: address = 0x7ffeea882970, value = 10 b: address = 0x7ffeea882970, value = 10
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### `nullptr` ### `nullptr`
A pointer can also designate no variables if initialized with the special value A pointer can also designate no variables if initialized with the special value
`nullptr`. It is then a mistake to try to access its pointed value (as we shall see later, an [`assert`](/notebooks/5-UsefulConceptsAndSTL/1-ErrorHandling.ipynb#Assert) is a good idea to ensure we do not try to dereference a `nullptr` value). `nullptr`. It is then a mistake to try to access its pointed value (as we shall see later, an [`assert`](/notebooks/5-UsefulConceptsAndSTL/1-ErrorHandling.ipynb#Assert) is a good idea to ensure we do not try to dereference a `nullptr` value).
It is strongly recommended to initialize a pointer when creating it: if you define an uninitialized pointer, it points to an arbitrary area of memory, which can create undefined behaviors that are not necessarily reproducible. It is strongly recommended to initialize a pointer when creating it: if you define an uninitialized pointer, it points to an arbitrary area of memory, which can create undefined behaviors that are not necessarily reproducible.
If the pointed area is known at initialization and never changes throughout the program, you should consider a reference rather than a pointer. If the pointed area is known at initialization and never changes throughout the program, you should consider a reference rather than a pointer.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int* p = nullptr; // define a null pointer p int* p = nullptr; // define a null pointer p
std::cout << "\t p: address = " << p << ", value = " << *p << std::endl; // Dereferencing p is misguided! std::cout << "\t p: address = " << p << ", value = " << *p << std::endl; // Dereferencing p is misguided!
} }
``` ```
%%%% Output: stream %%%% Output: stream
p: address = 0x0, value = p: address = 0x0, value =
%%%% Output: stream %%%% Output: stream
input_line_16:4:62: warning: null passed to a callee that requires a non-null argument [-Wnonnull] input_line_16:4:62: warning: null passed to a callee that requires a non-null argument [-Wnonnull]
std::cout << "\t p: address = " << p << ", value = " << *p << std::endl; // Dereferencing p is misguided! std::cout << "\t p: address = " << p << ", value = " << *p << std::endl; // Dereferencing p is misguided!
 ^  ^
 
%%%% Output: error %%%% Output: error
Interpreter Exception: Interpreter Exception:
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## Constant variables and pointers ## Constant variables and pointers
When declaring a variable of a predefined type, it is possible to specify its value can't be changed afterward by using the word `const` which may be placed before or after the type: When declaring a variable of a predefined type, it is possible to specify its value can't be changed afterward by using the word `const` which may be placed before or after the type:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
{ {
const double pi = 3.1415927; const double pi = 3.1415927;
double const pi_2 = 3.1415927; // equally valid; it is just a matter of taste. Mine is to put it before, double const pi_2 = 3.1415927; // equally valid; it is just a matter of taste. Mine is to put it before,
// so that is what you will see in the remaining of the tutorial. // so that is what you will see in the remaining of the tutorial.
pi = 5.; // COMPILATION ERROR! pi = 5.; // COMPILATION ERROR!
pi_2 = 7.; // COMPILATION ERROR! pi_2 = 7.; // COMPILATION ERROR!
} }
``` ```
%%%% Output: stream %%%% Output: stream
input_line_23:6:8: error: cannot assign to variable 'pi' with const-qualified type 'const double' input_line_23:6:8: error: cannot assign to variable 'pi' with const-qualified type 'const double'
pi = 5.; // COMPILATION ERROR! pi = 5.; // COMPILATION ERROR!
 ~~ ^  ~~ ^
input_line_23:3:18: note: variable 'pi' declared const here input_line_23:3:18: note: variable 'pi' declared const here
const double pi = 3.1415927; const double pi = 3.1415927;
 ~~~~~~~~~~~~~^~~~~~~~~~~~~~  ~~~~~~~~~~~~~^~~~~~~~~~~~~~
input_line_23:7:10: error: cannot assign to variable 'pi_2' with const-qualified type 'const double' input_line_23:7:10: error: cannot assign to variable 'pi_2' with const-qualified type 'const double'
pi_2 = 7.; // COMPILATION ERROR! pi_2 = 7.; // COMPILATION ERROR!
 ~~~~ ^  ~~~~ ^
input_line_23:4:18: note: variable 'pi_2' declared const here input_line_23:4:18: note: variable 'pi_2' declared const here
double const pi_2 = 3.1415927; // equally valid; it is just a matter of taste. Mine is to put it before, double const pi_2 = 3.1415927; // equally valid; it is just a matter of taste. Mine is to put it before,
 ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~
 
%%%% Output: error %%%% Output: error
Interpreter Error: Interpreter Error:
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
In the case of a pointer, we can declare the pointer itself constant, and/or the value pointed to depending on whether we place the keyword `const` before or after the type name (in this case it applies to the pointed value) or after the character `*` (in this case it applies to the pointer itself): In the case of a pointer, we can declare the pointer itself constant, and/or the value pointed to depending on whether we place the keyword `const` before or after the type name (in this case it applies to the pointed value) or after the character `*` (in this case it applies to the pointer itself):
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
{ {
int a { 2 }, b { 3 }; int a { 2 }, b { 3 };
int* p { &a }; // Both pointer and pointed values are modifiable. int* p { &a }; // Both pointer and pointed values are modifiable.
p = &b; // OK p = &b; // OK
*p = 5; // OK *p = 5; // OK
} }
``` ```
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
{ {
int a { 2 }, b { 3 }; int a { 2 }, b { 3 };
int* const p { &a }; // Value is modifiable, but not the address pointed to. int* const p { &a }; // Value is modifiable, but not the address pointed to.
*p = 5; // OK *p = 5; // OK
p = &b; // COMPILATION ERROR - if you comment it it will p = &b; // COMPILATION ERROR - if you comment it it will
} }
``` ```
%%%% Output: stream %%%% Output: stream
input_line_74:6:7: error: cannot assign to variable 'p' with const-qualified type 'int *const' input_line_74:6:7: error: cannot assign to variable 'p' with const-qualified type 'int *const'
p = &b; // COMPILATION ERROR - if you comment it it will p = &b; // COMPILATION ERROR - if you comment it it will
 ~ ^  ~ ^
input_line_74:4:16: note: variable 'p' declared const here input_line_74:4:16: note: variable 'p' declared const here
int* const p { &a }; // Value is modifiable, but not the address pointed to. int* const p { &a }; // Value is modifiable, but not the address pointed to.
 ~~~~~~~~~~~^~~~~~~~  ~~~~~~~~~~~^~~~~~~~
 
%%%% Output: error %%%% Output: error
Interpreter Error: Interpreter Error:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
{ {
int a { 2 }, b { 3 }; int a { 2 }, b { 3 };
const int* p { &a }; // Address pointed to is modifiable, but not the underlying value. const int* p { &a }; // Address pointed to is modifiable, but not the underlying value.
p = &b; // OK p = &b; // OK
*p = 5; // COMPILATION ERROR *p = 5; // COMPILATION ERROR
} }
``` ```
%%%% Output: stream %%%% Output: stream
input_line_75:7:8: error: read-only variable is not assignable input_line_75:7:8: error: read-only variable is not assignable
*p = 5; // COMPILATION ERROR *p = 5; // COMPILATION ERROR
 ~~ ^  ~~ ^
 
%%%% Output: error %%%% Output: error
Interpreter Error: Interpreter Error:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
{ {
int a { 2 }, b { 3 }; int a { 2 }, b { 3 };
const int* const p { &a }; // Nothing is modifiable const int* const p { &a }; // Nothing is modifiable
p = &b; // COMPILATION ERROR p = &b; // COMPILATION ERROR
*p = 5; // COMPILATION ERROR *p = 5; // COMPILATION ERROR
} }
``` ```
%%%% Output: stream %%%% Output: stream
input_line_76:6:7: error: cannot assign to variable 'p' with const-qualified type 'const int *const' input_line_76:6:7: error: cannot assign to variable 'p' with const-qualified type 'const int *const'
p = &b; // COMPILATION ERROR p = &b; // COMPILATION ERROR
 ~ ^  ~ ^
input_line_76:4:22: note: variable 'p' declared const here input_line_76:4:22: note: variable 'p' declared const here
const int* const p { &a }; // Nothing is modifiable const int* const p { &a }; // Nothing is modifiable
 ~~~~~~~~~~~~~~~~~^~~~~~~~  ~~~~~~~~~~~~~~~~~^~~~~~~~
input_line_76:7:8: error: read-only variable is not assignable input_line_76:7:8: error: read-only variable is not assignable
*p = 5; // COMPILATION ERROR *p = 5; // COMPILATION ERROR
 ~~ ^  ~~ ^
 
%%%% Output: error %%%% Output: error
Interpreter Error: Interpreter Error:
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
**IMPORTANT**: Even if declared `const`, the pointed value is **IMPORTANT**: Even if declared `const`, the pointed value is
not intrinsically constant. It just can't be not intrinsically constant. It just can't be
modified through this precise pointer. modified through this precise pointer.
If other variables reference the same memory area and If other variables reference the same memory area and
are not constant, they are able to modify the value: are not constant, they are able to modify the value:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int a { 2 }, b { 3 }; int a { 2 }, b { 3 };
const int* p { &a }; // Address pointed to is modifiable, but not the underlying value. const int* p { &a }; // Address pointed to is modifiable, but not the underlying value.
std::cout << "Value pointed by p (which doesn't allow value modification) is: " << *p << std::endl; std::cout << "Value pointed by p (which doesn't allow value modification) is: " << *p << std::endl;
int* p2 {&a}; // Pointer to the same memory area, but no constness here. int* p2 {&a}; // Pointer to the same memory area, but no constness here.
*p2 = 10; *p2 = 10;
std::cout << "Value pointed by p (and modified through p2) is: " << *p << std::endl; std::cout << "Value pointed by p (and modified through p2) is: " << *p << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
Value pointed by p (which doesn't allow value modification) is: 2 Value pointed by p (which doesn't allow value modification) is: 2
Value pointed by p (and modified through p2) is: 10 Value pointed by p (and modified through p2) is: 10
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
On the other hand, pointers can't be used as a work-around to modify a constant value: On the other hand, pointers can't be used as a work-around to modify a constant value:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
{ {
const int n { 3 }; const int n { 3 };
int* p_n { &n }; // COMPILATION ERROR int* p_n { &n }; // COMPILATION ERROR
const int* p_n2 { &n }; // OK const int* p_n2 { &n }; // OK
} }
``` ```
%%%% Output: stream %%%% Output: stream
input_line_25:4:16: error: cannot initialize a variable of type 'int *' with an rvalue of type 'const int *' input_line_25:4:16: error: cannot initialize a variable of type 'int *' with an rvalue of type 'const int *'
int* p_n { &n }; // COMPILATION ERROR int* p_n { &n }; // COMPILATION ERROR
 ^~  ^~
 
%%%% Output: error %%%% Output: error
Interpreter Error: Interpreter Error:
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## Arrays ## Arrays
The operator `[]` enables the creation of an array. The operator `[]` enables the creation of an array.
**Beware:** In C++, the indexes of an array start at 0. **Beware:** In C++, the indexes of an array start at 0.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int i[10] ; // Array of 10 integers - not initialised properly! int i[10] ; // Array of 10 integers - not initialised properly!
double x[3] = { 1., 2., 3. } ; // Array of 3 reals. double x[3] = { 1., 2., 3. } ; // Array of 3 reals.
std::cout << "i[2] = " << i[2] << " (may be gibberish: undefined behaviour due to lack of initialization!)" << std::endl; std::cout << "i[2] = " << i[2] << " (may be gibberish: undefined behaviour due to lack of initialization!)" << std::endl;
std::cout << "i[10] = " << i[10] << " (undefined behaviour: out of range. Warning identifies the issue)" << std::endl ; std::cout << "i[10] = " << i[10] << " (undefined behaviour: out of range. Warning identifies the issue)" << std::endl ;
std::cout << "x[1] = " << x[1] << " (expected: 2.)" << std::endl ; std::cout << "x[1] = " << x[1] << " (expected: 2.)" << std::endl ;
} }
``` ```
%%%% Output: stream %%%% Output: stream
input_line_18:7:32: warning: array index 10 is past the end of the array (which contains 10 elements) [-Warray-bounds] input_line_18:7:32: warning: array index 10 is past the end of the array (which contains 10 elements) [-Warray-bounds]
std::cout << "i[10] = " << i[10] << " (undefined behaviour: out of range. Warning identifies the issue)" << std::endl ; std::cout << "i[10] = " << i[10] << " (undefined behaviour: out of range. Warning identifies the issue)" << std::endl ;
 ^ ~~  ^ ~~
input_line_18:3:5: note: array 'i' declared here input_line_18:3:5: note: array 'i' declared here
int i[10] ; // Array of 10 integers - not initialised properly! int i[10] ; // Array of 10 integers - not initialised properly!
 ^  ^
 
%%%% Output: stream %%%% Output: stream
i[2] = 149375929 (may be nonsense: undefined behaviour due to lack of initialization!) i[2] = 149375929 (may be nonsense: undefined behaviour due to lack of initialization!)
i[10] = -87424866 (undefined behaviour: out of range. Warning identifies the issue) i[10] = -87424866 (undefined behaviour: out of range. Warning identifies the issue)
x[1] = 2 (expected: 2.) x[1] = 2 (expected: 2.)
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Multi-dimensional arrays are also possible: Multi-dimensional arrays are also possible:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int k[2][3] { { 5, 7, 0 }, { 3, 8, 9 }}; int k[2][3] { { 5, 7, 0 }, { 3, 8, 9 }};
std::cout << "k[0][0] = " << k[0][0] << " (expected: 5)" << std::endl; std::cout << "k[0][0] = " << k[0][0] << " (expected: 5)" << std::endl;
std::cout << "k[1][2] = " << k[1][2] << " (expected: 9)" << std::endl; std::cout << "k[1][2] = " << k[1][2] << " (expected: 9)" << std::endl;
int l[2][3] {}; // default initialization of all elements of the array. int l[2][3] {}; // default initialization of all elements of the array.
std::cout << "l[0][0] = " << l[0][0] << " (expected: 0)" << std::endl; std::cout << "l[0][0] = " << l[0][0] << " (expected: 0)" << std::endl;
std::cout << "l[1][2] = " << l[1][2] << " (expected: 0)" << std::endl; std::cout << "l[1][2] = " << l[1][2] << " (expected: 0)" << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
k[0][0] = 5 (expected: 5) k[0][0] = 5 (expected: 5)
k[1][2] = 9 (expected: 9) k[1][2] = 9 (expected: 9)
l[0][0] = 0 (expected: 0) l[0][0] = 0 (expected: 0)
l[1][2] = 0 (expected: 0) l[1][2] = 0 (expected: 0)
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
**IMPORTANT**: so far we have considered only the case of _static_ arrays, for which the size is already known at compilation. We will deal with dynamic ones [later in this tutorial](/notebooks/1-ProceduralProgramming/5-DynamicAllocation.ipynb#Arrays-on-heap) (and also with the standard libraries [alternatives](/notebooks/5-UsefulConceptsAndSTL/3-Containers.ipynb) such as std::vector or std::array which are actually much more compelling). **IMPORTANT**: so far we have considered only the case of _static_ arrays, for which the size is already known at compilation. We will deal with dynamic ones [later in this tutorial](/notebooks/1-ProceduralProgramming/5-DynamicAllocation.ipynb#Arrays-on-heap) (and also with the standard libraries [alternatives](/notebooks/5-UsefulConceptsAndSTL/3-Containers.ipynb) such as std::vector or std::array which are actually much more compelling).
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### Arrays and pointers ### Arrays and pointers
The variable designating an array is similar to a constant pointer pointing to the beginning of the array. Increasing this pointer is like moving around in the array. The variable designating an array is similar to a constant pointer pointing to the beginning of the array. Increasing this pointer is like moving around in the array.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int i[2] = { 10, 20 } ; int i[2] = { 10, 20 } ;
std::cout << *i << " (expected: 10)" << std::endl ; std::cout << *i << " (expected: 10)" << std::endl ;
std::cout << *i + 1 << " (expected: 11)" << std::endl ; std::cout << *i + 1 << " (expected: 11)" << std::endl ;
std::cout << *(i + 1) << " (expected: 20)" << std::endl ; std::cout << *(i + 1) << " (expected: 20)" << std::endl ;
int* j = i; // OK! int* j = i; // OK!
++j; // OK! ++j; // OK!
std::cout << "Value pointed by j is " << *j << " (expected: 20)" << std::endl; std::cout << "Value pointed by j is " << *j << " (expected: 20)" << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
10 (expected: 10) 10 (expected: 10)
11 (expected: 11) 11 (expected: 11)
20 (expected: 20) 20 (expected: 20)
Value pointed by j is 20 (expected: 20) Value pointed by j is 20 (expected: 20)
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
© _CNRS 2016_ - _Inria 2018_ © _CNRS 2016_ - _Inria 2018-2019_
_This notebook is an adaptation of a lecture prepared and redacted 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/)_ _This notebook is an adaptation of a lecture prepared and redacted 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 redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_ _The present version has been redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_
......
...@@ -1093,7 +1093,7 @@ ...@@ -1093,7 +1093,7 @@
"metadata": {}, "metadata": {},
"source": [ "source": [
"\n", "\n",
"© _CNRS 2016_ - _Inria 2018_ \n", "© _CNRS 2016_ - _Inria 2018-2019_ \n",
"_This notebook is an adaptation of a lecture prepared and redacted 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/)_ \n", "_This notebook is an adaptation of a lecture prepared and redacted 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/)_ \n",
"_The present version has been redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_" "_The present version has been redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_"
] ]
......
%% Cell type:markdown id: tags: %% 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](/notebooks/1-ProceduralProgramming/0-main.ipynb) - [Conditions and loops](/notebooks/1-ProceduralProgramming/2-Conditions-and-loops.ipynb)
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
<h1>Table of contents<span class="tocSkip"></span></h1> <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> <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: %% Cell type:markdown id: tags:
## Conditions ## Conditions
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### `if` condition followed by a single statement ### `if` condition followed by a single statement
%% Cell type:markdown id: tags: %% 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. 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: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int a = 2; int a = 2;
if (a > 0) if (a > 0)
std::cout << a << " is greater than 0" << std::endl; std::cout << a << " is greater than 0" << std::endl;
if (a < 0) if (a < 0)
std::cout << "This line won't be executed so nothing will be printed." << std::endl; 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 " std::cout << "But this line will be printed: without braces `{}` only the first instruction depends "
"on the condition!" << std::endl; "on the condition!" << std::endl;
} }
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Of course, the precedent 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! Of course, the precedent 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: Our case above would be much clearer however with a more logical indenting and spacing:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int a = 2; int a = 2;
if (a < 0) if (a < 0)
std::cout << "This line won't be executed so nothing will be printed." << std::endl; 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; std::cout << "It's much clearer now that this line is not encompassed by the condition!" << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
It's much clearer now that this line is not encompassed by the condition! It's much clearer now that this line is not encompassed by the condition!
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### `if` condition followed by a block ### `if` condition followed by a block
And if you need several lines to be encompassed by the condition, just use braces! And if you need several lines to be encompassed by the condition, just use braces!
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int a = 2; int a = 2;
if (a < 0) if (a < 0)
{ {
std::cout << "Should not be printed: the condition is false!" << std::endl; std::cout << "Should not be printed: the condition is false!" << std::endl;
++a; // won't be executed: the condition is false ++a; // won't be executed: the condition is false
} }
std::cout << "a was not modified and is still 2" << std::endl; std::cout << "a was not modified and is still 2" << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
a was not modified and is still 2 a was not modified and is still 2
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### No semicolon at the end of the `if` condition ### 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 doesn nothing... The risk is rather mitigated: any compiler worth its salt will warn you if you do this mistake. __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 doesn nothing... The risk is rather mitigated: any compiler worth its salt will warn you if you do this mistake.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
{ {
int a = 2; int a = 2;
if (a == 0); if (a == 0);
std::cout << "Will be printed: the statement after the condition is ';', which does nothing..." << std::endl; std::cout << "Will be printed: the statement after the condition is ';', which does nothing..." << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
input_line_11:4:16: warning: if statement has empty body [-Wempty-body] input_line_11:4:16: warning: if statement has empty body [-Wempty-body]
if (a == 0); if (a == 0);
 ^  ^
input_line_11:4:16: note: put the semicolon on a separate line to silence this warning input_line_11:4:16: note: put the semicolon on a separate line to silence this warning
%%%% Output: stream %%%% Output: stream
Will be printed: the statement after the condition is ';', which does nothing... Will be printed: the statement after the condition is ';', which does nothing...
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
{ {
int a = 2; int a = 2;
if (a == 2) if (a == 2)
; // putting the semicolon in a different line silences the warning; there are legitimate cases in ; // 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 // which it's useful to do so and the risk is
// slim this was written by mistake. // slim this was written by mistake.
} }
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### if ... else if ... else ### 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: 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: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int a = 2; int a = 2;
if (a < 0) if (a < 0)
std::cout << a << " is negative." << std::endl; std::cout << a << " is negative." << std::endl;
else if (a == 0) else if (a == 0)
{ {
std::cout << a << " is zero." << std::endl; std::cout << a << " is zero." << std::endl;
} }
else if (a < 10) else if (a < 10)
std::cout << a << " is positive but lower than 10." << std::endl; std::cout << a << " is positive but lower than 10." << std::endl;
else if (a < 100) else if (a < 100)
std::cout << a << " is in the interval [10, 20[." << std::endl; std::cout << a << " is in the interval [10, 20[." << std::endl;
else else
{ {
std::cout << a << "is greater than 20." << std::endl; std::cout << a << "is greater than 20." << std::endl;
} }
} }
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Please notice that: 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. * `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 didn't have to spell out in the (a < 100) case that a had to be greater than 10. * As soon as one condition is fulfilled, the execution of the condition blocks ends. I didn't have to spell out in the (a < 100) case that a had to be greater than 10.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### The ternary operator ### The ternary operator
%% Cell type:markdown id: tags: %% 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: 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: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int i = 5; int i = 5;
std::cout << "Is " << i << " even? -> " << (i % 2 == 0 ? "true" : "false") << std::endl; std::cout << "Is " << i << " even? -> " << (i % 2 == 0 ? "true" : "false") << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
Is 5 even? -> false Is 5 even? -> false
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
It is really the same as: It is really the same as:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int i = 5; int i = 5;
std::cout << "Is " << i << " even? -> "; std::cout << "Is " << i << " even? -> ";
if (i % 2 == 0) if (i % 2 == 0)
std::cout << "true" << std::endl; std::cout << "true" << std::endl;
else else
std::cout << "false" << std::endl; std::cout << "false" << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
Is 5 even? -> False Is 5 even? -> False
%% Cell type:markdown id: tags: %% 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: 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: %% Cell type:code id: tags:
``` C++17 ``` C++17
{ {
int i = 5; int i = 5;
const int is_strictly_positive = (i > 0 ? 1 : 0); const int is_strictly_positive = (i > 0 ? 1 : 0);
std::cout << is_strictly_positive << std::endl; std::cout << is_strictly_positive << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
1 1
%% Cell type:markdown id: tags: %% 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 it doesn't work: both ways to do so that might step in mind are flawed:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
{ {
int i = 5; int i = 5;
const int is_strictly_positive; const int is_strictly_positive;
if (i > 0) if (i > 0)
is_strictly_positive = 1; // COMPILATION ERROR: can't assign to const value! is_strictly_positive = 1; // COMPILATION ERROR: can't assign to const value!
// ... // ...
} }
``` ```
%%%% Output: stream %%%% Output: stream
input_line_67:4:15: error: default initialization of an object of const type 'const int' input_line_67:4:15: error: default initialization of an object of const type 'const int'
const int is_strictly_positive; const int is_strictly_positive;
 ^  ^
 = 0  = 0
input_line_67:7:30: error: cannot assign to variable 'is_strictly_positive' with const-qualified type input_line_67:7:30: error: cannot assign to variable 'is_strictly_positive' with const-qualified type
'const int' 'const int'
is_strictly_positive = 1; // COMPILATION ERROR: can't assign to ... is_strictly_positive = 1; // COMPILATION ERROR: can't assign to ...
 ~~~~~~~~~~~~~~~~~~~~ ^  ~~~~~~~~~~~~~~~~~~~~ ^
input_line_67:4:15: note: variable 'is_strictly_positive' declared const here input_line_67:4:15: note: variable 'is_strictly_positive' declared const here
const int is_strictly_positive; const int is_strictly_positive;
 ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
 
%%%% Output: error %%%% Output: error
Interpreter Error: Interpreter Error:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
{ {
int i = 5; int i = 5;
if (i > 0) if (i > 0)
{ {
const int is_strictly_positive = 1; const int is_strictly_positive = 1;
} }
else else
const int is_strictly_positive = 0; const int is_strictly_positive = 0;
std::cout << is_strictly_positive << std::endl; // COMPILATION ERROR: is_strictly_positive not std::cout << is_strictly_positive << std::endl; // COMPILATION ERROR: is_strictly_positive not
// in the current scope. // in the current scope.
} }
``` ```
%%%% Output: stream %%%% Output: stream
input_line_68:12:18: error: use of undeclared identifier 'is_strictly_positive' input_line_68:12:18: error: use of undeclared identifier 'is_strictly_positive'
std::cout << is_strictly_positive << std::endl; // COMPILATION ERROR... std::cout << is_strictly_positive << std::endl; // COMPILATION ERROR...
 ^  ^
 
%%%% Output: error %%%% Output: error
Interpreter Error: Interpreter Error:
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### `switch` statement ### `switch` statement
Very briefly: there is also a `switch` statement that can be used when: 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](/notebooks/1-ProceduralProgramming/3-Types.ipynb#Enumerations)) or might be convertible into one of those.
* The relationship considered is an equality. * 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](/notebooks/7-Appendix/Switch.ipynb) but we do not have yet seen all the elements needed to explain its interest.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## Logical operators ## Logical operators
A condition might be an amalgation of several conditions. The way to glue it is to use logical operators. A condition might be an amalgation of several conditions. The way to glue it is to use logical operators.
The operators are: The operators are:
* `&&` for the **and** operator. * `&&` for the **and** operator.
* `||` for the **or** operator. * `||` for the **or** operator.
* `!` for the **not** 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...). 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: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int a = 2; int a = 2;
int b = 3; int b = 3;
if (a == 2 || b == 5) if (a == 2 || b == 5)
std::cout << "Ok: first condition is true." << std::endl; std::cout << "Ok: first condition is true." << std::endl;
if (a == 2 or b == 5) if (a == 2 or b == 5)
std::cout << "Same as above illustrating the alternative representation." << std::endl; std::cout << "Same as above illustrating the alternative representation." << std::endl;
if (a == 2 && b == 5) if (a == 2 && b == 5)
std::cout << "Not printed: one condition is false." << std::endl; std::cout << "Not printed: one condition is false." << std::endl;
if (!(a < 0)) if (!(a < 0))
std::cout << "Ok: a < 0 is false so the `not` operator returns true." << std::endl; std::cout << "Ok: a < 0 is false so the `not` operator returns true." << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
Ok: first condition is true. Ok: first condition is true.
Same as above illustrating the alternative representation. Same as above illustrating the alternative representation.
Ok: a < 0 is false so the `not` operator returns true. Ok: a < 0 is false so the `not` operator returns true.
%% Cell type:markdown id: tags: %% 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: 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: %% Cell type:code id: tags:
``` C++17 ``` C++17
{ {
int a = 2; int a = 2;
int b = 3; int b = 3;
if (a == 5 || a == 2 && 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; 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)) if ((a == 5) || (a == 2 && b == 3))
std::cout << "Same but easier to grasp." << std::endl; std::cout << "Same but easier to grasp." << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
input_line_20:6:26: warning: '&&' within '||' [-Wlogical-op-parentheses] input_line_20:6:26: warning: '&&' within '||' [-Wlogical-op-parentheses]
if (a == 5 || a == 2 && b == 3) if (a == 5 || a == 2 && b == 3)
 ~~ ~~~~~~~^~~~~~~~~  ~~ ~~~~~~~^~~~~~~~~
input_line_20:6:26: note: place parentheses around the '&&' expression to silence this warning input_line_20:6:26: note: place parentheses around the '&&' expression to silence this warning
if (a == 5 || a == 2 && b == 3) if (a == 5 || a == 2 && b == 3)
 ^  ^
 ( )  ( )
 
%%%% Output: stream %%%% Output: stream
(a == 5) and (a == 2 && b == 3) are evaluated separately and the latter is true so this text is printed (a == 5) and (a == 2 && b == 3) are evaluated separately and the latter is true so this text is printed
Same but easier to grasp. Same but easier to grasp.
%% Cell type:markdown id: tags: %% 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! 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: %% Cell type:code id: tags:
``` C++17 ``` C++17
{ {
int a = 2; int a = 2;
int b = 3; int b = 3;
if (a > 0 || ++b < 10) if (a > 0 || ++b < 10)
std::cout << "b is still " << b << ": as the first operand was true ++b was never evaluated." << std::endl; std::cout << "b is still " << b << ": as the first operand was true ++b was never evaluated." << std::endl;
b = 3; b = 3;
if (++b < 10 || a > 0) if (++b < 10 || a > 0)
std::cout << "b is now " << b << ": the first operand run is not the same..." << std::endl; std::cout << "b is now " << b << ": the first operand run is not the same..." << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
b is still 3: as the first operand was true ++b was never evaluated. b is still 3: as the first operand was true ++b was never evaluated.
b is now 4: the first operand run is not the same... b is now 4: the first operand run is not the same...
%% Cell type:markdown id: tags: %% 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. 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: %% Cell type:markdown id: tags:
## Loops ## Loops
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### `while` loop ### `while` loop
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
The `while` instruction allows you to execute a block of instructions in a loop 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 as long as a condition is true. The condition is checked **before** each
iteration. iteration.
The rules about the instructions belonging to the loop are exactly the same as the ones described for `if` statements. The rules about the instructions belonging to the loop are exactly the same as the ones described for `if` statements.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int a = 0; int a = 0;
while (a++ < 5) while (a++ < 5)
std::cout << a << std::endl; std::cout << a << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
1 1
2 2
3 3
4 4
5 5
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
If the condition is never true in the first place, we never go inside the loop: If the condition is never true in the first place, we never go inside the loop:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int a = 0; int a = 0;
while (a++ < 0) while (a++ < 0)
std::cout << a << std::endl; std::cout << a << std::endl;
} }
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### `do`...`while` loop ### `do`...`while` loop
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
The `do` instruction allows you to execute a block of instructions in a loop as long as The `do` instruction allows you to execute a block of instructions in a loop as long as
that a condition is true. The condition is verified **after** each that a condition is true. The condition is verified **after** each
iteration. iteration.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int a = 0; int a = 0;
do do
{ {
std::cout << a << std::endl; std::cout << a << std::endl;
} while (a++ < 0); // there is a semicolon here. } while (a++ < 0); // there is a semicolon here.
} }
``` ```
%%%% Output: stream %%%% Output: stream
0 0
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### `for` loop ### `for` loop
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
#### Historical `for` loop #### Historical `for` loop
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
The historical `for` instruction allows you to execute a block of instructions as long as a The historical `for` instruction allows you to execute a block of instructions as long as a
condition is true; the difference with the `while` loop is that there are fields explicitly detailing: condition is true; the difference with the `while` loop is that there are fields explicitly detailing:
* The initial situation. * The initial situation.
* The condition to check at the end of each loop. * The condition to check at the end of each loop.
* What should be changed in next loop is one is called for. * What should be changed in next loop is one is called for.
Syntax is: Syntax is:
for (_initial situation_ ; _end loop condition_ ; _evolution for next loop_) for (_initial situation_ ; _end loop condition_ ; _evolution for next loop_)
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
for (int i = 0; i < 5; ++i) for (int i = 0; i < 5; ++i)
std::cout << i << std::endl; std::cout << i << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
0 0
1 1
2 2
3 3
4 4
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Any of these fields might be left empty: Any of these fields might be left empty:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int i = 0; // i might also be declared and initialized outside the block int i = 0; // i might also be declared and initialized outside the block
for ( ; i < 5; ) for ( ; i < 5; )
{ {
++i; // i might also be modified within the block ++i; // i might also be modified within the block
std::cout << i << std::endl; std::cout << i << std::endl;
} }
std::cout << "`for` loop stopped for i = " << i << std::endl; std::cout << "`for` loop stopped for i = " << i << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
1 1
2 2
3 3
4 4
5 5
`for` loop stopped for i = 5 `for` loop stopped for i = 5
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
#### New `for` loop #### New `for` loop
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
The `for`syntax we just saw is still very useful, but C++ 11 introduced a new syntax when for instance you want to iterate through all the items in a container, clearly taking inspiration from syntax present in languages such as Python: The `for`syntax we just saw is still very useful, but C++ 11 introduced a new syntax when for instance you want to iterate through all the items in a container, clearly taking inspiration from syntax present in languages such as Python:
for (_type_ _element_ : _container_) for (_type_ _element_ : _container_)
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
#include <vector> // we'll present this one more in detail later #include <vector> // we'll present this one more in detail later
{ {
std::vector<int> v { 2, 3, 5, 7 }; std::vector<int> v { 2, 3, 5, 7 };
for (int item : v) for (int item : v)
std::cout << item << std::endl; std::cout << item << std::endl;
} }
``` ```
%%%% Output: stream %%%% Output: stream
2 2
3 3
5 5
7 7
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
It might not seem much, but just for the record doing the same before C++ 11 was not for the faint of heart...: It might not seem much, but just for the record doing the same before C++ 11 was not for the faint of heart...:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
#include <vector> // we'll present this one more in detail later #include <vector> // we'll present this one more in detail later
{ {
std::vector<int> v { 2, 3, 5, 7 }; std::vector<int> v { 2, 3, 5, 7 };
for (std::vector<int>::const_iterator it = v.cbegin(), end = v.cend(); for (std::vector<int>::const_iterator it = v.cbegin(), end = v.cend();
it != end; it != end;
++it) ++it)
{ {
std::cout << *it << std::endl; std::cout << *it << std::endl;
} }
} }
``` ```
%%%% Output: stream %%%% Output: stream
2 2
3 3
5 5
7 7
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### continue, break and infinite loop ### continue, break and infinite loop
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
A danger with a loop is to make it infinite: you have to make sure an exit way is foreseen: A danger with a loop is to make it infinite: you have to make sure an exit way is foreseen:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
// WARNING: if you run this you will have to restart your kernel! (in Kernel menu) // WARNING: if you run this you will have to restart your kernel! (in Kernel menu)
{ {
int i = 2; int i = 2;
while (i > 0) // condition that is true for quite a long time... while (i > 0) // condition that is true for quite a long time...
std::cout << ++i << " "; std::cout << ++i << " ";
} }
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
The best is to write a palatable condition to end it, but when some loops become increasingly complex you may have to resort to `break`. Be aware it is slightly frown upon by some programmers, for the very same reasons [goto](https://en.wikipedia.org/wiki/Goto) instructions are avoided. The best is to write a palatable condition to end it, but when some loops become increasingly complex you may have to resort to `break`. Be aware it is slightly frown upon by some programmers, for the very same reasons [goto](https://en.wikipedia.org/wiki/Goto) instructions are avoided.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int i = 2; int i = 2;
while (i > 0) while (i > 0)
{ {
std::cout << i++ << " "; std::cout << i++ << " ";
if (i > 20) if (i > 20)
break; break;
} }
} }
``` ```
%%%% Output: stream %%%% Output: stream
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
In this trivial case writing the condition more properly would be of course much better: In this trivial case writing the condition more properly would be of course much better:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
int i = 2; int i = 2;
while (i > 0 and i <= 20) while (i > 0 and i <= 20)
std::cout << i++ << " "; std::cout << i++ << " ";
} }
``` ```
%%%% Output: stream %%%% Output: stream
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
but honestly in more complex cases `break` can help keep the code more readable. but honestly in more complex cases `break` can help keep the code more readable.
`continue` is related: it is useful when in some conditions you want to skip the remainder of the current loop iteration to go directly to the next: `continue` is related: it is useful when in some conditions you want to skip the remainder of the current loop iteration to go directly to the next:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
#include <iostream> #include <iostream>
{ {
for (int i = 2; i < 20; ++i) for (int i = 2; i < 20; ++i)
{ {
if (i == 2) if (i == 2)
{ {
std::cout << i << " is even and prime (hello 2!)." << std::endl; std::cout << i << " is even and prime (hello 2!)." << std::endl;
continue; continue;
} }
if (i % 2 == 0) if (i % 2 == 0)
{ {
std::cout << i << " is even." << std::endl; std::cout << i << " is even." << std::endl;
continue; // goes directly at the condition checking step in the loop, continue; // goes directly at the condition checking step in the loop,
// skipping the remaining code below. // skipping the remaining code below.
} }
std::cout << i << " is odd"; std::cout << i << " is odd";
bool is_prime = true; bool is_prime = true;
for (int j = 2; j < i / 2; ++j) for (int j = 2; j < i / 2; ++j)
{ {
if (i % j == 0) if (i % j == 0)
{ {
is_prime = false; is_prime = false;
break; // this break cuts the inner loop 'for (int j = 1; j < i / 2; ++j)' break; // this break cuts the inner loop 'for (int j = 1; j < i / 2; ++j)'
} }
} }
std::cout << (is_prime ? " and prime." : ".") << std::endl; std::cout << (is_prime ? " and prime." : ".") << std::endl;
} }
} }
``` ```
%%%% Output: stream %%%% Output: stream
2 is even and prime (hello 2!). 2 is even and prime (hello 2!).
3 is odd and prime. 3 is odd and prime.
4 is even. 4 is even.
5 is odd and prime. 5 is odd and prime.
6 is even. 6 is even.
7 is odd and prime. 7 is odd and prime.
8 is even. 8 is even.
9 is odd. 9 is odd.
10 is even. 10 is even.
11 is odd and prime. 11 is odd and prime.
12 is even. 12 is even.
13 is odd and prime. 13 is odd and prime.
14 is even. 14 is even.
15 is odd. 15 is odd.
16 is even. 16 is even.
17 is odd and prime. 17 is odd and prime.
18 is even. 18 is even.
19 is odd and prime. 19 is odd and prime.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Of course, in a trivial example like this one we could have written it much more cleanly without any `continue`, but in more complex cases it is really handful to use it: not using it could lead to code much more complicated to understand, and you really should always strive for code that is the most palatable for a reader. Of course, in a trivial example like this one we could have written it much more cleanly without any `continue`, but in more complex cases it is really handful to use it: not using it could lead to code much more complicated to understand, and you really should always strive for code that is the most palatable for a reader.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### So which loop should I use? ### So which loop should I use?
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Whichever you want in fact! Whichever you want in fact!
They are mostly interchangeable: They are mostly interchangeable:
* `while` and (historical) `for` are completely interchangeable, as: * `while` and (historical) `for` are completely interchangeable, as:
- A `while` loop is exactly like a `for ` loop with only the middle term. - A `while` loop is exactly like a `for ` loop with only the middle term.
- You can transform the loop into a while: putting the first term before the loop and the third one inside the loop to do so. - You can transform the loop into a while: putting the first term before the loop and the third one inside the loop to do so.
* `do..while` behaves slightly differently, but you can always mimic the behaviour with another type of loop. * `do..while` behaves slightly differently, but you can always mimic the behaviour with another type of loop.
Lots of programming language define these guys (at least `for` and `while`) so it's useful to know about them, but you can choose one and stick with it as well. Lots of programming language define these guys (at least `for` and `while`) so it's useful to know about them, but you can choose one and stick with it as well.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
© _CNRS 2016_ - _Inria 2018_ © _CNRS 2016_ - _Inria 2018-2019_
_This notebook is an adaptation of a lecture prepared and redacted 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/)_ _This notebook is an adaptation of a lecture prepared and redacted 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 redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_ _The present version has been redacted by Sébastien Gilles and Vincent Rouvreau (Inria)_
......
...@@ -1095,7 +1095,7 @@ ...@@ -1095,7 +1095,7 @@
"metadata": {}, "metadata": {},
"source": [