2012-03-08 7 views
0

Dans quelques exemples de code donné par un professeur:C: strncpy plus de caractères qu'alloué puis impression ... sortie inattendue?

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 

int main() 
{ 
    char alpha[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 
    printf("%s\n", alpha); 
    printf("%c\n", alpha[8]); 
    alpha[8] = 'Z'; /* segmentation fault if alpha is declared statically! */ 

    printf("%d\n", sizeof(alpha)); 
    printf("%d\n", strlen(alpha)); 

    char x[10]; 
    strncpy(x, alpha, 26); 
    /* strncpy() will NOT copy or append a '\0' */ 
    printf("%s\n", x); 

    return EXIT_SUCCESS; 
} 

Lors de la première compilation et l'exécution, le programme segfaults en raison, de ce que je vois en quelques minutes de recherche sur Google, un mécanisme de protection gcc contre les dépassements de mémoire tampon (déclenchée par le printf("%s\n", x); dans lequel x avait été rempli avec 26 octets d'alpha). C'est ce que je crois comprendre.

Cependant, lors de la désactivation du mécanisme de protection avec gcc -fno-stack-protecteur, la sortie que je vois est:

ABCDEFGHIJKLMNOPQRSTUVWXYZ 
I 
27 
26 
ABCDEFGHZJKLMNOPQRSTUVWXYZKLMNOPQRSTUVWXYZ 

I pensé que, depuis strncpy ne se termine pas nulle la chaîne, que lorsque X est imprimé il pourrait effectivement imprimer la valeur complète de alpha - mais en fait, il est l'impression de tous alpha, et encore plus alpha!

Quelqu'un peut-il donner un aperçu ici?

Répondre

1

Avec ce code:

char x[10]; 
    strncpy(x, alpha, 26); 

Vous copiez 26 octets de données à un tableau de 10 octets, ce qui signifie que vous écrasez 16 octets de mémoire ce qui se trouvait à côté de « x ».

Lorsque vous "printf" x, il continue d'imprimer jusqu'à ce qu'il frappe un octet nul, il imprime donc ce qui était adjacent à "x" était "alpha", donc vous avez frôlé une partie de votre tableau initial sur tous les 26 octets que vous avez copiés, plus tout ce qui est en mémoire (le contenu survivant de "alpha") jusqu'à l'octet nul suivant.

2

Vous êtes juste chanceux. L'écriture au-delà des limites d'un tableau entraîne Comportement indéfini. Un comportement indéfini signifie que tout comportement est possible, il ne doit pas nécessairement entraîner de défaut de segmentation. Cela signifie simplement que le programme n'est pas valide et peut présenter un comportement quelconque.

Oui, Votre programme peut même sembler fonctionner comme vous le souhaitez, mais il est toujours conforme à la norme.

2
char x[10]; strncpy(x, alpha, 26);  
/* strncpy() will NOT copy or append a '\0' */ 
printf("%s\n", x); 

Pour strncpy, vous passez, 26 comme la valeur de n, donc il copie 26 caractères, mais lorsque vous imprimez à l'aide printf, printf va essayer de rechercher un « \ 0 » comme le caractère de terminaison pour la chaîne Dans ce cas, le '\ 0' se trouve après "KLMNOPQRSTUVWXYZ".

Donc, en réalité, quand vous faites un tableau hors limites, vous pourriez obtenir toute sorte de résultat, un accident, une chaîne qui est trop long, etc.

+0

J'espérais qu'il y avait une raison déterministe que 'KLMNOPQRSTUVWXYZ' imprime directement après' ABCDEFGHZJKLMNOPQRSTUVWXYZ'; Je pense que si le caractère nul est venu après le Z, la deuxième sortie K-Z ne serait pas affichée. – Joseph

+1

Vous ne copiez que 26 caractères, donc le caractère nul qui aurait pu être présent après 'Z' en alpha n'est pas copié. Mais, un tableau hors limite ne garantit toujours rien, car pour x seulement 10 octets ont été alloués, la mémoire après le 10ème octet de x ne vous appartient pas et peut être utilisée de toute façon – Jay

+0

Bon point, merci! – Joseph

1

La question concerne la mise en page de la mémoire.
Dans ce programme, "alpha" est juste derrière "x". donc quand vous appelez

strncpy(x, alpha, 26); 

les données de alpha est en cours de modification.