Commit 461e5963 authored by ROUVREAU Vincent's avatar ROUVREAU Vincent
Browse files

Typo: a *= 7; // multiply current value of a by **3**

parent 20df7997
%% Cell type:markdown id: tags:
# [Getting started in C++](/) - [Procedural programming](./0-main.ipynb) - [Predefined types](./1-Variables.ipynb)
%% Cell type:markdown id: tags:
<h1>Table of contents<span class="tocSkip"></span></h1>
<div class="toc"><ul class="toc-item"><li><span><a href="#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="#Cheatsheet:-pointers-and-reference-syntax" data-toc-modified-id="Cheatsheet:-pointers-and-reference-syntax-3.1">Cheatsheet: pointers and reference syntax</a></span></li><li><span><a href="#Chaining-pointers" data-toc-modified-id="Chaining-pointers-3.2">Chaining pointers</a></span></li><li><span><a href="#nullptr" data-toc-modified-id="nullptr-3.3"><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:
## Ordinary variables
%% Cell type:markdown id: tags:
### Declaration
%% 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
the variable, followed by its name and a semicolon.
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
int number; // integer variable
double real; // floating-point variable
std::cout << number << std::endl;
std::cout << real << std::endl;
}
```
%% Cell type:markdown id: tags:
### Initialisation
%% Cell type:markdown id: tags:
Although not mandatory, it is **strongly** recommended to give a
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!
If you give braces without values, a predefined and associated value
to the type is used (usually a form of 0).
%% Cell type:code id: tags:
``` C++17
{
int nb1 { 1 }; // integer variable set with the value 1
int nb2 {}; // same as int nb2{0};
double pi { 3.14 }; // real variable
}
```
%% Cell type:markdown id: tags:
C++ actually supports many other historical forms
of initialization, which you will encounter everywhere, including in this tutorial,
with brackets and/or an equal sign. There are some subtle differences
between each other... that you can ignore most of the time.
%% Cell type:code id: tags:
``` C++17
{
int a = 5;
int b(5);
int c = { 5 };
}
```
%% Cell type:markdown id: tags:
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
important when we will define our own types).
%% Cell type:markdown id: tags:
### Affectation
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
on the right of the `=` sign is evaluated, and its result is assigned to the variable.
%% Cell type:code id: tags:
``` C++17
#include <iostream> // for std::cout and std::endl
{
int a {}, b {}, c {} ; // default initialization; set the values to 0
std::cout << "Default initialization: a = " << a << ", b = " << b << " and c = " << c << std::endl;
a = 4;
b = 7;
c = a + b;
std::cout << "After affectations: a = " << a << ", b = " << b << " and c = " << c << std::endl;
}
```
%% Cell type:markdown id: tags:
Affectations may be chained:
%% Cell type:code id: tags:
``` C++17
{
int a {}, b {}, c {};
a = b = c = 5;
std::cout << "a = " << a << ", b = " << b << " and c = " << c << std::endl;
}
```
%% 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:
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
int a {}, b {}, c {} ; // default initialization; set the values to 0
a += 4; // add 4 to the current value of a
std::cout << "a = " << a << std::endl;
a *= 7; // multiply current value of a by 3
a *= 7; // multiply current value of a by 7
std::cout << "a = " << a << std::endl;
a /= 5; // divide a by 5 and assign the quotient to a
std::cout << "a = " << a << std::endl;
}
```
%% Cell type:markdown id: tags:
### 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.
* 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**.
An example is the better way to explain the difference between both:
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
int a = 5;
int b = 3;
a++; // increment a by 1.
++a; // same, both are actually equivalents here.
int c = a + b;
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.
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.
std::cout << "a = " << a << ", b = " << b << " and c = " << c << std::endl;
}
```
%% Cell type:markdown id: tags:
Honestly it's usually better to remove any ambiguity by separating explicitly both operations:
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
int a = 7;
int b = 3;
int c = a + b;
std::cout << "a = " << a << ", b = " << b << " and c = " << c << std::endl;
c = a + b;
--a; // equivalent to a-- but for reasons related to the standard library I advise you
// to rather use the pre-increment form when both are equivalent.
std::cout << "a = " << a << ", b = " << b << " and c = " << c << std::endl;
++b; // same: equivalent to b++;
c = a + b;
std::cout << "a = " << a << ", b = " << b << " and c = " << c << std::endl;
}
```
%% Cell type:markdown id: tags:
### Comparing values
As shown above, `=` is the affectation operator. To compare two values, the symbol to use is `==`.
Other arithmetic operators are:
| Operator | Effect |
|:------------- |:-------------------------------------------:|
| `a == b` | `true` if a and b are equals |
| `a != b` | `true` if a and b are different |
| `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 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](../3-Operators/2-Comparison.ipynb)).
%% Cell type:markdown id: tags:
## References
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
indicating on which variable it should point; it cannot be changed after that.
The syntax is to add a `&` character just after the type:
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
int a { 2 };
int b { a };
b = b + 1;
int& c { a }; // c is a reference to a
std::cout << "Initial values : a = " << a << ", b = " << b << " and c = " << c << std::endl;
b = b + 5;
std::cout << "After b is modified: a = " << a << ", b = " << b << " and c = " << c << std::endl;
c = c + 1 ;
std::cout << "After c is modified: a = " << a << ", b = " << b << " and c = " << c << std::endl;
a *= 3;
std::cout << "After a is modified: a = " << a << ", b = " << b << " and c = " << c << std::endl;
}
```
%% Cell type:markdown id: tags:
Reference is a purely C++ concept that doesn't exist in C.
%% Cell type:markdown id: tags:
## Pointers
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
of another variable. To explicitly extract the address of this other variable,
we use the symbol `&`.
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
int a { 2 };
int* p {&a}; // define a pointer p which is initialized with the address of a
std::cout << "a = " << a << std::endl;
std::cout << "p = " << p << std::endl;
}
```
%% Cell type:markdown id: tags:
You may ask the underlying value at a given address with `*` (I reckon: this syntax may be _very_ confusing at first...)
%% Cell type:code id: tags:
``` C++17
{
int a { 2 };
int* p {&a}; // define a pointer p which is initialized with the address of a
std::cout << "a = " << a << std::endl;
std::cout << "p = " << p << std::endl;
std::cout << "Value stored at p = " << *p << std::endl;
}
```
%% Cell type:markdown id: tags:
The `*` syntax msy be used to modify the underlying value:
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
int a { 2 };
int* p {&a}; // define a pointer p which is initialized with the address of a
std::cout << "Pointer " << p << " stores the value " << *p << std::endl;
std::cout << "After *p = *p + 5:" << std::endl;
*p = *p + 5;
std::cout << "Pointer " << p << " stores the value " << *p << std::endl;
}
```
%% Cell type:markdown id: tags:
Pointers may be used as variables by themselves and see their actual content changed during execution of a program:
%% Cell type:code id: tags:
``` C++17
{
int a { 2 }, b { 3 };
int* p {&a}; // define a pointer p which is initialized with the address of a
std::cout << "a = " << a << std::endl;
std::cout << "b = " << b << std::endl;
std::cout << "Value stored at p = " << *p << std::endl;
p = &b;
std::cout << "Value stored at p = " << *p << std::endl;
}
```
%% Cell type:markdown id: tags:
We can therefore see the pointer as a kind of redefinable reference (pointers are a feature from C language whereas references are a C++ specific feature).
%% Cell type:markdown id: tags:
### Cheatsheet: pointers and reference syntax
%% Cell type:markdown id: tags:
| Applied to: | A type `T` | A variable `x`
|:------------- |:-------------------------------------------:|:-------------------------------------------:|
| * | Pointer to an object of type `T` | Variable under `x` if `x` is a pointer, invalid code otherwise |
| & | Reference to an object of type `T` | Address of the variable (i.e. a pointer) |
%% Cell type:markdown id: tags:
### Chaining pointers
It is possible to chain pointers:
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
int n = 5;
int* p = &n;
int** q = &p;
std::cout << "*q is a pointer to an int (i.e. an address): " << *q << " - it is the same as what is stored in p: " << p << std::endl;
std::cout << "**q gives the original `n` value: " << **q << std::endl;
}
```
%% Cell type:markdown id: tags:
This was something that was very common in C, but that I do not recommend in C++ as there are much better ways to achieve the same goals (that we do not have seen yet, so don't panic if you do not understand why we would need this).
%% Cell type:markdown id: tags:
### `nullptr`
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`](../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.
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:
``` C++17
#include <iostream>
{
int* p = nullptr; // define a null pointer p
std::cout << "\t p: address = " << p << ", value = " << *p << std::endl; // Dereferencing p is misguided!
}
```
%% Cell type:markdown id: tags:
`nullptr` was introduced in C++ 11; if you're working with a legacy codebase that doesn't use this standard use `NULL` (but stick to `nullptr` for modern code!)
%% Cell type:markdown id: tags:
## 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:
%% Cell type:code id: tags:
``` C++17
{
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,
// so that is what you will see in the remaining of the lecture.
// There are however persuasive arguments for the other convention for which there are vocal
// see http://slashslash.info/eastconst/
pi = 5.; // COMPILATION ERROR!
pi_2 = 7.; // COMPILATION ERROR!
}
```
%% 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):
%% Cell type:code id: tags:
``` C++17
{
int a { 2 }, b { 3 };
int* p { &a }; // Both pointer and pointed values are modifiable.
p = &b; // OK
*p = 5; // OK
}
```
%% Cell type:code id: tags:
``` C++17
{
int a { 2 }, b { 3 };
int* const p { &a }; // Value is modifiable, but not the address pointed to.
*p = 5; // OK
p = &b; // COMPILATION ERROR - if you comment it it will
}
```
%% Cell type:code id: tags:
``` C++17
{
int a { 2 }, b { 3 };
const int* p { &a }; // Address pointed to is modifiable, but not the underlying value.
p = &b; // OK
*p = 5; // COMPILATION ERROR
}
```
%% Cell type:code id: tags:
``` C++17
{
int a { 2 }, b { 3 };
const int* const p { &a }; // Nothing is modifiable
p = &b; // COMPILATION ERROR
*p = 5; // COMPILATION ERROR
}
```
%% Cell type:markdown id: tags:
**IMPORTANT**: Even if declared `const`, the pointed value is
not intrinsically constant. It just can't be
modified through this precise pointer.
If other variables reference the same memory area and
are not constant, they are able to modify the value:
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
int a { 2 }, b { 3 };
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;
int* p2 {&a}; // Pointer to the same memory area, but no constness here.
*p2 = 10;
std::cout << "Value pointed by p (and modified through p2) is: " << *p << std::endl;
}
```
%% Cell type:markdown id: tags:
On the other hand, pointers can't be used as a work-around to modify a constant value:
%% Cell type:code id: tags:
``` C++17
{
const int n { 3 };
int* p_n { &n }; // COMPILATION ERROR
const int* p_n2 { &n }; // OK
}
```
%% Cell type:markdown id: tags:
## Arrays
The operator `[]` enables the creation of an array.
**Beware:** In C++, the indexes of an array start at 0.
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
int i[10] ; // Array of 10 integers - not initialised properly!
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[10] = " << i[10] << " (undefined behaviour: out of range. Warning identifies the issue)" << std::endl ;
std::cout << "x[1] = " << x[1] << " (expected: 2.)" << std::endl ;
}
```
%% Cell type:markdown id: tags:
Multi-dimensional arrays are also possible:
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
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[1][2] = " << k[1][2] << " (expected: 9)" << std::endl;
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[1][2] = " << l[1][2] << " (expected: 0)" << std::endl;
}
```
%% 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](./5-DynamicAllocation.ipynb#Arrays-on-heap) (and also with the standard libraries [alternatives](../5-UsefulConceptsAndSTL/3-Containers.ipynb) such as std::vector or std::array which are actually much more compelling).
%% Cell type:markdown id: tags:
### 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.
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
int i[2] = { 10, 20 } ;
std::cout << *i << " (expected: 10)" << std::endl;
std::cout << *i + 1 << " (expected: 11)" << std::endl;
std::cout << *(i + 1) << " (expected: 20)" << std::endl;
int* j = i; // OK!
++j; // OK!
std::cout << "Value pointed by j is " << *j << " (expected: 20)" << std::endl;
}
```
%% Cell type:markdown id: tags:
© _CNRS 2016_ - _Inria 2018-2020_
_This notebook is an adaptation of a lecture prepared by David Chamont (CNRS) under the terms of the licence [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](http://creativecommons.org/licenses/by-nc-sa/4.0/)_
_The present version has been written by Sébastien Gilles and Vincent Rouvreau (Inria)_
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment