Upload
duonghanh
View
228
Download
2
Embed Size (px)
Citation preview
-
Programmation en Programmation en langage Clangage C
enseignants: C. Chatelain, S. Nicolas{clement.chatelain, stephane.nicolas}@univ-rouen.fr
U2.1.53
Licence EEA 2ème année
-
Plan du coursPlan du cours
Chaîne de production des programmes Structure générale d'un programme Eléments du langage Types fondamentaux VariablesStructures de contrôle FonctionsTableauxPointeursTypes composésEntrées / sorties
-
FonctionsFonctions
IntroductionValeur en retourArgumentsPortée des variablesProgrammation modulaireFonctions récursives
-
Les fonctionsLes fonctions
Découpage d'un programme en fonctions= sous programmes
Un programme :Au moins une fonction main = programme principal + des fonctions dans lesquelles des instructions sont déportées
Pourquoi ?Grand programme : difficile à lireÉviter les parties répétitivesPermet le partage et la réutilisation de code
-
Les fonctions : Les fonctions : implimpléémentationmentation
En C, il n'y a que des fonctions (pas de procédures)Prend en entrée des arguments, et renvoie une valeur en retour.Composées de deux parties :
Type_fonction nom_fonction(type1 arg1,…, typeN argN){
Déclaration des variables localesinstructions
.
.return();
}
En-tête ou prototype de la fonction
Code de la fonction
-
Les fonctions : exempleLes fonctions : exemple
#include <stdio.h>
int fonction_somme(int a, int b){
int tmp;tmp = a+b;return(tmp);
}
Void main(){
int i=2;int j=3;int somme;somme = fonction_somme(i,j);printf ("%d + %d = %d\n",i,j,somme);
}
Valeur en retourNom de la fonction
Arguments
Retour de la valeur= type de la fonction
Appel fonction
-
Valeur en retourValeur en retour
Une fonction renvoie une seule valeur du type de la fonction : instruction return(valeur);
return = fin de la fonction, Il est possible d'avoir plusieurs return :
Return peut contenir une expressionSi aucun type de donnée n'est précisé, le type int est pris par défaut.
int valeur_absolue(int n){
if (n>=0)return(n);
elsereturn(-1*n);
}
-
Valeur en retourValeur en retour
Une fonction peut ne rien renvoyer= "procédure" du langage pascalmot clef « void »return rien : return();Typiquement : les fonctions d'affichage
void affiche_n_hello(int n){
int i;for (i=0; i<n; i++)
printf("hello");return;
}
-
ArgumentsArguments
void mafonction(int x){ x = 0; return(); }
int main() {
int a=1;mafonction(a); printf("%d", a); /* affiche 1 */return 0;
}
Les variables a et b sont passées par le programme appelantDes copies sont passées à la fonction
une modification de ces valeurs dans la fonction ne sera pas prise en compte dans le programme appelant
Une fonction peut ne pas comporter d’arguments (ex : main() )
-
PortPortéée des variablese des variables
Variables locales#include <stdio.h>
int fonction_somme(int a, int b){
int tmp;tmp = a+b;return(tmp);
}
Void main(){
int i=2;int j=3;int somme;somme = fonction_somme(i,j);printf (« La somme de %d et % est %d\n« ,i,j,somme);
}
Variables locales :
Existent seulement dans la fonction où elles sont
déclarées
-
PortPortéée des variablese des variables
Variables globales#include <stdio.h>int i,j;
int fonction_somme(void){
return(i+j);}
Void main(){
i=2;j=3;int somme;somme = fonction_somme();printf (« La somme de %d et % est %d\n« ,i,j,somme);
}
Variables globales :
Existent dans toute la partie du fichier source qui
suit leur déclaration
-
PortPortéée des variablese des variables
Variables globales :#include <stdio.h>int i,j;
int fonction_somme(void){
i=-1;return(i+j);
}
Void main(){
i=2;j=3;int somme;somme = fonction_somme();printf (« La somme de %d et % est %d\n« ,i,j,somme);
}
Variables globales :
Peut se révéler pratique,
Mais TRES DANGEREUX
ATTENTION !!!
-
DDééclaration des fonctionsclaration des fonctions
Le programme appelant doit « connaître » la le prototype de la fonction
Plusieurs solutions :1. Le code de la fonction se trouve avant le
programme principal2. Le programme principal contient la déclaration de
la fonction3. La déclaration de la fonction se trouve dans un
fichier d’en tête (la meilleure solution !)
-
DDééclaration des fonctions :claration des fonctions :solution 1solution 1
#include <stdio.h>
int fonction_somme(int a, int b){
return(a+b);}
Void main(){
int i=2, j=3;int somme;somme = fonction_somme(i,j);printf ("%d + %d = %d\n",i,j,somme);
}
Le code de la fonction se trouve avant le programme principal
prototype (et code) avantL'appel de la fonction
-
DDééclaration des fonctions :claration des fonctions :solution 2solution 2
#include <stdio.h>
Void main(){
int fonction_somme(int a, int b);int i=2, j=3;int somme;somme = fonction_somme(i,j);printf ("%d + %d = %d\n",i,j,somme);
}
int fonction_somme(int a, int b){
return(a+b);}
Le programme principal contient la déclaration de la fonction
Prototype de la fonctionAvec un ';'
-
DDééclaration des fonctions :claration des fonctions :solution 3solution 3
#include <stdio.h>#include "ma_fonction.h"
Void main(){
int i=2, j=3;int somme;somme = fonction_somme(i,j);printf ("%d+%d=%d\n",i,j,somme);
}
La définition de la fonction se trouve dans un fichier séparéLa déclaration de la fonction se trouve dans un fichier d’en tête
#include <stdio.h>
int fonction_somme(int a, int b){
return(a+b);}int fonction_prod(int a, int b){
return(a*b);}
int fonction_somme(int a, int b);int fonction_prod (int a, int b);
Fichier d'en-tête "ma_fonction.h"
définition des fonctions dans un fichier séparé "ma_fonction.c"
Programme principal "principal.c"
-
DDééclaration des fonctions :claration des fonctions :solution 3 (suite)solution 3 (suite)
La déclaration de la fonction se trouve dans un fichier d’en tête
Idéalement, le principal.c ne contient que le mainCompilation : on place tous les fichiers *.c qu'on veut compiler: gcc principal.c ma_fonction.c –o prog
Utile car :Permet de réutiliser les fonctions qu'on a écrite dans d'autres programmesLes *.h permettent de connaître les fonctions disponibles sans avoir à rentrer dans le code"Programmation modulaire"
-
Les fonctions rLes fonctions réécursives cursives
Une fonction peut s'appeler elle-mêmeExemple classique de la fonction factorielle :
Peut être pratique et élégantMais pas très lisible, ni très optimisé : allocation mémoire sans libération à chaque appel …
int factorielle(int n){
if (n>1) return(n*factorielle(n-1));
elsereturn(1);
}
Descente :factorielle(5)5>1 donc factorielle(4)4>1 donc factorielle(3)3>1 donc factorielle(2)2>1 donc factorielle(1)return(1)
Remontée :factorielle(5) = 120
n=5 donc n*24=120n=4 donc n*6=24n=3 donc n*2=6n=2 donc n*1=2n=1
Déroulement du programme pour n=5
-
Les fonctions : conclusion Les fonctions : conclusion
Très utile !Réutilisabilité de parties de code, Amélioration de la lisibilité
Bonne pratique de programmation :Faire une fonction dès qu'on peut !!!Les fonctions doivent avoir une taille limitéeFichiers sources séparés
-
Erreurs courantes (1)Erreurs courantes (1)……
int addition(int, int) {
int c;c = a+b;return c;
}
Oubli du nom des variables
int addition(int a, int b); {
int c;c = a+b;return c;
}
Pas de point virgule
-
Erreurs courantes (2)Erreurs courantes (2)……
int addition(int a, int b) {
int a,b,c;c = a+b;return c;
}
Pas de redéclarationdes variables du prototype
int addition(int a, int b); {
int c;c = a+b;return;
}
La fonction n'est pas de type void, il faut renvoyer une valeur
-
Petit exercice Petit exercice ……
Écrire une fonction qui calcule Xn et son programme principal.
Ajouter la fonction factorielle non récursive
Modifier le programme pour placer ces 2 fonctions dans un fichier source séparémes_fonctions.c
-
#include<stdio.h>
float puissance(float X,int n) {
int i; float tmp=1;
for (i=0; i<n; i++) tmp*=X;
return(tmp); }
int factorielle(int n) {
int i; int tmp=1;
for (i=1; i<n; i++) tmp*=(i+1);
return(tmp); }
float puissance(float X,int n)int factorielle(int n);
#include<stdio.h> #include"mes_fonctions.h"
main() { float X=1.5; int n=5;
printf("%f puissance %d=%f\n", X,n,puissance(X,n));
printf("factorielle %d=%d\n", n, factorielle(n));
return; }
mes_fonctions.c mes_fonctions.h
principal.c
-
Tableaux : dTableaux : dééfinitionsfinitions
Un tableau permet de stocker une liste de variables de même type.Stockage des variables en mémoire les uns à la suite des autres.
Déclaration :<type> <identificateur>[<nb_elements>]
<type> : type des variables du tableau<identificateur> : nom du tableau<nb_elements> : nb d'éléments du tableau, constante.
(= pas de variable)
Exemples :#define NB_ELEMENTS 4int tab[5];float tableau_reels[NB_ELEMENTS];char tableau_de_lettres[20];
-
Tableaux : dTableaux : dééfinitionsfinitions
On accède aux éléments par<identificateur>[<indice>]
Exemples :tab[1]=100; // place 100 à l'indice 1
float tab[5];int i=2;
// affectation d'une case du tableau :tab[i]=0.513;
// accès à la donnée :printf("la valeur à l'indice %d est %f\n", i, tab[i]);
-
Tableaux : mTableaux : méémoiremoire
Que se passe t'il en mémoire?#define NB_MAX 5float tab[NB_MAX];
Réserve une zone mémoire pour 5 float
tab commence à l'indice 0tab[NB_MAX] n'existe pas
erreur si l'on tente d'y accéderindice toujours positifindice du dernier élément = taille du tableau -1
la variable tab sans les crochets vaut 0xBC347A68 = l'adresse de la première case du tableau (voir plus loin …)
…0xBC347A640xBC347A680xBC347A6C0xBC347A700xBC347A740xBC347A780xBC347A7C0xBC347A800xBC347A84…
tab[0]tab[1]tab[2]tab[3]tab[4]
-
Tableaux : exempleTableaux : exemple
Exemple de programme : remplir un tableau de 10 éléments avec la suite des entiers pairs
#include <stdio.h>
main(){
int tab[10];int i;// affectation d'une case du tableau :
for (i=0; i<10; i++) // on va bien de 0 à 9 = OKtab[i]=i*2;
// affichage du tableau :for (i=0; i<10; i++)
printf("tab[%d]=%d\n", i, tab[i]);
return();}
-
Tableaux : quelques Tableaux : quelques prpréécisionscisions
Ce qu'on peut faire :tab[i-2*j]; // si tab[i-2*j] existe !!!tab[factorielle(3)]=3;tab[autre_tableau[2]];tab[i]++;tab[5]={0,2,4,6,8};//affectation directechar tab[]="mot";
Ce qu'on ne peut pas faire :tab1=tab2; si tab1 et tab2 sont 2 tableaux d'entier(contrairement au pascal ou c'est autorisé)Il faut recopier les éléments un par un …
-
Tableaux Tableaux àà plusieurs plusieurs dimensionsdimensions
déclaration : int tab[10][5];Ex: initialiser un tableau 8*6 par les valeurs
indice_colonne/indice_ligne#include <stdio.h>
#define NB_COL 8#define NB_LIG 6
main(){
float tab[NB_COL][NB_LIG];int i_col, i_lig;
for (i_col=0; i_col<NB_COL; i_col++)for(i_lig=0; i_lig<NB_LIG; i_lig++)
tab[i_col][i_lig]=i_col/i_lig; return();
}
-
Tableaux Tableaux àà plusieurs plusieurs dimensions en mdimensions en méémoiremoire
Exemple pour int tab[2][3];Rangés en faisant varier les indices du dernier jusqu'au premier
…0xBC347A640xBC347A680xBC347A6C0xBC347A700xBC347A740xBC347A780xBC347A7C0xBC347A800xBC347A84…
tab[0][0]tab[0][1]tab[0][2]tab[1][0]tab[1][1]tab[1][2]
Ce qui implique :• tab[0][3] existe !!! = tab[1][0]• Pas de contrôle par le compilateur ATTENTION
-
Tableaux : 2 exercices Tableaux : 2 exercices (faciles!)(faciles!)
Moyenne de notes :Écrire un programme qui saisit les notes de 10 élèves, qui fait la moyenne des notes, puis qui affiche les notes au-dessus de la moyenne.
Transposition d'une matrice : Créer deux matrices de taille K × K et initialiser la première par des valeurs aléatoires. Calculer la transposition de cette matrice et la placer dans la seconde.
-
PointeursPointeurs
Définitions, opérateursArithmétique des pointeursLien avec les tableaux et les chaînes
de caractèresAllocation mémoireExemples
-
Pointeurs : IntroductionPointeurs : Introduction
En C, les variables sont stockées en mémoire sous la forme d'une suite d'octets. Exemple :
sizeof(float) = 4 octets, sizeof(int) = 4 octets, sizeof(char) = 1 octet, etc.
Chaque octet de la mémoire a une position = une adresseToute les variables ont donc une adresse : l'adresse du premier octet de la variable
float0xBF94B2E10xBF94B2E20xBF94B2E30xBF94B2E4………0xBF94B2E8…
Adresse du float :0xBF94B2E1
Adresse du char :0xBF94B2E8
mémoire
char
-
Pointeurs : dPointeurs : dééfinitionfinition
Un pointeur est une variable destinée à contenir l'adresse d'un autre objet (variable, fonction)Ce pointeur "pointe" le premier octet de l'objetLes adresses mémoires sont codées sur 32 bits, les pointeurs occupent donc 4 octets, ce sont des entiers.
pointeur0xBF94B2E1
objet de type float
0xBF94B2E10xBF94B2E20xBF94B2E30xBF94B2E4…
-
Pointeurs : dPointeurs : dééclarationclaration
Déclaration d'un pointeur :
<type> * <identificateur>;
<type> est le type de la variable pointée.<identificateur> est l'identificateur du pointeur Exemple : float *p;
p est une adresse.donc sizeof(p) = 4 octets
Action = déclare une adresse p qui pointera vers un floatPour l'instant, la valeur pointée par p est indéterminée
0xBC347A69 ???0xBC347A680xBC347A6C0xBC347A700xBC347A74…
p
-
Pointeurs : opPointeurs : opéérateursrateurs
l'opérateur & permet de récupérer l'adresse d'une valeur :si on a int a, alors &a désigne l'adresse de la variable a.
l'opérateur * permet de récupérer la valeur pointée par une adressesi on a int *p, alors p est l'adresse de la variable et *p est sa valeur
int a;int *p;a = 3;p = &a;printf("@ de a=%x\n", p);printf("valeur de a=%d\n, *p);
Affiche BC347B54
???0xBC347B54
adresse valeur
0xBC45B30A0xBC347B70
???
nom
a
p
3
0xBC347B54
3
-
ArithmArithméétique des pointeurstique des pointeurs
La valeur d'un pointeur = entier on peut lui appliquer des opérateurs arithmétiques classiques. Si int *p1, *p2;
3 opérations valides : addition : p1 + entier pointeursoustraction : p1 – entier pointeurdifférence : p1 – p2 entiersomme : NON, pas de sens
0xBF94B2E10xBF94B2E50xBF94B2E90xBF94B2ED…
int *p;printf("@ de p=%x\n", p);p=p+1;printf("@ de p=%x\n", p);
• Affiche 0xBF94B2E1, puis 0xBF94B2E5• Remarque sur l'affichage : %x affiche l'adresse en hexa; %ld en entiers
-
ArithmArithméétique des pointeurstique des pointeurs
main() {
int i = 3;int *p1, *p2;p1 = &i; p2 = p1 + 1;printf("p1 = %x et p2 = %x\n",p1,p2);
}
Affiche p1 = 0xBF94B2E1 etp2 = 0xBF94B2E5 car sizeof(int) = 4
Addition :
-
ArithmArithméétique des pointeurstique des pointeurs
main() {
double i = 3;double *p1, *p2;p1 = &i; p2 = p1 - 1;printf("p1 = %x et p2 = %x\n",p1,p2);
}
Soustraction :
Affiche p1 = 0xBF94B2B8 et p2 = 0xBF94B2B0 car sizeof(double) = 8
-
ArithmArithméétique des pointeurstique des pointeurs
main() {
float i = 3;float *p1, *p2;p1 = &i; p2 = p1 - 5;printf("p1 – p2 = %d\n", p1 - p2);
}
différence :
Affiche p1 – p2 = 5 (renvoie le nombre d'élément et non la taille)
-
Lien avec les tableauxLien avec les tableaux
On peut donc décrire une zone mémoire en incrémentant ou décrémentant un pointeur= tableau !int tab[5] = {0,2,4,6,8};
…0xBC347A640xBC347A680xBC347A6C0xBC347A700xBC347A740xBC347A780xBC347A7C0xBC347A800xBC347A84…
tab[0] = 0tab[1] = 2tab[2] = 4tab[3] = 6tab[4] = 8
• tab, c'est l'adresse 0xBC347A68• donc tab est un pointeur• tab[0] = *tab = 0• tab[1] = *(tab+1) = 2• …• et tab[5] ?
-
Lien avec les chaLien avec les chaîînes de nes de caractcaractèèresres
Les chaînes de caractères sont des tableaux de caractères
char mot[5] = "salut";
Donc ce sont aussi des pointeurs
…0xBC347A270xBC347A280xBC347A290xBC347A2A0xBC347A2B0xBC347A2C0xBC347A2D0xBC347A2E0xBC347A2F…
's''a''l''u''t'
• mot, c'est l'adresse 0xBC347A28• mot[0] est équivalent à *(mot) = 's'• mot[1] est équivalent à *(mot+1) = 'a'• …
-
Tableaux et pointeurs : Tableaux et pointeurs : DiffDifféérence entre les deux rence entre les deux
notationsnotations
Quand on déclare :int tab[5];On réserve l'adresse du tableau : tabET on réserve la zone mémoire
On peut écrire aux adresses tab, tab+1, … tab+4Mais ces valeurs ne sont pas initialisées= Allocation STATIQUELa taille du tableau est fixée à la compilation
tab0xBF94B2E1
-
Tableaux et pointeurs : Tableaux et pointeurs : DiffDifféérence entre les deux rence entre les deux
notationsnotations
Quand on déclare :int *tab;On réserve l'adresse du tableau : tabet on ne réserve pas la zone mémoire
On ne peut pas écrire aux adresses tab, tab+1, … tab+4
Il faut allouer de la mémoireAllocation dynamiquependant l'exécution
tab0xBF94B2E1
-
Allocation dynamiqueAllocation dynamique
Pourquoi ?La taille d'un tableau (ou pointeur, ou string) n'est pas toujours connue lorsqu'on écrit un programmeExemple : "faire un programme qui saisit nnombres au clavier et les ranger dans un tableau".Solution : tab[100000] … pas très satisfaisant !Il est utile de pouvoir allouer exactement la taille dont on a besoin pendant l'exécution= allocation dynamiqueUtilisation des fonctions malloc, calloc, realloc
-
Utilisation de Utilisation de mallocmalloc
But : réserver une zone mémoire pour stocker nvariables de même type.Utilisation :
- argument = taille de la zone à allouer en octets (utiliser sizeof)- renvoie un pointeur
Exemple :#include <stdlib.h>int *p; // p est l'@p = (int*)malloc(5*sizeof(int));
p0xBF94B2E1
p[0]p[1]p[2]p[3]p[4]
-
Utilisation de Utilisation de mallocmalloc
Renvoie NULL si erreur :char *pchar;pchar = (char*)malloc(3*sizeof(char));if (pchar==NULL)
printf("erreur d'allocation mémoire\n");
Lorsque l'on utilise une allocation dynamique, La mémoire allouée doit être libérée
fonction free(pointeur);
Exemple :free(pchar);
pchar0xBF94B2E1
pchar[0]pchar[1]pchar[2]
-
Utilisation de Utilisation de mallocmalloc
Exemple : allocation d'un tableau de n réels où n est saisi à l'exécution
void main() {
float *pfloat; // déclaration du tableauint nbfloat, i;
printf("Entrez le nb d'elts du tableau :\n");scanf("%d", &nbfloat);
// allocation dynamiquepfloat=(int*)malloc (nbfloat*sizeof(float));
// accès aux variables du tableaufor (i=0; i<nbfloat; i++)
pfloat[i]=rand()/RAND_MAX;free(pfloat);
}
-
Utilisation de Utilisation de calloccalloc etet reallocrealloc
calloc : idem que malloc + initialise la zone avec des 0. exemple:
int *p;p = (int*) calloc (n, sizeof(int)); // ! 2 arg
realloc : permet de modifier la taille d'une zone allouéereçoit l'adresse et la nouvelle taille totale. Renvoie une nouvelle adresse qui peut être différente, ou non. Ex : augmenter de 4 la taille du tableau p :
p = realloc (p, (n+4)*sizeof(int));
remarque : le premier malloc (ou calloc) n'est pas obligatoire
-
Utilisation de Utilisation de reallocrealloc : exemple: exemple
Stocker des int saisis par l'utilisateur dans un tableau jusqu'à ce qu'un 0 soit saisi.
int main () {
int nombre, nb_nombre=0; int *tab = NULL;
do { printf ("Entrez un nombre entier: ");scanf ("%d", &nombre); nb_nombre++; tab =(int*)realloc (tab, nb_nombre*sizeof(int)); tab[nb_nombre-1]=nombre;
} while (nombre!=0);
free (tab); return 0;
}
-
Allocation dynamique d'un Allocation dynamique d'un tableau tableau àà deux dimensionsdeux dimensions
Double pointeur : int **tab;tab = @ d'un tableau d'@
les tableaux peuvent avoirdes tailles différentes !
@@@@
tab@
intint
intintintintint
intint
int
-
Allocation dynamique d'un Allocation dynamique d'un tableau tableau àà deux dimensionsdeux dimensions
2 étapes : allocation du tableau de taille adresseallocation des différents tableaux de données
@@@@
tab@
intint
intintintint
intintint int
tab=(int**)malloc(taille*sizeof(int*));
for (i_taille=0; i_taille<taille; i_taille++)tab[i_taille] = (int*)malloc(nb*sizeof(int));
-
Allocation et initialisationAllocation et initialisationdu triangle de pascaldu triangle de pascal
int **pascal; int i_col, i_lig;
// allocation mémoirepascal = (int **)malloc(TAILLE*sizeof(int*));
for (i_lig=0; i_lig<TAILLE; i_lig++)pascal[i_lig] = (int*)malloc((i_lig+1)*sizeof(int));
// initialisation du tableaupascal[0][0]=1; // initfor (i_lig=1; i_lig<TAILLE; i_lig++){
pascal[i_lig][0]=1; // 1er élément ligne = 1pascal[i_lig][i_lig-1]=1; // dernier élément ligne = 1for (i_col=1; i_col<TAILLE-1; i_col++)
pascal[i_lig][i_col] = pascal[i_lig-1][i_col-1]+ pascal[i_lig-1][i_col];
// désallocationfor (i_lig=1; i_lig<TAILLE; i_lig++)
free(pascal[i_lig]);free(pascal);
111121133114641…
-
Les pointeurs :Les pointeurs :Guide de survieGuide de survie
Si int *p, p est l'adresse
*p est la donnéefaire des dessins pour distinguer @ et données !
Allocation statique : int p[5]fixé durant l'exécutionlibération non nécessaire
Allocation dynamique : int *ptant que *p n'est pas alloué, on ne peut pas acceder à *pp = (int*) malloc (5*sizeof(int));taille modifiable durant l'exécutionlibération obligatoire : free(p);
-
petit petit QuizzQuizz
si l'adresse de la variable a est 0x1130 …Quelle est la valeur de &a ? de pa ? Que vaut sizeof(a) ? sizeof(pa) ?Quelle est la valeur de *pa ?Quelle est la valeur de c ?Que valent :
sizeof(tabStatic) ? sizeof(*tabStatic) ? sizeof(tabDynamic) ? sizeof(*tabdynamic) ?
char a=2; char c, *pa;int tabStatic[5];int *tabDynamic;
pa = &a;*pa *= 2;c= 3*(5 - *pa); tabDynamic = (int*)malloc(4*sizeof(int));
-
Les pointeurs :Les pointeurs :exercice facileexercice facile
Ecrivez la fonctionint compare(char *s1, char *s2);
qui renvoie :0 si les deux chaînes de caractères sont identiques-1 sinon
Indications : - on utilisera la notation 'pointeur' et non 'tableau'- on pourra utiliser la fonction int strlen(char *s) qui donne
la taille d'une chaîne de caractère s
-
Les pointeurs :Les pointeurs :exercice facileexercice facile
int compare (char *s1, char *s2){
int taille_s1, taille_s2, i;taille_s1 = strlen(s1);taille_s2 = strlen(s2);
if (taille_s1 != taille_s2) return(-1);
for (i=0; i<taille_s1; i++){
if ( *(s1+i) != *(s2+i) ) return(-1);}
return(0);}
-
Les pointeurs :Les pointeurs :ExerciceExercice
Écrire un programme qui effectue la multiplication de deux matrices m*k et k*n dont les tailles sont saisies par l'utilisateur
rappel : nb_col matrice1 = nb_lig matrice 2résultat = matrice m*n
Programme :déclaration des variablessaisies des tailles des matrices m, k, nallouer les trois matrices initialiser les 2 matrices d'entréecalculer les valeurs de la matrice résultat
MK MN
KN
m lignes
k colonnes
k lignes
n colonnes
-
Les pointeurs :Les pointeurs :ExercicesExercices
#include <stdio.h>#include <stdlib.h>
void main(){// déclaration des variables int **MK, **KN, **NM; int n,m,k, i_n, i_m, i_k, somme =0;
// saisie tailles matricesprintf("entrez n:\n"); scanf("%d", &n);
printf("entrez m:\n"); scanf("%d", &m);
printf("entrez k:\n"); scanf("%d", &k);
-
Les pointeurs :Les pointeurs :ExercicesExercices
// allocation des matrices
// MKMK = (int **) malloc (m*sizeof(int *));for (i_m=0; i_m<m; i_m++)
MK[i_m]=(int*) malloc (k*sizeof(int));
// KNKN = (int **) malloc (k*sizeof(int *));for (i_k=0; i_k<k; i_k++)
KN[i_k]=(int*) malloc (n*sizeof(int));
// allocation matrice résultatNM = (int **) malloc (n*sizeof(int *));for (i_n=0; i_n<n; i_n++)
NM[i_n]=(int*) malloc (m*sizeof(int));
-
Les pointeurs :Les pointeurs :ExercicesExercices
// initialisation matricesfor (i_m=0; i_m<m; i_m++)
for (i_k=0; i_k<k; i_k++)MK[i_m][i_k] = i_m+i_k;
for (i_k=0; i_k<k; i_k++)for (i_n=0; i_n<n; i_n++)
KN[i_k][i_n] = i_k+i_n;
// calcul des éléments de NMfor (i_n=0; i_n<n; i_n++)
for (i_m=0; i_m<m; i_m++){somme=0;// NM[i_n][i_m]=somme_sur_k_de(MK[i_n][i_k]*KN[i_k][i_m])for (i_k=0; i_k<k; i_k++)somme += MK[i_m][i_k]*KN[i_k][i_n];
NM[i_n][i_m]=somme;}
// désallocation …}
variante : à refaire avec la notation pointeur
-
Les pointeurs :Les pointeurs :Retour sur les fonctionsRetour sur les fonctions
Limitation des fonctions : ne permettent de renvoyer qu'une seule valeur en retour …
Comment faire lorsqu'on souhaite renvoyer un tableau? un mot? etc.
Exemple : renvoyer un tableau trié
-
Les pointeurs :Les pointeurs :Retour sur les fonctionsRetour sur les fonctions
La solution qui ne fonctionne pas : renvoyer un tableau statique
#define N 10
int *triTableau(int *tabIn){int tab[N];
...return(tab);
}
int main(){int tabIn[N];int *tabOut;
...tabOut = triTableau(tabIn);
}
tab[5] est déclaré en variable locale dans la fonction triTableau
on renvoie seulement tab (@)mais les valeurs n'existent
plus à la sortie de la fonction triTableau
(Warning à la compil)
-
Les pointeurs :Les pointeurs :Retour sur les fonctionsRetour sur les fonctions
Une première solution qui fonctionne :
#define N 10
int *triTableau(int *tabIn){int *tab;tab = (int*) malloc (N*sizeof(int));
...return(tab);
}
int main(){int tabIn[N];int *tabOut;
...tabOut = triTableau(tabIn);
}
prototype idem que la solution précédente mais allocation dynamique
renvoyer un pointeur (une seule valeur = OK) sur une zone mémoire contenant le résultat.
Solution satisfaisante
-
Les pointeurs :Les pointeurs :Retour sur les fonctionsRetour sur les fonctions
Une deuxième solution qui fonctionne :
#define N 10
void triTableau(int *tabIn, int *tabOut){
tabOut = (int*) malloc (N*sizeof(int));...
return(tabOut);}
int main(){int tabIn[N];int *tabOut;
...triTableau(tabIn, tabOut);
}
idem solution précédente mais le pointeur sur le tableau àmodifier est passé en paramètre
-
Les pointeurs :Les pointeurs :Retour sur les fonctionsRetour sur les fonctions
Une troisième solution qui fonctionne : variable globale
#define N 10int tabOut[N]; // var. globale
void triTableau(int *tabIn){
// remplir tabOut avec tabInfor …
tabOut = …}
int main(){int tabIn[N];
...triTableau(tabIn);
}
pas très clair …
On ne sait pas que tabOut est modifié en voyant le prototype de triTableau
= dangereux, à éviter
-
Retour sur les chaRetour sur les chaîînes de nes de caractcaractèèresres
Dans <string.h> :
int strlen(char *s);connaître la taille d'une chaine de caractères
int strcmp(char *s1, char *s2);comparer deux chaînes de caractères (0 si =)
char *strcat (char *dest, char *src);char *strncat(char *dest, char *src, int n);concaténer deux chaînes de caractères
char *strcpy (char *dest, char *srce);char *strncpy(char *dest, char *srce, int n);recopier une chaîne de caractère dans une autre
-
exempleexemple
int strlen(char *s);connaître la taille d'une chaîne de caractères
#include <stdio.h>#include <string.h>#include <stdlib.h>
int main(){char stat[20];char *dyn;
dyn = (char*) malloc (15*sizeof(char));
printf("taille stat=%d\n", strlen(stat));printf("taille dyn =%d\n", strlen(dyn ));
}
affiche 20
et … 0 !
-
exempleexemple
char *strcat (char *dest, char *src);concaténer deux chaînes de caractères
#include <stdio.h> #include <string.h>
main() { char ch1[50] = "bonjour";char * ch2 = " monsieur";printf("avant :%s\n" ,ch1);strcat(ch1,ch2);printf("apres :%s\n" ,ch1);
}
affiche avant : bonjour
apres : bonjour monsieur
-
Types composTypes composéés : s : IntroductionIntroduction
Les types composés servent à organiser les données de type float, int, char, etc.
Les tableaux sont un type composé particulier, où :les éléments sont tous du même typeIls sont rangés de manière contigus en mémoire
Il existe d'autres type de types composés :les structuresles unionsles énumérations
-
Les structuresLes structures
Les structures sont une suite finie d'objets différents.Une structure peut posséder plusieurs membres ou champs.
Exemple 1 : les champs d'une structure décrivant un individu pourraient être :
nom (chaîne de caractères)âge (entier)taille (réel)emploi (chaîne de caractères)…
Exemple 2 : une structure point :nom du point (caractère)coordonnée en abscissecoordonnée en ordonnée
-
Les structures :Les structures :ddééclarationclaration
Mot clef struct, à déclarer au dessus du main ou dans un .h
Exemples :
struct point {
char lettre;float coord_x;float coord_y;
};
struct individu{
char *nom;int age;float taille;char *metier;
};
-
Les structures :Les structures :ddééclarationclaration
puis déclaration d'un variable de type "point" :struct point un_point;
ou bien directement déclaration structure + variable :
struct point {
char lettre;float coord_x;float coord_y;
} un_point;
-
Les structures :Les structures :utilisationutilisation
Accès aux membres d'une structures à l'aide de "."Exemple :
Initialisation d'une structure lors de la déclaration :
struct point un_point = {'A', 54.72,28.98};
struct point un_point;
un_point.lettre = 'A';un_point.coord_x = 54.72;un_point.coord_y = 28.98;
-
Les structures :Les structures :utilisationutilisation
On peut affecter une structure à une autre :struct point un_autre_point;un_autre_point = un_point;
Attention si une des structures contient des variables allouées dynamiquement … recopie de l'adresse !
Les structures peuvent être passés en argument d'une fonction : float distance(struct point A, struct point B){… EXO … }
Une fonction peut renvoyer une structureexemple : initialisation d'une structure pointstruct un_point fonction(char c, int x, int y)
{ … EXO …}= Un bon moyen pour renvoyer plusieurs valeur d'une fonction
-
Les structures :Les structures :exercice facileexercice facile
Écrire la structure de données qui permet de gérer un individu comportant un nom (<20 char), un âge et une taille. Écrire le programme qui saisit les champs de cet individu, puis les affiche
#include <stdio.h>#define TAILLE 2
struct individu{
char nom[20];int age;float taille;
};
int main(){
struct individu ind;
// saisieprintf("Entrez le nom de l'individu\n");scanf("%s", ind.nom); // pas de & car ind.nom est déjà l'@
printf("quel est son age ?\n");scanf("%d", &ind.age));
printf("quelle est sa taille (en m)\n", iTaille);scanf("%f", &ind.taille));
// affichageprintf("%s a %d ans et mesure %f\n", ind.nom, ind.age, ind.taille);
}
-
Les structures :Les structures :exercice + difficileexercice + difficile
Quelle est la structure de données qui permet de gérer une population de N individus dont le nom (<20 char), l'age et la taille sont spécifiés ?Écrire le programme qui saisit les champs de ces individus, et les affiche
#include <stdio.h>#define TAILLE 2
struct individu{
char nom[20];int age;float taille;
};
int main(){
int iTaille;struct individu pop[TAILLE];// saisiefor (iTaille=0; iTaille<TAILLE; iTaille++)
{printf("Entrez le nom de l'individu %d\n", iTaille);scanf("%s", pop[iTaille].nom);
printf("quel est son age ?\n");scanf("%d", &(pop[iTaille].age));
printf("quelle est sa taille (en m)\n", iTaille);scanf("%f", &(pop[iTaille].taille));
}// affichagefor (iTaille=0; iTaille<TAILLE; iTaille++)
printf("%s a %d ans et mesure %fm\n", iTaille, pop[iTaille].nom, pop[iTaille].age, pop[iTaille].taille);
}
question : les parenthèses sont elles nécessaires ?
-
ApartApartéé sur la prioritsur la prioritéé des des opopéérateursrateurs
très prioritaire
peu prioritaire
&(pop[iTaille].age)
Réponse : parenthèsesnon nécessaires !
-
Les structures :Les structures :exo toujours + difficile !!!exo toujours + difficile !!!
Écrire le programme qui saisit les champs de ces individus, et les afficheMême exercice avec une allocation dynamique
#include <stdio.h>#define TAILLE 2
struct individu{
char nom[20];int age;float taille;
};
int main(){
int taille, iTaille;struct individu *pop;
printf("entrez la taille de la population :\n");scanf("%d", &taille);
pop = (struct individu*)malloc(taille*sizeof(struct individu));
for (iTaille=0; iTaille<taille; iTaille++){
printf("Entrez le nom de l'individu %d\n", iTaille);scanf("%s", pop[iTaille].nom);
printf("quel est son age ?\n");scanf("%d", &pop[iTaille].age);
printf("quelle est sa taille (en m)\n", iTaille);scanf("%f", &pop[iTaille].taille);
}// affichage … pas la placefree(pop);}
-
Pointeur sur les structuresPointeur sur les structures
Précision sur les pointeurs de structures :L'opérateur flèche -> permet d'accéder directement aux champs d'un pointeur de structure afin d'éviter la notation *(pointeur).champ
#include <stdio.h>#include <stdlib.h>
struct individu {int age;float taille;
};
int main(){
struct individu *pind; // pointeur sur une structure// allocation mémoire pind = (struct individu *) malloc (sizeof(struct individu));pind->age=1;printf("age=%d\n",pind->age);free(pind);
}
-
Les unionsLes unions
Une union est un ensemble de types différents occupant alternativement une même zone mémoire Permet de définir un objet dont le type varieSi les types ont une longueur différente, sa taille est celle du type le plus grandExemple : union jour représente un jour de la semaine qui peut être représenté soit sous forme d'une lettre, soit sous la forme d'un numéro :
union jour{int numero;char lettre;};
int main(){union jour hier, demain;hier.lettre=’m’;printf("hier = %c\n",hier.lettre);hier.numero = 3;demain.numero = (hier.numero+2);printf("demain = d\n",demain.numero);}
-
Les Les éénumnuméérationsrations
Les énumérations permettent de définir un type par la liste des valeurs qu’il peut prendre. Un objet de type énumération est défini par le mot-clef enum et un identificateur de modèle, suivi par la liste des valeurs que peut prendre cette objet :
enum modele {const_1, const_2, ..., const_n};
Exemple : définition d'une énumération pour définir un booléen
int main(){enum booleen {faux, vrai};
enum booleen b;b=vrai;printf("b = %d\n",b);}
-
DDééfinition de types finition de types composcomposéés avec s avec typedeftypedef
Pour alléger l'écriture des programmes, on peut affecter un nouvel identificateur à un type composé à l'aide de typedef :typedef type_compose identificateur;
Exemple :struct nombre_complexe{ double reelle; double imaginaire;
};
typedef struct nombre_complexe type_complexe;
main() { type_complexe z; z.reelle = 2.0;...
}
-
EntrEntréées/sorties es/sorties conversationnellesconversationnelles
Sortie par défaut = l'écran, utilisation de la fonction printfsprintf("format", variables);
Affichage de la chaîne "format" qui peut contenir des variables
Entrée par défaut = le clavier, utilisation de la fonction scanfscanf ("format", @variables);
lecture de la chaîne "format" qui peut contenir des variables
-
EntrEntréées/sorties es/sorties conversationnellesconversationnelles
Formats des entrées sorties :
-
EntrEntréées/sorties dans les es/sorties dans les chachaîînes de caractnes de caractèèresres
Deux fonctions très pratiques : sprintf et sscanf
sprintf : écrire "format" dans une chaîne char *str :sprintf(char *str, "format", variables);
int i=12;char c='a';char mot[10]="toto";char str[50];sprintf (str, "concat%d%c%s",i,c,mot); printf("%s\n", str);
Affiche : concat12atoto
Remarque1 : sprintf n'alloue pas str !Remarque2 : sprintf peut remplacer strcat(mini exo : écrire l'équivalent d'un strcat avec sprintf)
-
EntrEntréées/sorties dans des es/sorties dans des chachaîînes de caractnes de caractèèresres
sscanf : lire "format" dans la chaîne str :sscanf (char *str, "format", @variables);
exemple : lire un entier dans la chaine "toto27"char mot[20]="toto27";int entier;sscanf(mot, "toto%d", &entier);printf("entier=%d", entier);
affiche : entier=27
-
Gestion de fichiersGestion de fichiers
Un identificateur sur un fichier se déclare avec :FILE *fic; // id sur un fichier
Fonctions de base pour manipuler des fichiers (commencent par f)
fopen : ouvrir un fichier // renvoie l'id utilisé par les autres fonctionsfclose : fermer un fichier
fprintf : écrire dans un fichierfscanf : lire dans un fichier
fwrite : écrire dans un fichierfread : lire dans un fichier
feof : test si fin de fichierfseek : se déplacer dans le fichierftell : renvoie la position courante dans un fichier
en mode texte
en mode binaire
-
Gestion de fichiersGestion de fichiers
fopen : ouvre un fichier à partir de son nomint fopen(char *nomfichier, char *mode)
nomfichier : chaîne de caractèremode : plusieurs mode d'ouverture :
valeur en retour : un identificateur de fichier si OKNULL si problème test
-
Gestion de fichiersGestion de fichiers
fclose : ferme un fichierfclose(FILE *fic);
Exemple pour fopen et fclose:
main() { FILE *fic;
// ouverture d'un fichier en mode lecturefic = fopen("toto.txt", "r");
// test si l'ouverture s'est bien passéeif (fic == NULL) printf("erreur d'ouverture du fichier\n");... fclose(fic);
}
-
Gestion de fichiersGestion de fichiers
2 modes d'ouverture des fichiers : mode texte = une suite de caractèresmode binaire = une suite d'octets
ì �. L’©d)™É&™)©Ÿ~ƒTõŒ-~¹…¹è9‡bò �' Œ��ùãî§9Z=ûðÉMî·¿ùQþÛýcpi×»ÑîR�6íÜÔÏÑ«ìæi§ºyÉM»<¨¼ûyJY�ãßgGS~~vã(?©è.ÏRÊîþÓMf>§ÿùû5eë �wý<��Ø¥ �E ;¾Óå×oÏ;5™Ý_ÿ±{úô°Óòý]iÞ<Ù)§JýåÏ�ûa÷·¿üÛO?Ôÿý³ÎnµÿukÒ§RÅ�v'¿ˆNš9¨ÕÖVÈgÇùì¦ãîÖŸ ¤y(ýQ»�”¶»Îöå‹¥†9îTŸm¬¿´ �_ 5î’;N¿ÿ�¤ �?Ô š”·�úã Bœƒ�Y>ö§ïøi‰ � �Q 0^ ø§ÏþZn§ä3i
Cette méthode de compression est basée sur l’utilisation d’un dictionnaire contenant les séquences rencontrées dans le fichier à compresser. Le fichier compressé contiendra uniquement les indices des séquences dans le dictionnaire.
Un fichier texte Un fichier binaire
-
Lecture/Lecture/éécriture dans des criture dans des fichiers en mode textefichiers en mode texte
fprintf et fscanf : s'utilise comme printf et sprintf, mais écriture dans un fichier en mode texte
fprintf(FILE *fic, "format", variables);fscanf (FILE *fic, "format", @variables);
Lorsqu'on lit dans le fichier avec fscanf, le curseur se déplace automatiquement.Exemple : lire un entier au format texte dans le fichier toto.txt
main() { FILE *fic;int entier;// ouverture d'un fichier en mode lecturefic = fopen("toto.txt", "r");fscanf(fic,"%d", &entier); // lecture entierfclose(fic);
}
12
toto.txt
-
Lecture/Lecture/éécriture dans des criture dans des fichiers en mode textefichiers en mode texte
Écriture dans un fichier : Exemple Écrire les N premières puissances de deux dans le fichier deux.txt
#define N 5
main() { FILE *fic;int i;int tmp;
// ouverture d'un fichier en mode écriturefic = fopen("deux.txt", "w+");
for (i=0; i<N; i++){tmp = pow(2,i);fprintf(fic,"%d ", tmp); // écriture entier
}fclose(fic);
}
-
Lecture/Lecture/éécriture dans des criture dans des fichiers en mode binairefichiers en mode binaire
Mode binaire : une suite d'octets, pas forcément des caractères
On utilise les fonction fread et fwrite
Lire n eléments de taille t dans le fichier fic et les placer àl'adresse addr :
fread (addr, n, t, fic);
Inversement, écrire n eléments de taille t dans le fichier ficdepuis l'adresse addr
fwrite (addr, n, t, fic);
Fonctions utiles pour manipuler des données de grande taille ou ayant un type composé
-
Lecture/Lecture/éécriture dans des criture dans des fichiers en mode binairefichiers en mode binaire
Écriture dans un fichier : Exemple Écrire les N entiers d'un tableau dans un fichier
#define NB 50 #define F_SORTIE "sortie"
int main(void) { FILE *f_in;int *tab;int i;tab = (int*)malloc(NB * sizeof(int));
for (i = 0 ; i < NB; i++) tab1[i] = i;
/* écriture du tableau dans F_SORTIE */ fwrite(tab, NB * sizeof(int), 1, f_out);fclose(f_out);
}
-
Test de fin de fichierTest de fin de fichier
Deux solutions pour le test fin de fichier :fonction feof(FILE *fic)ou caractère 'EOF'(seulement en texte)
Exemple avec feof : tant que le fichier toto.txt n'est pas fini, lire des entiers et les ranger dans un tableau
main() { FILE *fic;int entier[1000];
// ouverture d'un fichier en mode lecturefic = fopen("toto.txt", "w+");while (!feof(fic)){// lecture intfscanf(fic," %d ", &entier[nb_entier]);
}fclose(fic);
}
23 1 899 8756 1 12 0 43 7 7 65 230 99
toto.txt
-
Autres fonctions pour les Autres fonctions pour les fichiersfichiers
Utilisation de fseek et ftell :
Déplacer le curseur dans le fichier :int fseek (FILE *stream, long offset, int whence);
nouvelle position (en octets) = additionner offset octets au point de départ indique par whence. whence : SEEK_SET, SEEK_CUR ou SEEK_END
Connaître la position du curseur :long ftell (FILE *stream);
-
Autres fonctions pour les Autres fonctions pour les fichiersfichiers
Utilisation de fseek et ftell : exemple du format ppm
Une partie texte, et une partie binaire rgbrgbrgb …
stratégie pour la lecture :ouverture et lecture en mode texte, sauvegarder la position et fermetureréouverture en mode binairese placer à la position sauvegardéelecture en binaire
P6# CREATOR: The GIMP's PNM Filter Version 1.040 40255��€ �! ¿¦?ëá?ÿá?ÿá?ÿÖ?ÿÖ?ÿË?ÿË?ÿ¿?ÿ¿?ÿ´?ÿ©?ÿh?ë��¾??€etc…
-
Lecture d'une image PPM : Lecture d'une image PPM : partie textuellepartie textuelle
P6# CREATOR: The GIMP's PNM Filter Version 1.040 40255��€ �! ¿¦?ëá?ÿá?ÿá?ÿÖ?ÿÖ?ÿË?ÿË?ÿ¿?ÿ¿?ÿ´?ÿ©?ÿh?ë��¾??€etc…
FILE *fic;char nimp, *typefic;int nbcol, nblig, max
// ouverture et lecture en mode textef=fopen("ball.ppm", "r");fscanf(f, " %s \n", typefic); // lecture type fichier (P6)
while (nimp!='\n') // lecture chaine quelconquefscanf(f,"%c", &nimp);
fscanf(f,"%d %d \n", &nbcol, &nblig);fscanf(f,"%d \n", &max);cur = ftell(f); // sauvergarde position curseur
fclose(f);
-
Lecture d'une image PPM : Lecture d'une image PPM : partie binairepartie binaire
P6# CREATOR: The GIMP's PNM Filter Version 1.040 40255��€ �! ¿¦?ëá?ÿá?ÿá?ÿÖ?ÿÖ?ÿË?ÿË?ÿ¿?ÿ¿?ÿ´?ÿ©?ÿh?ë��¾??€etc…
f=fopen(NOMFIC, "rb"); // ouverture en binaire
fseek(f, cur+1, SEEK_SET); // on se place au bon endroit
// puis lecture rgb rgb rgb …for(i=0; i<nbcol*nblig; i++)
{fread(&r,sizeof(unsigned char), 1, f);fread(&g,sizeof(unsigned char), 1, f);fread(&b,sizeof(unsigned char), 1, f);printf("pixel n°%d: RGB=%hhu %hhu %hhu\n", i, r,g,b);
}
fclose(f);
-
Petit Exercice rPetit Exercice réécapitulatifcapitulatifavec pointeurs, fichiersavec pointeurs, fichiers
Écrire un programme qui stocke N réels dans un tableau où N est saisit à l'éxécution, puis écrire ce tableau dans un fichier.
-
#include <stdio.h>#include <stdlib.h>
int main(){
int N=0, i;float *tab;FILE *fic;char nomfic[20] = "toto.txt";
// saisie Nscanf("%d", &N);
// allocation dynamique + saisie des N nombrestab = (float*)malloc(N*sizeof(float));for (i=0; i<N; i++)
scanf("%d", &tab[i]); // autre moyen pour l'@ ?
// ouverture fichier en mode écriture + gestion erreurfic = fopen(nomfic, "w+");if (fic == NULL)
{printf("pb ouverture %s\n", nomfic); exit(0);}
// écriture des nombres dans le fic (mieux avec fwrite …)for (i=0; i<N; i++)
fprintf(fic, "%f ", tab[i]);
// ne pas oublier : fclose et free …fclose(fic);free(tab);
}
-
#include <stdio.h>#include <stdlib.h>
int main(){
int N=0, i;float *tab;FILE *fic;char nomfic[20] = "toto.txt";
// saisie Nscanf("%d", &N);
// allocation dynamique + saisie des N nombrestab = (float*)malloc(N*sizeof(float));for (i=0; i<N; i++)
scanf("%d", &tab[i]); // autre moyen pour l'@ ?
// ouverture fichier en mode écriture + gestion erreurfic = fopen(nomfic, "w+");if (fic == NULL)
{printf("pb ouverture %s\n", nomfic); exit(0);}
// écriture des nombres dans le fic avec fwrite// 2 avantages : 1seule instruction, fichier + petitfwrite(tab, N, sizeof(float), fic);
// ne pas oublier : fclose et free …fclose(fic);free(tab);
}
-
Exercice rExercice réécapitulatifcapitulatifavec pointeurs, structures, avec pointeurs, structures,
fichiersfichiers
Écrire un programme pour la gestion d'un polygone :
proposer des structures pour gérer un point (lettre, x,y), puis un polygone, c'est-à-dire une suite de points.
Prévoir :Initialisation du polygone avec le nb de pointsSa désallocation (évidemment …)Affichage des pointsCalcul du périmètresauvegarde :
chargement + sauvegarde
-
Polygone : dPolygone : dééfinitionfinition
Proposer des structures pour gérer un point (lettre, x,y), puis un polygone, c'est-à-dire une suite de points.
#include <stdio.h>#include <stdlib.h>
struct point{char lettre;int x;int y;
};
struct polygone{struct point *points;int nbpoints;
}poly;
-
Polygone : InitialisationPolygone : Initialisation
Initialisation du polygone avec le nb de points : initPolygone(int nb)
initPolygone(int nb){int i;poly.nbpoints = nb;// allocation du tableau de pointspoly.points = (struct point*)malloc(nb*sizeof(struct polygone));
for (i=0; i<nb; i++){
poly.points[i].lettre = i+65; // lettre = A,B,C, …
printf("point %c, entrez abs:\n", poly.points[i].lettre);scanf("%d", &poly.points[i].x);
printf("point %c, entrez ord:\n", poly.points[i].lettre);scanf("%d", &poly.points[i].y);
}}
-
Polygone : affichage + Polygone : affichage + ddéésallocationsallocation
Affichage des points
Désallocation du polygone
afficher(){int i;printf("il y a %d points dans le polygone\n", poly.nbpoints );for (i=0; i<poly.nbpoints; i++)
printf("%c %d %d\n", poly.points[i].lettre, poly.points[i].x, poly.points[i].y);
}
desallocation(){// seul le tableau de points est déclaré en dynamique …free(poly.points)
}
-
Polygone : pPolygone : péérimrimèètretre
Calcul du périmètre à l'aide d'une fonction distance
float perimetre(){float p=0;for (i=0; i<poly.nbpoints-1; i++)
{p+=distance(poly.points[i], poly.points[i+1]);
}p+=distance(poly.points[i+2], poly.points[0]); return(p);
float distance(struct point A, struct point B){int dx;int dy;dx = A.x - B.x;dy = A.y - B.y;return(pow(dx*dx+dy*dy, 1/2));
}
-
Polygone : sauvegarderPolygone : sauvegarder
sauvegarder(){FILE *fic;int i;
// ouverture fichier en écriturefic = fopen("poly.txt", "w+");if(fic==NULL) {printf("pb ouverture fic\n"); exit(0);}
// écriture du nb de pointsfprintf(fic, "%d\n", poly.nbpoints);
// écriture des pointsfor (i=0; i<poly.nbpoints; i++)fprintf(fic, "%c %d %d\n",
poly.points[i].lettre, poly.points[i].x, poly.points[i].y);
fclose(fic);}
remarque :utilisation possible de fwrite pour écrire les structures
-
Polygone : chargerPolygone : charger
charger(){FILE *ficIn;int i;
// ouverture fichierficIn = fopen("poly.txt", "r+");if(ficIn==NULL) {printf("pb ouverture fic\n"); exit(0);}
// lecture du nb de pointsfscanf(ficIn, "%d\n", &poly.nbpoints);
// allocation du tableau de pointspoly.points=(struct point*)malloc(poly.nbpoints
*sizeof(struct polygone));// lecture des pointsfor (i=0; i<poly.nbpoints; i++){
fscanf(ficIn, "%c %d %d\n", &poly.points[i].lettre,&poly.points[i].x, &poly.points[i].y);
}fclose(ficIn);
}
-
ConclusionConclusion
Pour maîtriser rapidement le langage CMalgré l'examen écrit, entraînez vous sur une machinerefaites les exercices du coursfaites des man pour voir ce que font exactement les fonctions
Vous ne participez pas au concours du programme C le plus obscur (The International Obfuscated C Code Contest).
Respectez les bonnes pratiques de programmation:commentairesfonctions pas trop longuescode clair et aérénoms de variables explicites : for (iTaille=0; iTaille<TAILLE; iTaille++)séparer implémentation / header