---
title: Chapitre 2
subtitle: Structures de contrôle
order: 20
nocite:
  - "@guerin2021"
  - "@gustedt2024"
abstract: Présentation des instructions conditionnelles et des boucles en
  langage C. Étude des structures de contrôle permettant la prise de décision et
  la répétition d’instructions.
objectives:
  - Utiliser les structures conditionnelles if, else et switch
  - Mettre en œuvre des boucles `for`, `while` et `do while`
  - Contrôler le flux d’exécution avec `break` et `continue`.
  - Conversion de types et affichages spécifiques.
---

<!--  On va plus loin sur les types signés ou non et leur représentation en mémoire + leurs affichages spécifiques.

Opérateurs bit à bits -->

```{python}
#| echo: false
#| output: false
%load_ext jupygcc
```

<!-- TODO explorer cxx2flow: https://github.com/Enter-tainer/cxx2flow/blob/master/README-en.md -->

# Notion de bloc et portée des variables

Un bloc est une séquence d'instructions regroupées entre accolades `{}`.

Les variables déclarées dans un bloc sont locales à ce bloc et ne sont pas accessibles en dehors de celui-ci.

[Pour plus de détails, voir la documentation de gnu](https://www.gnu.org/software/c-intro-and-ref/manual/html_node/Blocks.html)

***

::: example

de bloc et portée

```{python}
%%gcc
int a = 3;
int b = 5;
printf("HORS BLOC: a = %d, b = %d\n", a, b);
{
  int b = 4;
  printf("DANS BLOC: a = %d, b = %d\n", a, b);
}
printf("HORS BLOC: a = %d, b = %d\n", a, b);
```

:::

# Les instructions conditionnelles

[Chapitre 5 @gazi2024]{.cite}

## Structure conditionnelle

Les instructions conditionnelles sont exécutées lorsque la condition est vraie.

```c
if (condition) {
  // Instructions à exécuter lorsque la condition est vraie
}
```

```c
if (condition) {
  // Instructions à exécuter lorsque la condition est vraie
} else {
  // Instructions à exécuter lorsque la condition est fausse
}
```

Une condition est acceptée comme vraie si elle a une valeur non nulle ou si c'est une expression booléenne avec une valeur vraie.

::: example

### Valeur entière différente de zéro

```{python}
%%gcc
int a = 10;
if (a) {
  printf("Inside if part \n");
} else {
  printf("Inside else part \n");
}
```

:::

***

## Échelle conditionnelle (If Ladder)

La structure de l'échelle conditionnelle est montrée dans le code suivant :

```c
if (condition - 1) {
  statements - 1;
} else if (condition - 2) {
  statements - 2;
} else if (condition - 3) {
  statements - 3;
}
..else { statements; }
```

::: example

### Utilisation de l'échelle conditionnelle

```{python}
%%gcc
//| stdin: -5
int num;
printf("Please enter an integer : ");
scanf("%d", &num);
if (num > 0) {
  printf("You entered a positive integer.");
} else if (num < 0) {
  printf("You entered a negative integer.");
} else {
  printf("You entered zero.");
}

```

:::

***

## Notions de calcul booléen

Plusieurs conditions peuvent être vérifiées en utilisant les opérateurs logiques AND et OR.

Le calcul booléen permet de manipuler des valeurs de vérité (vrai ou faux) à l'aide d'opérateurs logiques.

### Opérateurs logiques

- `&&` : ET logique
- `|` : OU logique
- `!` : NON logique

```c
if (condition1 && condition2) {
  // instructions à exécuter si condition1 ET condition2 sont vraies
}
```

L'opérateur AND donne un résultat vrai si toutes les conditions sont vraies ; d'autre part, l'opérateur OR donne vrai si une des conditions est vraie.

::: example

### Utilisation des opérateurs logiques

```{python}
%%gcc
int a = 4, b = -1, c = 13;
int and_result = (a == 4) && (b < 0) && (c > 10);
printf("and_result = %d", and_result);

```

:::

***

## Syntaxe de If-Else imbriqué

La syntaxe de if-else imbriqué est montrée dans le code suivant où l'imbrication est faite seulement dans la partie if.

```c
if (condition - 1) {
  // Exécuté lorsque condition-1 est vraie
  if (condition - 2) {
    // Exécuté lorsque condition-2 est vraie
  } else {
    // Exécuté lorsque condition-2 est fausse
  }
} else {
  // Exécuté lorsque condition-1 est fausse
}
```

::: example

### Utilisation de la structure if-else imbriquée

```{python}
%%gcc
//| stdin: 25
int num;
printf("Please enter an integer between 0 and 100 : ");
scanf("%d", &num);
if (num < 50) {
  printf("You entered a number smaller than 50. \n");
  if (num < 25)
    printf("You entered a number smaller than 25. \n");
  else
    printf("You entered a number greater than 25. \n");
} else {
  printf("You entered a number greater than 49. \n");
  if (num > 75)
    printf("You entered a number greater than 75. \n");
  else
    printf("You entered a number smaller than 75. \n");
}

```

:::

***

## Opérateur conditionnel en C

La syntaxe de l'opérateur conditionnel est

```c
(a) ? [exécuté si a est vrai] : [exécuté si a est faux];
```

Notez que toute valeur autre que zéro est acceptée comme vraie.

::: example

### Utilisation de l'opérateur conditionnel

```{python}
%%gcc

int a = 7;
int b;
b = (a) ? 6 : 8;
printf("b is : %d", b);

```

:::

***

## Instruction `switch`

La syntaxe de l'instruction switch est montrée dans le code suivant.

```c
switch (variable - name) {
  case value - 1:
    statements - 1;
    break;
  case value - 2:
    statements - 2;
    break;
  ... case value - N:
    statements - N;
    break;
  default:
    statements;
}
```

::: example

### Utilisation de l'instruction switch

```{python}
%%gcc
//| stdin: 5
int num;
printf("Enter an integer between 1 and 4, \n1 and 4 are included : \n");
scanf("%d", &num);
switch (num) {
  case 1:
    printf("You entered 1.");
    break;
  case 2:
    printf("You entered 2.");
    break;
  case 3:
    printf("You entered 3.");
    break;
  default:
    printf("You entered 4.");
    break;
}

```

:::

# Les boucles en C

[Chapitre 6 @gazi2024]{.cite}

## La boucle bornée `for`

La boucle `for` est utilisée pour exécuter un bloc de code un certain nombre de fois.

| Syntaxe                                               | Description                                              |
| ----------------------------------------------------- | -------------------------------------------------------- |
| `for(initialisation; condition; mise à jour) { ... }` | Exécute un bloc de code tant que la condition est vraie. |

***

::: example

### Boucle For Simple

```{python}
%%gcc

for (int a = 0; a < 3; a++) {
  printf("Inside for-loop, a = %d \n", a);
}

```

:::

***

::: example

### Boucle For avec Décrémentation

```{python}
%%gcc

for (int a = 2; a >= 0; a--) {
  printf("Inside for-loop, a = %d \n", a);
}

```

:::

***

::: example

### Boucle For avec Variables Multiples

```{python}
%%gcc

for (int a = 0, b = 0; a < 3 && b < 3; a++, b++) {
  printf("Inside for-loop, a = %d, b = %d \n", a, b);
}

```

:::

## La Boucle non bornée `while`

La boucle `while` est utilisée pour exécuter un bloc de code tant qu'une condition est vraie.

| Syntaxe                    | Description                                              |
| -------------------------- | -------------------------------------------------------- |
| `while(condition) { ... }` | Exécute un bloc de code tant que la condition est vraie. |

***

::: example

### Boucle While Simple

```{python}
%%gcc

int a = 2;
while (a < 9) {
  printf("Inside while-loop, a = %d \n", a);
  a = a + 2;
}

```

:::

***

::: example

### Boucle `while` avec Condition Logique

```{python}
%%gcc
int a = 2;
while (a < 10 && a > 0) {
  printf("Inside while-loop, a = %d \n", a);
  a = a + 2;
}

```

:::

## La boucle non bornée `do {} while()`

La boucle `do {} while()` est utilisée pour exécuter un bloc de code au moins une fois, puis tant qu'une condition est vraie.

| Syntaxe                        | Description                                                                      |
| ------------------------------ | -------------------------------------------------------------------------------- |
| `do { ... } while(condition);` | Exécute un bloc de code au moins une fois, puis tant que la condition est vraie. |

::: example

### Boucle `do {} while()`

```{python}
%%gcc

int a = 2;
do {
  printf("Inside do-while loop, a = %d \n", a);
  a = a + 2;
} while (a < 9);

```

:::

## Instructions `continue` et `break`

Les instructions `continue` et `break` sont utilisées pour contrôler le flux des boucles.

| Instruction | Description                                |
| ----------- | ------------------------------------------ |
| `continue;` | Passe à l'itération suivante de la boucle. |
| `break;`    | Sort de la boucle.                         |

::: example

### Utilisation de `continue`

```{python}
%%gcc

for (int a = 0; a < 7; a++) {
  if (a == 3) continue;
  printf("a = %d \n", a);
}

```

:::

::: example

### Utilisation de `break`

```{python}
%%gcc
for (int a = 0; a < 7; a++) {
  if (a == 3) break;
  printf("a = %d \n", a);
}

```

:::

## La boucle `while`

La boucle `while` permet de répéter un bloc de code tant qu'une condition est vraie.

```c
while (condition) {
  // instructions à répéter tant que la condition est vraie
}
```

::: example

avec `while`

```{python}
%%gcc

int i = 0;
while (i < 5) {
  printf("i = %d\n", i);
  i++;
}
```

:::

***

## La boucle `for`

La boucle `for` permet de répéter un bloc de code un nombre spécifique de fois.

```c
for (initialisation; condition; progression) {
  // instructions à répéter
}
```

::: example

avec `for`

```{python}
%%gcc

for (int i = 0; i < 5; i++) {
  printf("i = %d\n", i);
}
```

:::

***

## La boucle `do while`

La boucle `do while` permet de répéter un bloc de code au moins une fois, puis tant qu'une condition est vraie.

```c
do {
  // instructions à répéter
} while (condition);
```

::: example

avec `do while`

```{python}
%%gcc

int i = 0;
do {
  printf("i = %d\n", i);
  i++;
} while (i < 5);

```

:::

***

## Les instructions `break` et `continue`

- `break` : permet de sortir d'une boucle.
- `continue` : permet de passer à l'itération suivante d'une boucle.

```c
for (int i = 0; i < 10; i++) {
  if (i == 5) {
    break;  // sort de la boucle lorsque i est égal à 5
  }
  if (i % 2 == 0) {
    continue;  // passe à l'itération suivante si i est pair
  }
  printf("i = %d\n", i);
}
```

***

## Les boucles imbriquées

Les boucles imbriquées permettent d'utiliser une boucle à l'intérieur d'une autre boucle.

```{python}
%%gcc
for (int i = 0; i < 3; i++) {
  for (int j = 0; j < 2; j++) {
    printf("i = %d, j = %d\n", i, j);
  }
}
```

***

## Les boucles infinies

Une boucle infinie est une boucle qui ne se termine jamais.

```c
while (1) {
  // instructions à répéter indéfiniment
}
```

::: {.callout-note collapse="true"}

### Affichages des entiers en C

| Format | Signification                                            | Exemple avec 1024 | Exemple avec -1024   |
| ------ | -------------------------------------------------------- | ----------------- | -------------------- |
| `%d`   | Entier signé (int)                                       | 1024              | -1024                |
| `%u`   | Entier non signé (unsigned int)                          | 1024              | 4294966296           |
| `%ld`  | Entier signé long (long int)                             | 1024              | -1024                |
| `%lu`  | Entier non signé long (unsigned long int)                | 1024              | 18446744073709551488 |
| `%x`   | Entier non signé en hexadécimal (unsigned int)           | 400               | ffffffffc00          |
| `%lx`  | Entier non signé long en hexadécimal (unsigned long int) | 400               | ffffffffffffffc00    |

:::

# A classer

::: {.callout-note collapse="true"}

### Conversions de type en C

En C, la conversion de type peut être explicite ou implicite. Voici un aperçu des différentes formes de conversion de type, avec des exemples utilisant des expressions arithmétiques:

#### Conversion Explicite (Casting)

La conversion explicite, également appelée "casting", est effectuée par le programmeur en utilisant l'opérateur de cast. Cela permet de convertir une variable d'un type de données à un autre.

\*\*Syntaxe: \*\*

```c
(type) expression
```

**Exemple**

```c
int a = 10;
float b = (float)a;  // Conversion explicite de int à float
```

#### Conversion Implicite

La conversion implicite est effectuée automatiquement par le compilateur lorsque cela est nécessaire pour éviter des erreurs de type. Il existe plusieurs types de conversions implicites:

##### Ordre des conversions

1. **Promotion intégrale** :

   `char`, `short`, `unsigned char`, `unsigned short` sont promus à `int` ou `unsigned int`.

2. **Conversion des types entiers** :

   `unsigned long long` > `long long` > `unsigned long` > `long` > `unsigned int` > `int`

3. **Conversion des types flottants** :

   `long double` > `double` > `float`

4. **Conversion de Booléen**

   En C, il n'y a pas de type booléen natif avant C99. Cependant, les expressions booléennes sont souvent représentées par des entiers, où `0` est faux et tout autre valeur est vrai.

   **Exemple**

   ```c
   int a = 5;
   if (a + 1) {  // Conversion implicite de int à booléen (vrai si a + 1 != 0) dans
                 // l'expression arithmétique
     // Code exécuté si a + 1 est vrai
   }
   ```

##### Points à Noter

- \*\*Perte de Données: \*\* Les conversions implicites peuvent entraîner une perte de données, surtout lors de la conversion de types flottants à des types entiers.
- \*\*Précision: \*\* Les conversions de types flottants peuvent également entraîner une perte de précision.
- \*\*Sécurité: \*\* Les conversions explicites doivent être utilisées avec prudence pour éviter des erreurs logiques.

:::

::: {.callout-warning}

### En C, l'affectation est à la fois une instruction et une expression.

- **Instruction**: Une unité de code qui spécifie une action à effectuer, généralement terminée par un point-virgule.
- **Expression**: Une combinaison de variables, opérateurs et valeurs qui évalue à une valeur.

L'affectation modifie l'état d'une variable (instruction) et produit une valeur (expression).

Par exemple:

```c
int a, b;
a = b = 5;  // L'affectation est une instruction qui contient l'expression b =
            // 5, retournant 5, qui est ensuite affecté à a.
```

Ainsi, l'affectation est à la fois une instruction et une expression.

:::

## Conversion de type en C

```{python}
%%gcc

float myFloat = 18;
printf("%f\n", myFloat);

```

## Conversion implicite

```{python}
%%gcc

int a = 23.45;
printf("%d\n", a);

```

## Conversion explicite

```{python}
%%gcc

float a = (float)7 / 2;
printf("a = %.1f\n", a);

```

## Perte d'information lors de la conversion d'une donnée d'ordre supérieur en une donnée d'ordre inférieur

```{python}
%%gcc

int a = 0B01111111111111110000000000000000;
short b = a;
printf("a = %d\n", a);
printf("b = %d\n", b);

```

## Perte d'information lors de la conversion entre types de données signés et non signés

```{python}
%%gcc

short int a = -8;
unsigned short int b = 4;
unsigned short int c = a + b;
printf("a = %hd\n", a);
printf("b = %hu\n", b);
printf("c = %hu\n", c);

```

# Conversion de type en C

## Introduction

La conversion de type est le processus de conversion d'une valeur d'un type de données à un autre.

## Méthodes de conversion de type

- Conversion implicite (automatique)
- Conversion explicite (manuelle)

## Conversion implicite

- Exemple :
  ```c
  float myFloat = 18;
  ```

## Conversion explicite

- Exemple :
  ```c
  float a = (float)7 / 2;
  ```

## Perte d'information lors de la conversion d'une donnée d'ordre supérieur en une donnée d'ordre inférieur

- Exemple :
  ```c
  int a = 0B01111111111111110000000000000000;
  short b = a;
  ```

## Perte d'information lors de la conversion entre types de données signés et non signés

- Exemple :
  ```c
  short int a = -8;
  unsigned short int b = 4;
  unsigned short int c = a + b;
  ```

***

## Entiers positifs

```{python}
%%gcc
int positif = 0xFF;
printf("Décimal : %d\n", positif);
```

## Forme du complément à deux

```{python}
%%gcc

int num = 0b10101110001000;
int complement_a_deux = ~num + 1;
printf("Complément à deux : %d\n", complement_a_deux);

```

## Entiers négatifs

```{python}
%%gcc

int negatif = -17;
printf("Binaire : %d\n", negatif);

```

## Registres

```{python}
%%gcc

int valeur_registre = 0b10101010;
printf("Valeur du registre : %d\n", valeur_registre);

```

## Unités de mémoire

```{python}
%%gcc

int adresse_memoire = 0x000000000065FE18;
printf("Adresse mémoire : %x\n", adresse_memoire);

```

## Little-Endian et Big-Endian

```{python}
%%gcc

int num = 0x1245A78F;
unsigned char *ptr = (unsigned char *)&num;
printf("Little-Endian : %x %x %x %x\n", ptr[0], ptr[1], ptr[2], ptr[3]);
printf("Big-Endian : %x %x %x %x\n", ptr[3], ptr[2], ptr[1], ptr[0]);

```

## Types de données et opérateurs

```{python}
%%gcc

int a = 7, b = 5;
float c = 7.0, d = 2.0;
printf("Résultats sont : %d %f %f\n", a / b, a / d, c / b);

```

# Types de données et opérateurs

[Chapitre 2 @gazi2024]{.cite}

## Introduction

La programmation en C implique divers types de données et opérateurs pour effectuer des opérations.

## Comment commencer à écrire un programme C

- Modèle de fonction principale :
  ```c
  int main(void) {
    // instructions
    return 0;
  }
  ```

## Premier programme C

- Exemple :
  ```c
  #include <stdio.h>
  int main() { printf("Bonjour le monde."); }
  ```

## Représentation des nombres binaires en C moderne

- Les nombres binaires peuvent être exprimés en utilisant le préfixe `0b` ou `0B`.
- Exemple :
  ```c
  char ch = 0b01111110;
  ```

## Opérateur `sizeof` en C

- Exemple :
  ```c
  printf("Taille de char est %d ", sizeof(char));
  ```

## Type de données Unsigned Char

- Exemple :
  ```c
  unsigned char uc_max = UCHAR_MAX;
  ```

## Opérateurs de décalage gauche et droite en C

- Exemple :
  ```{python}
  %%gcc
  unsigned char a = 5;
  unsigned char d = a << 2;
  printf("d = %d\n", d);
  printf("d = %c\n", d);
  ```

## Type de données Entier

- Exemple :
  ```c
  int num;
  ```

## Nombres hexadécimaux et octaux

- Exemple :
  ```c
  int num1 = 0xF;
  int num2 = 15;
  int num3 = 0B1111;
  int num4 = 017;
  ```

## Comment les entiers sont-ils stockés dans la mémoire de l'ordinateur ?

- Exemple :
  ```c
  int num = 0x12345678;
  ```

## Type de données Entier court

- Exemple :
  ```c
  short int variable_name;
  ```

## Types de données Entier long et Entier long-long

- Exemple :
  ```c
  long int variable_name;
  long long int variable_name;
  ```

## Type de données Entier non signé

- Exemple :
  ```c
  unsigned int variable_name;
  ```

## Opérateurs en programmation C

- Opérateurs arithmétiques : `+`, `-`, `*`, `/`, `%`
- Opérateurs logiques : `&&`, ` |`, `!`
- Opérateurs bit à bit : `&`, `|`, `^`, `<<`, `>>`, `~`
- Opérateurs d'incrémentation et de décrémentation : `++`, `--`

## Priorité des opérateurs

- Tableau de priorité des opérateurs :

\| Priorité | Opérateur | Description | |------------|----------|-------------| | 1 | `[]` `()` `++` `--` | Indice de tableau, Appel de fonction ou parenthèses, Incrémentation et décrémentation postfixées | | 2 | `->` `.` | Accès membre via pointeur, Accès membre de structure et d'union | | 3 | `++` `--` | Incrémentation et décrémentation préfixées | | 4 | `+` `-` | Plus unaire, Moins unaire | | 5 | `(type)` `!` `~` | Opérateur de cast, NON logique et NON bit à bit | | 6 | `*` `/` `%` | Multiplication, division et reste | | 7 | `+` `-` | Addition et soustraction | | 8 | `<<` `>>` | Décalage bit à bit gauche et décalage bit à bit droite | | 9 | `<` `<=` | Opérateurs relationnels < et <= | | 10 | `>` `>=` | Opérateurs relationnels > et >= | | 11 | `==` `!=` | Opérateurs relationnels == et != | | 12 | `&` | ET bit à bit | | 13 | `^` | OU exclusif bit à bit | | 14 | `|` | OU bit à bit ou OU inclusif | | 15 | `&&` | ET logique | | 16 | `||` | OU logique | | 17 | `?:` | Conditionnel ternaire | | 18 | `=` | Affectation | | 19 | `+=` `-=` | Addition et soustraction augmentées | | 20 | `*=` `/=` | Multiplication et division augmentées | | 21 | `%=` `&=` | Reste et ET bit à bit augmentés | | 22 | `^=` `|=` | OU exclusif et OU inclusif bit à bit augmentés | | 23 | `<<=` `>>=` | Décalage bit à bit gauche et décalage bit à bit droite augmentés | | 24 | `,` | Virgule (séparateur d'expression) |

***
