Aller au contenu

[RESOLU][C]probleme fonction initialiserStructure


zeyde

Messages recommandés

Salut a tous!

Alors je viens de me lancer dans la programmation en C.

Je suis le tutorial de SdZ et j'en suis au chapitre sur les structures.

J'ai un problème pour initialiser ma structure via une fonction initialiserStructure:

voila ma structure dans le fichier .h:

typedef struct Personne Personne;

struct Personne

{

char prenom[20];

char nom[20];

int age;

};

et voila ma fonction initialiserStructure dans le main.c:

void initialiserPersonne(Personne *personne)

{

personne->prenom[20]="test";

personne->nom[20]="initialiser";

personne->age=99;

}

la compile me sort 2 warning concernant les 2 lignes marquées en rouge:

"warning: assignment makes integer from pointer without a cast"

j arrive a lancer le programme mais si j affiche les nom et prenom de mes personnes, y a des valeur absurdes!!

Une idée?

Lien vers le commentaire
Partager sur d’autres sites

Si je suis bien tu en es au chapitre 6 de la partie 2.

Il faut que tu reviennes sur le chapitre 4 de la même partie, sur les chaines de caractères. Il faut que tu comprennes bien l'initialisaion d'une chaine.

Dans tes deux lignes litigieuses tu utilises un "=" là ou tu devrais utiliser une fonction comme strcpy pu strncpy.

Lien vers le commentaire
Partager sur d’autres sites

Si je suis bien tu en es au chapitre 6 de la partie 2.

Il faut que tu reviennes sur le chapitre 4 de la même partie, sur les chaines de caractères. Il faut que tu comprennes bien l'initialisaion d'une chaine.

Dans tes deux lignes litigieuses tu utilises un "=" là ou tu devrais utiliser une fonction comme strcpy pu strncpy.

Bon j'ai relu le chapitre 4 et effectivement, et si j'ai bien compris, une fois la chaine initialisée, on ne peut plus la modifié simplement par: chaine = "Salut"; On ne peut faire ça que lors de l'initialisation de la chaine. par exemple:

char chaine[] = "Salut";

Donc dans mon programme, puisque mes chaines prenom et nom sont déclarées lors de la déclaration de ma structure personne, je ne peux plus les modifier dans ma fonction initialiserStructure via un personne->prenom = "test". D'où l'utilisation de la fonction strcpy.

Arrêter moi si je dit des bêtises!!

Alors j'ai essayer avec la fonction strcpy de la maniere suivante:

void initialiserPersonne(Personne *personne)

{

strcpy( personne->prenom[tailleTableau],"test");

strcpy( personne->nom[tailleTableau],"initialisation");

personne->age=0;

return;

}

mais surprise, ça ne marche toujours pas!!

Toujours deux warning au même ligne(en rouge) qui dit:

warning: passing of arg 1 of 'strcpy' makes pointer from integer without a cast

Je comprends pas vraiment ce que ca veux dire mais j'ai l'impression que c'est toujours le même problème grosso modo.

Une idée? :)

Lien vers le commentaire
Partager sur d’autres sites

Bonjour

Alors j'ai essayer avec la fonction strcpy de la maniere suivante:

void initialiserPersonne(Personne *personne)

{

strcpy( personne->prenom[tailleTableau],"test");

strcpy( personne->nom[tailleTableau],"initialisation");

personne->age=0;

return;

}

mais surprise, ça ne marche toujours pas!!

Toujours deux warning au même ligne(en rouge) qui dit:

warning: passing of arg 1 of 'strcpy' makes pointer from integer without a cast

Je comprends pas vraiment ce que ca veux dire mais j'ai l'impression que c'est toujours le même problème grosso modo.

Une idée? :)

Je dis peut-être une bêtise (ça fait longtemps, le C), mais il me semble que strcpy() attend deux pointeurs sur des chaînes de caractères. Une chaine constante délimitée par des guillemets t'en donne un mais l'opérateur -> que tu utilises te renvoie le contenu du champ correspondant de ta structure, pas un pointeur dessus.

Tentative à vérifier:

void initialiserPersonne(Personne *personne)

{

strcpy( &(personne->prenom[tailleTableau]),"test");

strcpy( &(personne->nom[tailleTableau]),"initialisation");

personne->age=0;

return;

}

Lien vers le commentaire
Partager sur d’autres sites

T'as fait plusieurs fautes :

- déjà on fait pas un typedef avant de déclarer la structure, c'est débile, c'est comme dire "le surnom de Thomas sera Toto" alors qu'on ne sait pas qui est Thomas.

- par convention on met un "s_" ou un "_s" devant ou derrière le nom de la structure qu'on crée et un "t_" ou un "_t" aux noms de typedefs.

Donc soit tu fais :

struct s_mystruct
{
};

typedef struct s_mystruct   t_mystruct;

soit :

typedef struct s_mystruct
{
} t_mystruct;

Pour ce qui est de tes deux erreurs, c'est assez simple :

Qu'est-ce que la variable "prenom" ? Et la variable "prenom[42]" ? Quelle est la différence ?

Le premier est un char*, le deuxième un char tout court ... Il faut bien que tu comprenne ça.

Allez, je te donne une solution :

#include		<stdio.h>

typedef struct  s_personne
{
 char		  *prenom;
 char		  *nom;
 int		   age;
} t_personne;

void			init_pers(t_personne *super)
{
 super->prenom = "test";
 super->nom = "initialiser";
 super->age = 99;
}

int			 main()
{
 t_personne	super;

 init_pers(&super);
 printf("coucou je m'appelle %s %s et j'ai %i ans", super.prenom, super.nom, super.age);
 return (0);
}

PS: j'ai pas compilé y'a peut-être une erreur qui traine, à ton tour de me corriger ! :byebye:

Lien vers le commentaire
Partager sur d’autres sites

Salut Ramnes!!

Bon déjà, un grand merci à toi!! Le code marche à merveille!!

Ensuite même si c'est peut être bien ce qu'il peut paraitre pour un connaisseur, "débile" est surement pas ce qu'il y a de plus pédagogique. Enfin bref, un grand merci quand même!!

Sinon j'ai un petit soucis encore: si je veux demander ensuite dans le programme les informations concernant la structure à l'utilisateur, par exemple le prénom, j'ai essayer: " scanf("%s", super.prenom); " mais le programme plante. J'ai bien essayé deux trois trucs mais je vois pas, super.prenom est bien un pointeur sur caractère (char*)?

Et deuxième questions, si je tenais particulièrement a déclarer prenom et nom dans ma structure en tant que chaine de caractères et non en tant que char* en faisant comme suit:

typedef struct  s_personne
{
 char          prenom[50];
 char          nom[50];
 int           age;
} t_personne;

Comment écrire ma fonction init_pers ?

Voila merci d'avance et désolé si certaine question sont"débile" <--je rigole bien sur

Lien vers le commentaire
Partager sur d’autres sites

Un char* est une chaine de caractère !

Par contre, toi ce n'en est pas une, c'est un tableau de charactères ... et pour les remplir il faut utiliser strcpy (afin d'écrire case par case), ce qui est relativement casse-burnes.

En plus tu peux pas changer la taille du tableau, donc si il y a trop de caractères t'es bayzay, tandis qu'avec un tableau de pointeur tu peux alloc la mémoire (malloc ftw).

Bref, fais comme je t'ai montré, les tableaux de char ne te serviront que très rarement, et apprend à utiliser malloc. :roll:

Lien vers le commentaire
Partager sur d’autres sites

Merci pour ta réponse et tes conseils!

Bon j'ai fait une petite séries de test et y a vraiment un truc que je comprend pas. C'est par rapport à la saisie de données par un utilisateur via scanf(). J'ai cru comprendre que c'est pas la meilleur fonction pour ça alors j'aimerai savoir si mon problème viens de la fonction scanf() ou si c'est autre chose.

typedef struct s_personne
{
char *prenom;
//char *nom;
//int age;
} t_personne;

void init_perso(t_personne *super)
{
   strcpy(super->prenom,"test");
   //strcpy(super->nom, "init");
   //super->age=0;
}

int main()
{
   t_personne super;
   init_perso(&super);
   printf("%s",super.prenom);
   scanf("%s",super.prenom);
   printf("%s",super.prenom);

   return 0;
}

Ce code marche bien.

Par contre si j'utilise deux ou plus des mes variables dans ma structure(j'enleve les // correspondant), ça plante au niveau de la fonction ini_perso().

Si j'utilise super->prenom="test"; à la place du strcpy(), la ça plante au niveau du scanf mais j'arrive à initialiser plusieurs variables.(ça on s'en doutait car c'est le code que tu m'as suggéré).

Bref, comme on peut t'en douter, c'est pas très clair tout ça pour moi, donc si quelqu'un à une petite explication...

PS: par rapport à ta dernière réponse Ramnes, j'ai l'impression que strcpy() peut copier un chaine en entier, c'est ce que je fait dans mon code. Sinon pour malloc, j'ai découvert ça y a deux jours sur le tutorial de SdZ mais ftw je sais pas ce que c'est. J'ai lu à droite à gauche des histoires de parcours d'arborescence donc je vois pas trop le rapport. Bref merci quand même!!

Lien vers le commentaire
Partager sur d’autres sites

Un char* est une chaine de caractère !

Par contre, toi ce n'en est pas une, c'est un tableau de charactères ...

...

Bref, fais comme je t'ai montré, les tableaux de char ne te serviront que très rarement, et apprend à utiliser malloc. :craint:

Euh oui mais non.

Un char * n'est pas une chaine de caractères mais un pointeur sur un caractère, ou un pointeur sur une chaine de caractères, ou un pointeur sur un tableau de caractères, tout dépend comment tu le manipules. Et le les tableaux de char, ça sert quand même pas mal.

Lien vers le commentaire
Partager sur d’autres sites

Ce code marche bien.

Et ben non il ne marche pas bien mais tu ne le vois pas, car il ne cause pas de dégats suffisants...

Quand tu crées ta structure elle contient un char * qui est un pointeur, qui désigne une adresse mémoire. Cette adresse n'est alors pas initialisée, elle pointe alors n'importe aù en mémoire.

Ensuite, tu dans ton init_perso, tu fais un strcpy, qui va écrire ta série de caractères à l'adresse pointée par ton char *, c'est à dire n'importe où ! Tu viens de découvrir un des pièges classiques du C, l'écriture vers un pointeur non initialisé !

Là, suivant que tu as de la chance où pas, ça fait des dégats ton ton prog ou pas, ça semble fonctionner normalement ou pas...

Si tu rajoutes un autre pointeur, ça ajoute une écriture à une adresse plus ou moins aléatoire, et tu augmente tes risques de plantage.

Quand tu déclares un variable char toto[10], ça réserve 10 char en mémoire, et tu peux te servir de toto comme pointeur vers ton tableau pour strcpy ou autres fonction, par contre tu ne peux plus faire un truc du genre toto="test", car toto pointera toujours vers ces 10 char que tu as réservé.

Donc, soit tu déclares ta structure avec des tableaux et dans ce cas la mémoire est réservée au moment de la création de ta variable structure, et tu n'as pas de pointeur à initialiser, soit lors de l'init il faut pour chaque pointeur vers une chaine de caractère réserver de la mémoire avec malloc, et initialiser le pointeur pour qu'il pointe vers cette mémoire réservée.

Lien vers le commentaire
Partager sur d’autres sites

RTFM (read the fucking manual) :

http://linux.about.com/library/cmd/blcmdl3_scanf.htm

http://linux.about.com/library/cmd/blcmdl3_malloc.htm

Je peux pas mieux t'aider !

PS : "ftw" signifie "for the win". En gros ma parenthèse voulait dire "Vive malloc !".

Euh oui mais non.

Un char * n'est pas une chaine de caractères mais un pointeur sur un caractère, ou une chaine de caractères, ou un tableau de caractères, tout dépend comment tu le manipules. Et le les tableaux de char, ça sert quand même pas mal.

C'était pour simplifier et pas commencer à l'embrouiller avec des histoires de pointeurs ! :craint:

Perso pour ce qui est des tableaux de char, j'en ai que peu souvent l'utilité.

Lien vers le commentaire
Partager sur d’autres sites

C'était pour simplifier et pas commencer à l'embrouiller avec des histoires de pointeurs ! :craint:

Perso pour ce qui est des tableaux de char, j'en ai que peu souvent l'utilité.

OK

Pour ce qui est du "vive le malloc" c'est pas faux mais quand même je pense que pour débuter, pour ne pas additionner les problème c'est quand même plus simple de commencer avec des tableaux pour bien comprendre les manipulations de caractères et aborder les pointeurs... avant de se mettre aux allocs dynamiques.

Lien vers le commentaire
Partager sur d’autres sites

C'était pour simplifier et pas commencer à l'embrouiller avec des histoires de pointeurs ! :craint:

Perso pour ce qui est des tableaux de char, j'en ai que peu souvent l'utilité.

OK

Pour ce qui est du "vive le malloc" c'est pas faux mais quand même je pense que pour débuter, pour ne pas additionner les problème c'est quand même plus simple de commencer avec des tableaux pour bien comprendre les manipulations de caractères et aborder les pointeurs... avant de se mettre aux allocs dynamiques.

C'est vrai, n'empèche que la gestion de mémoire est quand même fondamentale en C, et je pense qu'il vaut mieux apprendre à gérer ça bien dès le début.

Lien vers le commentaire
Partager sur d’autres sites

Salut à tous!

Et bien un grand merci encore à vous pour touts ces conseils, votre temps et tout ça...

J'ai finalement réussi quelques chose de correct, enfin je crois, je vais quand même vous mettre le code des fois qu'il y est des "pièges classiques du C comme l'écriture vers un pointeur non initialisé" :transpi:. J'ai utilisé des tableaux de caractères dans ma structures, j'utilise strcpy() pour l'initialisation des tableaux et je crée un tableau de structures. Si vous avez le temps de jeter un coup d'oeil, sinon tant pi et merci beaucoup.

Le main.c:

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

#include "main.h"

int main()
{
   t_personne famille[2];

   int i=0;
   for(i=0 ; i<2 ; i++)
   {
           initialiserPersonne(&famille[i]);
   }
   int j=0;
   for (j=0 ; j<2 ; j++)
   {
           printf("\n%d: %s %s %dans",j+1,famille[j].prenom,famille[j].nom,famille[j].age);
   }

   for( i=0 ; i<2 ; i++ )
   {
           printf("\n\nEntre le prenom de la %deme personne de la famille: ",i+1);
           scanf("%s",famille[i].prenom);

           printf("Entre le nom de la %deme personne de la famille: ",i+1);
           scanf("%s",famille[i].nom);

           printf("Entre l'age de la %deme personne de la famille: ",i+1);
           scanf("%d",&famille[i].age);
    }

   for (j=0 ; j<2 ; j++)
   {
           printf("\n%d: %s %s %dans",j+1,famille[j].prenom,famille[j].nom,famille[j].age);
   }
   return 0;

}

void initialiserPersonne(t_personne *personne)
{
   strcpy(personne->prenom,"test");
   strcpy(personne->nom,"init");
   personne->age=0;
}

Le main.h:

#ifndef MAIN_H_INCLUDED
#define MAIN_H_INCLUDED
#define tailleTableau 100

typedef struct s_personne
{
   char prenom[30];
   char nom[30];
   int age;
} t_personne;

void initialiserPersonne(t_personne *personne);

#endif // MAIN_H_INCLUDED

Lien vers le commentaire
Partager sur d’autres sites

Ca me botte.

Un truc me parait louche quand même :

int main()
{
t_personne famille[2];

int i=0;
for(i=0; i<2; i++)
{
initialiserPersonne(&famille[i]);
}
int j=0;

le int j=0 ?

t'as le droit de déclarer une variable après du code ? T'es pas sur un compilateur C++ par hasard ?

Deuxio : pourquoi déclarer j et ne pas réutiliser i dans toutes tes boucles ? elles ne s'imbriquent pas, ça ne devrait pas poser de problèmes ?

Trois : t'as essayé de rentrer un nom de 30 caractères pour la déconne ? 31 ? (c'est sympa, et c'est le fameux buffer overflow qui cause tant de failles de par le monde :non: )

Lien vers le commentaire
Partager sur d’autres sites

Salut!

Oui on a le droit de déclarer une variable après du code. Ça marche sur C puisque j'ai choisis le compilateur C lors de l'ouverture du projet.(je suis sous code:blocks)

Par contre ca sert pas à grand chose je te l accorde i aurai suffit.

Effectivement ce code n'est pas protégé contre ce fameux buffer overflow, mais c'était pas l'objet de l'exercice. J'ai vu ça un peu après dans d'autre exercices.

Merci pour tes remarques.

PS: Je pense qu'un [RÉSOLUT] serait approprié dans le titre du sujet mais je sais pas comment faire :non:

Lien vers le commentaire
Partager sur d’autres sites

Tu m'a mis le doute avec ta déclaration après du code exécuté. J'ai donc testé ton code tel quel.

$ cc test.c
"test.c", line 31: syntax error before or at: int
"test.c", line 33: undefined symbol: j
"test.c", line 79: cannot recover from previous errors
cc: acomp failed for test.c

J'utilise le compilateur de SUN livré sur solaris.

Bon, ça marche chez toi, donc pas de problème. Tu dois avoir des options de compilation un peu laxistes avec C:B

Mais comme tu es en train d'apprendre, je pense que ce serait bien de prendre l'habitude de bien séparer tout ça.

PS pour le résolu, je crois qu'il faut éditer ton premier message. Tu devrais pouvoir changer le titre d'ici

Lien vers le commentaire
Partager sur d’autres sites

Archivé

Ce sujet est désormais archivé et ne peut plus recevoir de nouvelles réponses.

×
×
  • Créer...