Probleme avec les '[ ]' et les '*' dans une structure - C - Programmation
Marsh Posté le 10-04-2010 à 13:52:49
parce qu'un tableau n'ets pas un pointeur. Je te conseille de réviser tes bases avec une bonne lecture du K&
et à moins que tu alloues tes pointeurs et que tu utilsies strcpy pour y copeir tes chaines, non ca ne marche pas.
compiler != fonctionner
Marsh Posté le 10-04-2010 à 14:03:24
ReplyMarsh Posté le 10-04-2010 à 14:54:12
Non.
Un pointeur, c'est juste une variable contenant une adresse et un type.
Par exemple :
int a = 42; |
Ici, b est un pointeur sur l'entier a. C'est-à-dire que b sait où dans la mémoire commence le stockage de données de type "int" (données au pluriel : b ne sait pas du tout qu'il n'y a à cet endroit qu'un seul entier, c'est au programmeur de faire en sorte de ne pas sortir des bornes).
Un tableau quant à lui, c'est une séquence de données :
int tableau[] = { 1, 13, 42, 56 }; |
tableau ici est une séquence d'entiers (il y en a 4, mais ça le tableau ne le sait pas lui-même, c'est encore le taf du développeur de s'en souvenir).
Ensuite, il y a la mémoire allouée dynamiquement, dont l'adresse de début est effectivement stockée dans un pointeur :
int *pointeurVersUneZoneMemoire = malloc(42 * sizeof(int)); |
pointeurVersUneZoneMemoire est un pointeur vers l'adresse de début d'une zone mémoire de taille suffisante pour accueillir 42 entiers, zone mémoire dynamiquement créée lors de l'exécution du programme. Ce bout de mémoire n'existe pas du tout avant cette ligne de code, et il perdurera jusqu'à ce qu'un appel à free() vienne le libérer (une "fuite mémoire", ou "memory leak" en anglais, c'est donc de la mémoire qu'on alloue, mais qu'on ne libère jamais, et qui finit par faire grossir indéfiniment la taille du programme en mémoire durant son exécution).
Cette zone mémoire peut ensuite s'utiliser syntaxiquement comme un tableau. Mais seulement syntaxiquement.
Par contre, un tableau ne se comporte pas comme une zone de mémoire dynamique : tu n'alloues pas dynamiquement un tableau, tu ne le libères pas non plus. Et tu ne peux pas l'agrandir ou le déplacer.
Ton tableau est assujetti à la portée courante, et n'existe que dans la portée courante.
Une zone mémoire allouée dynamiquement peut être accédée à partir de n'importe où dans le programme, pas le tableau.
Vois donc un tableau comme une zone de mémoire fixe, contenant une séquence de données, de portée locale.
Et vois un pointeur comme un moyen d'accéder à un objet, et non l'objet lui-même.
Marsh Posté le 10-04-2010 à 15:24:49
lassault1 a écrit : Moi j'ai appris que les tableaux sont des pointeurs sur le 1er élément.. |
change d'école
Marsh Posté le 10-04-2010 à 16:50:43
lassault1 a écrit : Pourquoi ce code ne fonctionne pas lorsque je mets des '[]' dans les tableaux de ma structure ? |
Parce qu'on ne peut initialiser un tableau par une chaine qu'au moment de sa déclaration.
Quand tu fais:
joueur[0].nom = "Dupont";
C'est trop tard, car le tableau joueur[0].nom a déjà été initialisé lors de la déclaration
Personne joueur[2];
Donc a ce stade la, pour copier des caractères dans un tableau, on utilise tout simplement strcpy, strncpy, etc.
Ce code ci fonctionne (et j'ai modifié un petit pb de ta ligne avec le printf).
Code :
|
A+,
Marsh Posté le 10-04-2010 à 18:06:41
Merci a vous..mais il me reste quelques questions..
1/ si j'ai bien compris char nom[] est identique a char* nom et char *nom que dans les prototypes de fonction et non lors des déclarations.. ?
2/ Pour ma question initiale, dans ce code, quand je réponds 'Dupont' a la question Quel est votre nom ? c'est comme si je fais utilisateur.nom = "Dupont" alors que nom est un tableau (char nom[100]
Code :
|
3/ Pourquoi ce code fonctionne pas ??
Code :
|
Et celui oui sans utiliser de pointeur ni strcpy??
Code :
|
Marsh Posté le 10-04-2010 à 23:53:51
lassault1 a écrit : 3/ Pourquoi ce code fonctionne pas ??
|
C'est a se demander si tu as lu ma réponse.
char nom[100] = "Dupond";
Tu initialise un tableau au moment de sa déclaration: Ca, c'est autorisé par le C, parce qu'au moment ou le compilateur construit le tableau, il sait ce que tu va mettre dedans: Le compilo construit un tableau de 100 cases, et met les caractères 'D', 'u', 'p', 'o', 'n', 'd', '\0' dans les premières cases du tableau qu'il est en train de construire. Bref, en C, char nom[100] = "Dupond"; a un sens spécial, c'est une abréviation pour char nom[100] = {'D', 'u', 'p', 'o', 'n', 'd', 0};
tandis que
char nom[100];
Tu déclares un tableau, sans l'initialiser. Le compilo construit un tableau de 100 cases, et ne met rien de spécial dans les cases du tableau qu'il est en train de construire (leur contenu est donc n'importe quoi).
nom = "Dupond";
Ca tu ne peux pas, parce que a ce stade, le tableau est déja construit. Si tu veux que cette chaine soit contenue par le tableau, ce n'est plus une initialisation que tu vas faire, mais une modification du contenu des cases du tableau. Et pour faire une modification du contenu des cases d'un tableau, il y a diverses méthodes, par exemple:
strcpy(nom, "Dupond" );
ou bien
nom[0] = 'D'; nom[1] = 'u'; nom[2] = 'p'; nom[3] = 'o'; nom[4] = 'n'; nom[5] = 'd'; nom[6] = '\0'; (avec cette dernière écriture, on voit bien qu'on modifie le contenu des cases d'un tableau déja existant)
etc.
Grosso modo, tu peux te dire que si nom = "Dupond"; est incorrect, c'est parce que nom étant un tableau, il peut parfois être vu comme pointant sur une adresse fixe, celle de son premier élément. Comme cette adresse est fixe, elle ne peut pas être remplacée par celle de la chaine "Dupond".
Notes que pour être complet, si tu fais char nom[] = "Dupond"; c'est équivalent a déclarer un tableau, avec juste la bonne taille pour contenir la chaine (donc équivalent à char nom[7] = "Dupond"; ici).
Quand tu fais char nom[100] = "Dupond"; tu peux ensuite modifier les éléments du tableau nom.
Par contre, si tu fais:
char *nom = "Dupond";
ou bien
char *nom;
nom = "Dupond";
tu es dans un autre cas de figure: tu ne peux pas modifier le contenu de nom, tant qu'il pointe sur cette chaine.
Le compilo, quand il rencontre cette déclaration avec une initialisation (ou une assignation), il crée dans une zone mémoire de la place pour stocker la chaine "Dupond", et il fait pointer nom dessus. Mais le compilo, si ailleurs dans le programme, il rencontre a nouveau pointeur sur la chaine "Dupond" (char *pseudo = "Dupond";), plutôt que faire un doublon, il va réutiliser cette zone mémoire. Mais alors, il est important pour le compilo que cette zone mémoire ne soit pas modifiable, sinon, si je pouvais modifier le 3e caractère de nom, ca modifierais aussi le 3e caractère des autres pointeur sur la chaine "Dupond", alors qu'ils n'ont rien a voir avec nom.
Donc en C, char *nom = "Dupond"; définit une chaine constante, non modifiable (sinon, le programme plantera a l'exécution, en râlant), et un pointeur dessus.
A+,
Marsh Posté le 11-04-2010 à 11:23:25
Merci gilou c'est très bien expliqué..
Cependant il reste 2 petite questions :
Code :
|
Je pensé que "nom ici" était l'adresse du 1er élément du tableau dans tout les cas et non un tableau ..
Code :
|
J'ai pas vraiment compris pourquoi quand je fais :
char *nom;
nom = "Dupond";
alors ne ne peux pas modifier son contenu ?
Marsh Posté le 11-04-2010 à 13:26:08
Parce que quand il a vu "Dupond", le compilo, avec ses petites mains, il a créé une zone qui contient de manière consécutive 'D' 'u' 'p' 'o' 'n' 't' et il a fait pointer nom dessus (ie nom a pour valeur l'adresse de cette zone).
Mais si plus loin dans ton code le compilo trouve char * monautrepointeur; monautrepointeur = "Dupond"; le compilo, il se souvient qu'il a déja vu cela, et plutot que de recréer une zone qui contient de manière consécutive 'D' 'u' 'p' 'o' 'n' 't' et faire pointer monautrepointeur dessus, il réutilise la zone déja crée. [c'est une décision prise il y a longtemps, a la création du langage C, quand il y avait peu de mémoire pour les programmes, et qu'on essayait de l'économiser]
Donc maintenant nom et monautrepointeur pointent sur la même zone mémoire, qui contient 'D' 'u' 'p' 'o' 'n' 't'.
Mais maintenant, si nom modifie son contenu, ca va modifier aussi le contenu de monautrepointeur puisque c'est le même, alors qu'on veut peut être pas cela, puisque rien ne dit que les variables nom et monautrepointeur désignent la même chose. Peut être que nom désigne une variable de la fonction nom_client() et monautrepointeur une variable de la fonction nom_livreur() et que par hasard, ils portent le même nom à un moment donné.
Donc pour éviter ces modifications qui peuvent avoir des effets indésirables, les créateurs du langage C ont décrété que quand le compilo a vu "Dupond", le compilo, avec ses petites mains, il a créé une zone qui contient de manière consécutive 'D' 'u' 'p' 'o' 'n' 't' dans une zone de mémoire qui est décrétée "non-modifiable" et que si plus loin, au cours de l'exécution du programme, on essaye de modifier la mémoire dans cette zone, le programme déclenche une erreur (et en général, plante).
C'est une méthode brutale et directe, on aurait pu faire plus subtil, mais ça aurait nettement compliqué l'écriture d'un compilateur a l'époque, et les techniques d'écriture de compilateurs en étaient a leurs débuts a l'époque.
A+,
Marsh Posté le 10-04-2010 à 13:16:36
Bonjour et bon Samedi a tous
Pourquoi ce code ne fonctionne pas lorsque je mets des '[]' dans les tableaux de ma structure ?
Et lorsque je mets des '*' dans les tableaux de ma structure ça fonction nikel ?