37
Ecole Nationale d’Ingénieurs de Sfax Génie Electrique Enseignante : KESSENTINI Amina Cours Langage C NOTIONS DE BASE Les programmes en C sont composés essentiellement de fonctions et de variables. Définition d’une fonction en C |<Type du résultat de la fonction> <Nom de la Fonction> (<Typepar1> <Nompar1>, | <Typepar2> <Nompar2>,..) |{ |<déclarations des variables locales> |<instructions> |} Remarques En C, toute instruction simple est terminée par un point-virgule. En principe tout programme devrait retourner une valeur comme code d’erreur à son environnement. La fonction main est la fonction principale des programmes en C. Elle se trouve obligatoirement dans tous les programmes. L’exécution d’un programme entraine automatiquement l’appel de la fonction main. Si nous utilisons des fonctions prédéfinies (par exemple : printf ), il faut faire précéder la fonction de main par l’appel des bibliothèques correspondantes en utilisant l’instruction #include ( #include <stdio.h>) . Les commentaires Un commentaire commence toujours par les deux symboles /* et se termine par les symboles */. Il est interdit d’utiliser des commentaires imbriqués. Exemples /* Ceci est un commentaire correct */ /* Ceci est /* évidement */ défendu */ Les types entiers Type Description Valeur min Valeur max Nombre d’octets char Caractère -128 127 1 unsigned char caractère non signé 0 255 1 short entier court -32768 32768 2 unsigned short entier court non signé 0 65535 2 int entier standard -32768 32768 2 unsigned int entier standard non signé 0 65535 2 long entier long -2147483648 2147483647 4 unsigned long entier long non signé 0 4294967295 4

Ecole Nationale d'Ingénieurs de Sfax Génie Electrique Enseignante : KESSENTINI Amina Cours Langage C

Embed Size (px)

Citation preview

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

NOTIONS DE BASE

Les programmes en C sont composés essentiellement de fonctions et de variables.

Définition d’une fonction en C

|<Type du résultat de la fonction> <Nom de la Fonction> (<Typepar1> <Nompar1>,

| <Typepar2> <Nompar2>,..)

|{

|<déclarations des variables locales>

|<instructions>

|}

Remarques

En C, toute instruction simple est terminée par un point-virgule.

En principe tout programme devrait retourner une valeur comme code d’erreur à son

environnement.

La fonction main est la fonction principale des programmes en C. Elle se trouve

obligatoirement dans tous les programmes. L’exécution d’un programme entraine

automatiquement l’appel de la fonction main.

Si nous utilisons des fonctions prédéfinies (par exemple : printf ), il faut faire précéder

la fonction de main par l’appel des bibliothèques correspondantes en utilisant

l’instruction #include ( #include <stdio.h>) .

Les commentaires

Un commentaire commence toujours par les deux symboles /* et se termine par les

symboles */. Il est interdit d’utiliser des commentaires imbriqués.

Exemples

/* Ceci est un commentaire correct */

/* Ceci est /* évidement */ défendu */

Les types entiers

Type Description Valeur min Valeur max Nombre

d’octets

char Caractère -128 127 1

unsigned char caractère non signé 0 255 1

short entier court -32768 32768 2

unsigned short entier court non signé 0 65535 2

int entier standard -32768 32768 2

unsigned int entier standard non signé 0 65535 2

long entier long -2147483648 2147483647 4

unsigned long entier long non signé 0 4294967295 4

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

Les types rationnels

Les rationnels sont souvent appelés des flottants. Un rationnel est décrit comme suit :

<+/-> <mantisse>*10 <exposant>

Avec <+/-> est le signe positif ou négatif du nombre

< mantisse> est un décimal positif avec un seul chiffre devant la virgule.

<exposant> est un entier relatif

Quelques constants caractères :

Caractère Description

\n Passage à la ligne

\t Tabulation

\b Curseur arrière

\r Retour au début de la ligne

\a Signal acoustique

Opérateurs arithmétiques

+ Addition

- Soustraction

* Multiplication

/ Division entière et

rationnelle !)

% Modulo

Opérateurs relationnels :

> strictement supérieur

>= supérieur ou égal

< strictement inférieur

<= inférieur ou égal

== Egal

!= Différent

Attention à ne pas confondre l'opérateur de test d'égalité "==" avec l'opérateur d'affection

"=".

Type Précision Mantisse

Valeur min Valeur max Nombre

d’octets

float simple 6 3.4*10-38

3.4*1038

4

double double 15 1.7*10-308

1.7*10308

8

Long double suppl. 19 3.4*10-4932

3.4*104932

10

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

Opérateurs logiques booléens :

&& ET logique

|| OU logique

! négation logique

Opérateurs logiques sur les entiers bit à bit :

& ET

| OU

^ OU exclusif

~ Complément à 1 bit à bit

<< Décalage à gauche

>> Décalage à droite

Opérateurs d’affectation

Nous retrouvons souvent des affectations comme : i = i + 2

En C, nous utiliserons plutôt la formulation plus compacte : i += 2

Ceci est valable pour d’autres opérateurs détaillés dans ce tableau récapitulatif

+= Ajouter à

-= Dimimuer de

*= Multiplier par

/= Diviser par

Opérateurs d’incrémetation et de décrémentation

Les affectations les plus fréquentes sont du type :

I = I + 1 et I = I - 1

On peut utiliser ++ ou -- mais on doit distinguer les cas détaillés dans ce tableau

X = i++ Passe d’abord la valeur de i à x et incrémente après

X = ++i Incrémente d’abord et passe la valeur incrémentée à x

X= i-- Passe d’abord la valeur de i à x et décrémente après

X= --i Décrémente d’abord et passe la valeur décrémentée à x

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

Les priorités des opérateurs

Nous pouvons distinguer les classes de priorités suivantes :

Priorité 1 (la plus forte) ( )

Priorité 2 ! ++ --

Priorité 3 * / %

Priorité 4 + -

Priorité 5 < <= > >=

Priorité 6 == !=

Priorité 7 &&

Priorité 8 | |

Priorité 9 (la plus faible) = += -= *= /= %=

Les fonctions arithmétiques standard

Les fonctions suivantes sont prédéfinies dans la bibliothèque standard <math>. Pour

pouvoir les utiliser, le programme doit contenir la ligne : #include<math.h>.

Remarque : les arguents et les résultats des fonctions arithmétiques sont du type double.

Commande en C Explication

exp(x) Fonction exponentielle

log(x) Logarithme naturel

log10(x) Logarithme à base 10

pow(x,y) x exposant y

sqrt(x) Racine carrée de x

fabs(x) Valeur absolue de x

floor(x) Arrondi en moins

ceil(x) Arrondi en plus

fmod(x) Reste rationnel de x/y

sin(x), cos(x), tan(x) sinus, cosines, tangente de x

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

LIRE ET ECRIRE DES DONNEES

La bibliothèque standard < stdio> ( aussi < conio> ) contient un ensemble de fonctions

permettant la communication entre la machine et le monde extérieur. Nous citons par

exemple : printf ( ) , scanf( ), putchar( ) , getchar

Exemple printf : printf("La valeur de x est %d ", x ) ;

Message Format Paramètre

Affichage multiple de variables :

printf("%format1 %format2 .... %formatn", variable1, variable2, ..., variablen);

Exemple scanf : scanf( " %d ", &x );

Format Paramètre

Saisit multiple de variables :

scanf("%format1 %format2 .... %formatn", &variable1, &variable2, ..., &variablen);

Différents formats utilisés pour scanf et printf

Symbole Impression comme (pour printf) et lecture d’un (e) ( pour scanf)

%d ou % i Entier

%u Entier non signé

%o Entier exprimé en octal

%x Entier exprimé en hexadécimal

%c Caractère

%s Chaine de caractère

%f ou %e Réel ( float )

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

LES INSTRUCTIONS DE BRANCHEMENT

ET LES BOUCLES

L'instruction IF ... ELSE Syntaxe :

if (expression) { ............; /* bloc 1 d'instructions */ ............; }

else

{ ............; /* bloc 2 d'instructions */ ............; }

Remarque : Les {} ne sont pas nécessaires lorsque les blocs ne comportent qu'une seule instruction.

L’opérateur conditionnel "?" L’opérateur conditionnel "?" est équivalent à l’instruction if else. Sa syntaxe est la suivante :

condition ? expression_1 : expression_2 Cette expression est égale à expression_1 si condition est satisfaite, et à expression_2 sinon.

Exemple : recherche du maximum de deux nombres entiers

if (a > b) Max = a; équivalent à Max = (a > b ? a : b); else Max = b;

L’instruction SWITCH

Sa forme la plus générale est celle-ci :

switch (expression)

{

case constante-1 : liste d'instructions 1; break;

case constante-2 : liste d'instructions 2; break;

...

case constante-n : liste d'instructions n; break;

default : liste d'instructions;

}

Remarque : N'oubliez pas le break à la fin de chaque case dans une instruction switch. Si le break est

absent, l'exécution se poursuit dans le case suivant. Boucle FOR

for (exp 1 ; exp 2 ; exp 3)

{

............; /* bloc d'instructions */

............;

}

Avec : exp1 correspond à l'initialisation d'une variable de contrôle.

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

- exp2 est la condition de continuation de la boucle. - exp3 est l'incrémentation de la variable de contrôle (elle est effectuée après l'exécution

de l'instruction).

Boucle Do… While

Algorithmique Langage C

Répéter

bloc d'instructions

jusqu’à (condition)

Do

{

............; /* bloc d'instructions */

............;

while (condition);

Remarque : Le bloc d’instruction sera exécuté tant que la condition est vérifiée (ou non nulle). Le test

se faisant après, le bloc est exécuté au moins une fois même si l'expression est nulle à la première évaluation.

Boucle While

Algorithmique Langage C

tant que (condition) faire

bloc d'instructions

fin tant que

while (condition)

{

............; /* bloc d'instructions */

............;

............;

}

Tant que la condition est vérifiée (ou non nulle), le bloc d’instruction est exécuté. Le test ayant lieu avant l'exécution de l'instruction, celle-ci peut ne pas être exécutée si l'expression est nulle à la première évaluation. Remarque :

- Les {} ne sont pas nécessaires lorsque le bloc ne comporte qu'une seule instruction.

for(expr 1 ; expr 2 ; expr 3)

instructions ;

expr 1 ;

while ( expr 2 )

{

instructions ;

expr 3 ;

}

expr 1 ;

do

{

instructions ;

expr 3 ;

}

while (expr 2 ) ;

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

LES TABLEAUX Les tableaux à une dimension Déclaration

type nom[dim]

- type : définit le type d'élément que contient le tableau. Un tableau en langage C est

composé uniquement d'éléments de même type.

- nom: est le nom du tableau.

- dim : est un nombre entier qui détermine le nombre des éléments du tableau.

Exemple:

Int tab[10]; /* le compilateur réserve des places pour 10 entiers, soit 40 octets */

float tableau2[20]; /* le compilateur réserve des places pour 20 réels, soit 80 octets */

Remarque:

dim est nécessairement une VALEUR NUMERIQUE.

Accéder aux éléments d’un tableau

Pour accéder à un élément du tableau, il suffit de donner le nom du tableau, suivi de l'indice de

l'élément entre crochets :

nom[indice]

Exemples:

compteur[2] = 5;

nombre[i] = 6.789;

printf("%d",compteur[i]);

scanf("%f",&nombre[i]);

Remarques:

- L'indice du premier élément du tableau est 0.

- L’indice est toujours positif.

- L'indice du dernier élément du tableau est égal (dim– 1).

Les tableaux à plusieurs dimensions

Tableaux à deux dimensions Déclaration

type nom[dim1][dim2]

Exemples:

int compteur[4][5];

float nombre[2][10];

Un élément du tableau est repéré par ses indices. En langage C, les tableaux commencent aux indices

0. Les indices maximum sont donc (dim1-1) et (dim2-1).

Exemples :

int tab[3][4] /* 3 lignes et 4 colonnes */

tab[0][0] = 5;

printf("%d", tab[i][j]);

scanf("%f", &tab[i][j]);

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

Tableau[0][0] Tableau[0][1] Tableau[0][2] Tableau[0][3]

Tableau[1][0] Tableau[1][1] Tableau[1][2] Tableau[1][3]

Tableau[2][0] Tableau[2][1] Tableau[2][2] Tableau[2][3]

Initialisation des tableaux On peut initialiser les tableaux au moment de leur déclaration:

Exemples:

float nombre[4] = {2.67, 5.98 ,-8 ,0.09};

/* 2 lignes et 3 colonnes */

int x[2][3] = { {1, 5 ,7} , {8 ,4 ,3} };

Manipulation des tableaux Pour la manipulation des tableaux, on utilise les boucles (for ou while ou do … while).

Saisie et affichage d’un tableau

Ecrire un programme permettant de saisir un tableau de réel de taille 10 :

Boucle for Boucle while

main()

{

float nombre[10];

int i;

/* saisie du tableau*/

for( i=0; i<10; i++ )

{

printf("nombre[%d] = ", i);

scanf("%f", &nombre[i]);

}

/* affichage du tableau*/

for( i=0; i<10; i++ )

printf("nombre[%d] = %f ",i,nombre[i]);

}

main()

{

float nombre[10];

int i;

/* saisie du tableau*/

while( i<10 )

{

printf("nombre[%d] = ", i);

scanf("%f", &nombre[i]);

i++ ;

}

/* affichage du tableau*/

while( i<10 )

{

printf("nombre[%d] = %f ",i,nombre[i]);

i++;

} }

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

Exemple : Calcul de la moyenne d’un tableau

Ecrire un programme permettant de saisir un tableau de 10 entiers, de calculer et d’afficher leur

moyenne.

int tab[10];

int i,s;

float moy;

/*initialisation de la somme et la moyenne*/

s =0 ;

moy =0.0 ;

/* saisie du tableau*/

for(i=0;i<10;i++)

{

printf("tab[%d] = ",i);

scanf("%d", &tab[i]);

}

/* calcul de la moyenne */

for(i=0; i<10; i++)

s = s+ tab[i];

moy = s / 10;

/* affichage de la moyenne */

printf(”Moyenne du tableau = %f”, moy);

// ou bien printf(”Moyenne du tableau = %f”, float(s/10) );

Exemple : Rechercher le maximum d’un tableau

Ecrire un programme permettant de saisir la moyenne de 30 étudiants, de calculer et d’afficher la plus

grande moyenne.

float moy[30];

int i;

float max;

/* saisie du tableau*/

for(i=0; i<10; i++)

{

printf("moy[%d] = ",i);

scanf("%f", &moy[i]);

}

max = moy[0] ;

/* recherche du maximum */

for(i=0; i<10; i++)

if (moy[i] > max)

max = moy[i];

/* affichage du maximum */

printf(”Maximum du tableau = %f”, max);

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

Exemple : Saisir et afficher un tableau à 2 dimensions :

Ecrire un programme permettant de saisir un tableau de réel de taille 5x10 :

float nombre[5][10];

int i,j;

/* saisie du tableau*/

for( i=0; i<5; i++ )

for( j=0; j<10; j++ )

{

printf("nombre[%d][%d] = ", i,j);

scanf("%f", &nombre[i][j]);

}

/* affichage du tableau*/

for( i=0; i<5; i++ )

{

for( j=0; j<10; j++ )

printf("nombre[%d][%d] = %f ", i, j, nombre[i][j] );

printf("\n");

}

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

LES CHAINES DE CARACTERES Déclaration Une chaîne est un tableau de caractères dont le dernier élément significatif est le caractère '\0'. Il faut

donc différencier la longueur maximale de la chaîne (c'est à dire la dimension donnée lors de la

définition) de sa longueur réelle (c'est à dire le nombre de caractères jusqu'au '\0').

char nom[dim]

Exemple :

char texte[dim];

Le compilateur réserve (dim-1) places en mémoire pour la chaîne de caractères. En effet, il ajoute

toujours le caractère NUL ('\0') à la fin de la chaîne en mémoire.

Exemples : char chaine[] = "Hello";

H E l l o \0

char chaine[6] = "Hello";

H e l l o \0

char chaine[8] = "Hello";

H e l l o \0 0 0

char chaine[5] = "Hello";

H e l l o

==> Erreur pendant l’exécution

char chaine[4] = "Hello";

==> Erreur pendant la compilation

Affichage On peut utiliser la fonction printf avec le format %s :

char texte[10] = "BONJOUR";

printf("Voici le texte: %s\n", texte);

On peut aussi utiliser la fonction puts :

puts(texte); ≡ printf("%s\n",texte);

Saisit On peut utiliser la fonction scanf avec le format le format %s. On n'écrit pas le symbole &. On peut

aussi utiliser la fonction gets.

char texte[10];

printf("entrer un texte: ");

scanf("%s", texte); ≡ gets(texte);

Remarques :

- La fonction scanf ne permet pas la saisie d'une chaîne comportant des espaces : les

caractères saisis à partir de l'espace ne sont pas pris en compte. Pour saisir une chaîne

comportant des espaces, il faut utiliser la fonction gets.

- A l'issue de la saisie d'une chaîne de caractères, le compilateur ajoute '\0' en mémoire après

le dernier caractère.

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

Exemples :

char lieu[25];

int jour, mois, annee;

printf("Entrez lieu et date de naissance :");

scanf("%s %d %d %d", lieu, &jour, &mois, &annee);

Tableau de chaînes de caractères Les tableaux de chaînes de caractères sont des tableaux de tableaux de caractères.

Exemple :

char tab[5][10] = { "zero", "un", "deux", "trois", "quatre" }; /* 5 lignes et 10 colonnes */

Ce qui donne:

On constate que le tableau contient de l'espace inutilisé relativement important. Pour minimiser la

mémoire nécessaire au stockage des chaînes, on peut déclarer tab comme un tableau de pointeurs :

char *tab[5] = { "zero", "un", "deux", "trois", "quatre" };

Ce qui donne :

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

Fonctions permettant la manipulation des chaînes

Les bibliothèques fournies avec les compilateurs contiennent de nombreuses fonctions de traitement

des chaînes de caractères. En C++, elles appartiennent aux bibliothèques string.h ou stdlib.h. En voici

quelques exemples:

String.h :

strlen(s) Fournit la longueur de la chaîne sans compter le '\0' final

strcpy(s, t) Copie <t> vers <s>

strcat(s, t) Ajoute <t> à la fin de <s>

strcmp(s, t)

Compare <s> et <t> et fournit un résulta t :

négatif si <s> précède <t>

zéro si <s> est égal à <t>

positif si <s> suit <t>

strncpy(s, t, n) Copie au plus <n> caractères de <t> vers <s>

strncat(s, t, n) Ajoute au plus <n> caractères de <t> à la fin de <s>

strchr(s, c) Trouve la première occurrence du caractère c dans la chaîne s, c'est à

dire la première fois où il apparaît

strrev (s) Inversion de l’ordre de la chaîne s

strupr (s) Conversion des lettres minuscules en lettres majuscules de la chaîne s

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

LES POINTEURS

L'opérateur adresse &

L'opérateur adresse "&" retourne l'adresse d'une variable en mémoire.

Exemple :

int i = 8;

printf("i = %d\n", i);

printf("Son adresse en hexadécimal est : %p\n", &i);

Dans l’affichage, le format d'une adresse est %p (hexadécimal) ou %d (décimal).

Définition et déclaration des pointeurs

Un pointeur est une variable qui contient l’adresse d’une autre variable. Comme une adresse est un

nombre entier, on pourrait penser que les pointeurs sont des variables de type int. En fait pas

exactement, le langage C distingue les pointeurs suivant le type de la variable qu’ils pointent.

Une variable de type pointeur se déclare à l'aide de l'objet pointé précédé du symbole * (opérateur

d'indirection).

p contient l’adresse de la variable i ( p = &i )

==> p est un pointeur sur int

==> déclaration en langage C : int *p

Exemple :

char *pc; /* pc est un pointeur pointant sur un objet de type char */

int *pi; /* pi est un pointeur pointant sur un objet de type int */

float *pr; /* pr est un pointeur pointant sur un objet de type float */

L’opérateur "*" désigne en fait le contenu de l’adresse.

Exemple :

char *pc, c;

pc = &c;

*pc = 34 ;

printf("Contenu de la case mémoire : %c\n", *pc);

printf("Valeur de l'adresse en hexadécimal : %p\n", pc);

Structure de la mémoire d'un ordinateur

Un ordinateur comporte un processeur et de la mémoire. Les deux sont connectés par un bus, c'est-à-

dire un ensemble de lignes électriques (figure 6).

La mémoire d'un ordinateur est en fait un composant électronique (appelé RAM). Ce composant

stocke une série de bits dont on peut écrire la valeur et venir la relire plus tard. Pour des questions de

commodité on ne lit/écrit pas ces bits un par un mais par paquets de huit, ce que l'on appelle un octet

(byte). Un unique composant de RAM peut ainsi stocker plusieurs millions d'octets. Quand on veut en

lire ou en écrire un il faut naturellement indiquer au composant lequel. Pour cela il suffit de donner

son numéro, en effet tous les octets contenus dans la mémoire sont numérotés de 0 jusqu'à n-1 pour

une mémoire contenant n octets. Ce numéro permettant d'identifier individuellement chacun des octets

de la mémoire est appelé adresse. Graphiquement la mémoire d'un ordinateur peut donc être

représentée comme une série de cases numérotées de 0 à n-1 contenant chacune un octet, c'est à dire

un nombre entier de 0 à 255 (figure 7).

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

Figure6 : Structure d’un ordinateur et de la mémoire.

Figure 7 : Représentation simplifiée du début de la mémoire d'un ordinateur.

Grâce aux adresses, un composant de RAM peut donc identifier et lire ou écrire individuellement

chacun des octets qu'il contient. Toutefois afin d'aller plus vite et pour manipuler des nombres plus

grands, les microprocesseurs modernes lisent et écrivent quatre octets consécutifs (32 bits) de la

mémoire. C'est pourquoi, pour faciliter la lecture, plutôt que de représenter les octets un à un côte à

côte comme dans la figure 7, on a pour habitude dans les schémas, de les représenter groupés par blocs

de quatre. Par conséquent les adresses de chaque case évoluent de quatre en quatre comme dans la

figure 6. Dans cette figure, une portion de mémoire est représentée couvrant les adresses 1000 à 102b.

Par convention, les adresses sont représentées en notation hexadécimale (base 16), en utilisant les

chiffres 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f pour les valeurs 0 à 15. Chaque ligne de mémoire dans

la figure 6 contient donc 4 octets.

Lorsque vous déclarez des variables dans un programme C, le compilateur choisit lui-même des

emplacements disponibles dans la mémoire et établit une correspondance entre les noms de variables

choisis et les adresses de ces emplacements.

Opération sur les pointeurs

On peut déplacer un pointeur dans un plan mémoire à l'aide des opérateurs d'addition, de

soustraction, d'incrémentation, de décrémentation. On ne peut le déplacer que d'un nombre de cases

mémoire multiple du nombre de cases réservées en mémoire pour la variable sur laquelle il pointe.

Exemple :

main()

{

int v = 12 ;

int u = 10 ;

int *vp ; /*pointeur*/

vp = &v ; /* vp pointe sur la case v dans la figure */

u = *vp ; /* u est égal le contenu de vp = v */

printf("u=%d et v=%d \n", u, v) ;

*vp = 25 ;

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

printf("u=%d et v=%d \n", u, v) ;

*vp++ = 50 ; /* ici on va charger le contenu de vp par la valeur 50 puis

Incrémenter l’adresse du pointeur de 32 bits */

printf("u=%d et v=%d \n", u, v) ;

}

vp = &v u = *vp *vp = 25 *vp++ = 50

… 1000 … 1000 … 1000 … 1000

v 12 1004 V 12 1004 V 25 1004 v 50 1004

u 10 1008 U 12 1008 U 12 1008 u 12 1008

vp 1004 100C vp 1004 100C Vp 1004 100C vp 1008 100C

… 100E … 100E … 100E … 100E

Allocation dynamique

Lorsque l'on déclare une variable char, int, float .... un nombre de cases mémoire bien défini est

réservé pour cette variable. Il n'en est pas de même avec les pointeurs. Il existe en langage C, des

fonctions permettant d'allouer de la place en mémoire à un pointeur. Il faut absolument les utiliser dès

que l'on travaille avec les pointeurs.

La fonction malloc

Définie dans la bibliothèque alloc.h ou malloc.h.

Exemple :

char *pc;

int *pi,*pj,*pk;

float *pr;

pc = (char*)malloc(10); /* réserve 10 cases mémoire ≡ 10 caractères */

pi = (int*)malloc(16); /* réserve 16 cases mémoire ≡ 4 entiers */

pr = (float*)malloc(24); /* réserve 24 places en mémoire ≡ 6 réels */

pj = (int*)malloc(sizeof(int)); /* réserve la taille d'un entier en mémoire */

pk = (int*)malloc(3*sizeof(int)); /* réserve la place en mémoire pour 3 entiers */

La fonction free Définie dans la bibliothèque alloc.h. Elle permet de libérer de la mémoire.

free(pi); /* libère la place précédemment réservée pour pi */

free(pr); /* libère la place précédemment réservée pour pr */

Exemple :

Soit le code suivant :

char * mem1, * mem2, * mem3;

mem1 = (char*)malloc(100);

Adresse

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

printf("allocation de 100 octets en %p\n", mem1);

mem2 = (char*)malloc(50);

printf("allocation de 50 octets en %p\n", mem2);

free (mem1);

printf("libération de 100 octets en %p\n", mem1);

mem3 = (char*)malloc(60);

printf("allocation de 60 octets en %p\n", mem3);

Qu’affiche ce code si on suppose que l’adresse de mem1 est égale à 0x06AC ?

Le résultat est le suivant :

allocation de 100 octets en 06AC

allocation de 50 octets en 0710

libération de 100 octets en 06AC

allocation de 60 octets en 06E8

Affectation d'un pointeur On ne peut pas affecter directement une valeur à un pointeur. L’écriture suivante est interdite:

char *pc;

pc = 0xFFFE;

On peut cependant être amené à définir par programmation la valeur d'une adresse. On utilise pour

cela l'opérateur de "cast" ( ).

Exemples :

char *pc;

pc = (char*)0x1000; /* p est l'adresse 0x1000 et pointe sur un caractère */

int *pi;

pi = (int*)0xFFFA; /* i est l'adresse 0xFFFA et pointe sur un entier */

L'opérateur de "cast", permet d'autre part, à des pointeurs de types différents de pointer sur la même

adresse.

Exemple :

char *pc; /* pc pointe sur un caractère */

int *pi; /* pi pointe sur un entier */

pi = (int*)malloc(4) ; /* allocation dynamique pour pi */

pc = (char*)pi; /* pc et pi pointent sur la même adresse */

La fonction scanf

Pour saisir un caractère ou un nombre, on donne en fait l'adresse de ce caractère :

char c;

printf("Donner un caractère : ");

scanf("%c", &c);

On saisit ici le contenu de l'adresse &c c'est à dire le caractère c lui-même.

On peut donc aussi procéder ainsi :

char *adr;

printf("Donner un caractère : ");

scanf("%c", adr);

On saisit ici le contenu de l'adresse adr.

Cette méthode s'applique aux caractères (char), aux entiers (int), aux réels (float).

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

Les tableaux à une dimension

Les écritures suivantes sont équivalentes :

int *tableau; int tableau[10]; /* déclaration */

tableau = (int*)malloc(sizeof(int)*10);

*tableau tableau[0] /* le 1er élément */

*(tableau+i) tableau[i] /* l’élément numéro i */

tableau &tableau[0] /* adresse du 1er élément */

(tableau + i) &(tableau[i]) /* adresse l’élément numéro i */

Un tableau à deux dimensions est un pointeur vers un pointeur. Les éléments d’une matrice sont

organisés par ligne en mémoire.

On déclare un pointeur qui pointe sur un objet de type type * (deux dimensions) de la même manière

qu'un pointeur :

type **nom_pointeur;

De même un pointeur qui pointe sur un objet de type type ** (équivalent à un tableau à 3 dimensions)

se déclare comme suit :

type ***nom_pointeur;

Exemple :

Créer avec un pointeur de pointeur une matrice à k lignes et n colonnes à coefficients entiers :

main()

{

int k, n;

int **tab; /* Déclaration de la matrice */

tab = (int**)malloc(k * sizeof(int*)); /* Allocation de k lignes */

for (i = 0; i < k; i++)

tab[i] = (int*)malloc(n * sizeof(int)); /* Allocation de n colonnes */

for (i = 0; i < k; i++)

free(tab[i]);

free(tab);

}

La première allocation dynamique réserve pour l'objet pointe par tab l'espace mémoire correspondant à

k pointeurs sur des entiers. Ces k pointeurs correspondent aux lignes de la matrice. Les allocations

dynamiques suivantes réservent pour chaque pointeur tab[i] l'espace mémoire nécessaire pour stocker

n entiers (n colonnes).

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

On peut écrire également :

int tab[k][n] ;

Les écritures suivantes sont équivalentes :

int **v int t[3][4] /* déclaration */

v[0] &t[0][0] /* adresse du 1er élément de la 1ère ligne */

v[1] &t[1][0] /* adresse du 1er élément de la 2ème ligne */

v[i] &t[i][0] /* adresse du 1er élément de la ième ligne */

v[i]+1 &(t[i][1]) /* adresse du 2ème élément de la ième ligne */

*(v[i]+1) t[i][1] /* contenu du 2ème élément de la ième ligne */

Chaînes de caractères et les pointeurs Les chaînes de caractères sont des tableaux de caractères. A l'intérieur d'un tel tableau un caractère

nul, ’\0’, marque la fin de la chaîne. Tout ce qui a été dit concernant le passage de tableaux comme

arguments de fonctions s'applique donc aux fonctions recevant des chaînes de caractères comme

paramètres. Les chaînes de caractères ne sont passées aux fonctions que sous forme de pointeur vers

leur premier caractère. Toute modification dans une fonction d'une chaîne passée en paramètre

entraîne la modification de la chaîne originale.

Exemple : Ecrire une fonction permettant de saisir une chaîne de caractère, changer les lettres "o" en

lettres "a" dans une chaîne et d’afficher la nouvelle chaîne.

main()

{

int i = 0;

char chaine[20];

printf("Donner une chaine de caractere :") ;

gets(chaine);

for(i=0; chaine[i] != '\0'; i++)

if (chaine[i] == ’o’) chaine[i] = ’a’;

printf(“%s\n”, chaine);

}

Version avec pointeur :

main()

{

int i = 0;

char *chaine;

chaine = (char*)malloc(20);

printf("Donner une chaine de caractere :") ;

gets(chaine);

for(i=0; *(chaine+i) != '\0'; i++)

if (*(chaine+i) == ’o’) *(chaine+i) = ’a’;

printf(“%s\n”, chaine);

}

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

LES FONCTIONS

Les fonctions sont des parties de code source qui permettent de réaliser le même type de traitement

plusieurs fois et/ou sur des variables différentes.

Une fonction en langage C peut :

– modifier des données globales. Ces données sont dans une zone de mémoire qui peut être

modifiée par le reste du programme. Une fonction peut dans ces conditions réaliser plusieurs fois le

même traitement sur un ensemble de variables défini à la compilation ;

– communiquer avec le reste du programme par une interface. Cette interface est spécifiée à la

compilation. L’appel de la fonction correspond à un échange de données à travers cette interface, au

traitement de ces données (dans le corps de fonction), et à un retour de résultat via cette interface.

Ainsi, une fonction permet de réaliser le même traitement sur des ensembles de variables différents.

Lors de leur définition ou de leur utilisation les fonctions sont distinguées des variables par la présence

des parenthèses ouvrantes et fermantes. Une définition de fonction comporte :

– une interface ou un prototype ou une signature;

– un corps de fonction qui est en fait un bloc d’instructions.

type Nom (type_var1 nom_var1, ..., type_varn nom_varn)

{

/* corps de la fonction */

}

L’interface d’une fonction contient :

– la déclaration du type de retour et du nom de la fonction ;

– la déclaration des types et des noms des paramètres ;

Le corps de fonction est un bloc, c’est-à-dire :

– des déclarations de variables locales au bloc ;

– des instructions ;

int add(int a, int b) Interface

Fonction

{ int c; c = a + b ; return c ;

}

Corps de la fonction

Toute fonction qui n’est pas de type « void » retourne un résultat. Le type de ce résultat est celui de la

fonction. La génération du retour de fonction est provoquée par l’appel de l’instruction return dont la

syntaxe est la suivant :

return expression ;

Dans le corps de la fonction, le résultat est généré par le return. L’expression qui suit le return est

évaluée, et la valeur obtenue est retournée. Au niveau de la fonction appelante, le retour de fonction

peut être utilisé comme la valeur d’une expression. La valeur de cette expression est la valeur que

retourne la fonction. Son type doit être le même que celui qui a été spécifié dans l'en-tête de la

fonction.

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

Exemple1 :

Ecrire une fonction de prototype int puissance(int a, int b) qui calcule ab, a et b sont des entiers. La

mettre en œuvre dans main.

#include <stdio.h> int puissance(int x, int y) {

int i, p=1; for(i=1; i<=y; i++)

p = x*p; return(p);

} main() {

int a, b, res; printf("\nentrer A: "); scanf("%d", &a); printf("\nentrer B: "); scanf("%d", &b); res = puissance(a, b); printf("\A puissance B = %d\n", res);

}

Exemple1 :

tab1 et tab2 sont des variables locales à main:

int tab1[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19};

int tab2[10] = {-19, 18, -17, 16, -15, 14, -13, 12, -11, 10, -9, 8, -7, 6, -5, 4, -3, 2, -1, 0};

Ecrire une fonction de prototype void affiche(int tab[20]) qui permet d'afficher les 20 nombres suivant

un tableau 4x5. La mettre en oeuvre dans main pour afficher tab1 et tab2.

#include <stdio.h> void affiche(int tab[20]) {

int i; for(i=0; i<20; i++) if( (i+1)%5==0 )

printf("%d\n", tab[i]); else

printf("%d ", tab[i]); printf("\n");

}

main() {

int tab1[20] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; int tab2[20] = {-19,18,-17,16,-15,14,-13,12,-11,10,-9,8,-7,6,-5,4,-3,2,-1,0}; affiche(tab1); affiche(tab2); getch();

}

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

Variables globales On appelle variable globale une variable déclarée en dehors de toute fonction. Une variable globale est

connue du compilateur dans toute la portion de code qui suit sa déclaration. Les variables globales

sont systématiquement permanentes. Dans le programme suivant, n est une variable globale :

int n =10; /* variable globale */

void fonction()

{

n++;

printf("appel numero %d \n", n) ;

}

main()

{

int i ; /* variable locale */

for(i = 0 ; i<5 ; i++)

fonction() ;

}

Variables locales On appelle variable locale une variable déclarée à l'intérieur d'une fonction (ou d'un bloc

d'instructions) du programme. Par défaut, les variables locales sont temporaires. Quand une fonction

est appelée, elle place ses variables locales dans la pile. A la sortie de la fonction, les variables locales

sont dépilées et donc perdues.

Les variables locales n'ont en particulier aucun lien avec des variables globales de même nom. Par

exemple, le programme suivant

int n = 10; /* variable globale */

void fonction()

{

int n = 0 ; /* variable locale */

n++;

printf("appel numero %d \n", n) ;

}

main()

{

int i ; /* variable locale */

for(i = 0 ; i<5 ; i++)

fonction() ;

}

Les variables locales à une fonction ont une durée de vie limitée à une seule exécution de cette

fonction. Leurs valeurs ne sont pas conservées d'un appel au suivant.

Exemple :

Ecrire une fonction sans passage d’argument qui retourne le complément à 2 d’un entier n. Dans le

programme principal, saisir n et afficher son complément à 2.

#include <stdio.h>

int n;

int complement_2()

{

int c;

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

c = ~n + 1;

return(c);

}

main()

{

int resultat;

printf("entrer un nombre:");

scanf("%d", &n);

resultat = complement_2();

printf("complement à 2 de %d = %d\n", n, resultat);

}

Passage de paramètres d'une fonction Les paramètres d'une fonction sont traités de la même manière que les variables locales de classe

automatique : lors de l'appel de la fonction, les paramètres effectifs sont copies dans le segment de

pile. La fonction travaille alors uniquement sur cette copie. Cette copie disparaît lors du retour au

programme appelant. Cela implique en particulier que, si la fonction modifiée la valeur d'un de ses

paramètres, seule la copie sera modifiée ; la variable du programme appelant, elle, ne sera pas

modifiée. On dit que les paramètres d'une fonction sont transmis par valeurs.

void echange (int a, int b) {

int t ; printf("valeur initiale : a = %d et b = %d \n", a, b) ; t = a ; a = b ; b = t ; printf("valeur finale : a = %d et b = %d \n", a, b) ;

} main() {

int a = 2, b = 5 ; printf("valeur initiale, programme principal : a = %d et b = %d \n", a, b) ; echange (a, b) ; printf("valeur finale, programme principal : a = %d et b = %d \n", a, b) ;

} Pour qu'une fonction modifie la valeur d'un de ses arguments, il faut qu'elle ait pour paramètre

l'adresse de cet objet et non sa valeur. Par exemple, pour échanger les valeurs de deux variables, il faut

écrire :

void echange (int *adr_a, int *adr_b)

{

int t ;

printf("valeur initiale : a = %d et b = %d \n", *adr_a, *adr_b) ;

t = *adr_a ;

*adr_a = *adr_b ;

*adr_b = t ;

printf("valeur finale : a = %d et b = %d \n", *adr_a, *adr_b) ;

}

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

main()

{

int a = 2, b = 5 ;

printf("valeur initiale, programme principal : a = %d et b = %d \n", a, b) ;

echange (&a, &b) ;

printf("valeur finale, programme principal : a = %d et b = %d \n", a, b) ;

}

Rappelons qu'un tableau est un pointeur (sur le premier élément du tableau). Lorsqu'un tableau est

transmis comme paramètre à une fonction secondaire, ses éléments sont donc modifiés par la fonction.

Par exemple, le programme suivant initialise les éléments du tableau tab.

void init(int *tab, int n)

{

int i ;

for(i = 0 ; i < n ; i++)

tab[i] = i ;

}

main()

{

int i , n = 5 ;

int *tab ;

tab = (int*) malloc(n * sizeof(int));

init(tab, n)

}

Définition et utilisation des marcos

Un macro est un symbole dont la valeur est paramétrable. Un marco peut être définit dans ou

avant le programme principal.

Syntaxe :

#define nom_macro(identif1 , identif2, ... ) texte

Description :

Le préprocesseur remplace toute occurrence de nom_macro par texte. Les paramètres

formels identif1, identif2, ... sont remplacés par les paramètres effectifs.

Exemple :

#define MULTIPLIE(x,y) x*y

Remarques :

- nom_macro est immédiatement suivi d'une parenthèse ouvrante.

- Une macro ne peut pas être utilisée comme paramètre d'une fonction.

- Ne pas mettre un point virgule " ; " à la fin de la définition d’une macro.

Exemple :

Ecrire une fonction Max qui reçoit deux entiers a et b et retourne le maximum d’entre eux, en utilisant

les macros.

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

Dans le programme principal :

- Saisir deux entiers x et y.

- Calculer et afficher le maximum de x et y.

Exemple :

#include <stdio.h> #define Max(a, b) ( ((a) > (b)) ? (a) : (b) ) main() {

int x, y; printf("Entrer x: "); scanf("%d", &x); printf("Entrer y: "); scanf("%d", &y); printf(“max(x,y) = %d \n”, Max(x, y));

}

LES STRUCTURES Définition et déclaration Le langage C autorise la déclaration de types particuliers: les structures. Une structure est constituée

de plusieurs éléments ou champs de même ou de différent type.

typedef struct

{

type1 nom_champ1 ;

type2 nom_champ2 ;

. . .

typeN nom_champ_N ;

} nom_structure ;

Exemple :

typedef struct /* On définit un type struct */ {

char nom[10]; char prenom[10]; int age; float note;

} etudiant;

Cette structure définit les champs nom et prénom de type char, age de type int et note de type float.

Déclaration :

On déclare des variables par exemple : fiche e1, e2;

Utilisation:

strcpy(e1.nom, "ALI");

strcpy(e1.prenom, "Mohamed");

e1.age = 20;

e1.note = 11.75;

Rq :

L'affectation globale est possible avec les structures : e2 = e1;

Par contre, on ne peut pas comparer deux structures. Il faut les comparer champs par champs.

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

if ( e1 = = e2) ……

Exercice 1 :

Créer la structure etudiant ci-dessus, saisir un etudiant puis l'afficher.

Corrigé

#include<stdio.h>

typedef struct

{

char nom[10];

char prenom[10];

int age;

float note;

} etudiant;

main()

{

etudiant f;

printf("\n\nSaisir une fiche :\n");

printf("Nom : ");

gets(f.nom);

printf("Prenom : ");

gets(f.prenom);

printf("Age : ");

scanf("%d", &f.age);

printf("Note : ");

scanf("%f", &f.note);

printf("\n\nAffichage de la fiche :\n");

printf("Nom:%s Prenom:%s ", f.nom, f.prenom,);

printf("Age:%d Note:%f", f.age, f.note);

}

Structures et tableaux On peut définir un tableau de structures :

Déclaration :

etudiant e[10]; /* on déclare un tableau de type etudiant de taille 10 */

/* etudiant est la structure définie précédemment */

Utilisation :

strcpy(e[i].nom,"Ali") /* pour un indice i quelconque */

strcpy(e[i].prenom,"Mohamed");

e[i].age = 20;

e[i].note = 11.75;

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

Exercice 2 :

Créer une structure note{char nom[20] ; float d; float e;}

Saisir un tableau contenant 4 notes puis l’afficher.

Corrigé

#include <stdio.h>

typedef struct

{

char nom[20];

float d;

float e;

} note;

main()

{

note p[4]; /* tableau de note */

int i;

printf("Saisie des notes\n"); /* saisie */

for(i=0; i<4; i++)

{

printf("\nDonnez le nom de l’etudiant n:d\n", i);

gets(p[i].nom);

printf("Devoir= ");

scanf("%f", &p[i].d);

printf("Examen= ");

scanf("%f", &p[i].e);

}

printf("\nAffichage\n"); /* affichage */

for(i=0; i<4; i++)

{

printf("\nEtudiant n%d : %s", i, p[i].nom);

printf("\nDevoir= %f", p[i].d);

printf("\nExamen= %f\n", p[i].e);

}

}

Structures et pointeurs On peut déclarer des pointeurs sur des structures. Cette syntaxe est très utilisée en langage C, elle est

notamment nécessaire lorsque la structure est un paramètre modifiable dans la fonction.

Déclaration :

etudiant *e; /* on déclare un pointeur de type etudiant */

/* etudiant est la structure définie précédemment */

Utilisation :

Normalement, on utilise l’opérateur "." pour accéder aux différents champs de cette structure. Mais, la

priorité de l’opérateur "." est plus forte que celle de l’opérateur "*", on est obligé donc d’utiliser les

parenthèses : (*e).age.

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

Le langage C dispose d’un opérateur spécifique, l’opérateur "->".

e->age équivalent à (*e).age

e = (etudiant*)malloc(sizeof(etudiant)); /* réserve de la place mémoire pour 1 etudiant */

strcpy(e->nom, "ALI");

strcpy(e->prenom, "Mohamed");

e->age = 20;

e->note = 11.75;

Exemple 1 :

Créer une structure note {char nom[20] ; float d ; float e ;}.

Ecrire une fonction SAISIE qui permet de saisir une note et une fonction AFFICHAGE qui permet

d’afficher une note.

Les mettre en oeuvres dans main().

Corrigé

#include <stdio.h>

#include <alloc.h>

typedef struct

{

char nom[20];

float d;

float e;

} note;

void saisie(note *p)

{

printf("Donner le nom de l'etudiant =");

gets(p->nom);

printf("Devoir= ");

scanf("%f", &p->d);

printf("Examen= ");

scanf("%f", &p->e);

}

void affiche(note *p)

{

printf("\nEtudiant = %s ", p->nom);

printf("\nDevoir= %f", p->d);

printf("\nExamen= %f\n", p->e);

}

main()

{

note *pp;

pp = (note*)malloc(sizeof(note));

saisie(pp);

affiche(pp);

}

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

Structure de structure On peut utiliser une structure comme champ d’une autre structure.

Exemple :

On peut définir une structure adresse (contenant numéro et l’adresse d’une maison) qui pourra être

utilisée dans la structure repertoire (contenant les coordonnées d’une personne : nom, prénom et

adresse). Elle peut également être utilisée dans une autre structure.

typedef struct

{

int numero ;

char rue[50] ;

} adresse ;

typedef struct

{

char nom[20] ;

char prenom[20] ;

adresse maison ; /* déclaration d’un champ structure */

} repertoire ; /* de type ’adresse’ appelé ’maison’ */

Utilisation :

repertoire monrepertoire[100] ;

strcpy(monrepertoire[0].nom , "Salah") ;

strcpy(monrepertoire[0].prenom , "Mohamed") ;

monrepertoire[0].maison.numero = 19 ;

monrepertoire[0].maison.rue = "avenue_7_novembre" ;

strcpy(monrepertoire[1].nom , "Abid") ;

strcpy(monrepertoire[1].prenom , "Ali") ;

monrepertoire[1].maison.numero = 15 ;

monrepertoire[1].maison.rue = "rue_menzel_chaker" ;

Lorsqu’un tableau fait partie des champs d’une structure, on peut accéder aux valeurs de ce tableau

par :

char initiale ;

initiale = monrepertoire[1].prenom[0] ; /* initiale de Ali */

Exercice 1 :

Créer une structure etudiant contenant 3 champs :

- nom de type chaîne de caractère.

- prenom de type chaîne de caractère.

- moyen de type réel.

Créer une autre structure classe contenant 3 champs :

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

- Filière de type chaîne de caractère (TIT ou TET ou MSI). - Niveau de type entier (1 ou 2 ou 3). - Eleve de type etudiant

Ecrire un programme permettant de saisir les noms, prénom et moyen d’une classe de 10 étudiants.

Puis afficher les noms, prénom et moyen de cette classe.

Corrigé :

#include<stdio.h>

#include<conio.h>

#include<string.h>

typedef struct

{

char nom[10];

char prenom[10];

float moyen;

} etudiant;

typedef struct

{

char filiere[3];

int niveau;

etudiant eleve[10];

} classe;

main()

{

classe c;

int i;

strcpy(c.filiere , "IT");

c.niveau = 1;

/* saisie d’une classe */

printf("Saisie des etudiant de la classe\n");

for(i=0; i<10; i++)

{

printf("\nDonnez le nom de l'etudiant n %d: ", i);

gets(c.eleve[i].nom);

printf("\nDonnez le prenom de l'etudiant n %d: ", i);

gets(c.eleve[i].prenom);

printf("\nDonnez le moyen de l'etudiant n %d: ", i);

scanf("%f", &c.eleve[i].moyen);

}

/* affichage d’une classe */

printf("\nAffichage des etudiant de la classe %d %s, \n", c.niveau, c.filiere) ;

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

for(i=0; i<10; i++)

{

printf("Nom : %s", c.eleve[i].nom);

printf("\tPrenom= %s", c.eleve[i].prenom);

printf("\tMoyen= %f\n", c.eleve[i].moyen);

}

}

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

LES FICHIERS

Introduction Un fichier est une suite d'unités syntaxiques structurées accessibles séquentiellement ou

directement. C’est une ressource stockant des données.

L'intérêt du fichier réside dans le fait qu'un fichier sauvegarde des données pour une

utilisation future. Pour les traitements de données, on peut consulter et mettre à jour ces

données par programmation ou par édition de texte.

La contrainte principale d'utilisation d'un fichier donné par un programme, une requête, ou

un programmeur, est le droit d'accès.

Manipulation des fichiers

Déclaration: FILE *fichier; /* majuscules obligatoires pour FILE */

On définit un pointeur de type FILE. La déclaration des fichiers doit figurer avant la déclaration des

autres variables.

Ouverture : fopen(char *Nom, char *Mode);

Nom : nom du fichier.

Mode d’ouverture des fichiers :

- "r" : (read) lecture seulement. le fichier doit exister.

- "w" : (write) écriture seulement. Si le fichier n'existe pas, il est créé. S'il existe, son ancien contenu est perdu.

- "a" : (append) ajout à la fin. Si le fichier existe déjà, il sera étendu. S'il n'existe pas, il sera créé.

- "r+" : modification (lecture et écriture) en commençant au début du fichier. Le fichier doit exister.

- "w+" : comme pour "w" en autorisant la modification (lecture et écriture). Si le fichier existe, son ancien contenu est détruit. S'il n'existe pas, il sera créé.

- "a+" : comme pour "a" en autorisant la modification (lecture et écriture). Si le fichier n'existe pas, il est créé. S'il existe, le pointeur de fichier sera positionné en fin de fichier.

Exemple :

FILE *fichier ;

fichier = fopen("C:\\tdn4.txt ", "w") ;

Remarques :

- A l’ouverture, le pointeur est positionné au début du fichier (sauf pour "a" et "a+").

- Il n'est pas possible de réaliser une lecture à la suite d'une écriture ou réciproquement, sans

repositionner le pointeur au début du fichier.

Fermeture : fclose(FILE *fichier);

Retourne 0 si la fermeture s’est bien passée, EOF en cas d’erreur.

Il faut toujours fermer un fichier à la fin d'une session.

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

Exemple :

FILE *fichier ;

fichier = fopen(" C:\\tdn4.txt ", "w");

/* traitement */

……

fclose(fichier);

Destruction : remove(char *nom);

Exemple :

remove(" C:\\tdn4.txt ");

Renommer : rename(char *oldname, char *newname);

Positionnement du pointeur au début du fichier : rewind(FILE *fichier);

Positionnement du pointeur :

fseek(FILE *fichier, int offset, int origine) déplace le pointeur de offset cases à partir de l’origine.

Valeurs possibles pour origine sont :

0 : début du fichier.

1 : position courante.

2 : fin du fichier.

Lecture d’un fichier

int fscanf(FILE *fichier, char *formats, liste d'adresses);

Lit des données du fichier. La syntaxe est la même que celle de scanf.

Exemples :

fscanf (fichier, "%s\n" , nom);

fscanf (fichier, "%d" , &n);

fscanf (fichier, "%s %d" , nom, &n);

char *fgets(char *chaine, int n, FILE *fichier);

Lit (n-1) caractères à partir de la position du pointeur et les range dans chaîne en ajoutant '\0'.

int getc(FILE *fichier);

Lit un caractère, mais retourne un entier n ou retourne EOF si erreur ou fin de fichier. Le pointeur

avance d'une case.

Exemple :

char c ;

c = (char)getc(fichier) ;

int getw(FILE *fichier);

Idem avec un entier. Le pointeur avance de la taille d'un entier.

Exemple :

int n ;

n = getw(fichier) ;

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

Ecriture dans un fichier

int fprintf(FILE *fichier, char *format, liste d'expressions);

Le pointeur avance d'autant de cases mémoires.

Exemples :

fprintf(fichier, "%s\n", nom);

fprintf(fichier, "%d", n);

fprintf(fichier, "%s %d", nom, n);

int fputs(char *chaîne, FILE *fichier);

Idem avec une chaîne de caractères, le pointeur avance de la longueur de la chaîne. '\0' n'est pas rangé

dans le fichier.

Exemple :

fputs("BONJOUR", fichier);

int putc(char c, FILE *fichier);

Ecrit la valeur de c à la position courante du pointeur, le pointeur avance d'une case mémoire.

Exemple :

putc('A', fichier) ;

int putw(int n, FILE *fichier);

Idem, n de type int, le pointeur avance du nombre de cases correspondant à la taille d'un entier (4 cases

mémoire).

Gestion des erreurs

fopen retourne le pointeur NULL si erreur (Exemple: impossibilité d'ouvrir le fichier).

fgets retourne le pointeur NULL en cas d'erreur ou si la fin du fichier est atteinte.

int feof(FILE *fichier) retourne 0 tant que la fin du fichier n’est pas atteinte.

Exemple :

pf = fopen("C:\\tdn4.txt ", "w")

while ( !feof(pf) )

{

fscanf(pf, "%s\n", nom);

printf("Nom du fichier = %s”, nom);

}

Exemple 1 :

Créer un fichier qui contient le nom du fichier lui même. Puis afficher le contenu de ce fichier. Le nom

du fichier doit être saisit au clavier.

Corrigé :

#include<stdio.h>

#include<conio.h>

main()

{

FILE *fp;

char nom[20];

/* saisit du nom du fichier */

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

printf("Entrer un nom de fichier : ");

gets(nom);

/* ouverture du fichier en écriture uniquement */

fp = fopen(nom, "w")

/* écriture dans le fichier */

fprintf(fp, "Ce fichier se nomme: %s\n", nom);

/* fermeture du fichier */

fclose(fp)

/* ouverture du fichier en lecture uniquement */

fp = fopen(nom, "r")

/* lecture du fichier */

while (!feof(fp))

{

fscanf(fp, "%s\n", nom);

printf("Nom du fichier = %s”, nom);

}

/* fermeture du fichier */

fclose(fp)

getch();

}

Exemple 2 :

Ecrire une macro Puissance permettant de calculer ab, a et b étant deux paramètres entiers de cette

fonction.

Ecrire un programme principal permettant de saisir deux entiers x et y à partir d’un fichier

"Valeur.txt", calculer et afficher ab. Enregistrer le résultat dans le même fichier.

Corrigé :

#include<stdio.h>

#include<stdlib.h>

#define Puissance(a,b) ( b == 0 ? 1 : a * Puissance(a, b-1) )

main()

{

char nom_fich[20] = "c:\\Valeur.txt";

FILE *fichier;

int x, y;

fichier = fopen(nom_fich, "r"); /* ouverture du fichier en lecture */

Ecole Nationale d’Ingénieurs de Sfax Génie Electrique

Enseignante : KESSENTINI Amina Cours Langage C

while (!feof(fichier))

{

fscanf(fichier, "%d %d \n", &x, &y);

printf("x : %d\t", x);

printf("y : %d\t", y);

}

fclose(fichier); /* fermeture du fichier */

fichier = fopen(nom_fich, "w"); /* ouverture du fichier en lecture */

fprintf(fichier,"resultat = %d\n", Puissance(x,y)) ;

printf("resultat = %d\n", Puissance(x,y)) ;

fclose(fichier); /* fermeture du fichier */

}

Résumé sur les fichiers

Ouverture en écriture FP = fopen(Nom,"w");

Ouverture en lecture FP = fopen(Nom,"r");

Fermeture fclose(FP);

Fin du fichier feof(FP)

Ecriture fprintf(FP,"….", Adr); fputc(c, FP);

Lecture fscanf(FP,"....", Adr); c = fgetc(FP);