strncpy conduisant à une erreur de segmentation

Je suis juste en train de déconner avec strncpy.

Mon programme ressemble à ceci

typedef struct { char from_str[10]; }test; main () { test s1; memset(&s1,0,sizeof(test)); char src[10]="himansh"; char dest[10]; memset(dest,0,10); src[3]='\0'; printf("src is %s and strlen is %d \n", src,strlen(src)); fflush(stdout); strncpy(s1.from_str,src,100); printf("s1.from_str is %s , src is %s \n", s1.from_str,src); return 1; } 

Ici, avant de faire strncpy, j’ai ajouté un caractère “\ 0” dans la chaîne “src”, la longueur de la chaîne “src” devient 3, le tableau de destination est de taille 10. Mais dans strncpy j’ai mis un nombre d’octets à copier égal à 100 .

Cela signifie que ma chaîne source est terminée par NULL. Maintenant, comme toute fonction de chaîne, strncpy devrait essayer de ne copier que 3 octets, même si le nombre d’octets que je fournis est supérieur à 3 (dans ce cas, 100). C’est le cas, mais je reçois aussi une faute de segmentation.

Mon résultat est affiché ci-dessous

 src is him and strlen is 3 s1.from_str is him , src is him Segmentation fault (core dumped) 

Pourquoi cette faille de segmentation se passe-t-elle ici?

Est-ce que quelqu’un pourrait m’aider.

Je pourrais vous indiquer des pages de manuel, des sites Web, etc., mais ce qui compte en définitive, c’est la norme C elle-même. Dans la bibliothèque d’exécution standard, l’utilisation et le comportement sont définis dans C99-§7.23.2.4 comme suit:

 #include  char *strncpy(char * ressortingct s1, const char * ressortingct s2, size_t n); 

Description La fonction strncpy ne copie pas plus de n caractères (les caractères qui suivent un caractère nul ne sont pas copiés) du tableau pointé par s2 vers le tableau pointé par s1. Si la copie a lieu entre des objects qui se chevauchent, le comportement n’est pas défini. Si le tableau pointé par s2 est une chaîne plus courte que n caractères, des caractères nuls sont ajoutés à la copie dans le tableau pointé par s1, jusqu’à ce que n caractères aient été écrits.

strncpy renvoyées La fonction strncpy renvoie la valeur de s1.

Il y a des informations implicites significatives ici, le plus important étant: strncpy() NE terminera PAS votre chaîne de destination par un caractère nul si la longueur de la chaîne source (sans son caractère de fin de caractère nul) est égale ou supérieure à la longueur du tampon de destination spécifiée.

De plus, bien que clairement spécifié dans la norme (voir ci-dessus), le nombre d’ingénieurs strncpy() conscients que strncpy() remplit la mémoire tampon de la chaîne de destination avec des caractères nuls, jusqu’à ce que la longueur spécifiée n soit atteinte lorsque la longueur de la chaîne source est atteinte. est inférieure à la taille du tampon de destination. Ceci tire la conclusion inévitable suivante:

L’API strncpy() écrit TOUJOURS n caractères à l’adresse référencée par le tampon de destination.

Dans votre cas, étant donné que le tampon cible a une largeur de 10 caractères, vous écrivez 90 caractères supplémentaires au-delà de la fin définie de la mémoire inscriptible et entrez ainsi dans le pays du comportement indéfini .

A ce stade, vous devez vous demander “Quelle est l’utilisation?” Il existe un cas d’utilisation fondamental. Il vous permet de copier jusqu’à n caractères dans le tampon cible avec la prévisibilité de savoir que vous ne dépasserez pas les n caractères. Période. En fin de compte, cependant, vous voulez une chaîne terminée par un zéro, l’ utilisation correcte est la suivante:

 char dst[ N ]; strncpy(dst, src, N-1); dst[N-1] = 0; 

N est la longueur de la mémoire tampon dst en caractères et est supérieure ou égale à 1 . Notez que dst pourrait tout aussi bien être un pointeur de mémoire alloué dynamicment:

 char *dst = malloc( N * sizeof(char) ); strncpy(dst, src, N-1); dst[N-1] = 0; 

Avec ce qui précède, vous aurez toujours une chaîne terminée par un dst chez dst . Si la longueur de la chaîne source est inférieure à la longueur de la mémoire tampon cible spécifiée, strncpy() remplira le rest de la mémoire tampon avec des caractères nuls jusqu’à ce qu’un total de caractères source-copiés-copiés + caractères remplis-à-queue-nuls soit égal à n , et la déclaration finale est redondante. Si la longueur de la chaîne source est égale ou supérieure à la longueur du tampon cible, strncpy() arrête la copie dès que N-1 caractères sont atteints et l’instruction finale définit un caractère nul à la fin du tampon. Cela aboutit à une chaîne de préfixe “réduite” de la source d’origine, mais surtout, elle garantit que vous ne dépasserez PAS les limites de votre mémoire tampon cible avec un appel ultérieur d’API de chaîne qui recherche un terminateur.

L’utilité de la technique ci-dessus est toujours discutable. Je suis un gars en C ++, donc std::ssortingng sauve mon moi heureux de toute cette folie. Mais la réalité est la suivante: parfois, vous vous souciez de l’absence de copie dst src dans dst ; parfois vous ne le faites pas. L’utilité est très dépendante de la situation. Pour présenter des données de chaîne dans une interface utilisateur, cela n’aura (probablement) aucune importance. Pour copier une chaîne devant être utilisée pour des données critiques, une sous-chaîne de préfixe partiel ne sera pas acceptable. Lorsque la police émettra un mandat d’arrêt contre “Joseph Johnson Jr.”, certains s’expliqueront lorsque son père (“Joseph Johnson”) sera conduit en prison car le tampon de nom du logiciel d’émission des mandats ne contenait que 15 caractères. .

Cela dit, votre faute de segmentation se résume à cette affirmation:

 strncpy(s1.from_str,src, 100); // length parameter is wrong. 

Rappelez la déclaration en gras ci-dessus: strncpy() écrit TOUJOURS n caractères à l’adresse référencée par le tampon de destination.” . Cela signifie que le code ci-dessus écrira toujours 100 caractères dans la mémoire tampon cible, qui dans votre cas n’a qu’une largeur de 10 caractères, donc un comportement non défini et un ker-boom probable.

Corrigez cela en procédant comme suit si le tampon cible est un tableau de caractères de longueur fixe:

 strncpy(s1.from_str,src, sizeof(s1.from_str)/sizeof(s1.from_str[0])-1); s1.from_str[ sizeof(s1.from_str)/sizeof(s1.from_str[0])-1 ] = 0; 

Voir l’utilisation antérieure pour savoir comment procéder pour une chaîne dynamic de longueur `N caractères.

De http://www.cplusplus.com/reference/cssortingng/strncpy/

char * strncpy (char * destination, const char * source, size_t num);

Copier les caractères de la chaîne Copie les premiers chiffres de la source vers la destination. Si la fin de la chaîne C source (signalée par un caractère nul) est trouvée avant que les caractères numériques aient été copiés, la destination est complétée de zéros jusqu’à ce qu’un total de caractères numériques y ait été écrit.

Ainsi, bien que la longueur de la chaîne source soit inférieure à la taille de la taille du tampon de destination, en raison du comportement de strncpy, elle tente de superposer le rest des caractères au-delà de la taille du tampon de destination, ce qui provoque une erreur de segmentation.

Au lieu de copier au-delà des 100 caractères, la taille doit être égale à la taille maximale autorisée dans le tampon de destination. Vous auriez donc pu écrire

 strncpy(s1.from_str,src,sizeof(s1.from_str)/sizeof(s1.from_str[0]) - 1); Actual size -1 to accomodate the null terminator 

ou mieux d’écrire une macro _countof

 #define _countof(s) (sizeof(s)/sizeof(s[0])) ................ strncpy(s1.from_str,src,_countof(s1.from_str) - 1); 

Voir: http://www.manpagez.com/man/3/strncpy/

Les fonctions stpncpy () et strncpy () copient au plus n caractères de s2 en s1. Si s2 est inférieur à n caractères, le rest de s1 est rempli de caractères “\ 0”. Sinon, s1 n’est pas terminé.

Le rest est rempli ….

Alors:

 strncpy( s1.from_str, src, 10 ); 

strncpy(s1.from_str,src,100);

Pourquoi utilisez-vous 100 dans votre fonction, from_str et src ont tous deux 10 octets consécutifs alloués, mais vous copiez 100 octets, ce qui conduit à seg. faute.

utiliser comme ça,

strncpy(s1.from_str,src,10);