Vous êtes sur la page 1sur 61

1.

Introduction générale

2. Éléments de base

3. Les variables

4. Les entrées-Sorties (printf, scanf)

5. Opérateurs et expressions

6. Les structures de contrôle


• Déclaration d’un tableau de taille n :
type nom_tableau [n] ;
Þ réservation de n cases contiguës en mémoire

• ex. : déclaration d’un tableau d’entiers de


taille 10 appelé tb1 :
int tb1[10] ; 0 1 2 3 4 5 6 7 8 9
? ? ? ? ? ? ? ? ? ?
#include <stdio.h>
main()
{ int i, t[20] ;
for (i=0 ; i<20 ; i++)
{
printf ("donnez la note numéro %d : ", i+1) ;
scanf ("%d", &t[i]) ;
}
}
• La déclaration : int t[20]
• réserve l'emplacement pour 20 éléments de
type int.
• Chaque élément est repéré par sa "position"
dans le tableau, nommée "indice".
• La première position porte le numéro 0.
• Le premier élément du tableau sera désigné
par t[0], le troisième par t[2], le dernier par
t[19].
• Un élément de tableau est une valeur.
• Il peut donc apparaître à gauche d'un
opérateur d'affectation comme dans :
n t[2] = 5 ;
• Il peut aussi apparaître comme opérande d'un
opérateur d'incrémentation :
n t[3]++; --t[i];
• En revanche, il n'est pas possible, si A et B sont
des tableaux d'entiers, d'écrire A = B ;
• Un indice peut prendre la forme de n'importe
quelle expression arithmétique de type entier (ou
caractère, compte tenu des règles de conversion
systématique).
• Par exemple, si n, p, k et j sont de type int, ces
notations sont correctes :
¡ t[n-3]
¡ t[3*p-2*k+j%l]
• Il en va de même, si c1 et c2 sont de type char :
¡ t[c1+3]
¡ t[c2-c1]
• Il est possible d'initialiser (partiellement ou
totalement) un tableau lors de sa déclaration:
int A[5] = { 10, 20, 5, 0, 3 }
place les valeurs 10, 20, 5, 0 et 3 dans chacun
des cinq éléments du tableau A.
• Il est possible de ne mentionner dans les
accolades que certaines valeurs seulement,
comme dans l’exemple :
¡ int tab[5] = { 10, 20 }
• Les valeurs manquantes seront initialisées à
zéro.
• Il est possible d'omettre la dimension du
tableau, celle-ci étant alors déterminée par le
compilateur par le nombre de valeurs
énumérées dans l'initialisation:
¡ int A[] = { 10, 20, 5, 0, 3 }
=> Dimension de A = 5.
´ En C, un tableau à deux dimensions A est à
interpréter comme un tableau (uni-
dimensionnel) de dimension L dont chaque
composante est un tableau (uni-dimensionnel)
de dimension C.

´ On appelle L le nombre de lignes du tableau et


C le nombre de colonnes du tableau. L et C
sont alors les deux dimensions du tableau. Un
tableau à deux dimensions contient donc L*C
composantes.
´ On dit qu'un tableau à deux dimensions est
carré, si L est égal à C.

´ En faisant le rapprochement avec les


mathématiques, on peut dire que "A est une
matrice de dimensions L et C"
• Exemple
Considérons un tableau NOTES à une dimension pour mémoriser les notes de 20
élèves d'une classe dans un devoir:
int NOTE[20] = {45, 34, ... , 50, 48};

Pour mémoriser les notes des élèves dans les 10 devoirs d'un trimestre, nous pouvons
rassembler plusieurs de ces tableaux unidimensionnels dans un tableau NOTES à deux
dimensions :

int NOTE[10][20] = {{45, 34, ... , 50, 48},


{39, 24, ... , 49, 45},
... ... ...
{40, 40, ... , 54, 44}};

Dans une ligne nous retrouvons les notes de tous les élèves dans un devoir. Dans une
colonne, nous retrouvons toutes les notes d'un élève
• Déclaration

<TypeSimple> <NomTabl>[<DimLigne>][<DimCol>];

• Exemples:
int A[25][25];
A[25][25];
float B[100][10];
double B[100][10];
int C[10][2];
17
• Initialisation
Lors de la déclaration d'un tableau, on peut initialiser les composantes du
tableau, en indiquant la liste des valeurs respectives entre accolades. A
l'intérieur de la liste, les composantes de chaque ligne du tableau sont
encore une fois comprises entre accolades. Pour améliorer la lisibilité des
programmes, on peut indiquer les composantes dans plusieurs lignes.

• Exemples
int A[3][2] ={{ 0,10},{10,11},{ 1,12}};

Lors de l'initialisation, les valeurs sont affectées ligne par ligne en passant
de gauche à droite. Nous ne devons pas nécessairement indiquer toutes
les valeurs: Les valeurs manquantes seront initialisées par zéro. Il est
cependant défendu d'indiquer trop de valeurs pour un tableau.

• Réservation automatique
Si le nombre de lignes L n'est pas indiqué explicitement lors de
l'initialisation, l'ordinateur réserve automatiquement le nombre d'octets
nécessaires. 18
19
• Les éléments d'un tableau de dimensions L et C se présentent de
la façon suivante:

| A[0][0] A[0][1] A[0][2] . . . A[0][C-1] |


| A[1][0] A[1][1] A[1][2] . . . A[1][C-1] |
| A[2][0] A[2][1] A[2][2] . . . A[2][C-1] |
| ... ... ... ... ... |
| A[L-1][0] A[L-1][1] A[L-1][2] . . . A[L-1][C-1] |

• Attention !
Considérons un tableau A de dimensions L et C:
¡ les indices du tableau varient de 0 à L-1, respectivement de
0 à C-1.
¡ la composante de la Nième ligne et Mième colonne est notée:
A[N-1][M-1]
• AFFICHER
main()
{
int A[5][10];
int I,J;
// Pour chaque ligne …
for (I=0; I<5; I++)
{
// ... considérer chaque composante
for (J=0; J<10; J++)
printf(”%d", A[I][J]);
// Retour à la ligne
printf("\n");
}
return 0;
}
• REMPLIR

main()
{
int A[5][10];
int I,J;
// Pour chaque ligne ...
for (I=0; I<5; I++)
// ... considérer chaque composante
for (J=0; J<10; J++)
scanf("%d", &A[I][J]);
return 0;
}
• Ecrire un programme qui lit les dimensions L
et C d'un tableau T à deux dimensions..

• Remplir le tableau par des valeurs entrées


au clavier et afficher le tableau ainsi que la
somme de tous ses éléments.

24
• Type nom-fonction ( type-1 arg-1, …, type-n arg-n)
{
[déclarations de variables locales]
liste d'instructions
}
• Type : le type de la valeur que la fonction retourne, si
la fonction ne renvoie pas de valeur elle est de type
void.
• La fonction se termine par l'instruction return :
¡ return(expression); expression du type de la fonction

26
• Exemples :
int produit (int a, int b)
{
return(a * b);
}

int somme (int a, int b)


{ int s=a+b;
return(s);
}

void afficher (int a)


{
printf(‘’ a =%d’’,a);
} 27
• C n'autorise pas les fonctions imbriquées.

• On peut déclarer une fonction secondaire soit avant, soit


après la fonction principale main.

• Toutefois, il est indispensable que le compilateur


"connaisse" la fonction à son appel. Elle doit
impérativement être déclarée avant :
• type nom-fonction ( type-1, …, type-n);

28
• Exemple :
int somme (int , int);

int somme (int a, int b)


{
return(a+b);
}

main()
{
int a = 2, b = 5;
printf("%d\n",somme(a,b));
}
29
• L'appel de fonction fait par:
¡ nom-fonction(para-1,para-2, …, para-n);

• Exemple :
int somme (int a, int b){
return(a+b);
}
main()
{ int a = 2, b = 5, s;
s= somme(a,b);
printf("%d\n",s);
}

30
• Variable globale : variable déclarée en dehors des
fonctions.
int n=0;
void fonction ();
n est initialisée à 0
void fonction () appel numero 1
{ appel numero 2
n++; appel numero 3
appel numero 4
printf("appel numero %d\n",n);
appel numero 5
return;
}
main()
{
int i;
for (i = 0; i < 5; i++)
fonction(); 31
}
• Variable locale : variable déclarée à l'intérieur d'une
fonction (ou d'un bloc d'instruction).
int n = 10;
void fonction ();
n est initialisée à 10
void fonction ()
appel numero 1
{ appel numero 1
int n = 0; appel numero 1
n++; appel numero 1
printf("appel numero %d\n",n); appel numero 1
return;
}
main()
{
int i;
for (i = 0; i < 5; i++)
fonction(); 32
}
• Les paramètres de fonction sont traités de la même manière que
les variables locales. On dit que les paramètres d'une fonction
sont transmis par valeurs.
• Exemple :
void echange (int , int);
void echange (int a, int b)
{
int t;
printf("debut fonction :\n a = %d \t b = %d\n",a,b);
t = a;
a = b;
b = t;
printf("fin fonction : \n a = %d \t b = %d\n",a,b);
return;
33
}
main()
{
int a = 2, b = 5;
printf("debut programme principal : \n a = %d \t b = %d\n",a,b);
echange(a,b);
printf("fin programme principal : \n a = %d \t b = %d\n",a,b);
}
debut programme principal :
a=2 b=5
debut fonction :
a=2 b=5
fin fonction :
a=5 b=2
fin programme principal :
a=2 b=5
34
Retour sur les variables :
4 caractéristiques :
• un type
• un nom
• une valeur
• une adresse

les 3 premières déjà bien exploitées. Mais la 4ème ?


int a = 5;
printf("La variable a = %d", a);

n La variable a = 5
L’adresse de a ???
printf("L'adresse de la variable a est : %p", &a);
n L'adresse de la variable a est : 5A0F3
À Retenir :

• a : désigne la valeur de la variable a;


• &a : désigne l'adresse de la variable a.
Des variables faites pour contenir des adresses.
• p un pointeur
• a une variable

5A0F3 5

p a
• Pour créer une variable de type pointeur, on doit ajouter
le symbole * devant le nom de la variable.
• On doit connaître le type du contenu :
pointeur sur char;
pointeur sur int;
pointeur sur float;
etc...
• Type pointé précisé lors de la déclaration.
• Déclarer une variable p comme pointeur sur un
entier:
int *p;
• On peut faire: int* p;
• Après déclaration un pointeur ne pointe pas un
endroit précis dans la mémoire.
• Si l'on suit le pointeur, on va n'importe où :
erreur lors de l'exécution du programme.
ü int * p =NULL;
ü int a = 5;
int *p = &a; ó int *p;
p=&a;
int a = 5;
int *p = &a;
printf("%d", p);

>> 5A0F3

printf("%d", *p);

>> 5
• sur une variable « a »:
ü a : Signifie je veux la valeur de la
variable a.
ü &a : Signifie je veux l'adresse à laquelle se
trouve la variable a.
• sur un pointeur « p »:
ü p : Signifie je veux la valeur de p (cette
valeur étant une adresse).
ü *p : Signifie je veux la valeur de la
variable qui se trouve à l'adresse contenue
dans p.
• Pour qu'une fonction modifie la valeur de ses arguments, il faut il faut passer les
paramètres par adresse :
void echange (int *, int*);
void echange (int *adr_a, int *adr_b)
{
int t;
t = *adr_a;
*adr_a = *adr_b;
*adr_b = t;
return;
}
main()
{
int a = 2, b = 5;
printf("debut programme principal : \n a = %d \t b = %d\n",a,b);
echange(&a,&b);
printf("fin programme principal : \n a = %d \t b = %d\n",a,b);
48
}
• Exemple
void LIRE_TAB(int taille, int *Tableau)
//ou void LIRE_TAB(int taille, int Tableau[])
{
for(int i=0;i<taille;i++)
scanf("%d", &Tableau[i]);
// ou scanf("%d", Tableau+i);
}

• Dans la fonction main() :


LIRE_TAB(4, Tableau);

49
La fonction reçoive un pointeur sur le début de
la matrice et parcours tous les éléments comme
s'il s'agissait d'un tableau à une dimension N*M.
int SOMME(int *A, int N, int M)
{
int I;
int S;
for (I=0; I<N*M; I++)
S += A[I];
return S;
}

50
• En C, il existe une relation très étroite entre tableaux et pointeurs. Ainsi,
chaque opération avec des indices de tableaux peut aussi être exprimée à
l'aide de pointeurs.

• En général, les versions formulées avec des pointeurs sont plus compactes et
plus efficientes, surtout à l'intérieur de fonctions. Mais, du moins pour des
débutants, le 'formalisme pointeur' est un peu inhabituel.

1. Adressage des composantes d'un tableau


2. Arithmétique des pointeurs
3. Pointeurs et chaînes de caractères
4. Pointeurs et tableaux à deux dimensions

52
le nom d'un tableau représente l'adresse de son premier élément. En d'autre
termes:
&tableau[0] et tableau
sont une seule et même adresse.
En simplifiant, nous pouvons retenir que le nom d'un tableau est un pointeur
constant sur le premier élément du tableau.
• Exemple
En déclarant un tableau A de type int et un pointeur P sur int,
int A[10];
int *P;
l'instruction:
P = A; est équivalente à P = &A[0];

53
Si P pointe sur une composante quelconque d'un tableau, alors P+1 pointe sur la
composante suivante. Plus généralement,
P+i pointe sur la i-ième composante derrière P et
P-i pointe sur la i-ième composante devant P.
Ainsi, après l'instruction,
P = A;
le pointeur P pointe sur A[0], et
*(P+1) désigne le contenu de A[1]
*(P+2) désigne le contenu de A[2]
...
...
*(P+i) désigne le contenu de A[i]

54
Résumons: Soit un tableau A d'un type quelconque et i un
indice pour les composantes de A, alors
• A désigne l'adresse de A[0]
• A+i désigne l'adresse de A[i]
• *(A+i) désigne le contenu de A[i]
Si P = A, alors
• P pointe sur l'élément A[0]
• P+i pointe sur l'élément A[i]
• *(P+i) désigne le contenu de A[i]

55
A l'aide de ce bagage, il nous est facile de 'traduire' un programme écrit à l'aide du 'formalisme tableau' dans
un programme employant le 'formalisme pointeur'.
Exemple
Les deux programmes suivants copient les éléments positifs d'un tableau T dans un deuxième tableau POS.
Formalisme tableau
main(){
main(){
int T[10] = {-3, 4, 0, -7, 3, 8, 0, -1, 4, -9}, POS[10];
int T[10] = {-3, 4, 0, -7, 3, 8, 0, -1, 4, -9}, POS[10];
int I,J; /* indices courants dans T et POS */
int I,J; /* indices courants dans T et POS */
for (J=0,I=0 ; I<10 ; I++)
for (J=0,I=0 ; I<10 ; I++)
if (*(T+I)>0)
if (T[I]>0) {
{ *(POS+J) = *(T+I);
POS[J] = T[I]; J++;
J++; }
} return 0;
return 0; }
}
Nous pouvons remplacer systématiquement la notation tableau[I] par *(tableau + I), ce qui conduit à ce
programme:

56
• Ecrire un programme qui lit deux tableaux A et B et
leurs dimensions N et M au clavier et qui ajoute les
éléments de B à la fin de A. Utiliser le formalisme
pointeur à chaque fois que cela est possible.

57
• Affectation par un pointeur sur le même type
Soient P1 et P2 deux pointeurs sur le même type de données, alors l'instruction
P1 = P2;
fait pointer P1 sur le même objet que P2
• Addition et soustraction d'un nombre entier
Si P pointe sur l'élément A[i] d'un tableau, alors
P+n pointe sur A[i+n]
P-n pointe sur A[i-n]
• Incrémentation et décrémentation d'un pointeur
Si P pointe sur l'élément A[i] d'un tableau, alors après l'instruction
P++; P pointe sur A[i+1]
P+=n; P pointe sur A[i+n]
P--; P pointe sur A[i-1]
P-=n; P pointe sur A[i-n]
58
• L'addition, la soustraction, l'incrémentation et la
décrémentation sur les pointeurs sont seulement
définies à l'intérieur d'un tableau. Si l'adresse
formée par le pointeur et l'indice sort du
domaine du tableau, alors le résultat n'est pas
défini.

59
• Soustraction de deux pointeurs
Soient P1 et P2 deux pointeurs qui pointent dans le même tableau:
P1-P2 fournit le nombre de composantes comprises entre P1 et P2.
Le résultat de la soustraction P1-P2 est
¡ négatif, si P1 précède P2
¡ zéro, si P1 = P2
¡ positif, si P2 précède P1
¡ indéfini, si P1 et P2 ne pointent pas dans le même tableau
Plus généralement, la soustraction de deux pointeurs qui pointent dans le
même tableau est équivalente à la soustraction des indices correspondants.
• Comparaison de deux pointeurs
On peut comparer deux pointeurs par <, >, <=, >=, ==, !=.
La comparaison de deux pointeurs qui pointent dans le même tableau est
équivalente à la comparaison des indices correspondants. (Si les pointeurs ne
pointent pas dans le même tableau, alors le résultat est donné par leurs positions
relatives dans la mémoire).

60
• Soit P un pointeur qui 'pointe' sur un tableau A:
int A[] = {12, 23, 34, 45, 56, 67, 78, 89, 90};
int *P;
P = A;
• Quelles valeurs ou adresses fournissent ces expressions:

a) *P+2
b) *(P+2)
c) &P+1
d) &A[4]-3
e) A+3
f) &A[7]-P
g) P+(*P-10)
h) *(P+*(P+8)-A[7])

61

Vous aimerez peut-être aussi