Guide complet : Comparaison entre strcpy et strncpy
En C, les fonctions strcpy
et strncpy
servent à copier des chaînes de caractères d’une source à une destination. Bien qu’elles soient similaires, elles diffèrent en termes de fonctionnement, sécurité, et cas d’utilisation. Ce guide explique leurs différences et propose des exemples pratiques.
1. Introduction
1.1 strcpy
- But : Copier une chaîne entière, y compris le caractère nul (
\0
), d’une source vers une destination. - Limitation majeure : Ne vérifie pas si la destination a suffisamment d’espace pour contenir la source, ce qui peut entraîner un buffer overflow.
- Prototype :
char *strcpy(char *destination, const char *source);
1.2 strncpy
- But : Copier un nombre spécifié de caractères d’une source vers une destination, limitant ainsi la quantité de données copiées.
- Limitation majeure : Si la source dépasse la taille spécifiée,
\0
n’est pas ajouté automatiquement. - Prototype :
char *strncpy(char *destination, const char *source, size_t n);
2. Différences fondamentales
Aspect | strcpy | strncpy |
---|---|---|
Copie complète | Copie toute la chaîne jusqu’à \0 . | Copie jusqu’à n caractères maximum. |
Caractère nul (\0 ) | Toujours ajoute \0 . | N’ajoute pas \0 si la source dépasse n . |
Sécurité | Ne vérifie pas la taille de destination . | Limite la copie pour éviter les dépassements. |
Performance | Légèrement plus rapide (moins de vérifications). | Légèrement plus lente (vérification de limite). |
Utilisation typique | Copie complète d’une chaîne connue pour être sûre. | Copie partielle ou sécurisée avec limite de taille. |
3. Comparaison pratique
Exemple avec strcpy
#include <stdio.h>
#include <string.h>
int main() {
char source[] = "Bonjour";
char destination[10];
strcpy(destination, source); // Copie toute la chaîne
printf("Source : %s\n", source);
printf("Destination : %s\n", destination);
return 0;
}
- Avantage : Simple, copie toute la chaîne.
- Risque : Si
destination
est trop petite, il y a un buffer overflow.
Exemple avec strncpy
#include <stdio.h>
#include <string.h>
int main() {
char source[] = "Bonjour";
char destination[5];
strncpy(destination, source, sizeof(destination) - 1); // Limite à 4 caractères
destination[sizeof(destination) - 1] = '\0'; // Ajouter manuellement `\0`
printf("Source : %s\n", source);
printf("Destination : %s\n", destination);
return 0;
}
- Avantage : Empêche les dépassements de mémoire en limitant la copie.
- Risque : L’utilisateur doit ajouter
\0
manuellement si nécessaire.
4. Cas particuliers
4.1 Si destination
est trop petite
- Avec
strcpy
:- Provoque un dépassement de mémoire (buffer overflow), écrasant potentiellement d’autres données.
- Avec
strncpy
:- Copie uniquement les premiers
n
caractères, mais n’ajoute pas automatiquement le caractère nul.
- Copie uniquement les premiers
Solution pour strncpy
:
Toujours ajouter \0
après la copie :
destination[n - 1] = '\0';
4.2 Si la source est plus courte que la limite spécifiée
- Avec
strcpy
:- Fonctionne correctement.
- Avec
strncpy
:- Copie toute la chaîne, mais remplit les caractères restants de la destination avec des zéros (
\0
).
- Copie toute la chaîne, mais remplit les caractères restants de la destination avec des zéros (
Exemple :
#include <stdio.h>
#include <string.h>
int main() {
char source[] = "C";
char destination[5];
strncpy(destination, source, sizeof(destination)); // Remplit le reste avec `\0`
printf("Destination : ");
for (int i = 0; i < sizeof(destination); i++) {
printf("%c ", destination[i] == '\0' ? '_' : destination[i]); // Affiche `_` pour les zéros
}
printf("\n");
return 0;
}
4.3 Si la chaîne source est vide
- Avec
strcpy
:- Copie simplement le caractère nul.
- Avec
strncpy
:- Même comportement si
n >= 1
.
- Même comportement si
5. Bonnes pratiques
5.1 Quand utiliser strcpy
- La taille de
destination
est garantie suffisante pour contenirsource
. - Vous êtes certain que les données sont sûres (pas de risque de dépassement).
Exemple sécurisé :
char destination[50];
char source[] = "Texte sûr";
if (strlen(source) < sizeof(destination)) {
strcpy(destination, source);
}
5.2 Quand utiliser strncpy
- Lorsque la taille de
destination
est limitée ou doit être respectée. - Pour copier uniquement une partie de
source
.
Astuce pour éviter les erreurs :
Ajoutez toujours \0
après une copie partielle avec strncpy
.
6. Alternatives modernes
6.1 snprintf
Offre une sécurité accrue en limitant la taille de la chaîne copiée tout en s’assurant qu’elle est terminée par \0
.
Exemple :
#include <stdio.h>
int main() {
char source[] = "Bonjour";
char destination[5];
snprintf(destination, sizeof(destination), "%s", source);
printf("Destination : %s\n", destination);
return 0;
}
6.2 strlcpy
(non standard, disponible sur certains systèmes)
Limite la taille copiée tout en garantissant la terminaison par \0
.
Exemple :
#include <bsd/string.h>
char destination[5];
strlcpy(destination, source, sizeof(destination));
7. Tableau comparatif
Critère | strcpy | strncpy |
---|---|---|
Terminaison par \0 | Toujours | Non garanti si la source dépasse la limite |
Gestion de dépassement | Non sécurisé, dépassement possible | Limite la copie |
Remplissage restant | Aucun remplissage | Remplit les caractères restants avec \0 |
Performance | Plus rapide | Légèrement plus lent |
Utilisation idéale | Copie complète lorsque la taille est sûre | Copie partielle ou sécurisée |
8. Exercices corrigés
Exercice 1 : Copie sécurisée avec strncpy
Allouez un tableau dynamique pour copier une chaîne de manière sécurisée avec strncpy
.
Solution :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char source[] = "Programmation C";
size_t max_size = 10;
char *destination = (char *)malloc(max_size);
if (destination == NULL) {
printf("Erreur d'allocation mémoire.\n");
return 1;
}
strncpy(destination, source, max_size - 1);
destination[max_size - 1] = '\0'; // Assurez la terminaison
printf("Destination : %s\n", destination);
free(destination);
return 0;
}
Exercice 2 : Différences entre strcpy
et strncpy
Copiez une chaîne de 15 caractères dans une destination de 10 caractères. Comparez le comportement de strcpy
et strncpy
.
Solution :
#include <stdio.h>
#include <string.h>
int main() {
char source[] = "Chaîne très longue";
char destination1[10];
char destination2[10];
// Utilisation de strcpy (comportement indéfini)
// strcpy(destination1, source); // Peut causer un buffer overflow
// Utilisation de strncpy
strncpy(destination2, source, sizeof(destination2) - 1);
destination2[sizeof(destination2) - 1] = '\0';
printf("Avec strncpy : %s\n", destination2);
return 0;
}
9. Conclusion
Résumé
strcpy
: Rapide et simple, mais non sécurisé.strncpy
: Plus sûr, mais nécessite une gestion manuelle de\0
.
Recommandations
- Préférez
strncpy
pour éviter les dépassements de mémoire. - Ajoutez systématiquement
\0
après une copie partielle avecstrncpy
. - Pour une sécurité accrue, utilisez des alternatives comme
snprintf
oustrlcpy
si disponibles.