-
orestis.malaspin authoredorestis.malaspin authored
- Historique (1/2)
- Historique (2/2)
- Qu'est-ce que le C?
- Exemple de programme
- Génération d'un exécutable
- La simplicité de C?
- Déclaration et typage
- Types de base (1/4)
- Numériques
- Types de base (2/4)
- Types de base (3/4)
- Booléens
- Types de base (4/4)
- Conversions
- Expressions et opérateurs (1/6)
- Expressions simples
- Expressions complexes
- Expressions et opérateurs (2/6)
- Opérateurs relationnels
- Expressions et opérateurs (3/6)
- Opérateurs logiques
- Expressions et opérateurs (4/6)
- Opérateurs arithmétiques
- Expressions et opérateurs (5/6)
- Opérateurs d'assignation
- Expressions et opérateurs (6/6)
- Opérateurs d'assignation (suite)
- Structures de contrôle: if{.C} .. else if{.C} .. else{.C} (1/2)
- Syntaxe
- Structures de contrôle: if{.C} .. else if{.C} .. else{.C} (2/2)
- Pièges
- Structures de contrôle: switch{.C} .. case{.C} (1/2)
- Structures de contrôle: switch{.C} .. case{.C} (2/2)
- Structures de contrôle: for{.C}, while{.C}, do ... while{.C} (1/4)
- La boucle for{.C}
- La boucle while{.C}
- La boucle do ... while{.C}
- Structures de contrôle: for{.C}, while{.C}, do ... while{.C} (2/4)
- La boucle for{.C}
- Structures de contrôle: for{.C}, while{.C}, do ... while{.C} (3/4)
- La boucle while{.C}
- La boucle do ... while{.C}
- Structures de contrôle: continue{.C}, break{.C} (4/4)
- Les variables (1/2)
- Variables et portée
- Les variables (2/2)
- Exemple
- Entrées/sorties: printf(){.C} (1/2)
- Généralités
- Entrées/sorties: printf(){.C} (2/2)
- Exemple
- Entrées/sorties: scanf(){.C} (1/2)
- Généralités
- Entrées/sorties: scanf(){.C} (2/2)
- Exemple
% Programmation séquentielle en C % Base I - Inspirés des slides de F. Glück % 18 septembre 2019
Historique (1/2)
- Conçu initialement pour la programmation des systèmes d’exploitation (UNIX).
- Créé par Dennis Ritchie à Bell Labs en 1972 dans la continuation de CPL, BCPL et B.
- Standardisé entre 1983 et 1988 (ANSI C).
- La syntaxe de C est devenue la base d’autres langages comme C++, Objective-C, Java, Go, C#, Rust, etc.
- Révisions plus récentes, notamment C99, C11, puis C18.
Historique (2/2)
- Développement de C lié au développement d’UNIX.
- UNIX a été initialement développé en assembleur:
- Les instructions assembleur sont de très bas niveau
- Les instructions assembleur sont spécifiques à l’architecture du processeur.
- Pour rendre UNIX portable, un langage de haut niveau (en 1972) était nécessaire.
- Comparé à l’assembleur, le C est :
- Un langage de "haut niveau": C offre des fonctions, des structures de données, des constructions de contrôle de flots (
while
{.C},for
{.C}, etc). - Portable: un programme C peut être exécuté sur un très grand nombre de plateformes (il suffit de recompiler le même code pour l’architecture voulue).
- Un langage de "haut niveau": C offre des fonctions, des structures de données, des constructions de contrôle de flots (
Qu'est-ce que le C?
- "Petit langage simple" (en 2019).
- Langage compilé, statiquement (et faiblement) typé, procédural, portable, très efficace.
- Langage "bas niveau" (en 2019): management explicite et manuelle de la mémoire (allocation/désallocation), grande liberté pour sa manipulation.
- Pas de structures de haut niveau: chaînes de caractères, vecteurs dynamiques, listes, ...
- Aucune validation ou presque sur la mémoire (pointeurs, overflows, ...).
Exemple de programme
#include <stdio.h>
#include <stdlib.h>
int main() {
printf("Enter n: "); // affichage
int n = 0; // déclaration et initialisation de n
scanf("%d", &n); // entrée au clavier
int sum = 0; // déclaration et initialisation de sum
for (int i = 0; i <= n; ++i) { // boucle
sum += i;
}
printf("Sum of the %d first integers: %d\n", n, sum);
if (sum != n * (n+1) / 2) { // branchement cond.
printf("Error: the answer is wrong.\n");
return EXIT_FAILURE; // code d'erreur
}
return EXIT_SUCCESS; // code de réussite
}
Génération d'un exécutable
-
Pour pouvoir être exécuté un code C doit être d'abord compilé (avec
gcc
ouclang
). -
Pour un code
prog.c
la compilation "minimale" est$ clang prog.c $ ./a.out # exécutable par défaut
-
Il existe une multitude d'options de compilation:
-
-std=c11
utilisation de C11. -
-Wall et -Wextra
activation des warnings. -
-fsanitize=…
contrôles d’erreurs extensifs à l’exécution (au prix d’un coût en performance). Sur Ubuntu 14.04-fsanitize=leak
et-fsanitize=undefined
ne sont pas supportés (cat /etc/lsb-release
indique la version). -
-g
symboles de débogages sont gardés. -
-o
défini le fichier exécutable à produire en sortie.
-
$ clang -std=c11 -Wall -Wextra -g porg.c -o prog
-fsanitize=address -fsanitize=leak -fsanitize=undefined
La simplicité de C?
- 32 mots-clé et c'est tout
auto
{.C} double
{.C} int
{.C} struct
{.C}
break
{.C} else
{.C} long
{.C} switch
{.C}
case
{.C} enum
{.C} register
{.C} typedef
{.C}
char
{.C} extern
{.C} return
{.C} union
{.C}
const
{.C} float
{.C} short
{.C} unsigned
{.C}
continue
{.C} for
{.C} signed
{.C} void
{.C}
default
{.C} goto
{.C} sizeof
{.C} volatile
{.C}
do
{.C} if
{.C} static
{.C} while
{.C}
Déclaration et typage
En C lorsqu'on veut utiliser une variable (ou une constante), on doit déclarer son type
const double two = 2.0; // déclaration et init.
int x; // déclaration (instruction)
char c; // déclaration (instruction)
x = 1; // affectation (expression)
c = 'a'; // affectation (expression)
int y = x; // déclaration et initialisation en même temps
int a, b, c; // déclarations multiples
int d = e = f = 1; // décl./init. multiples
Types de base (1/4)
Numériques
Type Signification (gcc pour x86-64)
char
{.C}, unsigned char
{.C} Entier signé/non-signé 8-bit
short
{.C}, unsigned short
{.C} Entier signé/non-signé 16-bit
int
{.C}, unsigned int
{.C} Entier signé/non-signé 32-bit
long
{.C}, unsigned long
{.C} Entier signé/non-signé 64-bit
float
{.C} Nombre à virgule flottante, simple précision
double
{.C} Nombre à virgule flottante, double précision
La signification de short
{.C}, int
{.C}, ... dépend du compilateur et de l'architecture.
Types de base (2/4)
Voir <stdint.h>
pour des représentations portables
Type Signification
int8_t
{.C}, uint8_t
{.C} Entier signé/non-signé 8-bit
int16_t
{.C}, uint16_t
{.C} Entier signé/non-signé 16-bit
int32_t
{.C}, uint32_t
{.C} Entier signé/non-signé 32-bit
int64_t
{.C}, uint64_t
{.C} Entier signé/non-signé 64-bit
Types de base (3/4)
Booléens
- Le ANSI C n'offre pas de booléens.
- L'entier
0
{.C} signifie faux, tout le reste vrai. - Depuis C99, la librairie
stdbool
met à disposition un typebool
{.C}. - En réalité c'est un entier:
-
1 \Rightarrow
true
{.C} -
0 \Rightarrow
false
{.C}
-
- On peut les manipuler comme des entier (les sommer, les multiplier, ...).
Types de base (4/4)
Conversions
- Les conversions se font de manière:
- Explicite:
int a = (int)2.8; double b = (double)a; int c = (int)(2.8+0.5);
- Implicite:
int a = 2.8; // warning, si activés, avec clang double b = a + 0.5; char c = b; // pas de warning... int d = 'c';
- Explicite:
Expressions et opérateurs (1/6)
Une expression est tout bout de code qui est évalué.
Expressions simples
- Pas d'opérateurs impliqués.
- Les littéraux, les variables, et les constantes.
const int L = -1; // 'L' est une constante, -1 un littéral
int x = 0; // '0' est un litéral
int y = x; // 'x' est une variable
int z = L; // 'L' est une constante
Expressions complexes
- Obtenues en combinant des opérandes avec des opérateurs
int x; // pas une expression (une instruction)
x = 4 + 5; // 4 + 5 est une expression
// dont le résultat est affecté à 'x'
Expressions et opérateurs (2/6)
Opérateurs relationnels
Opérateurs testant la relation entre deux expressions:
-
(a opérateur b)
retourne1
{.C} si l'expression s'évalue àtrue
{.C},0
{.C} si l'expression s'évalue àfalse
{.C}.
Opérateur | Syntaxe | Résultat |
---|---|---|
< {.C} |
a < b {.C} |
1 si a < b; 0 sinon |
> {.C} |
a > b {.C} |
1 si a > b; 0 sinon |
<= {.C} |
a <= b {.C} |
1 si a <= b; 0 sinon |
>= {.C} |
a >= b {.C} |
1 si a >= b; 0 sinon |
== {.C} |
a == b {.C} |
1 si a == b; 0 sinon |
!= {.C} |
a != b {.C} |
1 si a != b; 0 sinon |
Expressions et opérateurs (3/6)
Opérateurs logiques
Opérateur | Syntaxe | Signification |
---|---|---|
&& {.C} |
a && b {.C} |
ET logique |
` | `{.C} | |
! {.C} |
!a {.C} |
NON logique |
Expressions et opérateurs (4/6)
Opérateurs arithmétiques
Opérateur | Syntaxe | Signification |
---|---|---|
+ {.C} |
a + b {.C} |
Addition |
- {.C} |
a - b {.C} |
Soustraction |
* {.C} |
a * b {.C} |
Multiplication |
/ {.C} |
a / b {.C} |
Division |
% {.C} |
a % b {.C} |
Modulo |
Expressions et opérateurs (5/6)
Opérateurs d'assignation
Opérateur | Syntaxe | Signification |
---|---|---|
= {.C} |
a = b {.C} |
Affecte la valeur b à la variable a
|
et retourne la valeur de b
|
||
+= {.C} |
a += b {.C} |
Additionne la valeur de b à a et |
assigne le résultat à a . |
||
-= {.C} |
a -= b {.C} |
Soustrait la valeur de b à a et |
assigne le résultat à a . |
||
*= {.C} |
a *= b {.C} |
Multiplie la valeur de b à a et |
assigne le résultat à a . |
||
/= {.C} |
a /= b {.C} |
Divise la valeur de b à a et |
assigne le résultat à a . |
||
%= {.C} |
a %= b {.C} |
Calcule le modulo la valeur de b à a et |
assigne le résultat à a . |
Expressions et opérateurs (6/6)
Opérateurs d'assignation (suite)
Opérateur | Syntaxe | Signification |
---|---|---|
++ {.C} |
a++ {.C} |
Incrémente la valeur de a de 1 et |
retourne le résultat (a += 1 ). |
||
-- {.C} |
a-- {.C} |
Décrémente la valeur de a de 1 et |
retourne le résultat (a -= 1 ). |
||
++ {.C} |
++a {.C} |
Retourne a {.C} et incrémente a de 1. |
-- {.C} |
--a {.C} |
Retourne a {.C} et décrémente a de 1. |
if
{.C} .. else if
{.C} .. else
{.C} (1/2)
Structures de contrôle: Syntaxe
if (expression) {
instructions;
} else if (expression) { // optionnel
// il peut y en avoir plusieurs
instructions;
} else {
instructions; // optionnel
}
if (x) { // si x s'évalue à `vrai`
printf("x s'évalue à vrai.\n");
} else if (y == 8) { // si y vaut 8
printf("y vaut 8.\n");
} else {
printf("Ni l'un ni l'autre.\n");
}
if
{.C} .. else if
{.C} .. else
{.C} (2/2)
Structures de contrôle: Pièges
int x = y = 3;
if (x = 2)
printf("x = 2 est vrai.\n");
else if (y < 8)
printf("y < 8.\n");
else if (y == 3)
printf("y vaut 3 mais cela ne sera jamais affiché.\n");
else
printf("Ni l'un ni l'autre.\n");
x = -1; // toujours évalué
switch
{.C} .. case
{.C} (1/2)
Structures de contrôle: switch (expression) {
case constant-expression:
instructions;
break; // optionnel
case constant-expression:
instructions;
break; // optionnel
// ...
default:
instructions;
}
Que se passe-t-il si break
{C} est absent?
switch
{.C} .. case
{.C} (2/2)
Structures de contrôle: int x = 0;
switch (x) {
case 0:
case 1:
printf("0 ou 1\n");
break;
case 2:
printf("2\n");
break;
default:
printf("autre\n");
}
Dangereux, mais c'est un moyen d'avoir un "ou" logique dans un case.
for
{.C}, while
{.C}, do ... while
{.C} (1/4)
Structures de contrôle:
for
{.C}
La boucle for (expression1; expression2; expression3) {
instructions;
}
while
{.C}
La boucle while (expression) {
instructions;
}
do ... while
{.C}
La boucle do {
instructions;
} while (expression);
for
{.C}, while
{.C}, do ... while
{.C} (2/4)
Structures de contrôle:
for
{.C}
La boucle int sum = 0; // syntaxe C99
for (int i = 0; i < 10; i++) {
sum += i;
}
for (int i = 0; i != 1; i = rand() % 4) { // ésotérique
printf("C'est plus ésotérique.\n");
}
for
{.C}, while
{.C}, do ... while
{.C} (3/4)
Structures de contrôle:
while
{.C}
La boucle int sum = 0, i = 0;
while (i < 10) { // pas assuré·e·s de faire un tour
sum += i;
i += 1;
}
do ... while
{.C}
La boucle int sum = 0, i = 0;
do { // assuré·e·s de faire un tour
sum += i;
i += 1;
} while (i < 10);
continue
{.C}, break
{.C} (4/4)
Structures de contrôle: -
continue
{.C} saute à la prochaine itération d'une boucle.int i = 0; while (i < 10) { if (i == 3) { continue; } printf("%d\n", i); i += 1; }
-
break
{.C} quitte le bloc itératif courant d'une boucle.for (int i = 0; i < 10; i++) { if (i == 3) { break; } printf("%d\n", i); }
Les variables (1/2)
Variables et portée
- Une variable est un identifiant, qui peut être liée à une valeur (un expression).
- Une variable a une portée qui définit où elle est visible (où elle peut être accédée).
- La portée est globale ou locale.
- Une variable est globale est accessible à tout endroit d'un programme et doit être déclarée en dehors de toute fonction.
- Une variable est locale lorsqu'elle est déclarée dans un bloc,
{...}
{.C}. - Une variable est dans la portée après avoir été déclarée.
Les variables (2/2)
Exemple
int bar() { // x, y pas visibles ici, max oui }
int foo() {
int x = 1; // x est locale à foo
{
// x est visible ici, y pas encore
int y = 2;
bar(); // ni x ni y sont visible dans bar()
} // y est détruite à la sortie du bloc
} // x est à la sortie de foo
float max; // variable globale accessible partout
int main() {
int z; // locale, à main
} // z est détruite ici, max aussi
printf()
{.C} (1/2)
Entrées/sorties: Généralités
-
La fonction
printf()
{.C} permet d'afficher du texte sur le terminal:int printf(const char *format, ...);
-
Nombre d'arguments variables.
-
format
{.C} est le texte, ainsi que le format (type) des variables à afficher. -
Les arguments suivants sont les expressions à afficher.
printf()
{.C} (2/2)
Entrées/sorties: Exemple
#include <stdio.h>
#include <stdlib.h>
int main() {
printf("Hello world.\n");
int val = 1;
printf("Hello world %d time.\n", val);
printf("%f squared is equal to %f.\n", 2.5, 2.5*2.5);
return EXIT_SUCCESS;
}
scanf()
{.C} (1/2)
Entrées/sorties: Généralités
-
La fonction
scanf()
{.C} permet de lire du texte formaté entré au clavier:int scanf(const char *format, ...);
-
format
{.C} est le format des variables à lire (commeprintf()
{.C}). -
Les arguments suivants sont les variables où sont stockées les valeurs lues.
scanf()
{.C} (2/2)
Entrées/sorties: Exemple
#include <stdio.h>
#include <stdlib.h>
int main() {
printf("Enter 3 numbers: \n");
int i, j, k;
scanf("%d %d %d", &i, &j, &k);
printf("You entered: %d %d %d\n", i, j, k);
return EXIT_SUCCESS;
}