114
- Programmation en Programmation en langage C langage C enseignants: C. Chatelain, S. Nicolas {clement.chatelain, stephane.nicolas}@univ-rouen.fr U2.1.53 Licence EEA 2ème année

Programmation en langage C - Welcome to my website ...clement.chatelain.free.fr/enseignements/coursc.pdf · = "procédure" du langage pascal ... Tableaux à plusieurs dimensions en

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

-

TableauxTableaux

Définitions, Tableaux à une dimensionTableaux à plusieurs dimensionsExemples

-

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ééss

IntroductionStructuresUnionsEnumérationTypedef

-

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 sortieses sorties

Entrées/sorties conversationnellesChaîne de caractèresFichiers

-

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