🕒 : 3 h maximum
Prérequis:
- utilisation de gcc et gdb
- Monia base algorithme , organigrammes , pseudo langage
But:
- apprendre à passer des paramètres a un programme écrit en c
- Organigrammes (monia et PL)
- traduire un code en Pseudo Langage en C et réciproquement
Répertoire du travail:
~/Works/TP2_C
Présentation:
En langage C, la fonction main constitue le point d’entrée principal d’un programme.Cours sur le passage de paramètres en c
argc et argv
dans un répertoire param0
param0.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char ** argv)
{
int i;
printf("Nombre d'arguments : %d\n", argc);
for (i = 0; i < argc; i++) {
printf("Argument %d : %s\n", i, argv[i]);
}
return EXIT_SUCCESS;
}
compiler , tester ce code.
le for est introduit dans ce code , vous allez faire du pas à pas avec gdb, regarder comment fonctionne la boucle for .
etudiant@ordi:~/Works/TP2_C/param0$ gcc param0.c -o param0 -Wall -ansi -pedantic -g
etudiant@ordi:~/Works/TP2_C/param0$
etudiant@ordi:~/Works/TP2_C/param0$ ./param0
Nombre d'arguments : 1
Argument 0 : ./param0
etudiant@ordi:~/Works/TP2_C/param0$ ./param0 un deux trois
Nombre d'arguments : 4
Argument 0 : ./param0
Argument 1 : un
Argument 2 : deux
Argument 3 : trois
etudiant@ordi:~/Works/TP2_C/param0$
Expliquer le rôle de argc et le rôle argv .
compiler le code de test param0.c, et le lancer dans gdb
Vous n’allez forcèment pas retrouver les mêmes adresses mais le fonctionnement sera identique .
etudiant@ordi:~/Works/TP2_C/param0$ ls
param0 param0.c
etudiant@ordi:~/Works/TP2_C/param0$ gdb param0
GNU gdb (Ubuntu 15.0.50.20240403-0ubuntu1) 15.0.50.20240403-git Copyright (C) 2024 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <https://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from param0... (gdb)
gdb possède le code param0
on va lister notre précieux code c !
(gdb) l 1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int main(int argc,char *argv[]) 5 { 6 int i; 7 8 printf("Nombre d'arguments : %d\n", argc); 9 10 for (i = 0; i < argc; i++) { (gdb) l 11 printf("Argument %d : %s\n", i, argv[i]); 12 } 13 14 return EXIT_SUCCESS; 15 } 16 (gdb)
on va voir comment exécuter notre code en passant des paramètres
(gdb) run un deux trois Starting program: /home/etudiant/Works/TP2_C/param0/param0 un deux trois This GDB supports auto-downloading debuginfo from the following URLs: <https://debuginfod.ubuntu.com> Enable debuginfod for this session? (y or [n]) y Debuginfod has been enabled. To make this setting permanent, add 'set debuginfod enabled on' to .gdbinit. [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Nombre d'arguments : 4 Argument 0 : /home/etudiant/Works/TP2_C/param0/param0 Argument 1 : un Argument 2 : deux Argument 3 : trois [Inferior 1 (process 4007) exited normally] (gdb)
c’est parfait notre code fonctionne bien !
mais c’est la qu’il faut placer au moins un point d’arrêt !
on va utiliser br main ou br 8 , car ligne juste créer une variable i de type int .. il ne passe rien ! et 7 juste un passage à la ligne.
(gdb) br main Breakpoint 1 at 0x55555555515c: file param0.c, line 8. (gdb)
et on lance l’execution
(gdb) run un deux trois Starting program: /home/etudiant/Works/TP2_C/param0/param0 un deux trois [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Breakpoint 1, main (argc=4, argv=0x7fffffffe2f8) at param0.c:8 8 printf("Nombre d'arguments : %d\n", argc); (gdb)
Donc ici nous sommes à la ligne 8 non exécutée encore!
on voit que argc contient l’entier 4 et on sait à partir de la que nous avons 4 arguments disponibles de argv[0] à argv[3] et uniquement !
on peut les voir :
(gdb) print argv[0] $1 = 0x7fffffffe58b "/home/etudiant/Works/TP2_C/param0/param0" (gdb) print argv[1] $2 = 0x7fffffffe5b4 "un" (gdb) p argv[2] $3 = 0x7fffffffe5b7 "deux" (gdb) p argv[3] $4 = 0x7fffffffe5bc "trois" (gdb) p argv[4] $5 = 0x0 (gdb) p argv[5] $6 = 0x7fffffffe5c2 "SHELL=/bin/bash" (gdb)
on remarque argv[4] contient 0x0 , la valeur NULL , zéro ! (et ce n’est pas un argument passé)
ici nous allons nous intéresser au pointeur char ** à l’adresse 0x7fffffffe5b4 qui pointe la chaine argv[1]
syntaxe dans gdb pour lister par byte (octet)
x/<nombre><format> adresse
(gdb) x/10xb 0x7fffffffe5b4 0x7fffffffe5b4: 0x75 0x6e 0x00 0x64 0x65 0x75 0x78 0x00 0x7fffffffe5bc: 0x74 0x72 (gdb)
0x75: ‘u’ , 0x6e:’n’ , 0x00 : fin de chaîne
0x64:’d » , 0x65:’e’ , 0x75:’u’ , 0x78:’x’ , 0x00 : NUL
.. etc
on voit bien ici que les données (les paramètres) sont stockés sous forme d’octets contenant les codes ASCII
ainsi on comprends ce qu’est un pointeur sur char .
on va regarder
(gdb) print argv $16 = (char **) 0x7fffffffe2f8
on voit que argv est encore une autre adresse
g = giant word = 8 octets = 64 bits , ici les pointeurs sont codés sur 64 bits (8octets)
(gdb) p sizeof(char *)
$1 = 8
pour visualiser 5 nombres de 64 bits
x/5gx <adresse>
(gdb) print argv $16 = (char **) 0x7fffffffe2f8 (gdb) x/5gx 0x7fffffffe2f8 0x7fffffffe2f8: 0x00007fffffffe58b 0x00007fffffffe5b4 0x7fffffffe308: 0x00007fffffffe5b7 0x00007fffffffe5bc 0x7fffffffe318: 0x0000000000000000
on retrouve les adresses de chaque pointeur sur char , argv[0] , argv[1] , argv[2] , argv[3]; argv [4] qui est égal a NULL le dernier de la liste !
on va s’intéresser comment sont mis les 64 bits
(gdb) p argv $18 = (char **) 0x7fffffffe2f8
(gdb) x/8bx 0x7fffffffe2f8
0x7fffffffe2f8: 0x8b 0xe5 0xff 0xff 0xff 0x7f 0x00 0x00
(gdb)
on remarque ici que c’est bien l’adresse de argv[0] , contenu mais c’est l’envers , en fait c’est a l’endroit mais tout est relatif !
C’est ce qu’on appel du little ebdian
Les octets les moins significatifs sont stockés en premier (à l’adresse la plus basse).
Par exemple, un pointeur 0x00007fffffffe58b est en mémoire :
| Octet # | Adresse | Contenu |
|---|---|---|
| 0 | 0x7fffffffe2f8 | 0x8b ← LSB |
| 1 | 0x7fffffffe2f9 | 0xe5 |
| 2 | 0x7fffffffe2fa | 0xff |
| 3 | 0x7fffffffe2fb | 0xff |
| 4 | 0x7fffffffe2fc | 0xff |
| 5 | 0x7fffffffe2fd | 0x7f |
| 6 | 0x7fffffffe2fe | 0x00 |
| 7 | 0x7fffffffe2ff | 0x00 ← MSB |
Et pour argc
(gdb) p &argc $19 = (int *) 0x7fffffffe1bc (gdb) p sizeof(int) $20 = 4
(gdb) x/1hx 0x7fffffffe1bc
0x7fffffffe1bc: 0x0004
(gdb)
donner les explications chez vous !
(gdb) x/4bx 0x7fffffffe1bc
0x7fffffffe1bc: 0x04 0x00 0x00 0x00
(gdb)
donner les explications chez vous !
Code c ,add , qui va additionner 2 entier.
Utilisation des passages de paramètres et algorithmie
on va utiliser monia
on va faire un répertoire monia_add
on y retrouvera
- le fichier monia: add.xmo
- le fichier add.pl
- add.c
- add (exécutable final)
il faut noter ici que le pl est donné ! et il faut transformer le pseudo langage en langage C
on veut un code qui va donner cela:
./add 5 6
la somme donne 11
./add 5
il faut 2 arguments. ex .:add 2 3
L’organigramme

Il faut refaire avec Monia ce code en organigramme
En extraire le fichier .pl (Pseudo langage)
# ---------------------------------------------------------------------------- # Nom : add.pl # Sujet : Programme d'addition de 2 nombres # Version : 0.1 # # Auteur : Bogt # Création : 16/07/2025 # Mise à jour : 16/07/2025 # ---------------------------------------------------------------------------- # source généré par MoniaOrg version 0.38 Programme nom_du_programme ; ##FORWARDCOMMENT## VAR nb1 : entier ; nb2 : entier ; somme : entier ; DEBUTPROG SI ( argc=3 ) ALORS nb1 est la valeur entiere contenu dans argv[1] ; nb2 est la valeur entière contenu dans argv[2] ; somme= nb1+nb2 ; Aficher "la somme est : (somme) " ; SINON Afficher " Il faut 2 arguments , ex: ./add 2 3" ; FINSI FINPROG ~ ~ ~ ~ ~ 4,19 Tout
Traduire PL en c (travail final !)
A vous de jouer , vous allez avoir besoin de transformer une chaîne de caractère en entier
pseudo langage :
nb1 est la valeur entiere contenu dans argv[1]
traduction en langage C
nb1=atoi(argv[1]); /* a vous de déduire la suite */
la fonction int atoi(const char *nptr) voir le man 3 atoi
man atoi
atoi(3) Library Functions Manual atoi(3)
NAME
atoi, atol, atoll - convert a string to an integer
LIBRARY
Standard C library (libc, -lc)
SYNOPSIS
#include <stdlib.h>
int atoi(const char *nptr);
long atol(const char *nptr);
long long atoll(const char *nptr);
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
atoll():
_ISOC99_SOURCE
|| /* glibc <= 2.19: */ _BSD_SOURCE || _SVID_SOURCE
DESCRIPTION
The atoi() function converts the initial portion of the string pointed to by nptr to int. The behavior is the same as
...
atoi , lire a to i
transforme une chaîne de caractère ASCII en type entier
test_atoi.c dans le repertoire test_atoi
#include <stdlib.h>
#include <stdio.h>
int main(int argc,char **argv)
{
int nombre;
if (argc==2)
{
nombre=atoi(argv[1]);
printf ("la chaine %s donne en entier : %d \n",argv[1],nombre);
return (EXIT_SUCCESS);
}
printf("Il le faut une chaine avec un nombre entier dedans! \n");
return(EXIT_FAILURE);
}
test le code test_atoi pour comprendre l’usage de la fonction atoi()
code en c (et organigramme et pl) de soustract
répertoire soustrac, soustrac.c, soustrac.xmo soustrac.pl
avec Monia réaliser un fichier organigramme
de monia en extraire le fichier soustrac.pl
traduire le pl en c
compiler et tester le code
code en c (et organigramme et pl) de multi
répertoire multi , multi.c, multi.xmo, multi.pl
avec Monia réaliser un fichier organigramme
de monia en extraire le fichier multi.pl
traduire le pl en c
compiler et tester le code
code en c (et organigramme et pl) de div
répertoire div , div.c, div.xmo, div.pl
avec Monia réaliser un fichier organigramme
de monia en extraire le fichier div.pl
traduire le pl en c
compiler et tester le code
Erreur à ne jamais faire !
L’étudiant tôt ou tard fera cette erreur , vous allez analyser et conclure!
répertoire nogood ; nogood.c
/* crash test */ #include <stdio.h> int main(int argc,char **argv) { printf("argv[1][0]=%c, argv[1][1]=%c \n",argv[1][0],argv[1][1]); return 0; } ~ ~ "nogood.c" 8L, 148B 6,37-44 Tout [albert] 0:bash 1:bash 2:bash- 3:ssh* "workboot" 08:33 17-juil.-25
nous avons appris que argv est pointeur sur un pointeur sur char , en d’autres mots un pointeur sur une chaîne de caractères
tout va bien si argv[1] existe , normal non?
etudiant@ordi:~/Works/TP2_C/nogood$ ./nogood un
argv[1][0]=u, argv[1][1]=n
etudiant@ordi:~/Works/TP2_C/nogood$
la tout est pour le mieux dans le meilleur des mondes !
au passage justifier le résultat obtenu
maintenant le crash !
etudiant@ordi:~/Works/TP2_C/nogood$ ./nogood
Erreur de segmentation (core dumped)
etudiant@ordi:~/Works/TP2_C/nogood$
cette erreur de segmentation est courante chez les débutants !
Et ou argv[1] n’existe pas ici argc=1 non pas 2 !
et on demande au système d’afficher des caractères n’existant pas !
Corriger le code en testant argc
proposer un code good.c
Avec gdb
Avec gdb tester et voir l’erreur de segmentation .. de nogood
Avec gdb teste et voir que l’erreur ne sa fait plus avec good
