Maîtrisez les tableaux à une dimension, les tableaux multidimensionnels, les tableaux dynamiques, les fonctions manipulant des tableaux, les pointeurs, les allocations mémoire ainsi que les principales techniques utilisées dans les applications professionnelles grâce à des explications détaillées, des programmes complets, des cas pratiques et de nombreux exercices corrigés.
Déclaration, initialisation, parcours, recherche, tri, copie et manipulation des tableaux classiques.
Tableaux à deux dimensions, matrices, affichage, calculs, parcours ligne par ligne et applications numériques.
malloc(), calloc(), realloc(), free(), redimensionnement, gestion de la mémoire et bonnes pratiques.
Exercices progressifs, programmes commentés, solutions détaillées et erreurs fréquentes expliquées.
✔ Déclaration des tableaux • ✔ Initialisation • ✔ Parcours avec les boucles • ✔ Fonctions manipulant les tableaux • ✔ Tableaux de chaînes de caractères • ✔ Matrices • ✔ Pointeurs et tableaux • ✔ Allocation dynamique • ✔ Cas pratiques • ✔ Exercices corrigés
Un tableau dynamique est créé pendant l’exécution du programme. Sa taille peut
dépendre d’une saisie utilisateur, d’un fichier ou d’un calcul. Sa mémoire est
réservée avec malloc, modifiée avec realloc puis libérée
avec free.
La fonction malloc réserve une zone mémoire suffisamment grande
pour contenir le nombre d’éléments demandé.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int taille;
printf("Nombre d'elements : ");
scanf("%d", &taille);
if (taille <= 0)
{
printf("La taille doit etre positive.\n");
return 1;
}
int *tableau = malloc((size_t)taille * sizeof(int));
if (tableau == NULL)
{
fprintf(stderr, "Erreur d'allocation memoire.\n");
return 1;
}
for (int i = 0; i < taille; i++)
{
tableau[i] = (i + 1) * 10;
}
printf("Contenu du tableau :\n");
for (int i = 0; i < taille; i++)
{
printf("tableau[%d] = %d\n", i, tableau[i]);
}
free(tableau);
tableau = NULL;
return 0;
} Chaque case du tableau peut être remplie à partir d’une saisie utilisateur.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int taille;
printf("Taille du tableau : ");
scanf("%d", &taille);
if (taille <= 0)
{
printf("Taille invalide.\n");
return 1;
}
int *tableau = malloc((size_t)taille * sizeof(int));
if (tableau == NULL)
{
fprintf(stderr, "Allocation impossible.\n");
return 1;
}
for (int i = 0; i < taille; i++)
{
printf("Valeur %d : ", i + 1);
scanf("%d", &tableau[i]);
}
printf("\nValeurs saisies : ");
for (int i = 0; i < taille; i++)
{
printf("%d ", tableau[i]);
}
printf("\n");
free(tableau);
tableau = NULL;
return 0;
} Une fonction peut créer un tableau dynamique puis retourner son adresse.
#include <stdio.h>
#include <stdlib.h>
int *creerTableau(int taille)
{
if (taille <= 0)
{
return NULL;
}
int *tableau = malloc((size_t)taille * sizeof(int));
if (tableau == NULL)
{
return NULL;
}
for (int i = 0; i < taille; i++)
{
tableau[i] = i + 1;
}
return tableau;
}
int main(void)
{
int taille = 5;
int *valeurs = creerTableau(taille);
if (valeurs == NULL)
{
fprintf(stderr, "Impossible de creer le tableau.\n");
return 1;
}
for (int i = 0; i < taille; i++)
{
printf("%d ", valeurs[i]);
}
free(valeurs);
valeurs = NULL;
return 0;
} free.
La fonction calloc réserve la mémoire et initialise automatiquement
tous les octets à zéro.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int taille = 6;
int *tableau = calloc((size_t)taille, sizeof(int));
if (tableau == NULL)
{
fprintf(stderr, "Erreur d'allocation.\n");
return 1;
}
for (int i = 0; i < taille; i++)
{
printf("tableau[%d] = %d\n", i, tableau[i]);
}
free(tableau);
tableau = NULL;
return 0;
} calloc, les éléments numériques commencent généralement à zéro.
La fonction realloc permet de modifier la taille d’une zone mémoire
déjà allouée.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int ancienneTaille = 3;
int nouvelleTaille = 6;
int *tableau = malloc(
(size_t)ancienneTaille * sizeof(int)
);
if (tableau == NULL)
{
fprintf(stderr, "Erreur d'allocation.\n");
return 1;
}
for (int i = 0; i < ancienneTaille; i++)
{
tableau[i] = (i + 1) * 10;
}
int *temporaire = realloc(
tableau,
(size_t)nouvelleTaille * sizeof(int)
);
if (temporaire == NULL)
{
free(tableau);
fprintf(stderr, "Erreur pendant realloc.\n");
return 1;
}
tableau = temporaire;
for (int i = ancienneTaille; i < nouvelleTaille; i++)
{
tableau[i] = (i + 1) * 10;
}
for (int i = 0; i < nouvelleTaille; i++)
{
printf("%d ", tableau[i]);
}
free(tableau);
tableau = NULL;
return 0;
} realloc. Une affectation directe pourrait faire perdre l’adresse initiale en cas d’échec. Cette version regroupe le pointeur, la taille utilisée et la capacité totale dans une structure.
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int *donnees;
size_t taille;
size_t capacite;
} TableauDynamique;
int initialiserTableau(
TableauDynamique *tableau,
size_t capaciteInitiale
)
{
if (tableau == NULL || capaciteInitiale == 0)
{
return 0;
}
tableau->donnees = malloc(
capaciteInitiale * sizeof(int)
);
if (tableau->donnees == NULL)
{
tableau->taille = 0;
tableau->capacite = 0;
return 0;
}
tableau->taille = 0;
tableau->capacite = capaciteInitiale;
return 1;
}
int ajouterValeur(
TableauDynamique *tableau,
int valeur
)
{
if (tableau == NULL)
{
return 0;
}
if (tableau->taille == tableau->capacite)
{
size_t nouvelleCapacite =
tableau->capacite * 2;
int *temporaire = realloc(
tableau->donnees,
nouvelleCapacite * sizeof(int)
);
if (temporaire == NULL)
{
return 0;
}
tableau->donnees = temporaire;
tableau->capacite = nouvelleCapacite;
}
tableau->donnees[tableau->taille] = valeur;
tableau->taille++;
return 1;
}
void afficherTableau(
const TableauDynamique *tableau
)
{
if (tableau == NULL)
{
return;
}
printf("Tableau : ");
for (size_t i = 0; i < tableau->taille; i++)
{
printf("%d ", tableau->donnees[i]);
}
printf("\n");
}
void libererTableau(
TableauDynamique *tableau
)
{
if (tableau == NULL)
{
return;
}
free(tableau->donnees);
tableau->donnees = NULL;
tableau->taille = 0;
tableau->capacite = 0;
}
int main(void)
{
TableauDynamique tableau;
if (!initialiserTableau(&tableau, 2))
{
fprintf(stderr, "Initialisation impossible.\n");
return 1;
}
ajouterValeur(&tableau, 10);
ajouterValeur(&tableau, 20);
ajouterValeur(&tableau, 30);
ajouterValeur(&tableau, 40);
ajouterValeur(&tableau, 50);
afficherTableau(&tableau);
printf("Taille : %zu\n", tableau.taille);
printf("Capacite : %zu\n", tableau.capacite);
libererTableau(&tableau);
return 0;
} Pour supprimer un élément, les valeurs situées après sa position sont décalées vers la gauche.
int supprimerValeur(
TableauDynamique *tableau,
size_t position
)
{
if (tableau == NULL || position >= tableau->taille)
{
return 0;
}
for (size_t i = position; i + 1 < tableau->taille; i++)
{
tableau->donnees[i] =
tableau->donnees[i + 1];
}
tableau->taille--;
return 1;
} supprimerValeur(&tableau, 1);
afficherTableau(&tableau); Une matrice dynamique peut être créée sous la forme d’un tableau de pointeurs.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int lignes = 3;
int colonnes = 4;
int **matrice = malloc(
(size_t)lignes * sizeof(int *)
);
if (matrice == NULL)
{
return 1;
}
for (int i = 0; i < lignes; i++)
{
matrice[i] = malloc(
(size_t)colonnes * sizeof(int)
);
if (matrice[i] == NULL)
{
for (int j = 0; j < i; j++)
{
free(matrice[j]);
}
free(matrice);
return 1;
}
}
for (int i = 0; i < lignes; i++)
{
for (int j = 0; j < colonnes; j++)
{
matrice[i][j] = i + j;
}
}
for (int i = 0; i < lignes; i++)
{
for (int j = 0; j < colonnes; j++)
{
printf("%d ", matrice[i][j]);
}
printf("\n");
}
for (int i = 0; i < lignes; i++)
{
free(matrice[i]);
}
free(matrice);
matrice = NULL;
return 0;
} | Erreur | Conséquence | Correction |
|---|---|---|
Ne pas tester malloc | Utilisation possible d’un pointeur nul | Vérifier que le résultat est différent de NULL |
Oublier free | Fuite de mémoire | Libérer toute mémoire qui n’est plus utilisée |
Utiliser le pointeur après free | Comportement indéfini | Mettre le pointeur à NULL |
| Dépasser la taille allouée | Écriture hors mémoire | Contrôler les indices et la capacité |
Affecter directement realloc | Perte du pointeur initial en cas d’échec | Utiliser un pointeur temporaire |
| Libérer deux fois le même pointeur | Erreur mémoire grave | Mettre le pointeur à NULL après libération |
| Fonction | Utilisation | Initialisation |
|---|---|---|
malloc | Créer une nouvelle zone mémoire | Contenu non initialisé |
calloc | Créer un tableau de plusieurs éléments | Mémoire initialisée à zéro |
realloc | Agrandir ou réduire une zone existante | Les nouvelles cases ne sont pas initialisées |
free | Libérer la mémoire allouée | Le pointeur ne doit plus être utilisé |
Fonctions qui Retournent des Tableaux en C
Voici une série d’exercices corrigés sur les tableaux en langage C, allant des bases aux concepts plus avancés. Ces exercices vous aideront à mieux comprendre la manipulation des tableaux et les opérations associées.
Écrivez un programme en C qui remplit un tableau de 5 entiers donnés par l’utilisateur et affiche ensuite les éléments du tableau.
#include <stdio.h>
int main() {
int tableau[5];
// Saisie des éléments du tableau
for(int i = 0; i < 5; i++) {
printf("Entrez l'élément %d : ", i + 1);
scanf("%d", &tableau[i]);
}
// Affichage des éléments du tableau
printf("Les éléments du tableau sont :\n");
for(int i = 0; i < 5; i++) {
printf("%d ", tableau[i]);
}
printf("\n");
return 0;
} tableau[5] est utilisé pour stocker 5 entiers.for remplit le tableau avec les entrées de l’utilisateur.for affiche les éléments du tableau.Écrivez un programme en C qui demande à l’utilisateur de remplir un tableau de 10 entiers, puis trouve et affiche la valeur maximale dans ce tableau.
#include <stdio.h>
int main() {
int tableau[10];
int max;
// Saisie des éléments du tableau
for (int i = 0; i < 10; i++) {
printf("Entrez l'élément %d : ", i + 1);
scanf("%d", &tableau[i]);
}
// Initialisation de la variable max avec le premier élément du tableau
max = tableau[0];
// Recherche du maximum
for (int i = 1; i < 10; i++) {
if (tableau[i] > max) {
max = tableau[i];
}
}
// Affichage du maximum
printf("La valeur maximale est : %d\n", max);
return 0;
} max avec le premier élément du tableau.Écrivez un programme en C qui lit 5 nombres flottants, les stocke dans un tableau, et affiche ensuite la moyenne de ces nombres.
#include <stdio.h>
int main() {
float tableau[5], somme = 0.0, moyenne;
// Saisie des éléments du tableau
for(int i = 0; i < 5; i++) {
printf("Entrez l'élément %d : ", i + 1);
scanf("%f", &tableau[i]);
somme += tableau[i]; // Ajouter chaque élément à la somme
}
// Calcul de la moyenne
moyenne = somme / 5;
// Affichage de la moyenne
printf("La moyenne des éléments est : %.2f\n", moyenne);
return 0;
} tableau[5] contient des nombres flottants.Écrivez un programme en C qui lit 6 entiers, les stocke dans un tableau, puis affiche les éléments dans l’ordre inverse.
#include <stdio.h>
int main() {
int tableau[6];
// Saisie des éléments du tableau
for(int i = 0; i < 6; i++) {
printf("Entrez l'élément %d : ", i + 1);
scanf("%d", &tableau[i]);
}
// Affichage des éléments dans l'ordre inverse
printf("Les éléments du tableau dans l'ordre inverse sont :\n");
for(int i = 5; i >= 0; i--) {
printf("%d ", tableau[i]);
}
printf("\n");
return 0;
} for inverse les éléments en commençant par le dernier et en affichant chaque élément.Écrivez un programme en C qui lit 5 entiers, les stocke dans un tableau, puis les trie dans l’ordre croissant en utilisant l’algorithme du tri par sélection.
#include <stdio.h>
int main() {
int tableau[5], i, j, min, temp;
// Saisie des éléments du tableau
for(i = 0; i < 5; i++) {
printf("Entrez l'élément %d : ", i + 1);
scanf("%d", &tableau[i]);
}
// Tri par sélection
for(i = 0; i < 4; i++) {
min = i;
for(j = i + 1; j < 5; j++) {
if(tableau[j] < tableau[min]) {
min = j;
}
}
// Échange des éléments
temp = tableau[min];
tableau[min] = tableau[i];
tableau[i] = temp;
}
// Affichage du tableau trié
printf("Le tableau trié est :\n");
for(i = 0; i < 5; i++) {
printf("%d ", tableau[i]);
}
printf("\n");
return 0;
} Écrivez un programme en C qui lit deux tableaux de 5 entiers chacun, puis les fusionne dans un troisième tableau.
#include <stdio.h>
int main() {
int tableau1[5], tableau2[5], tableau_fusion[10];
// Saisie des éléments du premier tableau
printf("Entrez les éléments du premier tableau :\n");
for(int i = 0; i < 5; i++) {
scanf("%d", &tableau1[i]);
}
// Saisie des éléments du deuxième tableau
printf("Entrez les éléments du deuxième tableau :\n");
for(int i = 0; i < 5; i++) {
scanf("%d", &tableau2[i]);
}
// Fusion des deux tableaux
for(int i = 0; i < 5; i++) {
tableau_fusion[i] = tableau1[i];
tableau_fusion[i + 5] = tableau2[i];
}
// Affichage du tableau fusionné
printf("Le tableau fusionné est :\n");
for(int i = 0; i < 10; i++) {
printf("%d ", tableau_fusion[i]);
}
printf("\n");
return 0;
} Ces exercices tableaux en langage C vous permettent de pratiquer les bases et des concepts légèrement plus avancés liés aux tableaux en C. Vous pouvez essayer d’autres variantes, comme implémenter des algorithmes de tri plus complexes ou travailler sur des tableaux dynamiques.
Les tableaux à deux dimensions en langage C, également appelés tableaux bidimensionnels ou matrices, permettent de stocker des données organisées sous forme de lignes et de colonnes. Ils sont utilisés dans de nombreux domaines : calcul scientifique, traitement d’images, intelligence artificielle, statistiques, jeux vidéo, finance, robotique et programmation embarquée.
Maîtriser les matrices en C constitue une étape essentielle avant d’aborder les structures de données plus avancées comme les pointeurs, les tableaux dynamiques ou les algorithmes matriciels.
int notes[4][3];
Ce tableau contient :
int matrice[3][3]={
{1,2,3},
{4,5,6},
{7,8,9}
};
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
printf("%d ",matrice[i][j]);
}
printf("\n");
}
| Exercice | Objectif | Difficulté |
|---|---|---|
| 1. Afficher une matrice | Parcourir lignes et colonnes | ⭐ |
| 2. Calculer la somme des éléments | Boucles imbriquées | ⭐ |
| 3. Moyenne d’une ligne | Calcul statistique | ⭐⭐ |
| 4. Addition de deux matrices | Double parcours | ⭐⭐ |
| 5. Transposer une matrice | Échanger lignes et colonnes | ⭐⭐⭐ |
| 6. Rechercher une valeur | Recherche séquentielle | ⭐⭐⭐ |
| 7. Calcul de la diagonale principale | Indices identiques | ⭐⭐⭐ |
| 8. Multiplication de matrices | Trois boucles imbriquées | ⭐⭐⭐⭐ |
En langage C, les tableaux et les pointeurs sont étroitement liés. Le nom d’un tableau représente généralement l’adresse de son premier élément. Cette relation permet de parcourir, transmettre et modifier un tableau à l’aide de l’arithmétique des pointeurs.
tab, les expressions tab[i] et *(tab + i) désignent la même valeur. Considérons un tableau de cinq entiers :
int tab[5] = {10, 20, 30, 40, 50};
Dans la plupart des expressions, tab correspond à l’adresse
du premier élément du tableau, c’est-à-dire à &tab[0].
| Expression | Signification |
|---|---|
tab | Adresse du premier élément |
&tab[0] | Adresse du premier élément |
*tab | Valeur du premier élément |
tab + 2 | Adresse du troisième élément |
*(tab + 2) | Valeur du troisième élément |
printf("%d\n", tab[2]);
printf("%d\n", *(tab + 2));
Les deux instructions affichent 30. L’indice
2 indique que le programme doit avancer de deux éléments
depuis l’adresse de départ du tableau.
Un pointeur peut recevoir l’adresse du premier élément du tableau, puis avancer case par case.
#include <stdio.h>
int main(void)
{
int tab[5] = {10, 20, 30, 40, 50};
int *p = tab;
for (int i = 0; i < 5; i++)
{
printf("%d ", *(p + i));
}
return 0;
}
Le pointeur p contient l’adresse du premier élément.
L’expression p + i désigne l’adresse de l’élément situé à
l’indice i.
int tab[4] = {2, 4, 6, 8};
int *p = tab;
for (int i = 0; i < 4; i++)
{
*(p + i) = *(p + i) * 2;
} Après l’exécution, le tableau contient : 4, 8, 12 et 16. Le pointeur permet donc de lire mais aussi de modifier directement les cases du tableau.
Lorsqu’un tableau est transmis à une fonction, celle-ci reçoit en réalité l’adresse de son premier élément.
#include <stdio.h>
void afficherTableau(const int *tab, int taille)
{
for (int i = 0; i < taille; i++)
{
printf("%d ", tab[i]);
}
}
int main(void)
{
int valeurs[5] = {3, 6, 9, 12, 15};
afficherTableau(valeurs, 5);
return 0;
} Les écritures suivantes sont équivalentes dans les paramètres d’une fonction :
void afficher(int tab[], int taille);
void afficher(int *tab, int taille); #include <stdio.h>
int sommeTableau(const int *tab, int taille)
{
int somme = 0;
for (int i = 0; i < taille; i++)
{
somme += *(tab + i);
}
return somme;
}
int main(void)
{
int nombres[5] = {5, 10, 15, 20, 25};
printf("Somme : %d", sommeTableau(nombres, 5));
return 0;
} Le programme affiche : Somme : 75.
| Caractéristique | Tableau | Pointeur |
|---|---|---|
| Stockage | Réserve un bloc de mémoire | Stocke une adresse |
| Réaffectation | Le nom du tableau ne peut pas changer d’adresse | Le pointeur peut recevoir une autre adresse |
| sizeof | Retourne la taille totale du tableau | Retourne la taille du pointeur |
| Accès | tab[i] | *(p + i) |
Dans la fonction principale, il est possible de calculer le nombre d’éléments d’un tableau avec :
int taille = sizeof(tab) / sizeof(tab[0]); Cette méthode ne fonctionne plus après le passage du tableau à une fonction, car le paramètre est alors traité comme un pointeur. Il faut transmettre explicitement la taille du tableau.
sizeof. sizeof sur un paramètre de fonction.Écrire un programme qui recherche la plus grande valeur d’un tableau en utilisant uniquement un pointeur.
#include <stdio.h>
int maximum(const int *tab, int taille)
{
int max = *tab;
for (int i = 1; i < taille; i++)
{
if (*(tab + i) > max)
{
max = *(tab + i);
}
}
return max;
}
int main(void)
{
int tab[6] = {14, 7, 32, 18, 45, 11};
printf("Maximum : %d", maximum(tab, 6));
return 0;
} Résultat obtenu : Maximum : 45.
tab[i] et *(tab + i).sizeof.malloc, calloc et realloc.L’allocation dynamique en langage C permet de réserver de la mémoire pendant l’exécution du programme. Contrairement à un tableau fixe, dont la taille est déterminée à la compilation, un tableau dynamique peut être créé selon une valeur saisie par l’utilisateur ou calculée par le programme.
Cette technique repose principalement sur les fonctions
malloc(), calloc(), realloc() et
free(), disponibles dans la bibliothèque
<stdlib.h>.
free() lorsqu’elle devient inutile. Un tableau classique possède une taille fixe :
int tab[100]; Ce tableau réserve toujours la mémoire nécessaire pour 100 entiers, même si le programme n’en utilise que 10. À l’inverse, l’allocation dynamique permet d’adapter la taille du tableau au besoin réel.
| Tableau fixe | Tableau dynamique |
|---|---|
| Taille souvent connue à l’avance | Taille définie pendant l’exécution |
| Mémoire réservée automatiquement | Mémoire réservée manuellement |
| Taille difficile à modifier | Taille modifiable avec realloc() |
Pas de free() | free() obligatoire |
La fonction malloc() réserve un nombre d’octets donné et retourne
l’adresse du premier octet réservé.
int *tab = malloc(taille * sizeof(int));
L’expression taille * sizeof(int) calcule la quantité de mémoire nécessaire
pour stocker le nombre demandé d’entiers.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int taille;
printf("Nombre d'elements : ");
scanf("%d", &taille);
int *tab = malloc(taille * sizeof(int));
if (tab == NULL)
{
printf("Erreur d'allocation memoire.\n");
return 1;
}
for (int i = 0; i < taille; i++)
{
printf("tab[%d] = ", i);
scanf("%d", &tab[i]);
}
for (int i = 0; i < taille; i++)
{
printf("%d ", tab[i]);
}
free(tab);
tab = NULL;
return 0;
} malloc() ne parvient pas à réserver la mémoire demandée, elle retourne NULL. Le programme doit tester ce résultat avant d’utiliser le pointeur.
La fonction calloc() réserve une zone mémoire et initialise tous ses octets
à zéro. Elle reçoit deux arguments : le nombre d’éléments et la taille d’un élément.
int *tab = calloc(taille, sizeof(int)); Pour un tableau d’entiers, les cases sont ainsi initialisées à zéro avant leur première utilisation.
| Fonction | Réservation | Initialisation |
|---|---|---|
malloc() | Oui | Valeurs indéterminées |
calloc() | Oui | Octets initialisés à zéro |
La fonction realloc() modifie la taille d’une zone mémoire déjà réservée.
Elle peut conserver la même adresse ou déplacer les données vers une nouvelle zone.
int *temp = realloc(tab, nouvelleTaille * sizeof(int));
Il est préférable d’utiliser un pointeur temporaire. En cas d’échec, realloc()
retourne NULL, mais l’ancienne zone mémoire reste encore valide.
int *temp = realloc(tab, nouvelleTaille * sizeof(int));
if (temp == NULL)
{
printf("Impossible de redimensionner le tableau.\n");
free(tab);
return 1;
}
tab = temp;
La fonction free() restitue au système une zone réservée avec
malloc(), calloc() ou realloc().
free(tab);
tab = NULL;
L’affectation de NULL après free() permet d’éviter de conserver
un pointeur vers une zone mémoire qui n’est plus accessible.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int taille;
double somme = 0.0;
printf("Combien de notes souhaitez-vous saisir ? ");
scanf("%d", &taille);
if (taille <= 0)
{
printf("La taille doit etre positive.\n");
return 1;
}
double *notes = malloc(taille * sizeof(double));
if (notes == NULL)
{
printf("Erreur d'allocation memoire.\n");
return 1;
}
for (int i = 0; i < taille; i++)
{
printf("Note %d : ", i + 1);
scanf("%lf", ¬es[i]);
somme += notes[i];
}
printf("Moyenne : %.2f\n", somme / taille);
free(notes);
notes = NULL;
return 0;
} Une matrice dynamique peut être représentée par un tableau de pointeurs. Chaque pointeur correspond à une ligne.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int lignes = 3;
int colonnes = 4;
int **matrice = malloc(lignes * sizeof(int *));
if (matrice == NULL)
{
return 1;
}
for (int i = 0; i < lignes; i++)
{
matrice[i] = malloc(colonnes * sizeof(int));
if (matrice[i] == NULL)
{
for (int k = 0; k < i; k++)
{
free(matrice[k]);
}
free(matrice);
return 1;
}
}
for (int i = 0; i < lignes; i++)
{
for (int j = 0; j < colonnes; j++)
{
matrice[i][j] = i + j;
}
}
for (int i = 0; i < lignes; i++)
{
free(matrice[i]);
}
free(matrice);
matrice = NULL;
return 0;
} NULL.<stdlib.h>.free().realloc().Le programme suivant crée un tableau de trois entiers, puis l’agrandit pour ajouter deux nouvelles valeurs.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int taille = 3;
int *tab = malloc(taille * sizeof(int));
if (tab == NULL)
{
return 1;
}
tab[0] = 10;
tab[1] = 20;
tab[2] = 30;
int nouvelleTaille = 5;
int *temp = realloc(tab, nouvelleTaille * sizeof(int));
if (temp == NULL)
{
free(tab);
return 1;
}
tab = temp;
tab[3] = 40;
tab[4] = 50;
for (int i = 0; i < nouvelleTaille; i++)
{
printf("%d ", tab[i]);
}
free(tab);
tab = NULL;
return 0;
} Résultat : 10 20 30 40 50
malloc().calloc().realloc().free().
En langage C, une chaîne de caractères est représentée par un tableau de
variables de type char. Chaque case contient un caractère et la chaîne se
termine obligatoirement par le caractère spécial '\0', appelé caractère nul.
La maîtrise des chaînes de caractères permet de traiter des noms, des phrases, des mots de passe, des fichiers texte, des commandes utilisateur et de nombreuses données saisies au clavier.
'\0'. Sans ce caractère, les fonctions de traitement ne peuvent pas déterminer où la chaîne se termine. Une chaîne peut être déclarée comme un tableau de caractères :
char nom[20];
Ce tableau peut contenir jusqu’à 19 caractères utiles. La dernière case doit rester disponible
pour le caractère nul '\0'.
char ville[] = "Paris"; Le compilateur crée automatiquement le tableau suivant :
Les deux déclarations suivantes produisent le même résultat :
char ville[] = "Paris";
char ville[] = {'P', 'a', 'r', 'i', 's', '\0'}; #include <stdio.h>
int main(void)
{
char langage[] = "Langage C";
printf("%s\n", langage);
return 0;
}
Le spécificateur %s permet d’afficher les caractères jusqu’à la rencontre de
'\0'.
La fonction scanf() peut lire un mot simple :
char prenom[30];
printf("Prenom : ");
scanf("%29s", prenom);
La limite 29 protège le tableau contre un dépassement de capacité. Cependant,
scanf("%s") s’arrête au premier espace.
Jean Dupont, seul le mot Jean sera enregistré avec scanf("%s").
La fonction fgets() est mieux adaptée pour lire une phrase contenant des espaces.
#include <stdio.h>
int main(void)
{
char phrase[100];
printf("Saisissez une phrase : ");
fgets(phrase, sizeof(phrase), stdin);
printf("Phrase : %s", phrase);
return 0;
}
fgets() limite automatiquement le nombre de caractères lus selon la taille du tableau.
Elle peut toutefois conserver le caractère de retour à la ligne '\n'.
#include <stdio.h>
#include <string.h>
int main(void)
{
char nom[50];
printf("Nom complet : ");
fgets(nom, sizeof(nom), stdin);
nom[strcspn(nom, "\n")] = '\0';
printf("Bonjour %s\n", nom);
return 0;
}
La fonction strcspn() repère la position du premier retour à la ligne.
Celui-ci est ensuite remplacé par '\0'.
La bibliothèque <string.h> fournit plusieurs fonctions pour manipuler les chaînes.
| Fonction | Rôle | Exemple |
|---|---|---|
strlen() | Calculer la longueur | strlen(texte) |
strcpy() | Copier une chaîne | strcpy(copie, source) |
strcat() | Concaténer deux chaînes | strcat(texte, suite) |
strcmp() | Comparer deux chaînes | strcmp(a, b) |
strchr() | Chercher un caractère | strchr(texte, 'a') |
strstr() | Chercher une sous-chaîne | strstr(texte, "C") |
#include <stdio.h>
#include <string.h>
int main(void)
{
char mot[] = "programmation";
printf("Longueur : %zu\n", strlen(mot));
return 0;
}
strlen() compte les caractères situés avant '\0'.
Le caractère nul ne fait donc pas partie de la longueur retournée.
#include <stdio.h>
#include <string.h>
int main(void)
{
char source[] = "Tableau";
char copie[20];
strcpy(copie, source);
printf("%s\n", copie);
return 0;
} Le tableau de destination doit être suffisamment grand pour recevoir la chaîne source ainsi que le caractère nul final.
#include <stdio.h>
#include <string.h>
int main(void)
{
char phrase[50] = "Langage";
char suite[] = " C";
strcat(phrase, suite);
printf("%s\n", phrase);
return 0;
} Le résultat est Langage C. La chaîne de destination doit disposer d’un espace suffisant pour contenir les deux chaînes réunies.
L’opérateur == ne compare pas le contenu de deux chaînes. Il compare leurs adresses.
Pour comparer leur texte, il faut utiliser strcmp().
#include <stdio.h>
#include <string.h>
int main(void)
{
char mot1[] = "code";
char mot2[] = "code";
if (strcmp(mot1, mot2) == 0)
{
printf("Les chaines sont identiques.\n");
}
return 0;
} | Résultat de strcmp() | Interprétation |
|---|---|
0 | Les chaînes sont identiques |
| Valeur négative | La première chaîne précède la seconde |
| Valeur positive | La première chaîne suit la seconde |
#include <stdio.h>
int main(void)
{
char mot[] = "ordinateur";
for (int i = 0; mot[i] != '\0'; i++)
{
printf("%c\n", mot[i]);
}
return 0;
}
La boucle continue tant que le caractère rencontré est différent de '\0'.
#include <stdio.h>
int main(void)
{
char texte[] = "programmation";
int voyelles = 0;
for (int i = 0; texte[i] != '\0'; i++)
{
char c = texte[i];
if (c == 'a' || c == 'e' || c == 'i' ||
c == 'o' || c == 'u' || c == 'y')
{
voyelles++;
}
}
printf("Nombre de voyelles : %d\n", voyelles);
return 0;
} #include <stdio.h>
#include <ctype.h>
int main(void)
{
char texte[] = "langage c";
for (int i = 0; texte[i] != '\0'; i++)
{
texte[i] = (char)toupper((unsigned char)texte[i]);
}
printf("%s\n", texte);
return 0;
}
La fonction toupper(), disponible dans <ctype.h>,
convertit une lettre minuscule en majuscule.
#include <stdio.h>
#include <string.h>
int main(void)
{
char mot[] = "tableau";
int gauche = 0;
int droite = (int)strlen(mot) - 1;
while (gauche < droite)
{
char temp = mot[gauche];
mot[gauche] = mot[droite];
mot[droite] = temp;
gauche++;
droite--;
}
printf("%s\n", mot);
return 0;
} Le programme affiche uaelbat.
Un tableau à deux dimensions peut stocker plusieurs chaînes de même capacité maximale.
#include <stdio.h>
int main(void)
{
char villes[4][20] = {
"Paris",
"Lyon",
"Marseille",
"Toulouse"
};
for (int i = 0; i < 4; i++)
{
printf("%s\n", villes[i]);
}
return 0;
} Le tableau contient quatre lignes. Chaque ligne peut stocker une chaîne de 19 caractères maximum, plus le caractère nul.
#include <stdio.h>
int main(void)
{
const char *villes[] = {
"Paris",
"Lyon",
"Marseille",
"Toulouse"
};
int nombre = sizeof(villes) / sizeof(villes[0]);
for (int i = 0; i < nombre; i++)
{
printf("%s\n", villes[i]);
}
return 0;
}
Chaque case du tableau contient ici un pointeur vers le premier caractère d’une chaîne.
Le mot-clé const évite de modifier les littéraux de chaîne.
'\0'.gets(), une fonction dangereuse supprimée du standard moderne.==.strcpy() sans vérifier la capacité de destination.strlen() avec sizeof().fgets().#include <stdio.h>
#include <string.h>
int main(void)
{
char mot[] = "chat";
printf("strlen : %zu\n", strlen(mot));
printf("sizeof : %zu\n", sizeof(mot));
return 0;
}
strlen(mot) retourne 4, car elle compte les lettres.
sizeof(mot) retourne 5, car elle inclut également
le caractère nul final.
Un palindrome est un mot qui se lit de la même manière dans les deux sens, comme radar.
#include <stdio.h>
#include <string.h>
int main(void)
{
char mot[50];
int palindrome = 1;
printf("Saisissez un mot : ");
scanf("%49s", mot);
int longueur = (int)strlen(mot);
for (int i = 0; i < longueur / 2; i++)
{
if (mot[i] != mot[longueur - 1 - i])
{
palindrome = 0;
break;
}
}
if (palindrome)
{
printf("Le mot est un palindrome.\n");
}
else
{
printf("Le mot n'est pas un palindrome.\n");
}
return 0;
} '\0'.scanf().fgets().strlen(), strcpy(), strcat() et strcmp().Les algorithmes sur tableaux en langage C permettent de rechercher, classer, compter, comparer ou transformer une série de valeurs. Ils constituent une base essentielle de l’algorithmique et préparent à l’étude des pointeurs, des structures de données, de la complexité et de l’optimisation des programmes.
La recherche séquentielle parcourt le tableau case par case jusqu’à trouver la valeur recherchée.
#include <stdio.h>
int rechercher(const int tab[], int taille, int valeur)
{
for (int i = 0; i < taille; i++)
{
if (tab[i] == valeur)
{
return i;
}
}
return -1;
}
int main(void)
{
int tab[] = {12, 7, 25, 18, 9};
int taille = sizeof(tab) / sizeof(tab[0]);
int position = rechercher(tab, taille, 18);
if (position != -1)
{
printf("Valeur trouvee a l'indice %d\n", position);
}
else
{
printf("Valeur absente\n");
}
return 0;
} Dans le pire des cas, le programme examine toutes les cases du tableau. Sa complexité est donc O(n).
La recherche dichotomique fonctionne uniquement sur un tableau déjà trié. Elle divise la zone de recherche par deux à chaque étape.
int rechercheDichotomique(const int tab[], int taille, int valeur)
{
int gauche = 0;
int droite = taille - 1;
while (gauche <= droite)
{
int milieu = gauche + (droite - gauche) / 2;
if (tab[milieu] == valeur)
{
return milieu;
}
if (tab[milieu] < valeur)
{
gauche = milieu + 1;
}
else
{
droite = milieu - 1;
}
}
return -1;
} Sa complexité est O(log n), ce qui la rend nettement plus rapide sur les grands tableaux triés.
| Méthode | Condition | Complexité |
|---|---|---|
| Recherche séquentielle | Tableau trié ou non | O(n) |
| Recherche dichotomique | Tableau obligatoirement trié | O(log n) |
int minimum(const int tab[], int taille)
{
int min = tab[0];
for (int i = 1; i < taille; i++)
{
if (tab[i] < min)
{
min = tab[i];
}
}
return min;
}
int maximum(const int tab[], int taille)
{
int max = tab[0];
for (int i = 1; i < taille; i++)
{
if (tab[i] > max)
{
max = tab[i];
}
}
return max;
} L’inversion échange la première valeur avec la dernière, la deuxième avec l’avant-dernière, puis continue jusqu’au centre.
void inverser(int tab[], int taille)
{
int gauche = 0;
int droite = taille - 1;
while (gauche < droite)
{
int temp = tab[gauche];
tab[gauche] = tab[droite];
tab[droite] = temp;
gauche++;
droite--;
}
} Le tri à bulles compare les valeurs voisines et les échange lorsqu’elles sont dans le mauvais ordre. Il est simple à comprendre, mais peu performant sur de grands tableaux.
void triBulles(int tab[], int taille)
{
for (int i = 0; i < taille - 1; i++)
{
int echange = 0;
for (int j = 0; j < taille - 1 - i; j++)
{
if (tab[j] > tab[j + 1])
{
int temp = tab[j];
tab[j] = tab[j + 1];
tab[j + 1] = temp;
echange = 1;
}
}
if (!echange)
{
break;
}
}
} Le tri par sélection recherche la plus petite valeur dans la partie non triée, puis la place à la position correcte.
void triSelection(int tab[], int taille)
{
for (int i = 0; i < taille - 1; i++)
{
int indiceMin = i;
for (int j = i + 1; j < taille; j++)
{
if (tab[j] < tab[indiceMin])
{
indiceMin = j;
}
}
if (indiceMin != i)
{
int temp = tab[i];
tab[i] = tab[indiceMin];
tab[indiceMin] = temp;
}
}
} Le tri par insertion construit progressivement une partie triée du tableau. Il est particulièrement efficace sur les petits tableaux ou les tableaux presque triés.
void triInsertion(int tab[], int taille)
{
for (int i = 1; i < taille; i++)
{
int valeur = tab[i];
int j = i - 1;
while (j >= 0 && tab[j] > valeur)
{
tab[j + 1] = tab[j];
j--;
}
tab[j + 1] = valeur;
}
} | Algorithme | Cas moyen | Atout principal |
|---|---|---|
| Tri à bulles | O(n²) | Très pédagogique |
| Tri par sélection | O(n²) | Peu d’échanges |
| Tri par insertion | O(n²) | Bon sur tableau presque trié |
int supprimerDoublons(int tab[], int taille)
{
if (taille == 0)
{
return 0;
}
int nouvelleTaille = 1;
for (int i = 1; i < taille; i++)
{
if (tab[i] != tab[nouvelleTaille - 1])
{
tab[nouvelleTaille] = tab[i];
nouvelleTaille++;
}
}
return nouvelleTaille;
} Cette méthode suppose que le tableau est déjà trié. Les valeurs identiques sont alors voisines.
void fusionner(const int a[], int tailleA,
const int b[], int tailleB,
int resultat[])
{
int i = 0;
int j = 0;
int k = 0;
while (i < tailleA && j < tailleB)
{
if (a[i] <= b[j])
{
resultat[k++] = a[i++];
}
else
{
resultat[k++] = b[j++];
}
}
while (i < tailleA)
{
resultat[k++] = a[i++];
}
while (j < tailleB)
{
resultat[k++] = b[j++];
}
} int compterOccurrences(const int tab[], int taille, int valeur)
{
int compteur = 0;
for (int i = 0; i < taille; i++)
{
if (tab[i] == valeur)
{
compteur++;
}
}
return compteur;
} void decalageDroite(int tab[], int taille)
{
if (taille <= 1)
{
return;
}
int dernier = tab[taille - 1];
for (int i = taille - 1; i > 0; i--)
{
tab[i] = tab[i - 1];
}
tab[0] = dernier;
} #include <stdio.h>
void triInsertion(int tab[], int taille)
{
for (int i = 1; i < taille; i++)
{
int valeur = tab[i];
int j = i - 1;
while (j >= 0 && tab[j] > valeur)
{
tab[j + 1] = tab[j];
j--;
}
tab[j + 1] = valeur;
}
}
int rechercheDichotomique(const int tab[], int taille, int valeur)
{
int gauche = 0;
int droite = taille - 1;
while (gauche <= droite)
{
int milieu = gauche + (droite - gauche) / 2;
if (tab[milieu] == valeur)
{
return milieu;
}
if (tab[milieu] < valeur)
{
gauche = milieu + 1;
}
else
{
droite = milieu - 1;
}
}
return -1;
}
int main(void)
{
int tab[] = {34, 12, 7, 45, 19, 28};
int taille = sizeof(tab) / sizeof(tab[0]);
triInsertion(tab, taille);
int position = rechercheDichotomique(tab, taille, 19);
printf("Position de 19 : %d\n", position);
return 0;
} | Exercice | Compétence | Niveau |
|---|---|---|
| Rechercher la première occurrence | Recherche séquentielle | ⭐ |
| Trouver le deuxième maximum | Comparaison | ⭐⭐ |
| Inverser un tableau sans second tableau | Échange | ⭐⭐ |
| Trier les notes par ordre croissant | Tri | ⭐⭐⭐ |
| Fusionner deux tableaux triés | Fusion | ⭐⭐⭐ |
| Comparer les temps de recherche | Complexité | ⭐⭐⭐⭐ |
Cette série de 30 exercices sur les tableaux en langage C rassemble les principales notions étudiées : tableaux simples, matrices, chaînes de caractères, pointeurs, allocation dynamique, recherche, tri et algorithmes classiques.
Les exercices sont organisés selon une difficulté progressive. Chaque sujet précise la compétence travaillée, l’objectif attendu et une proposition de correction en langage C.
Ce premier niveau porte sur la déclaration, la saisie, l’affichage et les calculs simples dans un tableau à une dimension.
Créez un tableau de cinq entiers, demandez à l’utilisateur de saisir les valeurs, puis affichez-les dans le même ordre.
Compétence : déclaration, saisie et parcours d’un tableau.
#include <stdio.h>
int main(void)
{
int tab[5];
for (int i = 0; i < 5; i++)
{
printf("Valeur %d : ", i + 1);
scanf("%d", &tab[i]);
}
printf("Tableau : ");
for (int i = 0; i < 5; i++)
{
printf("%d ", tab[i]);
}
return 0;
} Calculez et affichez la somme de tous les éléments d’un tableau.
Compétence : accumulation dans une boucle.
#include <stdio.h>
int main(void)
{
int tab[] = {4, 8, 12, 3, 7};
int taille = sizeof(tab) / sizeof(tab[0]);
int somme = 0;
for (int i = 0; i < taille; i++)
{
somme += tab[i];
}
printf("Somme : %d\n", somme);
return 0;
} Calculez la moyenne des valeurs contenues dans un tableau d’entiers.
Compétence : somme, conversion et division.
#include <stdio.h>
int main(void)
{
int tab[] = {10, 14, 8, 16, 12};
int taille = sizeof(tab) / sizeof(tab[0]);
int somme = 0;
for (int i = 0; i < taille; i++)
{
somme += tab[i];
}
double moyenne = (double)somme / taille;
printf("Moyenne : %.2f\n", moyenne);
return 0;
} Recherchez la plus petite valeur d’un tableau.
Compétence : comparaison et mémorisation d’une valeur.
#include <stdio.h>
int main(void)
{
int tab[] = {18, 7, 25, 4, 11};
int taille = sizeof(tab) / sizeof(tab[0]);
int minimum = tab[0];
for (int i = 1; i < taille; i++)
{
if (tab[i] < minimum)
{
minimum = tab[i];
}
}
printf("Minimum : %d\n", minimum);
return 0;
} Affichez la plus grande valeur du tableau ainsi que sa position.
Compétence : distinction entre valeur et indice.
#include <stdio.h>
int main(void)
{
int tab[] = {5, 29, 13, 42, 17};
int taille = sizeof(tab) / sizeof(tab[0]);
int indiceMax = 0;
for (int i = 1; i < taille; i++)
{
if (tab[i] > tab[indiceMax])
{
indiceMax = i;
}
}
printf("Maximum : %d\n", tab[indiceMax]);
printf("Indice : %d\n", indiceMax);
return 0;
} Comptez le nombre de valeurs paires présentes dans un tableau.
Compétence : test avec l’opérateur modulo.
#include <stdio.h>
int main(void)
{
int tab[] = {4, 7, 10, 13, 18, 21};
int taille = sizeof(tab) / sizeof(tab[0]);
int compteur = 0;
for (int i = 0; i < taille; i++)
{
if (tab[i] % 2 == 0)
{
compteur++;
}
}
printf("Nombres pairs : %d\n", compteur);
return 0;
} Affichez les éléments du dernier au premier sans modifier le tableau.
Compétence : parcours décroissant.
#include <stdio.h>
int main(void)
{
int tab[] = {2, 4, 6, 8, 10};
int taille = sizeof(tab) / sizeof(tab[0]);
for (int i = taille - 1; i >= 0; i--)
{
printf("%d ", tab[i]);
}
return 0;
} Copiez les valeurs d’un premier tableau dans un second tableau de même taille.
Compétence : manipulation simultanée de deux tableaux.
#include <stdio.h>
int main(void)
{
int source[] = {3, 6, 9, 12, 15};
int copie[5];
int taille = sizeof(source) / sizeof(source[0]);
for (int i = 0; i < taille; i++)
{
copie[i] = source[i];
}
for (int i = 0; i < taille; i++)
{
printf("%d ", copie[i]);
}
return 0;
} Ce niveau introduit la recherche, les occurrences, les pointeurs, les chaînes de caractères et les tableaux bidimensionnels.
Demandez une valeur à l’utilisateur et affichez son premier indice dans le tableau.
Affichez -1 si elle est absente.
Compétence : recherche séquentielle.
#include <stdio.h>
int main(void)
{
int tab[] = {8, 14, 3, 21, 14, 9};
int taille = sizeof(tab) / sizeof(tab[0]);
int valeur;
int position = -1;
printf("Valeur recherchee : ");
scanf("%d", &valeur);
for (int i = 0; i < taille; i++)
{
if (tab[i] == valeur)
{
position = i;
break;
}
}
printf("Position : %d\n", position);
return 0;
} Comptez le nombre de fois qu’une valeur apparaît dans le tableau.
Compétence : recherche exhaustive.
#include <stdio.h>
int main(void)
{
int tab[] = {4, 7, 4, 9, 4, 12};
int taille = sizeof(tab) / sizeof(tab[0]);
int valeur = 4;
int occurrences = 0;
for (int i = 0; i < taille; i++)
{
if (tab[i] == valeur)
{
occurrences++;
}
}
printf("Occurrences de %d : %d\n", valeur, occurrences);
return 0;
}
Multipliez chaque valeur du tableau par deux en utilisant l’écriture
*(tab + i).
Compétence : relation entre tableaux et pointeurs.
#include <stdio.h>
int main(void)
{
int tab[] = {2, 5, 8, 11};
int taille = sizeof(tab) / sizeof(tab[0]);
for (int i = 0; i < taille; i++)
{
*(tab + i) *= 2;
}
for (int i = 0; i < taille; i++)
{
printf("%d ", *(tab + i));
}
return 0;
} Comptez les caractères d’une chaîne jusqu’au caractère nul.
Compétence : parcours d’un tableau de caractères.
#include <stdio.h>
int main(void)
{
char texte[] = "programmation";
int longueur = 0;
while (texte[longueur] != '\0')
{
longueur++;
}
printf("Longueur : %d\n", longueur);
return 0;
} Comptez le nombre de voyelles présentes dans un mot ou une phrase.
Compétence : traitement de chaînes.
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char texte[] = "Langage C";
int voyelles = 0;
for (int i = 0; texte[i] != '\0'; i++)
{
char c = (char)tolower((unsigned char)texte[i]);
if (c == 'a' || c == 'e' || c == 'i' ||
c == 'o' || c == 'u' || c == 'y')
{
voyelles++;
}
}
printf("Voyelles : %d\n", voyelles);
return 0;
} Calculez la somme de tous les éléments d’une matrice de trois lignes et trois colonnes.
Compétence : boucles imbriquées.
#include <stdio.h>
int main(void)
{
int matrice[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
int somme = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
somme += matrice[i][j];
}
}
printf("Somme : %d\n", somme);
return 0;
} Calculez la somme des éléments situés sur la diagonale principale d’une matrice carrée.
Compétence : exploitation des indices identiques.
#include <stdio.h>
int main(void)
{
int matrice[3][3] = {
{2, 4, 6},
{1, 5, 9},
{3, 7, 8}
};
int somme = 0;
for (int i = 0; i < 3; i++)
{
somme += matrice[i][i];
}
printf("Somme diagonale : %d\n", somme);
return 0;
} Additionnez deux matrices de même dimension et stockez le résultat dans une troisième matrice.
Compétence : manipulation simultanée de plusieurs matrices.
#include <stdio.h>
int main(void)
{
int a[2][2] = {
{1, 2},
{3, 4}
};
int b[2][2] = {
{5, 6},
{7, 8}
};
int resultat[2][2];
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
resultat[i][j] = a[i][j] + b[i][j];
}
}
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
printf("%d ", resultat[i][j]);
}
printf("\n");
}
return 0;
} Les exercices avancés combinent tri, transposition, allocation dynamique, fonctions et traitement plus complet des données.
Modifiez le tableau afin que ses valeurs soient stockées dans l’ordre inverse.
Compétence : échange de valeurs sans second tableau.
#include <stdio.h>
void inverser(int tab[], int taille)
{
for (int i = 0; i < taille / 2; i++)
{
int temp = tab[i];
tab[i] = tab[taille - 1 - i];
tab[taille - 1 - i] = temp;
}
}
int main(void)
{
int tab[] = {1, 2, 3, 4, 5, 6};
int taille = sizeof(tab) / sizeof(tab[0]);
inverser(tab, taille);
for (int i = 0; i < taille; i++)
{
printf("%d ", tab[i]);
}
return 0;
} Triez un tableau avec l’algorithme du tri à bulles.
Compétence : comparaison et échange de valeurs voisines.
#include <stdio.h>
void triBulles(int tab[], int taille)
{
for (int i = 0; i < taille - 1; i++)
{
for (int j = 0; j < taille - 1 - i; j++)
{
if (tab[j] > tab[j + 1])
{
int temp = tab[j];
tab[j] = tab[j + 1];
tab[j + 1] = temp;
}
}
}
}
int main(void)
{
int tab[] = {14, 3, 27, 8, 19};
int taille = sizeof(tab) / sizeof(tab[0]);
triBulles(tab, taille);
for (int i = 0; i < taille; i++)
{
printf("%d ", tab[i]);
}
return 0;
} Recherchez une valeur dans un tableau trié en divisant la zone de recherche par deux.
Compétence : recherche en O(log n).
#include <stdio.h>
int rechercheDichotomique(const int tab[], int taille, int valeur)
{
int gauche = 0;
int droite = taille - 1;
while (gauche <= droite)
{
int milieu = gauche + (droite - gauche) / 2;
if (tab[milieu] == valeur)
{
return milieu;
}
if (tab[milieu] < valeur)
{
gauche = milieu + 1;
}
else
{
droite = milieu - 1;
}
}
return -1;
}
int main(void)
{
int tab[] = {2, 5, 8, 12, 18, 25, 31};
int taille = sizeof(tab) / sizeof(tab[0]);
printf("Indice : %d\n",
rechercheDichotomique(tab, taille, 18));
return 0;
} Transformez les lignes d’une matrice en colonnes.
Compétence : changement d’indices dans une matrice.
#include <stdio.h>
int main(void)
{
int matrice[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
int transposee[3][2];
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
transposee[j][i] = matrice[i][j];
}
}
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 2; j++)
{
printf("%d ", transposee[i][j]);
}
printf("\n");
}
return 0;
}
Demandez la taille du tableau à l’utilisateur, réservez la mémoire avec
malloc(), puis calculez la somme des valeurs.
Compétence : allocation dynamique et libération mémoire.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int taille;
int somme = 0;
printf("Taille : ");
scanf("%d", &taille);
if (taille <= 0)
{
return 1;
}
int *tab = malloc((size_t)taille * sizeof(*tab));
if (tab == NULL)
{
return 1;
}
for (int i = 0; i < taille; i++)
{
scanf("%d", &tab[i]);
somme += tab[i];
}
printf("Somme : %d\n", somme);
free(tab);
tab = NULL;
return 0;
} Créez un tableau dynamique de trois valeurs, puis agrandissez-le pour ajouter deux éléments.
Compétence : redimensionnement sécurisé d’une zone mémoire.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int taille = 3;
int *tab = malloc((size_t)taille * sizeof(*tab));
if (tab == NULL)
{
return 1;
}
tab[0] = 10;
tab[1] = 20;
tab[2] = 30;
int nouvelleTaille = 5;
int *temp = realloc(tab,
(size_t)nouvelleTaille * sizeof(*tab));
if (temp == NULL)
{
free(tab);
return 1;
}
tab = temp;
tab[3] = 40;
tab[4] = 50;
for (int i = 0; i < nouvelleTaille; i++)
{
printf("%d ", tab[i]);
}
free(tab);
return 0;
} Vérifiez qu’un mot se lit de la même manière de gauche à droite et de droite à gauche.
Compétence : comparaison symétrique dans une chaîne.
#include <stdio.h>
#include <string.h>
int main(void)
{
char mot[50];
int palindrome = 1;
printf("Mot : ");
scanf("%49s", mot);
size_t longueur = strlen(mot);
for (size_t i = 0; i < longueur / 2; i++)
{
if (mot[i] != mot[longueur - 1 - i])
{
palindrome = 0;
break;
}
}
if (palindrome)
{
printf("Palindrome\n");
}
else
{
printf("Pas un palindrome\n");
}
return 0;
} Supprimez logiquement les valeurs répétées d’un tableau déjà trié.
Compétence : taille logique et réécriture en place.
#include <stdio.h>
int supprimerDoublons(int tab[], int taille)
{
if (taille == 0)
{
return 0;
}
int nouvelleTaille = 1;
for (int i = 1; i < taille; i++)
{
if (tab[i] != tab[nouvelleTaille - 1])
{
tab[nouvelleTaille] = tab[i];
nouvelleTaille++;
}
}
return nouvelleTaille;
}
int main(void)
{
int tab[] = {1, 1, 2, 2, 2, 4, 5, 5};
int taille = sizeof(tab) / sizeof(tab[0]);
taille = supprimerDoublons(tab, taille);
for (int i = 0; i < taille; i++)
{
printf("%d ", tab[i]);
}
return 0;
} Ces derniers exercices associent plusieurs thèmes et demandent une bonne maîtrise des tableaux, des pointeurs, de la mémoire dynamique et des algorithmes.
Fusionnez deux tableaux triés dans un troisième tableau, lui aussi trié.
Compétence : parcours synchronisé de deux tableaux.
#include <stdio.h>
void fusionner(const int a[], int tailleA,
const int b[], int tailleB,
int resultat[])
{
int i = 0;
int j = 0;
int k = 0;
while (i < tailleA && j < tailleB)
{
if (a[i] <= b[j])
{
resultat[k++] = a[i++];
}
else
{
resultat[k++] = b[j++];
}
}
while (i < tailleA)
{
resultat[k++] = a[i++];
}
while (j < tailleB)
{
resultat[k++] = b[j++];
}
}
int main(void)
{
int a[] = {1, 4, 7, 10};
int b[] = {2, 3, 8, 12, 15};
int resultat[9];
fusionner(a, 4, b, 5, resultat);
for (int i = 0; i < 9; i++)
{
printf("%d ", resultat[i]);
}
return 0;
} Multipliez une matrice de deux lignes et trois colonnes par une matrice de trois lignes et deux colonnes.
Compétence : calcul matriciel avec trois boucles imbriquées.
#include <stdio.h>
int main(void)
{
int a[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
int b[3][2] = {
{7, 8},
{9, 10},
{11, 12}
};
int resultat[2][2] = {0};
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
for (int k = 0; k < 3; k++)
{
resultat[i][j] += a[i][k] * b[k][j];
}
}
}
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
printf("%d ", resultat[i][j]);
}
printf("\n");
}
return 0;
} Créez une matrice dont le nombre de lignes et de colonnes est choisi par l’utilisateur.
Compétence : double pointeur et allocation dynamique en deux dimensions.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int lignes;
int colonnes;
printf("Lignes et colonnes : ");
scanf("%d %d", &lignes, &colonnes);
if (lignes <= 0 || colonnes <= 0)
{
return 1;
}
int **matrice = malloc((size_t)lignes *
sizeof(*matrice));
if (matrice == NULL)
{
return 1;
}
for (int i = 0; i < lignes; i++)
{
matrice[i] = malloc((size_t)colonnes *
sizeof(*matrice[i]));
if (matrice[i] == NULL)
{
for (int k = 0; k < i; k++)
{
free(matrice[k]);
}
free(matrice);
return 1;
}
}
for (int i = 0; i < lignes; i++)
{
for (int j = 0; j < colonnes; j++)
{
matrice[i][j] = i + j;
printf("%d ", matrice[i][j]);
}
printf("\n");
}
for (int i = 0; i < lignes; i++)
{
free(matrice[i]);
}
free(matrice);
return 0;
}
Triez plusieurs noms de villes par ordre alphabétique avec strcmp()
et strcpy().
Compétence : tableau à deux dimensions et fonctions de string.h.
#include <stdio.h>
#include <string.h>
int main(void)
{
char villes[5][30] = {
"Toulouse",
"Paris",
"Lyon",
"Marseille",
"Bordeaux"
};
char temporaire[30];
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4 - i; j++)
{
if (strcmp(villes[j], villes[j + 1]) > 0)
{
strcpy(temporaire, villes[j]);
strcpy(villes[j], villes[j + 1]);
strcpy(villes[j + 1], temporaire);
}
}
}
for (int i = 0; i < 5; i++)
{
printf("%s\n", villes[i]);
}
return 0;
} Trouvez la deuxième plus grande valeur distincte sans trier le tableau.
Compétence : suivi simultané de deux valeurs maximales.
#include <stdio.h>
#include <limits.h>
int main(void)
{
int tab[] = {14, 9, 32, 18, 32, 27};
int taille = sizeof(tab) / sizeof(tab[0]);
int maximum = INT_MIN;
int deuxieme = INT_MIN;
for (int i = 0; i < taille; i++)
{
if (tab[i] > maximum)
{
deuxieme = maximum;
maximum = tab[i];
}
else if (tab[i] > deuxieme &&
tab[i] != maximum)
{
deuxieme = tab[i];
}
}
if (deuxieme == INT_MIN)
{
printf("Aucune deuxieme valeur distincte.\n");
}
else
{
printf("Deuxieme maximum : %d\n", deuxieme);
}
return 0;
} Créez un programme qui saisit dynamiquement les notes d’une classe, calcule la moyenne, recherche la meilleure note et trie les résultats par ordre décroissant.
Compétences : allocation dynamique, fonctions, pointeurs, tri, moyenne et recherche du maximum.
#include <stdio.h>
#include <stdlib.h>
double calculerMoyenne(const double notes[], int taille)
{
double somme = 0.0;
for (int i = 0; i < taille; i++)
{
somme += notes[i];
}
return somme / taille;
}
double trouverMaximum(const double notes[], int taille)
{
double maximum = notes[0];
for (int i = 1; i < taille; i++)
{
if (notes[i] > maximum)
{
maximum = notes[i];
}
}
return maximum;
}
void trierDecroissant(double notes[], int taille)
{
for (int i = 0; i < taille - 1; i++)
{
for (int j = 0; j < taille - 1 - i; j++)
{
if (notes[j] < notes[j + 1])
{
double temp = notes[j];
notes[j] = notes[j + 1];
notes[j + 1] = temp;
}
}
}
}
int main(void)
{
int nombreEleves;
printf("Nombre d'eleves : ");
scanf("%d", &nombreEleves);
if (nombreEleves <= 0)
{
return 1;
}
double *notes = malloc((size_t)nombreEleves *
sizeof(*notes));
if (notes == NULL)
{
return 1;
}
for (int i = 0; i < nombreEleves; i++)
{
do
{
printf("Note de l'eleve %d : ", i + 1);
scanf("%lf", ¬es[i]);
}
while (notes[i] < 0.0 || notes[i] > 20.0);
}
printf("Moyenne : %.2f\n",
calculerMoyenne(notes, nombreEleves));
printf("Meilleure note : %.2f\n",
trouverMaximum(notes, nombreEleves));
trierDecroissant(notes, nombreEleves);
printf("Classement : ");
for (int i = 0; i < nombreEleves; i++)
{
printf("%.2f ", notes[i]);
}
free(notes);
notes = NULL;
return 0;
} string.hmalloc()realloc()Les tableaux en C sont des structures de données qui permettent de stocker plusieurs éléments du même type dans un bloc de mémoire contigu. Ils sont particulièrement utiles lorsque vous devez manipuler une collection d’éléments, comme des nombres ou des chaînes de caractères.
Pour déclarer un tableau, il suffit de spécifier le type des éléments, le nom du tableau, et le nombre d’éléments à stocker dans ce tableau.
Syntaxe :
type nom_du_tableau[taille]; int tableau_entiers[10]; // Tableau de 10 entiers
float tableau_flottants[5]; // Tableau de 5 nombres flottants
char tableau_caracteres[20]; // Tableau de 20 caractères 0, le deuxième à l’indice 1, et ainsi de suite.Un tableau peut être initialisé au moment de sa déclaration en spécifiant les valeurs à l’intérieur d’accolades {}.
int tableau[5] = {1, 2, 3, 4, 5}; // Tableau initialisé avec 5 valeurs Si vous ne spécifiez pas le nombre d’éléments, le compilateur allouera automatiquement l’espace nécessaire pour toutes les valeurs spécifiées.
int tableau[] = {1, 2, 3, 4, 5}; // Taille déduite automatiquement L’accès aux éléments d’un tableau se fait en utilisant son indice.
int tableau[5] = {10, 20, 30, 40, 50};
printf("%d\n", tableau[0]); // Affiche 10
printf("%d\n", tableau[4]); // Affiche 50 tableau[2] = 100; // Change la valeur à l'indice 2 en 100 Pour parcourir un tableau, on utilise généralement une boucle for ou while.
for :int tableau[5] = {10, 20, 30, 40, 50};
for (int i = 0; i < 5; i++) {
printf("%d ", tableau[i]); // Affiche les éléments du tableau
} En C, vous pouvez déclarer des tableaux à plusieurs dimensions (comme les matrices). Un tableau à 2 dimensions est similaire à une matrice, où les éléments sont organisés en lignes et en colonnes.
Déclaration :
type nom_du_tableau[taille1][taille2]; int matrice[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}; printf("%d\n", matrice[0][1]); // Affiche 2 Un tableau de caractères (ou chaîne de caractères) est un tableau d’éléments de type char.
Exemple :
char nom[10] = "Alice"; // Chaîne de caractères Dans ce cas, le tableau contient les caractères 'A', 'l', 'i', 'c', 'e' suivis d’un caractère nul (\0), qui marque la fin de la chaîne.
Vous pouvez créer un tableau de chaînes de caractères pour stocker plusieurs mots ou phrases.
char noms[3][10] = {"Alice", "Bob", "Charlie"}; En C, lorsqu’un tableau est passé à une fonction, c’est l’adresse de son premier élément qui est transmise (par référence).
void afficher_tableau(int tableau[], int taille) {
for (int i = 0; i < taille; i++) {
printf("%d ", tableau[i]);
}
printf("\n");
}
int main() {
int tableau[5] = {1, 2, 3, 4, 5};
afficher_tableau(tableau, 5); // Passe le tableau à la fonction
return 0;
} Les tableaux en C occupent de la mémoire contiguë, c’est-à-dire que les éléments sont stockés les uns à la suite des autres.
Taille d’un tableau :
Vous pouvez utiliser l’opérateur sizeof pour obtenir la taille en octets d’un tableau, ou la taille d’un élément.
int tableau[5];
printf("Taille du tableau : %lu octets\n", sizeof(tableau)); // Taille totale en octets
printf("Taille d'un élément : %lu octets\n", sizeof(tableau[0])); // Taille d'un élément Pour obtenir le nombre d’éléments :
int taille = sizeof(tableau) / sizeof(tableau[0]); tableau[5] alors que le tableau a été déclaré avec 5 éléments (tableau[0] à tableau[4]).| Commande | Description |
|---|---|
type nom[taille]; | Déclare un tableau de taille fixe. |
nom[indice] = valeur; | Modifie la valeur d’un élément du tableau. |
int nom[][] = {{...},{...}} | Déclare un tableau multidimensionnel. |
sizeof(tableau) | Renvoie la taille totale en octets d’un tableau. |
nom[indice] | Accède à l’élément à l’indice spécifié dans le tableau. |
En résumé, les tableaux en C sont un moyen efficace de manipuler des collections d’éléments du même type, que ce soit en 1D (tableau simple) ou en 2D (tableau multidimensionnel). Leur gestion requiert de la prudence en ce qui concerne la gestion des indices et la mémoire allouée.
Le métier de marchand de biens immobiliers consiste à acquérir des biens dans une logique…
Le succès d'un événement se prépare bien avant l'ouverture des portes. Une communication structurée permet…
La chromatographie liquide haute performance (HPLC) est aujourd'hui l'une des techniques analytiques les plus utilisées…
La HPLC (Chromatographie Liquide Haute Performance) est aujourd'hui l'une des techniques analytiques les plus utilisées…
Créer une SCI répond souvent à un projet de long terme. Certains souhaitent acquérir un…
Organiser un mariage est une aventure aussi enthousiasmante qu'exigeante. Derrière chaque cérémonie réussie se cachent…
This website uses cookies.