Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • programmation_sequentielle/cours
  • yassin.elhakoun/cours-de-prog
2 results
Select Git revision
Show changes
Commits on Source (59)
Showing
with 4294 additions and 151 deletions
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Ce programme prend en argument deux
// entiers se trouvant chacun
// sur une nouvelle ligne et affiche
// la somme des deux entiers en argument
// sur une nouvelle ligne.
// Ex:
// 12
// 19
//
// 31
void sum_two() {
int a, b;
scanf("%d %d", &a, &b);
printf("\n%d\n", a + b);
}
// Ce programme prend en argument 12 nombres à
// virgule flottante se trouvant chacun
// sur une nouvelle ligne. Multiplie chaque
// nombre par deux et affiche leur somme
// sur une nouvelle ligne suivi de CHF.
// Ex:
// 12.2
// 45.5
// 1.5
// 65.1
// 89.4
// 567.6
// 112.8
// 67.0
// 35.1
// 112.2
// 3.3
// 9.8
//
// 2243.000000 CHF
void sum_array() {
float sum = 0.0;
for (int i = 0; i < 12; ++i) {
float a = 0.0;
scanf("%f", &a);
a *= 2.0;
sum += a;
}
printf("\n%f CHF\n", sum);
}
// Ce programme prend en argument 2 chaînes de
// caractères sur des lignes séparées (longueur
// max de 80), les sépare au milieu et retourne
// les 4 chaînes chacune sur une nouvelle ligne
// (si la longueur N est paire on sépare en 2
// chaînes de longueur N/2, sinon la première
// aura une longueur de N/2 et la seconde N/2+1).
// Ex:
// abcdefgh
// asdfghjkl
//
// abcd
// efgh
// asdf
// ghjkl
void split_mid() {
char str_one[2][41], str_two[2][41];
for (int j = 0; j < 2; ++j) {
char str[81];
scanf("%s", str);
int n = strlen(str);
int n1 = n / 2;
int n2 = n - n1;
for (int i = 0; i < n1; ++i) {
str_one[j][i] = str[i];
}
str_one[j][n1] = '\0';
for (int i = 0; i < n2; ++i) {
str_two[j][i] = str[n1 + i];
}
str_two[j][n2] = '\0';
}
printf("\n");
for (int j = 0; j < 2; ++j) {
printf("%s\n", str_one[j]);
printf("%s\n", str_two[j]);
}
}
int main() {
/* sum_two(); */
sum_array();
/* split_mid(); */
}
#include <stdio.h>
#include <stdlib.h>
int main() {
printf("Enter n: "); // affichage chaine de caractères
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 for
sum += i;
}
printf("The sum of the %d first integers is: %d\n", n, sum); // affichage de n et sum
printf("The analytical formula is %d * (%d + 1) / 2 = %d.\n", n, n, n*(n+1)/2); // on peut mettre n'importe quelle expression
if (sum != n * (n+1) / 2) { // branchement conditionnel
printf("Error: The answer we computed is wrong.\n");
return EXIT_FAILURE; // code d'erreur
}
return EXIT_SUCCESS; // code de réussite
}
\ No newline at end of file
---
Language: Cpp
# BasedOnStyle: Google
AccessModifierOffset: -4
AlignAfterOpenBracket: AlwaysBreak
AlignConsecutiveAssignments: None
AlignConsecutiveBitFields: None
AlignConsecutiveDeclarations: None
AlignConsecutiveMacros: true
AlignEscapedNewlines: Left
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortLambdasOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: MultiLine
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakInheritanceList: AfterColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: AfterColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 100
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
SortPriority: 0
- Regex: '^<.*\.h>'
Priority: 1
SortPriority: 0
- Regex: '^<.*'
Priority: 2
SortPriority: 0
- Regex: '.*'
Priority: 3
SortPriority: 0
IncludeIsMainRegex: '([-_](test|unittest))?$'
IncludeIsMainSourceRegex: ''
IndentCaseLabels: false
IndentCaseBlocks: false
IndentGotoLabels: false
IndentPPDirectives: None
IndentExternBlock: AfterExternBlock
IndentWidth: 4
IndentWrappedFunctionNames: true
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Right
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- 'c++'
- 'C++'
CanonicalDelimiter: ''
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
- ParseTestProto
- ParsePartialTestProto
CanonicalDelimiter: ''
BasedOnStyle: google
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
Standard: Auto
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 4
UseCRLF: false
UseTab: Never
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
...
mermaid-filter.err
index.md
.puppeteer.json
......@@ -27,6 +27,7 @@ all: puppeteer $(PDF) # La cible par défaut (all) exécute les cibles %.html et
puppeteer:
@echo "Setting chromium to $(CHROMIUM) for puppeteer"
# @echo "{\n\"executablePath\":" \"$(CHROMIUM)\" ",\n\"args\": [\"--no-sandbox\"]\n}" > .puppeteer.json
@echo -e "{\n\"executablePath\":" \"$(CHROMIUM)\" ",\n\"args\": [\"--no-sandbox\"]\n}" > .puppeteer.json
markdown: $(MARKDOWN) # La markdown les cibles %.markdown
......
---
title: "Allocation dynamique de mémoire"
date: "2024-12-03"
---
# Allocation dynamique de mémoire (1/8)
- La fonction `malloc`{.C} permet d'allouer dynamiquement (pendant l'exécution du programme) une zone de mémoire contiguë.
```C
#include <stdlib.h>
void *malloc(size_t size);
```
- `size`{.C} est la taille de la zone mémoire **en octets**.
- Retourne un pointeur sur la zone mémoire ou `NULL`{.C} en cas d'échec: **toujours vérifier** que la valeur retournée est `!= NULL`{.C}.
- Le *type* du retour est `void *`{.C} (un pointeur de type quelconque).
# Allocation dynamique de mémoire (2/8)
- Allocation *sur le tas* d'un type de base:
```C
int *val = malloc(sizeof(int)); // réserve 4 octets sur le tas
*val = 4; // les 4 octets contiennent la valeur 4
```
- Presque la même chose que:
```C
int val = 4; // ici l'allocation et l'initialisation
// sont faites en une fois mais se trouve sur
// le *tas* (mémoire managée automatiquement)
```
- Attention:
```C
int *val = 4; // Ca c'est très faux...
```
# Allocation dynamique de mémoire (3/9)
- On peut allouer et initialiser une `fraction_t`{.C}:
```C
fraction_t *frac = malloc(sizeof(fraction_t));
frac->num = 1;
frac->denom = -1;
```
- La zone mémoire **n'est pas** initialisée.
- Désallouer la mémoire explicitement, sinon **fuites mémoires**.
- Il faut connaître la **taille** des données à allouer.
![La représentation mémoire de `fraction_t` et fuites.](figs/pointer_struct_ok.svg){width=100%}
# Allocation dynamique de mémoire (4/9)
- La fonction `free()`{.C} permet de libérer une zone préalablement allouée avec `malloc()`{.C}.
```C
#include <stdlib.h>
void free(void *ptr);
```
- A chaque `malloc()`{.C} doit correspondre exactement un `free()`{.C}.
- Si la mémoire n'est pas libérée: **fuite mémoire** (l'ordinateur plante quand il y a plus de mémoire).
- Si la mémoire est **libérée deux fois**: *seg. fault*.
- Pour éviter les mauvaises surprises mettre `ptr`{.C} à `NULL`{.C} après
libération.
# Allocation dynamique de mémoire (5/9)
## Tableaux dynamiques
- Pour allouer un espace mémoire de 50 entiers: un tableau
```C
int *p = malloc(50 * sizeof(int));
for (int i = 0; i < 50; ++i) {
p[i] = 0;
}
```
## Arithmétique de pointeurs
- Parcourir la mémoire différemment qu'avec l'indexation
```C
int *p = malloc(50 * sizeof(int));
// initialize somehow
int a = p[7];
int b = *(p + 7); // on avance de 7 "int"
p[0] == *p; // le pointeur est le premier élément
```
# Allocation dynamique de mémoire (6/9)
## Arithmétique de pointeurs
![L'arithmétique des pointeurs.](figs/pointer_arithmetics.svg){width=100%}
## Quelle est la complexité de l'accès à une case d'un tableau?
. . .
$$
\mathcal{O}(1).
$$
# Allocation dynamique de mémoire (7/9)
## Pointeur de pointeur
- Tout comme une valeur a une adresse, un pointeur a lui-même une adresse:
```C
int a = 2;
int *b = &a;
int **c = &b;
```
- En effet, un pointeur est aussi une variable (une variable qui contient une adresse mémoire).
- Chaque `*`{.C} rajoute une indirection.
# Allocation dynamique de mémoire (8/9)
## Pointeur de pointeur
![Les références de pointeurs.](figs/double_pointeur.svg){height=100%}
# Allocation dynamique de mémoire (9/9)
- Avec `malloc()`, on peut allouer dynamiquement des tableaux de pointeurs:
```C
int **p = malloc(50 * sizeof(int*));
for (int i = 0; i < 50; ++i) {
p[i] = malloc(70 * sizeof(int));
}
int a = p[5][8]; // on indexe dans chaque dimension
```
- Ceci est une matrice (un tableau de tableaux).
# Tableau dynamique en argument d'une fonction
## Implémenter la fonction ci-dessous
```C
int32_t *p = malloc(50 * sizeof(*p));
initialize_to(p, 50, -1); // initialise un tableau à -1
free(p); // ne pas oublier
```
. . .
```C
void initialize_to(int32_t *p, size_t size, int32_t val) {
for (size_t i = 0; i < size; ++i) {
p[i] = val;
}
}
```
# Tableau dynamique retourné d'une fonction
## Implémenter la fonction ci-dessous
```C
// alloue un tableau de taille 50 et l'initialise à -1
int32_t *p = initialize_to(50, -1);
free(p); // ne pas oublier
```
. . .
```C
int32_t *initialize_to(size_t size, int32_t val) {
int32_t *p = malloc(size * sizeof(*p));
for (size_t i = 0; i < size; ++i) {
p[i] = val;
}
return p;
}
```
## Pourquoi on peut retourner un tableau dynamique et pas un statique?
. . .
* Le tableau est alloué sur le **tas** et non sur la **pile**.
* La mémoire est gérée manuellement sur le tas, automatiquement sur la pile.
# Les *sanitizers*
Problèmes mémoire courants:
* Dépassement de capacité de tableaux.
* Utilisation de mémoire non allouée.
* Fuites mémoire.
* Double libération.
Outils pour leur détection:
* Valgrind (outil externe).
* Sanitizers (ajouts de marqueurs à la compilation).
Ici on utilise les sanitizers (modification de la ligne de compilation, modifiez donc vos *Makefile*):
```bash
gcc -o main main.c -g -fsanitize=address -fsanitize=leak
```
**Attention:** Il faut également faire l'édition des liens avec les sanitizers.
# Questions
## Que fait le code suivant?
```C
int *p = malloc(50 * sizeof(int));
p[10] = 1;
```
. . .
* On alloue de la place pour 50 entiers.
* On initialise le 11ème élément du tableau à 1.
* Les autres éléments sont non-initialisés.
# Questions
## Que fait le code suivant?
```C
float *p = malloc(50);
p[20] = 1.3;
```
. . .
* On déclare un pointeur de floats de taille 50 octets.
* Mais il ne peut contenir que `50 / 4` floats (un float est composé de 32 bits).
* On dépasse la capacité de la mémoire allouée: comportement indéfini.
# Questions
* Soit le code suivant
```C
int *p = malloc(50 * sizeof(int));
for (int i = 0; i < 50; ++i) {
p[i] = 0;
}
```
* Le réécrire en utilisant uniquement l'arithmétique de pointeurs.
. . .
```C
int *p = malloc(50 * sizeof(int));
for (int i = 0; i < 50; ++i) {
*(p+i) = 0;
}
```
# Questions
## Que valent les expressions suivantes?
```C
in32_t *p = malloc(50 * sizeof(int32_t));
sizeof(p);
sizeof(*p);
(p + 20);
*(p + 20);
p[-1];
p[50];
7[p];
```
---
title: "Boucles et conditions"
date: "2023-09-28"
date: "2024-09-24"
---
# Quiz
......@@ -86,6 +86,7 @@ if (x) { // si x s'évalue à `vrai`
int i = 0;
while (i < 10) {
if (i == 3) {
i += 1;
continue;
}
printf("%d\n", i);
......@@ -122,10 +123,11 @@ if (x) { // si x s'évalue à `vrai`
```C
int main() {
// ...
if (error)
if (error) {
return EXIT_FAILURE;
else
} else {
return EXIT_SUCCESS;
}
}
```
......
---
title: "Introduction à la l'interface en ligne de commande"
date: "2023-09-28"
date: "2024-09-24"
---
# Introduction
......
---
title: "Compilation séparée et Makefile"
date: "2023-11-02"
date: "2024-11-19"
---
# Prototypes de fonctions (1/3)
......
---
title: "Précisions pour l'examen"
date: "2023-11-16"
date: "2024-11-05"
---
# Administration
......@@ -9,9 +9,12 @@ date: "2023-11-16"
- L'examen dure au plus 4h (il est prévu pour 3 exceptions jusqu'à 4).
- Votre code devra être dans le répertoire prévu à cet effet.
- Chaque exercice dans un répertoire (`ex1`, `ex2`, `ex3`, ...).
- Chaque exercice doit posséder son propre `Makefile` pour la compilation.
- Compilation
- Il est impératif de compiler avec les warnings.
- Le `Makefile` ainsi qu'un fichier minimal sera mis à disposition pour chaque exercice.
- Vous devez être capables d'écrire la ligne de compilation de votre code:
```console
gcc -o ex1 ex1.c -Wall -Wextra -pedantic
```
# Documents
......@@ -29,12 +32,12 @@ date: "2023-11-16"
- Une partie "exemple" (pas obligatoire) où d'autres exemples sont donnés afin de tester l'exécution de votre programme.
- Votre code doit avoir **exactement** le comportement des exemples donnés **sous peine de sanctions**.
- Chaque code doit être **dans un unique fichier .c** (`ex1.c`, `ex2.c`, ...).
- Donc **inutile** d'écrire des fichiers `.h` ou d'avoir d'autres `.c`
- Donc **inutile** et **interdit** d'écrire d'autres fichiers
# Évaluation (technique)
- L'évaluation se base surtout sur des critères de fonctionnement:
- le code compile-t-il? (on regarde même pas)
- le code compile-t-il? (on regarde même pas si la réponse est non)
- s'exécute-t-il? (on regarde un peu)
- le code demandé est-il réalisé?
- donne-t-il des résultats corrects?
......@@ -69,7 +72,7 @@ leur somme sur une nouvelle ligne.
## Exemple
```bash
$ ./prog 12 19
./prog 12 19
31
```
......@@ -86,7 +89,7 @@ sur une nouvelle ligne suivi de CHF.
## Exemple
```bash
$ ./prog 12 12.2 45.5 1.5 65.1 89.4 567.6 112.8 67.0 35.1 112.2 3.3 9.8
./prog 12 12.2 45.5 1.5 65.1 89.4 567.6 112.8 67.0 35.1 112.2 3.3 9.8
2243.000000 CHF
```
......
---
title: "Lecture/écriture de fichiers"
date: "2025-03-31"
---
# Les fichier en C
* Un fichier en C est représenté par un pointeur de fichier.
```C
#include <stdio.h>
FILE *fp;
```
* `FILE *`{.C} est une structure de donnée *opaque* contenant les informations sur l'état du fichier.
* Il est manipulé à l'aide de fonctions dédiées.
* Le pointeur de fichier est toujours passé *par copie*.
# Manipulations de fichier
* Pour lire/écrire dans un fichier il faut toujours effectuer trois étapes:
1. Ouvrir le fichier (`fopen()`{.C}).
2. Écrire/lire dans le fichier (`fgets()`{.C}, `fputs()`{.C}, `fread()`{.C}, `fwrite()`{.C}, ...).
3. Fermer le fichier (`fclose()`{.C}).
* Nous allons voir brièvement ces trois étapes.
# Ouverture d'un fichier
* L'ouverture d'un fichier se fait avec la fonction `fopen()`{.C}
```C
FILE *fp = fopen(filename, mode);
```
* `filename`{.C} est une chaîne de caractères (incluant le chemin).
* `mode`{.C} est le mode d'ouverture (`"r"`{.C}, `"w"`{.C}, ... voir `man 3 fopen`{.bash}) qui est une chaîne de caractères.
* Si l'ouverture échoue (pas la bonne permission, ou n'existe pas) `fopen()`{.C} retourne `0`.
* **Toujours** tester le retour de `fopen()`{.C}
```C
if (NULL == fp) {
fprintf(stderr, "Can't open output file %s!\n",
filename); // affiche dans le canal d'erreur
exit(EXIT_FAILURE);
}
```
# Fermeture d'un fichier
* Il faut **toujours** fermer un fichier à l'aide de `fclose()`{.C}
```C
FILE *fp = fopen("mon_fichier", "w");
// écritures diverses
fclose(fp);
```
* Les données sont transférées dans une mémoire tampon, puis dans le disques.
* Si la mémoire tampon est pleine, le fichier est fermé, ... les données sont écrites sur le disque.
* Si la mémoire tampon contient encore des données à la fin du programme les données sont **perdues**.
# Lecture d'un fichier (1/2)
```C
char *fgets(char *s, int size, FILE *stream)
```
* Lit une ligne de taille d'au plus `size-1` et la stocke dans `s`, depuis `stream`.
* Retourne `s` ou `NULL` si échoue.
```C
FILE *fp = fopen("text.txt", "r");
char buffer[100];
fgets(buffer, 37, fp);
// lit 36 caractères au plus et les écrit dans buffer
// s'arrête si rencontre EOF, ou "\n".
// ajoute un "\0" terminal
fclose(fp);
```
# Lecture d'un fichier (2/2)
```C
size_t fread(void *ptr, size_t size, size_t nmemb,
FILE *stream)
```
* Lit `nmemb` éléments de taille `size` octets et les écrit à l'adresse `ptr` dans le fichier `stream`.
* Retourne le nombre d'éléments lus.
```C
FILE *fp = fopen("doubles.bin", "rb");
double buffer[100];
size_t num = fread(buffer, sizeof(double), 4, fp);
// lit 4 double, se trouvant dans le fichier fp au
// format binaire et les écrit dans buffer, puis
// retourne 4
fclose(fp);
```
# Écriture dans un fichier (1/2)
```C
int fprintf(FILE *stream, const char *format, ...)
```
* Écrit la chaîne de caractères `format` dans le fichier stream.
* `format` a la même syntaxe que pour `printf()`.
* Retourne le nombre de caractères écrit sans le `\0` terminal(si réussite).
```C
FILE *fp = fopen("text.txt", "w");
fprintf(fp, "Hello world! We are in %d\n", 2020);
// Écrit "Hello world! We are in 2020"
// dans le fichier fp
fclose(fp);
```
# Écriture dans un fichier (2/2)
```C
size_t fwrite(const void *ptr, size_t size,
size_t nmemb, FILE *stream)
```
* Écrit `nmemb` éléments de taille `size` octets se trouvant à l'adresse `ptr` dans le fichier `stream`.
* Retourne le nombre d'éléments écrits.
```C
FILE *fp = fopen("doubles.bin", "wb");
double buffer[] = {1.0, 2.0, 3.0, 7.0};
size_t num = fwrite(buffer, sizeof(double), 4, fp);
// écrit 4 double, se trouvant à l'adresse
// buffer dans le fichier fp au format binaire
// retourne 4
fclose(fp);
```
# Les pointeurs de fichiers spéciaux
* Il existe trois `FILE *`{.C} qui existent pour tout programme:
* `stdin`{.C}: l'entrée standard.
* `stdout`{.C}: la sortie standard.
* `stderr`{.C}: l'erreur standard.
* Lors d'un fonctionnement dans le terminal:
* l'entrée standard est le *clavier*
* la sortie et erreur standard sont affichés dans le *terminal*.
* Ainsi on a
```C
fprintf(stdout, "texte\n"); // == printf("texte\n");
int a;
fscanf(stdin, "%d", &a); // == scanf("%d", &a);
```
This diff is collapsed.
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="245.24887mm"
height="86.080841mm"
viewBox="0 0 245.24887 86.080843"
version="1.1"
id="svg8"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
sodipodi:docname="pointer_struct_ok.svg">
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.98994949"
inkscape:cx="483.38263"
inkscape:cy="105.54084"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1884"
inkscape:window-height="1052"
inkscape:window-x="36"
inkscape:window-y="0"
inkscape:window-maximized="1"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0">
<inkscape:grid
originy="-104.07588"
originx="12.489411"
type="xygrid"
id="grid819" />
</sodipodi:namedview>
<defs
id="defs2">
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker3314"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lend">
<path
inkscape:connector-curvature="0"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path3312" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker3284"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lend">
<path
inkscape:connector-curvature="0"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path3028" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="Arrow2Lstart"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lstart">
<path
inkscape:connector-curvature="0"
transform="matrix(1.1,0,0,1.1,1.1,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path3025" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="Arrow2Lend"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lend">
<path
inkscape:connector-curvature="0"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path8951" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="Arrow2Lend-7"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lend">
<path
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path8951-5"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="Arrow2Lend-9"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lend">
<path
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path8951-8"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="Arrow2Lend-7-2"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lend">
<path
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path8951-5-8"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="Arrow2Lend-1"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lend">
<path
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path8951-3"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker3284-4"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lend">
<path
inkscape:connector-curvature="0"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path3028-7" />
</marker>
</defs>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(12.489412,-106.8433)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<g
style="fill:none;stroke:#0000ff;stroke-width:0.71586478;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="g846-7-2"
transform="matrix(0.48784069,0,0,1,-44.968279,-20.032731)">
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#0000ff;stroke-width:0.71586478;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect821-3-5-2"
width="29.104166"
height="9.260417"
x="99.218758"
y="156.77083" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#0000ff;stroke-width:0.71586478;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect821-6-3-8"
width="29.104166"
height="9.260417"
x="128.32292"
y="156.77083" />
</g>
<g
style="fill:none;stroke:#0000ff;stroke-width:0.71586478;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="g846-5-1"
transform="matrix(0.48784069,0,0,1,-16.571887,-20.032726)">
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#0000ff;stroke-width:0.71586478;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect821-3-6-9"
width="29.104166"
height="9.260417"
x="99.218758"
y="156.77083" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#0000ff;stroke-width:0.71586478;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect821-6-2-4"
width="29.104166"
height="9.260417"
x="128.32292"
y="156.77083" />
</g>
<g
id="g1489"
transform="translate(-82.051746)">
<g
transform="matrix(0.4878407,0,0,1,93.949527,-20.032732)"
id="g846-7-2-6"
style="fill:none;stroke:#ff0007;stroke-width:0.71586478;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1">
<rect
y="156.77083"
x="99.218758"
height="9.260417"
width="29.104166"
id="rect821-3-5-2-7"
style="opacity:1;fill:none;fill-opacity:1;stroke:#ff0007;stroke-width:0.71586478;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<rect
y="156.77083"
x="128.32292"
height="9.260417"
width="29.104166"
id="rect821-6-3-8-5"
style="opacity:1;fill:none;fill-opacity:1;stroke:#ff0007;stroke-width:0.71586478;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
</g>
<g
transform="matrix(0.4878407,0,0,1,122.34592,-20.032727)"
id="g846-5-1-9"
style="fill:none;stroke:#ff0007;stroke-width:0.71586478;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1">
<rect
y="156.77083"
x="99.218758"
height="9.260417"
width="29.104166"
id="rect821-3-6-9-1"
style="opacity:1;fill:none;fill-opacity:1;stroke:#ff0007;stroke-width:0.71586478;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<rect
y="156.77083"
x="128.32292"
height="9.260417"
width="29.104166"
id="rect821-6-2-4-2"
style="opacity:1;fill:none;fill-opacity:1;stroke:#ff0007;stroke-width:0.71586478;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
</g>
</g>
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path2993"
d="M -1.3502974,178.91256 C -10.434806,165.66351 -12.664615,164.59117 0.16160744,145.99852"
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3284)" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path2993-6"
d="M -1.6432048,189.1699 C -12.064062,177.52447 -18.226203,141.46875 -3.5290926,116.46165"
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3284-4)" />
<g
id="g1518"
transform="translate(3.2072343)">
<g
transform="matrix(0.48784068,0,0,1,-23.535649,-49.569597)"
id="g846-7-2-5"
style="fill:none;stroke:#0000ff;stroke-width:0.71586478;stroke-miterlimit:4;stroke-dasharray:0.7158648, 1.43172961;stroke-dashoffset:0;stroke-opacity:1">
<rect
y="156.77083"
x="99.218758"
height="9.260417"
width="29.104166"
id="rect821-3-5-2-6"
style="opacity:1;fill:none;fill-opacity:1;stroke:#0000ff;stroke-width:0.71586478;stroke-miterlimit:4;stroke-dasharray:0.7158648, 1.43172961;stroke-dashoffset:0;stroke-opacity:1" />
<rect
y="156.77083"
x="128.32292"
height="9.260417"
width="29.104166"
id="rect821-6-3-8-9"
style="opacity:1;fill:none;fill-opacity:1;stroke:#0000ff;stroke-width:0.71586478;stroke-miterlimit:4;stroke-dasharray:0.7158648, 1.43172961;stroke-dashoffset:0;stroke-opacity:1" />
</g>
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#0000ff;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:0.50000001, 1.00000003;stroke-dashoffset:0;stroke-opacity:1"
id="rect821-3-6-7-37"
width="14.198196"
height="9.260417"
x="-3.5290926"
y="107.20123" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#0000ff;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:0.50000001, 1.00000003;stroke-dashoffset:0;stroke-opacity:1"
id="rect821-6-2-3-4"
width="14.198196"
height="9.260417"
x="10.669104"
y="107.20123" />
<g
transform="translate(-85.25898)"
id="g1481">
<g
style="fill:none;stroke:#ff0007;stroke-width:0.71586478;stroke-miterlimit:4;stroke-dasharray:0.71586478, 1.43172956;stroke-dashoffset:0;stroke-opacity:1"
id="g846-7-2-6-4"
transform="matrix(0.48784071,0,0,1,90.258825,-49.569599)">
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#ff0007;stroke-width:0.71586478;stroke-miterlimit:4;stroke-dasharray:0.71586478, 1.43172956;stroke-dashoffset:0;stroke-opacity:1"
id="rect821-3-5-2-7-3"
width="29.104166"
height="9.260417"
x="99.218758"
y="156.77083" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#ff0007;stroke-width:0.71586478;stroke-miterlimit:4;stroke-dasharray:0.71586478, 1.43172956;stroke-dashoffset:0;stroke-opacity:1"
id="rect821-6-3-8-5-0"
width="29.104166"
height="9.260417"
x="128.32292"
y="156.77083" />
</g>
<g
style="fill:none;stroke:#ff0007;stroke-width:0.71586478;stroke-miterlimit:4;stroke-dasharray:0.71586478, 1.43172956;stroke-dashoffset:0;stroke-opacity:1"
id="g846-5-1-9-8"
transform="matrix(0.48784071,0,0,1,118.65522,-49.569594)">
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#ff0007;stroke-width:0.71586478;stroke-miterlimit:4;stroke-dasharray:0.71586478, 1.43172956;stroke-dashoffset:0;stroke-opacity:1"
id="rect821-3-6-9-1-4"
width="29.104166"
height="9.260417"
x="99.218758"
y="156.77083" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#ff0007;stroke-width:0.71586478;stroke-miterlimit:4;stroke-dasharray:0.71586478, 1.43172956;stroke-dashoffset:0;stroke-opacity:1"
id="rect821-6-2-4-2-3"
width="29.104166"
height="9.260417"
x="128.32292"
y="156.77083" />
</g>
</g>
</g>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:9.61108494px;line-height:1.25;font-family:monospace;-inkscape-font-specification:monospace;letter-spacing:0px;word-spacing:0px;stroke-width:0.24027713"
x="2.3449361"
y="132.47079"
id="text1455"><tspan
sodipodi:role="line"
id="tspan1453"
x="2.3449361"
y="132.47079"
style="stroke-width:0.24027713">fraction_t</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:1.25;font-family:monospace;-inkscape-font-specification:monospace;letter-spacing:0px;word-spacing:0px;stroke-width:0.26458332"
x="2.2523637"
y="155.76122"
id="text1459"><tspan
sodipodi:role="line"
id="tspan1457"
x="2.2523637"
y="155.76122"
style="stroke-width:0.26458332">num</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:1.25;font-family:monospace;-inkscape-font-specification:monospace;letter-spacing:0px;word-spacing:0px;stroke-width:0.26458332"
x="59.490494"
y="155.76122"
id="text1463"><tspan
sodipodi:role="line"
id="tspan1461"
x="59.490494"
y="155.76122"
style="stroke-width:0.26458332">denom</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.47521019px;line-height:1.25;font-family:monospace;-inkscape-font-specification:monospace;letter-spacing:0px;word-spacing:0px;stroke-width:0.21188024"
x="0.21260698"
y="181.14244"
id="text1467"><tspan
sodipodi:role="line"
id="tspan1465"
x="0.21260698"
y="181.14244"
style="stroke-width:0.21188024">fraction_t *frac = malloc(sizeof(fraction_t));</tspan><tspan
sodipodi:role="line"
x="0.21260698"
y="191.73645"
style="stroke-width:0.21188024"
id="tspan1471">frac = NULL; // addresse mémoire inaccessible</tspan></text>
</g>
</svg>
---
title: "Fonctions d'ordre supérieur"
date: "2025-05-16"
---
# Tribute
Rendons à Cesar:
* Ces slides ont été écrits par Michaël El Kharroubi
* J'arrive pas à changer l'auteur simplement sur un slide donc....
* Merci à lui pour ses efforts et qu'il soit crédité comme il se doit!
# Présentation du problème
* Imaginons que nous ayons la structure d'un vecteur en 3 dimensions suivante
```C
typedef struct _vec3 {
double x;
double y;
double z;
} vec3;
```
* On souhaite implémenter 3 opérations différentes
* La somme
* La soustraction
* Le produit de Hadamard (produit composantes à composantes)
# Présentation du problème (suite)
On a donc les fonctions suivantes
* Addition
```c
vec3 add(vec3 lhs, vec3 rhs){
vec3 res;
res.x = lhs.x + rhs.x;
res.y = lhs.y + rhs.y;
res.z = lhs.z + rhs.z;
return res;
}
```
# Présentation du problème (suite)
* Soustraction
```c
vec3 sub(vec3 lhs, vec3 rhs){
vec3 res;
res.x = lhs.x - rhs.x;
res.y = lhs.y - rhs.y;
res.z = lhs.z - rhs.z;
return res;
}
```
# Présentation du problème (suite)
* Produit de Hadamard
```c
vec3 mul(vec3 lhs, vec3 rhs){
vec3 res;
res.x = lhs.x * rhs.x;
res.y = lhs.y * rhs.y;
res.z = lhs.z * rhs.z;
return res;
}
```
* Quel est le problème avec ces trois fonctions?
# Présentation du problème (suite)
* Le problème avec ces fonctions c'est la **répétition**.
* La seule chose qui change, c'est l'opérateur (+,-,*).
* Problèmes possibles
* Tentation de copier-coller du code (donc risque d'erreurs)
* Faible résilience au changement (imaginons que je veuille des vecteurs 2d, 4d, nd)
# Présentation du problème (solution)
* Vecteur de taille dynamique
```c
typedef struct _vecn {
int size;
double *xs;
} vecn;
```
* Règle le problème de résilience du code, mais ne règle pas le problème de répétition...
# Fonction d'ordre supérieur (solution au problème)
* Pour notre problème, nous aimerions donc découpler l'opération (opération entre deux termes : +,-,*) de l'itération sur les composantes.
* Ce qui nous donne conceptuellement en pseudo c
```c
// Attention pseudo c, ne compile pas !!!!!
vec3 apply_operator(operator op, vec3 lhs, vec3 rhs){
vec3 res;
res.x = lhs.x op rhs.x;
res.y = lhs.y op rhs.y;
res.z = lhs.z op rhs.z;
return res;
}
```
# Fonction d'ordre supérieur (solution au problème)
* Avec notre fonction conceptuelle `apply_operator`, on pourrait faire (toujours en pseudo c)
```c
// Attention pseudo c, ne compile pas !!!!!
vec3 add(vec3 lhs, vec3 rhs){
return apply_operator(+, lhs, rhs);
}
vec3 sub(vec3 lhs, vec3 rhs){
return apply_operator(-, lhs, rhs);
}
vec3 mul(vec3 lhs, vec3 rhs){
return apply_operator(*, lhs, rhs);
}
```
* En fait, on vient de créer ce qu'on appelle une fonction d'ordre supérieur.
# Fonction d'ordre supérieur (définition)
* Une fonction d'ordre supérieur est une fonction qui prend en paramètre et/ou retourne une(des) autre(s) fonction(s).
* Si on essayait de définir `operator`, c'est en fait une fonction qui prend deux paramètres (un terme de gauche et un terme de droite). On s'en aperçoit clairement avec la notation préfix (polonaise).
* `L + R -> + L R`
* `L - R -> - L R`
* `L * R -> * L R`
* Comment l'implémenter concrètement en C?
# Implémentation
* Si on reprend la signature de notre fonction d'exemple, on a
```c
vec3 apply_operator(operator op, vec3 lhs, vec3 rhs);
```
* Nous avons déterminé que les `operator` étaient des fonctions qui prennaient deux paramètres.
* Pour passer une fonction en paramètre en C, nous devons la passer par référence, c'est à dire à l'aide d'un pointeur de fonction.
# Pointeur de fonctions
* Un pointeur de fonction se définit ainsi
```c
<type retour> (*<nom ptr fonc>)(<type params(s)>);
```
* Ou encore avec un `typedef`
```c
typedef <type retour> (*<nom ptr fonc>)(<type params(s)>);
```
* Dans notre cas, nous avons donc un type de fonction nommé `operator`, qui prend en entrée deux `double`{.c} et qui retourne un `double`{.c}. Ce qui nous donne
```c
typedef double (*operator)(double, double);
```
# Implémentation (suite)
* En reprenant notre fonction `apply_operator`, on a donc
```c
vec3 apply_operator(operator op, vec3 lhs, vec3 rhs){
vec3 res;
res.x = op(lhs.x, rhs.x);
res.y = op(lhs.y, rhs.y);
res.z = op(lhs.z, rhs.z);
return res;
}
```
* NB : On voit que pour appeler notre fonction passée en paramètre, nous avons pu le faire comme avec n'importe quelle fonction.
# Résultat
```c
typedef double (*operator)(double, double);
vec3 apply_operator(operator op, vec3 lhs, vec3 rhs){
vec3 res;
res.x = op(lhs.x, rhs.x);
res.y = op(lhs.y, rhs.y);
res.z = op(lhs.z, rhs.z);
return res;
}
double add_dbl(double lhs, double rhs){
return lhs + rhs;
}
vec3 add(vec3 lhs, vec3 rhs){
return apply_operator(add_dbl, lhs, rhs);
}
```
# Fonctions d'ordre supérieur appliquées aux tableaux
* Comment appliquer des opérations sur un vecteur de taille n?
* Map (application d'une fonction)
* `add_one`, `square`
* Filter (discrimination selon un prédicat)
* `is_even`, `is_lower_than_five`
* Reduce (réduction d'un vecteur à un seul élément)
* `sum`, `multiply`
# Le map
* Exemple d'application
```c
typedef double (*operator)(double);
double *map(operator op, double *tab, size_t size) {
double *res = malloc(sizeof(*res) * size);
for (int i = 0; i < size; ++i) {
res[i] = op(tab[i]);
}
return res;
}
double add_one(double val) {
return val + 1;
}
double sqr(double val){
return val * val;
}
double tab[] = {1.0, 2.0, 3.0};
double *square = map(sqr, tab, 3);
double *and_one = map(add_one, square, 3);
```
# Le map
* Permettrait le chaînage.
```C
double *sqr_and_one = map(add_one, map(sqr, tab, 3), 3);
```
. . .
* Problème?
. . .
* Allocation dynamique... fuite mémoire.
. . .
* Solution?
. . .
```c
typedef double (*operator)(double);
double *map(operator op, double *tab, size_t size) {
double *res = malloc(sizeof(*res) * size);
for (int i = 0; i < size; ++i) {
res[i] = op(tab[i]);
}
free(tab);
return res;
}
```
* Problème potentiel?
* **Attention au double free!**
---
title: "La généricité"
date: "2025-05-16"
---
# Problématique
* En C on doit écrire chaque algorithme/structures de données pour des types
précis (`int`, `double`, `char`, ...).
```
void int_sort(int size, int tab[size]); // tri d'entiers
void double_sort(int size, int tab[size]); // tri de double
void char_sort(int size, char tab[size]); // tri de char
```
* Duplication du code pour chaque type possible et imaginable.
* On aimerait un moyen pour pouvoir représenter "n'importe quel type" sans
réécrire tout le code.
# La généricité
## Une "solution": `void *`{.C}
* En général, un pointeur connaît son **adresse** et le **type** des données sur lesquelles il pointe.
```C
int *a = malloc(sizeof(*a));
int *b = malloc(sizeof(int));
```
* Un `void *`{.C} le connaît **que** son adresse, au programmeur de pas faire n'importe quoi.
* Vous avez déjà utilisé des fonctions utilisant des `void *`{.C}
```C
void *malloc(size_t size);
void free(void *);
```
# Attention danger
* Ne permet pas au compilateur de vérifier les types.
* Les données pointées n'ayant pas de type, il faut déréférencer avec précaution:
```C
int a = 2;
void *b = &a; //jusqu'ici tout va bien
double c = *b; // argl!
```
* Une attention accrue est nécessaire.
# Cas particuier: on sait pas comment libérer la mémoire
## Exemple
```C
struct tab {
int *t;
}
struct tab *tmp = malloc(sizeof(*tmp));
tmp->t = malloc(10 * sizeof(*(tmp->t)));
free(tmp); // memory leak of tmp->t...
```
. . .
## Solution: tout faire à la main
```C
free(tmp->t);
free(tmp);
```
# Exemple simple
* On souhaite échanger deux pointeurs
```C
int *a = malloc();
int *b = malloc();
swap(&a, &b);
```
* Comment écrire `swap()` pour que le code ci-dessus marche pour n'importe quel
type?
. . .
```C
void swap(void **a, void **b) {
void *tmp = *a;
*a = *b;
*b = tmp;
}
```
# Cas d'utilisation (1/4)
\footnotesize
* La somme d'un tableau de type arbitraire (facile non?)
```C
void sum(void *tab, int length, size_t size_elem, void *zero,
void (*add)(void *, void *)) {
for (int i = 0; i < length; ++i) {
void *rhs = (void *)((char *)tab + i * size_elem);
add(zero, rhs);
} // de combien on "saute" avec un void *?
}
```
* Pour des entiers
```C
void int_add(void *lhs, void *rhs) {
*((int *)lhs) += *((int *)rhs); // cast d'entiers
}
int zero = 0;
int tab[] = {1, -2, 4, 5};
sum(tab, 4, sizeof(int), &zero, int_add);
printf("%d\n", zero);
```
# Cas d'utilisation (2/4)
## Que fait cette fonction?
\footnotesize
```C
void *foo(void *tab, int n_items, int s_items,
bool (*bar)(void *, void *)) {
if (n_items <= 0 || s_items <= 0 || NULL == tab) {
return NULL;
}
void *elem = tab;
for (int i = 1; i < n_items; ++i) {
// void pointer arithmetics is illegal in C
// (gcc is ok though)
void *tmp_elem = (void *)((char *)tab + i*s_items);
if (bar(elem, tmp_elem)) {
elem = tmp_elem;
}
}
return elem;
}
```
# Cas d'utilisation (3/4)
## Avec un tableau de `int`{.C}
```C
bool cmp_int(void *a, void *b) {
return (*(int *)a < *(int *)b);
}
int main() {
int tab[] = {-1, 2, 10, 3, 8};
int *a = foo(tab, 5, sizeof(int), cmp_int);
printf("a = %d\n", *a);
}
```
# Cas d'utilisation (4/4)
## Avec un tableau de `double`{.C}
```C
bool cmp_dbl(void *a, void *b) {
return (*(double *)a < *(double *)b);
}
int main() {
double tab[] = {-1.2, 2.1, 10.5, 3.6, 18.1};
double *a = foo(tab, 5, sizeof(double), cmp_dbl);
printf("a = %f\n", *a);
}
```
---
title: "Introduction générale"
date: "2023-09-21"
date: "2024-09-17"
---
# La hotline
......@@ -9,7 +9,7 @@ Nom Mél Bureau
-------------------- ------------------------------ --------------------
Kevin Heirich kevin.heirich@hesge.ch A403
Quentin Leblanc quentin.leblanc@hesge.ch A403
Raphael Bach raphael.bach@hesge.ch B411
Damian Boquete damian.boquete@hesge.ch B403
Michaël El Kharroubi michael.el-kharroubi@hesge.ch A403
Paul Albuquerque paul.albuquerque@hesge.ch B410
Orestis Malaspinas orestis.malaspinas@hesge.ch A401
......@@ -23,24 +23,21 @@ Tout le contenu de ce qu'on raconte se trouve sur cyberlearn:
- Algorithmes et structures de données
- <https://cyberlearn.hes-so.ch/course/view.php?id=7276>
- Clé d'inscription: algo_2023_24
- Clé d'inscription: algo_2024_25
- Programmation Sequentielle en C
- <https://cyberlearn.hes-so.ch/course/view.php?id=7282>
- Clé d'inscription: prog_seq_2023_24
- Clé d'inscription: prog_seq_2024_25
* Espace de discussion
[Matrix](https://matrix.to/#/!aKYVlcclmPGYXQFxAK:matrix.org?via=matrix.org),
installez [element.io](https://element.io).
![](figs/matrix_qr.png){width=20%}
* Communauté Lemmy: <https://lemmy.hepiapp.ch/c/prog_seq>
# Organisation du cours (1/3)
## But: Illustration des concepts vus au cours d'algorithmique
- Salle A502 pour la "théorie" (présentation langage et TPs).
- Salles A406-A432-A433 pour la "pratique".
- Salle B119 pour la "théorie" (présentation langage et TPs).
- Salles A404-A406-A432-A433 pour la "pratique".
## Le bâton
......@@ -69,7 +66,6 @@ Tout le contenu de ce qu'on raconte se trouve sur cyberlearn:
- Il y a un certain nombre de ressources se trouvant sur <https://malaspinas.academy>.
- Mon bureau est toujours ouvert (tapez *assez fort* sur la porte).
- N'hésitez pas à utiliser le salon *Element*...
- Et/ou lemmy.
# Évaluations
......@@ -91,6 +87,12 @@ Tout le contenu de ce qu'on raconte se trouve sur cyberlearn:
**Installez un lecteur de QR code s'il-vous-plaît.**
# Install Party
* Ubuntu 24 LTS
* `gcc`, `clang`, `make`, `docker` en mode rootless, `codium` (ou `neovim`)
* Quand tout est installé: TP du nombre secret sur <https://malaspinas.academy>
# Questions?
- N'hésitez pas à poser des *questions*, nous sommes là pour ça! [^3] [^4]
......
---
title: "Dojo"
date: "2025-02-21"
---
# Le Dojo
* Plateforme d'exercices pour la programmation,
* Outil à la ligne de commande basé sur `gitedu`,
* Correction automatique des exercices,
* Fait maison par Michël Minelli (aller en A403 pour le voir),
* En cours de développement, n'hésitez pas à ouvrir des [\alert{Issues}](https://gitedu.hesge.ch/dojo_project/issues).
# Prérequis
* Installer `docker`!
* Pour savoir s'il est installé faire
```console
docker --version
```
* Voir \alert{le lien suivant}: <https://docs.docker.com/engine/install/>.
* \alert{Activez l'exécution}: <https://docs.docker.com/engine/install/linux-postinstall/> de docker sans les privilèges super utilisateur·trice
# Installation
* Détails sur \alert{ce lien}: <https://dojo.isc-hesge.ch/>.
* Sur MacOS / linux-postinstall
```console
curl -L "https://dojo.isc-hesge.ch/installer.sh" | sh
```
# Authentification
* Détails sur \alert{ce lien} <https://dojo.isc-hesge.ch/user-doc/cli/authentification/>
## Résumé
* Authentification via `gitedu`
```console
dojo auth login
```
* Ouverture de gitedu dans votre navigateur,
* Cliquer sur *autoriser*,
* Est-ce que ça a marché?
```console
$ dojo auth test
ℹ Checking Dojo session:
✔ The session is valid
✔ Student permissions
✔ Teaching staff permissions
✔ Admin permissions
ℹ Checking Gitlab token:
✔ Read access
✔ Write access
```
# Faire un exercice (1/3)
* Détails sur [\alert{ce lien}](https://gitedu.hesge.ch/dojo_project/projects/ui/dojocli/-/wikis/UserDocumentation/3-Exercise-creation).
## Création de l'exercice
* Création de l'exercice (liste chaînée de strings)
```C
dojo exercise create -a c_game_of_life -c .
...
ℹ Checking Dojo session:
✔ The session is valid
✔ Student permissions
ℹ Checking assignment:
✔ Assignment "c_game_of_life" exists
✔ Assignment "c_game_of_life" is published
...
```
* Cette commande clone également le repo de l'exercice créé dans le répertoire courant
* Laissez l'opération se terminer
* Ne quittez **JAMAIS** le repo git sur `gitedu`
# Faire un exercice (2/3)
## Récupération de l'énoncé
* Quand vous avez créé l'exercice, vous pouvez clone le repo comme n'importe quel autre repo gitedu
```console
git clone https://gitedu.hesge.ch/dojo/exercise/dojo-ex_c_game_of_life_e24b65b3-c0e5-4a10-a67a-72dad4ff5ea1 c_game_of_life
```
# Faire un exercice (3/3)
## Exécution des tests
* Faire l'exercice
```console
$ cd c_game_of_life
```
* \alert{LIRE L'ÉNONCÉ JUSQU'À LA FIN!}
* Pour réussir le TP il faut passer tous les tests se trouvant dans:
```console
src/test_suite.cpp
```
* Pour compiler localement deux choix
* Utiliser make
```console
cd src
make
```
* Ou `dojo`
```console
dojo exercice run --verbose
```
* Vous pouvez également commit/push chaque fois que nécessaire (et surtout à la fin).
# Conseils
* Chaque exercice est un repo git (vous pouvez intéragir avec comme pour n'importe quel repo)
* Éditez le code en fonction de l'énoncé
* `make` lance tout un tas de tests unitaires (tout comme `dojo exercise run`)
* \alert{Faites les fonctions les unes après les autres, pas tous les tests d'un coup}
* \alert{Allez lire les tests unitaires} ça peut aider à comprendre es exos
* S'il y a trop d'erreurs et que ça vous fait paniquer, commentez les tests
* Il y a deux types d'erreurs: algorithmiques (erreur dans les tests unitaires), de mémoire (erreurs des sanitizers)
---
title: "La ligne de commande"
date: "2023-11-02"
date: "2024-11-05"
---
# La ligne de commande (1/4)
......@@ -32,7 +32,7 @@ int main(int argc, char **argv)
Pour l'exécution suivante on a
```bash
$ ./prog -b 50 file.txt
./prog -b 50 file.txt
```
```C
......@@ -92,3 +92,4 @@ int main(int argc, char **argv) {
$ ./prog Paul 29
Hello Paul, you are 29 years old.
```
---
title: "Makefile++"
date: "2024-12-17"
---
# make avancé
## Rappel: utilité
- Automatiser le processus de conversion d'un type de fichier à un autre, en *gérant les dépendances*.
- Effectue la conversion des fichiers qui ont changé uniquement.
- Utilisé pour la compilation:
- Création du code objet à partir des sources.
- Création de l'exécutable à partir du code objet.
- Tout "gros" projet utilise `make` (pas uniquement en `C`).
- Un `Makefile` bien écrit ne recompile que ce qui est **nécessaire**!
- Il existe d'autres outils pour le `C` et d'autres langages (`cmake`, `meson`, `maven`, `cargo`, ...).
# Utilisation de `make`
:::::::::::::: {.columns}
::: {.column width="60%"}
## `Makefile` simple
```makefile
galaxy: galaxy.o stars.o vec.o
gcc -o galaxy galaxy.o stars.o \
vec.o
galaxy.o: galaxy.c stars.h
gcc -c galaxy.c
stars.o: stars.c stars.h vec.h
gcc -c galaxy.c
vec.o: vec.c vec.h
gcc -c vec.c
clean:
rm -f *.o galaxy
```
:::
::: {.column width="40%"}
## Terminal
```console
$ make
gcc -c galaxy.c
gcc -c stars.c
gcc -c vec.c
gcc -o galaxy galaxy.o
stars.o vec.o
$ make clean
rm -f *.o galaxy
```
:::
::::::::::::::
**Dessinez le diagramme de dépendances de ce `Makefile`**.
# Diagramme de dépendances
~~~{.mermaid format=png}
graph TD;
galaxy.o --> galaxy
stars.o --> galaxy
vec.o --> galaxy
galaxy.c --> galaxy.o
stars.c --> stars.o
stars.h --> stars.o
stars.h --> galaxy.o
vec.h --> stars.o
vec.h --> vec.o
vec.c --> vec.o
~~~
# Variables
\footnotesize
## Variables utilisateur
- Déclaration
```makefile
id = valeur
id = valeur1 valeur2 valeur3
```
- Utilisation
```makefile
$(id)
```
- Déclaration à la ligne de commande
```console
make CFLAGS="-O3 -Wall"
```
## Variables internes
- `$@` : la cible
- `$^` : la liste des dépendances
- `$<` : la première dépendance
- `$*` : le nom de la cible sans extension
# `Makefile` plus complexe (1/3)
```makefile
# Un Makefile typique
# Le compilateur
CC = gcc
# La variable CFLAGS contient les flags de compilation:
# -g compile avec les infos de debug
# -Wall Plein de warning
# -Wextra Encore plus de warnings
# -pedantic Warning lvl archimage
# -O0 Option d'optimisation (0,1,2,3)
# -std=c11 Utilisation du standard c11
# -fsanitize=address Utilisation des sanitizers
CFLAGS = -g -Wall -Wextra -pedantic -O0 -std=c11 -fsanitize=address
```
# `Makefile` plus complexe (2/3)
```makefile
# La variable LDFLAGS contient les flags pour l'éditeur
# de liens:
# -lm dit d'éditer les liens avec la lib math
# -lSDL2 dit d'éditer les liens avec la lib SDL2
LDFLAGS = -lm -lSDL2
# Définition des sources
SOURCES = galaxy.c stars.c vec.c
# OBJECTS contient SOURCES avec .c qui devient .o
OBJECTS = $(SOURCES:.c=.o)
# galaxy sera l'exécutable (galaxy.c contient le main)
TARGET = galaxy
# Jusqu'ici on a aucune cible.
```
# `Makefile` plus complexe (3/3)
```makefile
# TARGET est la première cible et sera donc exécuté à
# l'invocation de `make`. Elle dépend de OBJECTS
$(TARGET) : $(OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
# $@ : la cible, $ˆ : la liste des dépendances
# PHONY signifie qu'on ne crée rien avec les cibles
# mentionnées. Ici clean est la cible utilisée pour
# enlever tous les fichier .o et l'exécutable
# exécute toujours clean, même si un ficher `clean` existe
.PHONY: clean
clean: # aucune dépendance
rm -f $(TARGET) $(OBJECTS)
```
# Gestion implicite (1/2)
## Question
Pourquoi n'a-t-on pas besoin de générer les `OBJECTS`?
## Réponse
`make` possède une série de règles implicites (voir [ce lien](https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_10.html#SEC95) pour une liste).
## Fonctionnement
Si `make` rencontre une dépendance sans règle, il va voir dans sa liste de règles implicites pour la générer.
```makefile
galaxy: galaxy.o stars.o vec.o
gcc -o galaxy galaxy.o stars.o vec.o $(CFLAGS) $(LDFLAGS)
# implicitement pour galaxy.c, stars.c et vec.c
$(CC) -c $< $(CFLAGS) -o $@
```
# Gestion implicite (2/2)
## Question
Et pour les dépendances des cibles implicites ça se passe comment?
## Réponse
On peut définir individuellement les dites dépendances!
## Fonctionnement
Quand `make` rencontre une dépendance sans règle, il va voir dans sa liste de règles implicites pour la générer.
```makefile
# pas besoin des .c qui sont implicites
galaxy.o: stars.h vec.h
stars.o: *.h
vec.o: vec.h
```
# Le symbole `:=` vs `=` (1/2)
Deux façon (flavors) d'assigner des variables (voir [ce lien](https://www.gnu.org/software/make/manual/html_node/Flavors.html#Flavors)):
## Le symbole `=`
- Façon **récursive**:
```makefile
foo = $(bar)
bar = $(ugh)
ugh = Huh?
```
ici `foo` vaut `Huh?`.
- Valeurs remplacées "récursivement".
- Variables remplacées à chaque appel (lent + imprédictible!).
# Le symbole `:=` vs `=` (2/2)
Deux façon (flavors) d'assigner des variables (voir [ce lien](https://www.gnu.org/software/make/manual/html_node/Flavors.html#Flavors)):
## Le symbole `:=`
- Façon **simplement développée** (`Simply expanded variable`):
```makefile
x := foo
y := $(x) bar
x := later
```
ici `y` vaut `foo bar` et `x` vaut `later` (avec des `=`, `y` vaudrait `later bar`).
- Les variables se comportent comme en `C`.
- En particulier dans les *longs* `Makefile` le comportement est plus prédictible.
# Pour aller plus loin (pas ici...)
Il est possible de prendre **tous** les fichiers `.c`
```makefile
SOURCES = $(wildcard *.c)
OBJECTS = $(SOURCES:.c=.o)
```
Ou encore mieux
```makefile
OBJECTS := $(patsubst %.c,%.o,$(wildcard *.c))
```
# That escalated quickly: `*`, `%`, `:=`
```makefile
# version "longue"
SOURCES = $(wildcard *.c)
OBJECTS = $(SOURCES:.c=.o)
# version "courte"
OBJECTS := $(patsubst %.c,%.o,$(wildcard *.c))
```
Let's take one step at a time:
- Les `*`,
- Les `%`, et leurs différences.
- Les fonctions, ici `wildcard` et `patsubst` (voir respectivement [ce lien](https://www.gnu.org/software/make/manual/html_node/Wildcard-Function.html) et [ce lien](https://www.gnu.org/software/make/manual/html_node/Text-Functions.html)).
- Le symbole `:=` vs `=`.
# Le symbole `*`
## `make` peut "développer" (expand) des `wildcards` (`*`)
- dans les recettes le `*` est géré par le shell
```makefile
clean:
rm -f *.o galaxy
```
- dans les dépendances
```makefile
galaxy.o: *.h
```
mais des fichiers `.h` doivent exister sinon il interprète `*.h` le nom du fichier.
## Par contre ile ne peut pas
```makefile
OBJECTS = *.o
# il faut utiliser
OBJECTS := $(wildcard *.o) # retourne tous les fichier .o
```
# La différence entre `*` et `%`
- Le symbole `*` sert à générer une *liste* d'objets.
- Le symbole `%` sert comme *emplacement* (placeholder).
## Exemple
```makefile
%.o: %.c # % est la partie avant .c
$(CC) -o $@ -c $< $(CFLAGS) # la règle pour chaque `%.c`
# équivalent à
galaxy.o: galaxy.c
stars.o: stars.c
vec.o: vec.c
```
## Application
```makefile
$(patsubst # Substitution de texte pour chaque
%.c,\ # Le pattern "avant" le .c
%.o,\ # Le pattern "avant" le .o
$(wildcard *.c)\ # Tous les fichiers .c
)
```