C - structure
Résolu/Fermé
Woshi
-
Modifié par Woshi le 24/08/2011 à 11:28
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 - 24 août 2011 à 23:00
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 - 24 août 2011 à 23:00
A voir également:
- C - structure
- Logiciel calcul structure bois gratuit - Télécharger - Architecture & Déco
- Structure d'un rapport de stage - Guide
- Dans la table des matières du document à télécharger, le chapitre 6 et ses 2 sections n'apparaissent pas. trouvez l'erreur dans la structure du document et corrigez-la. mettez à jour la table des matières. quel est le mot formé par les lettres en majuscules de la table des matières après sa mise à jour ? ✓ - Forum Word
- Structure adresse ip - Guide
- Problème mise à jour table des matières - Forum Word
4 réponses
Bonjour
Ce que tu montres est l'image de l'exécution, pas de la compilation.
Pour copier une chaîne dans une autre en C, on n'utilise pas "=" mais la fonction strcpy : remplace
Ce que tu montres est l'image de l'exécution, pas de la compilation.
Pour copier une chaîne dans une autre en C, on n'utilise pas "=" mais la fonction strcpy : remplace
perso[0].nom[100] = "Dupuis";par
strcpy (perso[0].nom,"Dupuis");(idem pour les autres affectations de chaînes)
Le soucis vient de l'assignation des chaines de caracteres ("Dupuis", "Jean", etc)
Tu confonds 2 choses tres importantes, le fait de faire
char nom[100] = "Dupuis";
et
char nom[100];
nom[100] = "Dupuis";
sont des choses extremement differentes.
La premiere methode fonctionne, et evidemment, ce n'est pas celle que tu as utilisé, étant donné que tu as déclaré tes structures, et que ensuite tu as essayé d'y assigner des valeurs en chaine de caractère.
Ce que ça a fait exactement ?
Et bien en faisant
perso[0].nom[100] = "Dupuis";
Tu as mis la lettre D à la 100eme case de perso[0].nom
Bref, tu ne pourras pas reussir ce que tu essayes de faire sans utiliser de fonctions de la lib C (sauf si tu veux t'amuser a les recoder, mais bon tu n'en es pas encore la :p)
Bref, voila une solution
strcpy(perso[0].nom, "Dupuis");
(copie le 2eme argument dans le 1er)
Sinon, je te donne aussi une syntaxe pour faire un typedef sur une structure en meme temps que tu la declares, si ca peut t'aider
typedef struct Personne
{
char nom[100];
char prenom[100];
int age;
int fille;
} Personne;
Perso je trouve ça plus lisible ;)
Tu confonds 2 choses tres importantes, le fait de faire
char nom[100] = "Dupuis";
et
char nom[100];
nom[100] = "Dupuis";
sont des choses extremement differentes.
La premiere methode fonctionne, et evidemment, ce n'est pas celle que tu as utilisé, étant donné que tu as déclaré tes structures, et que ensuite tu as essayé d'y assigner des valeurs en chaine de caractère.
Ce que ça a fait exactement ?
Et bien en faisant
perso[0].nom[100] = "Dupuis";
Tu as mis la lettre D à la 100eme case de perso[0].nom
Bref, tu ne pourras pas reussir ce que tu essayes de faire sans utiliser de fonctions de la lib C (sauf si tu veux t'amuser a les recoder, mais bon tu n'en es pas encore la :p)
Bref, voila une solution
strcpy(perso[0].nom, "Dupuis");
(copie le 2eme argument dans le 1er)
Sinon, je te donne aussi une syntaxe pour faire un typedef sur une structure en meme temps que tu la declares, si ca peut t'aider
typedef struct Personne
{
char nom[100];
char prenom[100];
int age;
int fille;
} Personne;
Perso je trouve ça plus lisible ;)
Groarh
Messages postés
682
Date d'inscription
vendredi 1 août 2008
Statut
Membre
Dernière intervention
28 juin 2015
185
24 août 2011 à 12:14
24 août 2011 à 12:14
Tu peux nous en dire plus sur strcpy ? Ça m'intéresse.
à partir du moment ou on est à l'aise avec les pointeurs, il vaut mieux utiliser strdup et strndup qui réalloue la mémoire qu'il faut.
Ce que je n'aime pas avec strcpy ?
Premièrement, la mémoire dans la première chaine de caractère doit déjà être suffisament grande pour qu'on y colle une autre chaine.
Cela veut dire qu'avant l'appel de strcpy/strncpy, on se retrouve avec un tableau de par exemple 50 cases, alors qu'on ne voudrait en utiliser qu'une partie.
Ensuite, imaginons un cas concret (petit cours de sécurité ;))
Le programme consisterait a faire apparaitre des messages entrés par l'utilisateur.
J'ai donc une chaine de caractere
char message[100] = "message =";
j'ai volontairement utilisé un tableau statique pour cet exemple, avoir un pointeur sur une chaine allouée ne ferait aucune différence
l'utilisateur va donc entrer (en argv[1], en scanf ou autre) une chaine de caractere, qui sera passé en second argument de strcpy. Le code ressemblerait donc à ceci
strcpy(message, " j'ecris un message");
printf("%s\n", message);
Jusque la, pas de probleme, on aura bien "message = j'ecris un message" qui apparaitra lors de l'execution.
Cependant, si l'utilisateur entre un message suffisament grand pour remplir message[100] et va plus loin que la limite autorisé, il atteindra des cases mémoires ne faisant pas parti de ce tableau. Avec le script approprié, il pourra donc atteindre certaines parties sensibles.
un petit exemple (assez simplistes, mais qui suffira à montrer que ça marche pas comme on veut)
char test[2];
char test2[6] = "salut";
strcpy(test, test2);
ensuite, faites un printf de test et test2, vous devriez etre surpris.
On peut donc modifier les autres variables compris dans la fonction a volonté, mais il y a pire que ca. Apres les adresses des variables de la fonction, on arrive a l'adresse de retour de cette fonction. Cela veut dire que je peux ecrire un script dans ma chaine de caractere, et une fois que j'ai depassé cette chaine, je pourrais modifier l'adresse de retour de fonction pour qu'elle pointe sur le début de ma chaine. Le programme executera alors mon propre code, et je pourrais faire plein de bêtises avec :)
Il s'agit d'une faille de type "buffer overflow" (pour ceux que la sécurité intéresse, vous pourrez faire quelques recherches dessus).
Pour conclure, comme je le disais donc, si vous maitrisez les pointeurs, allouez vos chaines de caractères à la bonne taille et utilisez strdup/strndup, qui recréent une chaine de caractère avec la taille des 2 chaines passées en paramètre.
ps : je n'ai pas retesté l'exemple donné vu que je suis au boulot, mais si je ne me trompe pas, vous aurez comme résultat test = salut et test2 = lut, ou quelque chose dans le genre, à moins que ça seg fault tout simplement, auquel cas l'exemple n'illustrerait pas ce que j'essaye de vous montrer :p.
Ce que je n'aime pas avec strcpy ?
Premièrement, la mémoire dans la première chaine de caractère doit déjà être suffisament grande pour qu'on y colle une autre chaine.
Cela veut dire qu'avant l'appel de strcpy/strncpy, on se retrouve avec un tableau de par exemple 50 cases, alors qu'on ne voudrait en utiliser qu'une partie.
Ensuite, imaginons un cas concret (petit cours de sécurité ;))
Le programme consisterait a faire apparaitre des messages entrés par l'utilisateur.
J'ai donc une chaine de caractere
char message[100] = "message =";
j'ai volontairement utilisé un tableau statique pour cet exemple, avoir un pointeur sur une chaine allouée ne ferait aucune différence
l'utilisateur va donc entrer (en argv[1], en scanf ou autre) une chaine de caractere, qui sera passé en second argument de strcpy. Le code ressemblerait donc à ceci
strcpy(message, " j'ecris un message");
printf("%s\n", message);
Jusque la, pas de probleme, on aura bien "message = j'ecris un message" qui apparaitra lors de l'execution.
Cependant, si l'utilisateur entre un message suffisament grand pour remplir message[100] et va plus loin que la limite autorisé, il atteindra des cases mémoires ne faisant pas parti de ce tableau. Avec le script approprié, il pourra donc atteindre certaines parties sensibles.
un petit exemple (assez simplistes, mais qui suffira à montrer que ça marche pas comme on veut)
char test[2];
char test2[6] = "salut";
strcpy(test, test2);
ensuite, faites un printf de test et test2, vous devriez etre surpris.
On peut donc modifier les autres variables compris dans la fonction a volonté, mais il y a pire que ca. Apres les adresses des variables de la fonction, on arrive a l'adresse de retour de cette fonction. Cela veut dire que je peux ecrire un script dans ma chaine de caractere, et une fois que j'ai depassé cette chaine, je pourrais modifier l'adresse de retour de fonction pour qu'elle pointe sur le début de ma chaine. Le programme executera alors mon propre code, et je pourrais faire plein de bêtises avec :)
Il s'agit d'une faille de type "buffer overflow" (pour ceux que la sécurité intéresse, vous pourrez faire quelques recherches dessus).
Pour conclure, comme je le disais donc, si vous maitrisez les pointeurs, allouez vos chaines de caractères à la bonne taille et utilisez strdup/strndup, qui recréent une chaine de caractère avec la taille des 2 chaines passées en paramètre.
ps : je n'ai pas retesté l'exemple donné vu que je suis au boulot, mais si je ne me trompe pas, vous aurez comme résultat test = salut et test2 = lut, ou quelque chose dans le genre, à moins que ça seg fault tout simplement, auquel cas l'exemple n'illustrerait pas ce que j'essaye de vous montrer :p.
Groarh
Messages postés
682
Date d'inscription
vendredi 1 août 2008
Statut
Membre
Dernière intervention
28 juin 2015
185
24 août 2011 à 22:33
24 août 2011 à 22:33
D'accord, c'est simplement que strcpy ne vérifie pas la longueur des deux chaînes. Je croyais que tu allais me parler d'un comportement imprévisible comme un effet de bord au autre...
strcpy n'est pas dangereux tant qu'on connaît la taille de ses chaînes. Et en l'occurence, c'est le cas. Et comme le fait remarquer Dualife, on peut toujours se rassurer en utilisant à la place strncpy.
Et sinon, il me semble que ça ne segfault pas tant qu'on reste dans la mémoire allouée au programme. Mais je ne sais plus si c'est le cas pour le heap. Question : est-ce que ça segfault si on tente de faire « déborder » une chaîne avec strdup ?
En tout cas, bravo, pour cette belle explication :)
strcpy n'est pas dangereux tant qu'on connaît la taille de ses chaînes. Et en l'occurence, c'est le cas. Et comme le fait remarquer Dualife, on peut toujours se rassurer en utilisant à la place strncpy.
Et sinon, il me semble que ça ne segfault pas tant qu'on reste dans la mémoire allouée au programme. Mais je ne sais plus si c'est le cas pour le heap. Question : est-ce que ça segfault si on tente de faire « déborder » une chaîne avec strdup ?
En tout cas, bravo, pour cette belle explication :)
+1 le pere
et pour faire propre il faudrai que tu initialise ta memoire a zero
avec bzero par exemple
bzero(Personne perso, sizeof(Personne));
et pour faire propre il faudrai que tu initialise ta memoire a zero
avec bzero par exemple
bzero(Personne perso, sizeof(Personne));
fiddy
Messages postés
11069
Date d'inscription
samedi 5 mai 2007
Statut
Contributeur
Dernière intervention
23 avril 2022
1 842
24 août 2011 à 23:00
24 août 2011 à 23:00
Pour faire propre ? Je ne vois pas en quoi cela fait propre à part rendre le programme plus "secure" en cas de dump mémoire.
En tout cas, bzero n'est pas une fonction conseillée. Il vaut mieux utiliser memset.
En tout cas, bzero n'est pas une fonction conseillée. Il vaut mieux utiliser memset.
Modifié par Groarh le 24/08/2011 à 11:47
Je rajoute qu'à la compilation avec GCC, j'ai ceci :
Ce n'est pas parce que ce sont des warnings qu'il faut les ignorer. Un warning en C est souvent équivalent à une erreur fatale en Java, car le compilateur C est très permissif. En l'occurence, ces messages indiquent tous un problème de pointeur qui aurait dû te mettre sur la voie, Woshi. Il suffit d'un peu d'habitude pour déchiffrer les messages du compilateur ;)
Ah aussi, un détail : pour utiliser strcpy, il faut importer string.h.