une erreur en C que je n'arrive pas à résoudre !

une erreur en C que je n'arrive pas à résoudre ! - C - Programmation

Marsh Posté le 14-10-2006 à 20:05:47    

salut à tous,
 
je suis en train décrire un truc tout con en C, et j'ai une erreur bête que j'arrive pas à résoudre. Ca utilise des objets de type struct tm qui permet de manipuler les heures (pour ceux qui connaitraient pas). Voilà le code en gros:
 

Code :
  1. struct tm* saisie_encheres(int nbr_encheres, struct tm tm_encheres)
  2. {
  3.        struct tm objet_tm;
  4.        
  5.        patati patata, je rempli l'objet objet_tm
  6.        tm_encheres[i]=objet_tm;
  7.                            
  8.        return &tm_encheres;
  9. }


 
et j'obtient, sur la ligne "tm_encheres[i]=objet_tm;", l'erreur de compilation "subscripted value is neither array nor pointer "
 
J'arrive pas à comprendre !
 
merci !


Message édité par bb charlie le 01-11-2006 à 21:23:35
Reply

Marsh Posté le 14-10-2006 à 20:05:47   

Reply

Marsh Posté le 14-10-2006 à 20:14:21    

Le message est pourtant clair : le truc auquel tu applique [i] (tm_encheres) n'est ni un tableau ni un pointer.
 
J'imagine que le but de ta fonction est d'initialiser un certain nombre de struct tm_encheres dans un espace mémoire passé en argument ? Dans ce cas il faut passer un struct tm *tm_emcheres, qui sera l'adresse de la zone en question.

Reply

Marsh Posté le 14-10-2006 à 20:18:10    

arf, je savais bien que le message était clair, mais impossible de mettre la main sur l'erreur...forcément, si j'oublie * en argument, ça risque pas de passer , quel cèpe  [:am7]  
 
merci !

Message cité 1 fois
Message édité par bb charlie le 14-10-2006 à 20:18:44
Reply

Marsh Posté le 14-10-2006 à 21:45:42    

Eh, le cèpe, n'oublie pas de remplacer  

bb charlie a écrit :

return &tm_encheres



par la ligne

return tm_encheres


sinon ton compilateur ralera parce que tu chercheras à renvoyer un "struct tm **" dans une fonction de type "struct tm*". :sol:  


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 14-10-2006 à 22:19:34    

oui, c'est fait depuis un moment, merci !
Par contre, j'ai quand même des souçis lors de l'appel à cette fonction dans le main...
Bon, je résume:

Code :
  1. struct tm* saisie(int nbr, struct tm tab_tm[])
  2. {
  3.     remplissage du tableau tab_tm (qui contient des objets de type struct tm donc);
  4.     return tab_tm;
  5. }


puis dans le main:

Code :
  1. int main()
  2. {
  3. struct tm tab_tm[nb_max]; //(avec nb_max en static)
  4. ......
  5. tab_tm=saisie(nbr,tab_tm);
  6. ...
  7. }


et le compilo râle: "incompatible types in assignment" (je tiens à préciser que je comprends ce qu'il me dit hein  :D ). Pourtant, tab_tm est bien un tableau de type struct tm, je le donne à bouffer à ma fonction saisie, il me revoie bien un pointeur et je peux donc faire l'égalité non ? J'ai essayé de faire un retour de tableau explicitement dans la fonction saisie, à savoir:

Code :
  1. struct tm[] saisie(int nbr, struct tm tab_tm[])

mais ça lui plait pas...
 
une idée ?

Message cité 1 fois
Message édité par bb charlie le 14-10-2006 à 22:26:45
Reply

Marsh Posté le 14-10-2006 à 22:59:26    

De part ta déclaration struct tm tab_tm[nb_max]; , tab_tm est un tableau c'est-à-dire que sa valeur est une constante, donc il n'est pas content si tu lui dis ensuite que tab_tm change de valeur par l'assignation tab_tm = saisie...

Reply

Marsh Posté le 14-10-2006 à 23:56:26    

mouais, j'ai pas trouvé comment lui faire plaisir facilement. Du coup, j'ai passé ce tableau en global et voilà, y'a plus de souçis. Merci !

Reply

Marsh Posté le 15-10-2006 à 00:51:15    

Je ne comprend pas trop pourquoi ta fonction saisie revoit quelque chose ; ça ne sert à rien. Autant la faire void, ou bien renvoyer un int pour signifier succès/echec.

Reply

Marsh Posté le 15-10-2006 à 00:53:54    

comment ça, ça ne sert à rien ?? Ca ne sert à rien maintenant que je les ai mise en variables globales, OK, mais avant, elle il fallait bien que je passe le tableau en argument de cette fonction pour le manipuler et le renvoyer après pour le récuper dans le main !

Reply

Marsh Posté le 15-10-2006 à 01:12:57    

bb charlie a écrit :

comment ça, ça ne sert à rien ?? Ca ne sert à rien maintenant que je les ai mise en variables globales, OK, mais avant, elle il fallait bien que je passe le tableau en argument de cette fonction pour le manipuler et le renvoyer après pour le récuper dans le main !


Ben non. Quand tu passes l'adresse d'un objet, la fonction peut le modifier indirectement (via l'opérateur de déréférencement). Il n'y a rien à renvoyer en plus. La modification de l'original se produit avant le return.

Message cité 1 fois
Message édité par Emmanuel Delahaye le 15-10-2006 à 01:21:46

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 15-10-2006 à 01:12:57   

Reply

Marsh Posté le 15-10-2006 à 01:14:55    

Emmanuel Delahaye a écrit :

Ben non. Quand tu passes l'adresse d'un objet, la fonction peut le modifier indirectement (via l'pérateur de déréférencement). Il n'y a rien à renvoyer en plus. La modification de l'original se produit avant le return.


arf, heuuuuu, oui c'est vrai ça au fait, c'est un peu l'intéret des pointeurs ça  [:alex_]

Reply

Marsh Posté le 15-10-2006 à 17:09:02    

bb charlie a écrit :

...maintenant que je les ai mise en variables globales...


Les variables globales c'est mal....
 


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 15-10-2006 à 18:11:48    

tant pis, ça marche, ça me suffit  :D  
J'ai pas trouvé comment enlever cette erreur de compilation sans faire ça, donc j'en reste là pour le moment !

Reply

Marsh Posté le 15-10-2006 à 18:14:13    

Et ça ne te laisse pas un petit goût amer de travail pas fini ?

Reply

Marsh Posté le 15-10-2006 à 18:16:41    

ça me laisse surtout le temps de le finir quand j'aurais le temps, j'avais besoin de ce petit prog rapido !
En plus, je dis n'importe quoi: en passant la fonction saisie en void, le problème aurait été réglé sans avoir à passer par les variables globales, donc je le changerai à l'occasion, c'est rien à faire, et je serait plus un pas beau...


Message édité par bb charlie le 15-10-2006 à 18:25:20
Reply

Marsh Posté le 15-10-2006 à 18:23:50    

Trap D a écrit :

Et ça ne te laisse pas un petit goût amer de travail pas fini ?


Moi, ça m'empêcherai de dormir... Un vrai artisan aime le travail bien fini... Il se relève la nuit pour aller pisser retirer cette globale...


Message édité par Emmanuel Delahaye le 15-10-2006 à 18:25:52

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 15-10-2006 à 18:28:12    

Lol, ben moi ça risque pas de m'en empêcher, faut arrêter de faire une fixation sur les variables globales sérieux. Elles existent, c'est pas pour rien, ou alors les personne qui ont développées le C sont des tâchons...
 
J'avais besoin d'un prog, il marche comme ça, je l'utilise parceque j'en ai besoin immédiatement, et à l'occasion je repasserai les variables en local, et puis voilà, arrêtez d'être un tantinet méprisant avec n'importe qui pour si peu franchement... :o

Message cité 1 fois
Message édité par bb charlie le 15-10-2006 à 18:32:45
Reply

Marsh Posté le 15-10-2006 à 19:08:16    

bb charlie a écrit :

Lol, ben moi ça risque pas de m'en empêcher, faut arrêter de faire une fixation sur les variables globales sérieux. Elles existent, c'est pas pour rien, ou alors les personne qui ont développées le C sont des tâchons...


Elles existent pour des cas très spécifiques et doivent être évitées à tout prix. La qualité du code s'en ressent immédiatement.
 
Et ça n'a rien à voir avec le C. C'est un principe de programmation général applicable à tous les langages, et qui a fait que le BASIC ancien (10 GOTO 10) n'a jamais été utilisé professionellement :  
- pas de locales
- goto
- pas de fonctions (mais GOSUB)
- pas de paramètres (mais des globales)
 
Bref, le jour où je suis passé au Pascal,  après 2 ans de BASIC laborieux ne menant qu'à l'énervement, ça a été la Révélation. Le passage Pascal vers C a été un jeu d'enfant.

Citation :


J'avais besoin d'un prog, il marche comme ça, je l'utilise parceque j'en ai besoin immédiatement, et à l'occasion je repasserai les variables en local, et puis voilà, arrêtez d'être un tantinet méprisant avec n'importe qui pour si peu franchement... :o


L'expérience montre qu'on revient rarement sur du code qui fonctionne. Espérons par contre que ça te guide pour la prochaine fois. Je recommande d'appliquer les Bonnes Pratiques dès la première ligne de code.
 
Méprisant ? Attends, je relis pour voir :sweat: ...  rien trouvé. Tu peux citer ?


Message édité par Emmanuel Delahaye le 15-10-2006 à 19:12:13

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 15-10-2006 à 19:20:23    

je ne doute pas que les globales soit utiles dans certains cas, ni qu'il faut les éviter quand on peut.  
 
Il me sera difficile de te citer, c'est bien pour ça que j'ai précisé "un tantinet"...mais avoue quand même que lorsque deux types arrivent et te sortent "ah ouais, et t'as pas l'impression d'avoir fait un boulot inachevé ?", et que l'autre surrenchérit "ah, moi, ça m'aurait empêché de dormir, un vrai artisan aime le travail bien fini", ça veut un peu (beaucoup) dire que je fais un boulot de gougnaffier, je veux pas dire...
Alors non, je code pas comme un déguelasse, seulement j'avais besoin de ce prog rapidement et je trouvais pas l'erreur, donc j'ai mis du global, c'est pas bien je m'en tape pour le moment, mais je tiens compte des remarques et, maintenant que je sais où était l'erreur, je l'arrangerai à la première occasion (et même si l'expérience montre qu'en général on ne le fait pas, moi je le fais parceque ce code est en constante évolution...)

Message cité 1 fois
Message édité par bb charlie le 15-10-2006 à 19:24:44
Reply

Marsh Posté le 15-10-2006 à 19:25:03    

bb charlie a écrit :

Il me sera difficile de te citer, c'est bien pour ça que j'ai précisé "un tantinet"...mais avoue quand même que lorsque deux types arrivent et te sortent "ah ouais, et t'as pas l'impression d'avoir fait un boulot inachevé ?", et que l'autre surrenchérit "ah, moi, ça m'aurait empêché de dormir, un vrai artisan aime le travail bien fini", ça veut un peu (beaucoup) dire que je fais un boulot de gougnaffier, je veux pas dire...


C'est une façon, que j'espère fine, de faire passer le message. Désolé d'être un peu 'passioné' sur le sujet, mais quand tu auras passé des nuits (au sens propre) à corriger du code de chacal, tu comprendras qu'on essaye de traiter le problème en amont et qu'on a du mal a laisser passer ce genre de chose...
 
L'important est que tu saches quoi faire maintenant.


Message édité par Emmanuel Delahaye le 15-10-2006 à 19:27:43

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 15-10-2006 à 19:34:45    

Ben perso je trouve ça tout aussi désagréable que de lire "tu fais un boulot dégueu", voire plus...non, je n'ai pas envie de quelque chose de plus radical comme tu dis, mais encore une fois, le ton n'est pas super agréable...
 
Et encore une fois, ce n'est pas une question de savoir quoi faire ! J'ai trouvé une solution temporaire, la question de faire du boulot dégueu n'a pas sa place ici (c'est mon avis)! Si c'était à recommencer, je le ferai!  
 
Tu préfères quoi: te retrouver en rade parceque tu avais besoin de ton prog mais que tu t'es refusé à utiliser une variable globale en attendant de trouver l'erreur, et du coup t'as que dalle, ou bien trouver une solution temporaire, faire ce que tu as à faire, te faire titiller (c'est mieux  :D ) par des programmeurs qui te disent que tu fais du boulot dégueu au passage, et trouver pourquoi ça clochait ensuite ? Moi j'ai opté pour la seconde option...
Je ne te repproche rien et ai pris tes remarques en compte depuis le début, au contraire, c'est toi qui as mis le doigt sur mon bug, alors je me permettrais pas !
 
edit: je vois que tu as enlevé le "on peut être plus radical si tu veux". Du coup, zappe ce qui y fait allusion dans mon post  ;)

Message cité 1 fois
Message édité par bb charlie le 15-10-2006 à 19:37:59
Reply

Marsh Posté le 16-10-2006 à 04:11:12    

bb charlie a écrit :

Tu préfères quoi: te retrouver en rade parceque tu avais besoin de ton prog mais que tu t'es refusé à utiliser une variable globale en attendant de trouver l'erreur, et du coup t'as que dalle, ou bien trouver une solution temporaire, faire ce que tu as à faire, te faire titiller (c'est mieux  :D ) par des programmeurs qui te disent que tu fais du boulot dégueu au passage, et trouver pourquoi ça clochait ensuite ? Moi j'ai opté pour la seconde option...


Le problème, c'est que si ton compilo te dit qu'il y a une erreur au niveau des paramètres, c'est qu'il y en a réellement une. La masquer en remplaçant les paramètres par des globales ne te permet pas de comprendre le pourquoi de l'erreur. Total, si demain tu recommences un autre programme, tu risques de faire une erreur similaire et opter encore pour la facilité.
De plus, cette erreur montre une certaine ignorance des caractéristiques de base tableaux/pointeurs et cette ignorance peut se répercuter en s'amplifiant sur d'autres trucs plus profond.
 
Total, vaut mieux essayer de se forcer à comprendre la cause de l'erreur que de la masquer...
 

bb charlie a écrit :

Code :
  1. struct tm* saisie(int nbr, struct tm tab_tm[])
  2. {
  3.     remplissage du tableau tab_tm (qui contient des objets de type struct tm donc);
  4.     return tab_tm;
  5. }


puis dans le main:

Code :
  1. int main()
  2. {
  3. struct tm tab_tm[nb_max]; //(avec nb_max en static)
  4. ......
  5. tab_tm=saisie(nbr,tab_tm);
  6. ...
  7. }


et le compilo râle: "incompatible types in assignment". Pourtant, tab_tm est bien un tableau de type struct tm, je le donne à bouffer à ma fonction saisie, il me revoie bien un pointeur et je peux donc faire l'égalité non ? J'ai essayé de faire un retour de tableau explicitement dans la fonction saisie, à savoir:

Code :
  1. struct tm[] saisie(int nbr, struct tm tab_tm[])

mais ça lui plait pas...


Ici, tu commences par créer un tableau "tab_tm". A ce moment là, le compilo te crée "nb_max" cases de type "struct tm". Chaque case nommée "tab_tm[x]" peut contenir une structure. Mais il te crée aussi une variable supplémentaire nommée "tab_tm" (sans crochet) qui contient l'adresse de cette première case
Autrement dit, si "tab_tm[0]" se trouve à l'adresse "0x1000", alors "tab_tm" contient "0x1000".
Ensuite, tu fais "tab_tm=qqchose". Là, c'est incorrect car "tab_tm" contient déjà quelque chose de correct (0x1000). Le compilo t'indique donc que tu fais qqchose d'incorrect (preuve qu'il fait bien son boulot).
 
Maintenant, pour ton code, t'as 2 solutions
1) tu laisses la fonction "saisie" remplir et allouer de l'espace tant qu'il y en a besoin. Une fois cette fonction terminée, elle aura allouée une grosse zone mémoire qu'elle n'aura plus qu'à renvoyer à ton main. Ton main, lui, ne contiendra qu'un simple pointeur ne correspondant à rien au départ mais contenant ensuite le début de cette zone mémoire


struct tm* saisie(int nbr)
{
    struct tm *zone_allouee;
    int i;
 
    // Allocation espace nécessaire et vérification
    zone_allouee=malloc(nbr * sizeof(struct_tm));
    if (zone_allouee == NULL)
    {
        // Allocation échouée - On s'arrête
        return NULL;
    }
 
    // Remplissage
    for (i=0; i < nbr; i++)
    {
        zone_allouee[i]=blablabla_remplissage_blablabla
    }
     
    // Renvoi adresse zone allouée
    return zone_allouee;
}
     
int main()
{
    // Déclaration pointeur
    struct tm *tab_tm;
 
    // Le poiteur récupère l'adresse de la zone mémoire allouée et remplie
    tab_tm=saisie(nbr);
    if (tab_tm == NULL)
    {
        // Gestion de l'allocation échouée
        return -1;
    }
 
    // Ici tu peux travailler avec "tab_tm[i]"
    blablabla tab_tm[i] blablabla
 
    // Fin du travail - Je libère la zone allouée parce que je ne suis pas un goret
    free(tab_tm);
}


 
2) tu prépares dans ton main l'espace dont tu as besoin, et tu passes cet espace à la fonction "saisir" qui n'a plus qu'à le remplir. Dans ce cas, elle n'a rien besoin de renvoyer (sauf éventuellement une info comme "réussi/échec" ou "nb d'éléments remplis" ou autre...)


int saisie(struct tm*, int nbr)
{
    int i;
 
    // Remplissage
    for (i=0; i < nbr; i++)
    {
        zone_allouee[i]=blablabla_remplissage_blablabla
    }
     
    // Renvoi nb d'éléments remplis (peut être égal à nbr ou pas selon certaines conditions)
    return i;
}


 
Ton main, lui, a maintenant besoin d'avoir l'espace nécessaire. Cet espace peut être réservé avec malloc() et libéré avec free()...

int main()
{
    struct tm *tab_tm;
    int nb_reelement_remplis;
 
    // Allocation mémoire et vérification
    tab_tm=malloc(1500 * sizeof(struct tm));
    if (tab_tm == NULL)
    {
        // Gestion de l'allocation échouée
        return -1;
    }
 
    // Remplissage    
    nb_rellement_remplis=saisie(tab_tm, 1500);
 
    // Ici tu peux travailler avec "tab_tm[i]"
    blablabla tab_tm[i] blablabla
 
    // Fin du travail - Je libère la zone allouée parce que je ne suis pas un goret
    free(tab_tm);
}


 
... ou directement par un tableau. Dans ce cas, pas besoin de freer...

int main()
{
    struct tm tab_tm[1500];
    int nb_reelement_remplis;
   
    nb_rellement_remplis=saisie(tab_tm, 1500);
 
    // Ici tu peux travailler avec "tab_tm[i]"
    blablabla tab_tm[i] blablabla
 
    // Fin du travail - L'espace réservé pour "tab_tm[]" par le système sera libéré aussi par le système
}


Dans les 2 cas, t'auras aucune erreur ni aucune globale...
 
Dernier détail: chaque fois que t'utiliseras "tab_tm[i]", le programme fera l'opération
- je me place sur l'adresse "tab_tm"
- je me décale de "i" cases
- je travaille avec le contenu de l'endroit où je me trouve
Ces opérations prenant du temps, si t'as souvent besoin d'accéder à "tab_tm[i]", il sera plus efficace/rapide d'utiliser un second pointeur "pt" contenant déjà l'adresse de "tab_tm[i]". Il te suffira ensuite d'utiliser "*pt" à la place de "tab_tm[i]"...
Ex:

// Exemple 1 - Travail avec indice
int main()
{
    struct tm tab_tm[1500];
    int i;
 
    for (i=0; i < 1500; i++)
    {
        // Travail plusieurs fois sur "tab_tm[i]"
        blablabla tab_tm[i] blablabla tab_tm[i] blablabla tab_tm[i]
    }
}
 
// Exemple 2 - Travail avec pointeur
int main()
{
    struct tm tab_tm[1500];
    struct tm *pt;
    int i;
 
    for (i=0, pt=tab_tm; i < 1500; i++, pt++)
    {
        // Travail plusieurs fois sur "*pt" correspondant aussi à "tab_tm[i]"
        blablabla *pt blablabla *pt blablabla *pt
    }
}


Message édité par Sve@r le 16-10-2006 à 04:16:45

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 16-10-2006 à 09:12:27    

merci pour ta réponse que je vais étudier en détail tu peux en être sûr. Encore une fois, je n'ai jamais dit qu'utiliser une variable globale était une solution propre, c'est une solution qui m'a permi de faire ce que j'avais à faire avec mon prog, alors arrêtez de m'accabler de "mettre un global ne résoud pas le problème, c'est pas bien"  :cry:  ;) !
Maintenant que j'ai trouvé l'erreur (grâce à matafan et Delahaye), qui était simplement de faire renvoyer quelque chose à ma fonction saisir au lieu de la mettre en void tout simplement, je vais arranger ça et ça marchera, c'est sûr...


Message édité par bb charlie le 16-10-2006 à 09:14:36
Reply

Marsh Posté le 16-10-2006 à 10:06:42    

En tout cas merci Sve@r !
 :jap: Je ne savais pas du tout que cela prenait plus de temps d'utiliser un tab[x] plutôt qu'un pointeur sur la même adresse  :jap:

Reply

Marsh Posté le 01-11-2006 à 19:23:34    

Petit déterrage de mon propre post pour vous montrer que je ne suis pas resté sur mes variables globales et que j'ai arrangé mon problème comme vous l'avais dit.
@Sve@r: j'ai opté pour la solution qui m'a semblé la plus naturelle: la solution 2 avec des tableaux. Bon, cependant, y'a un truc assez incroyable qui c'est produit: deux chose apparemment totalement indépendantes entrent en conflit. Je m'explique: dans mon prog, entre autres, je fais d'une part ce fameux replissage de tableau de struct tm qui est le sujet initial de ce post, et d'autre part je lis en début du main() des chaines de caractères dans un fichier param.txt.  
 
Ces valeurs récupérées n'interviennent en rien dans le tableau de struct tm, et pourtant, voici ce qu'il se passe:  
* Si je laisse mon prog avec les fameuses variables globales pour mon tableau, la lecture du fichier en début de main se passe nickel et le prog suit son cours sans problème, donc la fonction de lecture est correcte et le fichier lu aussi.
* Bon, maintenant je décide d'en finir avec les variables globales et que je fais du travail propre comme celui que l'on m'a conseillé dans ce post, et là, voilà à quoi j'ai droit: la lecture du fichier au début du main me fait planter le programme sauvagement ! Et, comble de l'incohérence (enfin, faut croire que non !?), si j'enlève la lecture du fichier en début de programme, tout se passe bien, ce qui veut dire que tout ce passe bien du coté du tableau  :ouch: ...
 
Alors là, je capte vraiment pas...si quelqu'un voit quel est le rapport, ce serait sympa de me donner un coup de pouce.  
Voilà un code abrégé pour vous aider à voir plus clair:
la fonction de lecture du fichier (qui possède une ligne avec "toto" "titi" )

Code :
  1. void lecture_params(char *smtp, char *destinataire)
  2. {
  3.      FILE* fichier = NULL;
  4.    
  5.      fichier = fopen("params.txt", "r" );
  6.     if (fichier != NULL)
  7.     {
  8.         fscanf(fichier,"%s %s",smtp,destinataire);
  9.         fclose(fichier);
  10.     }   
  11. }


la fonction de remplissage du tableau struct_tm:

Code :
  1. int saisie(int nbr,struct tm tm_tab[],int x[],int y[])
  2. {
  3.     int i=0;
  4.     // Remplissage
  5.     for (i=0; i < nbr; i++)
  6.     {
  7.         tm_tab[i]=remplissage_blablabla
  8.     }
  9.     return i;
  10. }


et enfin le main:

Code :
  1. #Define MAX 100
  2. void main()
  3. {
  4.     char *destinataire;
  5.     char *smtp;
  6.     struct tm tm_tab[MAX];
  7.     int x[MAX];
  8.     int y[MAX];
  9.     lecture_params(smtp,destinataire);
  10.     printf("smtp: %s\ndestinataire: %s\n",smtp,destinataire); // fonctionne avec l'ancienne version (avec les variables  
  11.                                                             // globales) mais fait planter avec la version "propre"  
  12.     saisie(nbr,tm_tab,x,y);
  13. }

Message cité 1 fois
Message édité par bb charlie le 01-11-2006 à 20:42:20
Reply

Marsh Posté le 01-11-2006 à 19:38:57    

Ca serait bien que tu initialises les variables destinataire et smtp, comme tu passes les pointeurs par valeurs et non par adresse au retour de la fonction lecture_param ils reprennent leur valeur initiale, problème courant quand on débute avec les pointeurs.
D'autre part, comme on te l'a déjà dit, un des prototypes de main est int main(void).
Enfin, à quoi sert char chaine[MAX_CHAR] = ""; // Chaîne vide de taille MAX_CHAR      dans ta fonction lecture_params(char *smtp, char *destinataire) ?

Message cité 2 fois
Message édité par Trap D le 01-11-2006 à 19:41:20
Reply

Marsh Posté le 01-11-2006 à 19:43:26    

heuu, je ne crois pas puisque comme je l'ai dit cela fonctione très bien avec l'ancienne version de mon programme (qui utilisait tm_tab, x et y en variables globales). J'obtenais bien les bonnes valeurs de smtp et destinataire après lecture du fichier (cf le printf du main)....
 
edit: à rien, c'est un vieux copier coller !


Message édité par bb charlie le 01-11-2006 à 19:53:11
Reply

Marsh Posté le 01-11-2006 à 19:45:06    

Il est temps de lire un bon bouquin de C !

Reply

Marsh Posté le 01-11-2006 à 19:49:07    

ah bon, si c'est si évident, tu peux donc m'expliquer pourquoi le printf du main me donne les bonnes valeurs de smtp et destinataire après la lecture du fichier et que ça plante lorsque je change un truc qui n'a rien à voir (la fonction saisie) ?
 

Trap D a écrit :

Ca serait bien que tu initialises les variables destinataire et smtp, comme tu passes les pointeurs par valeurs et non par adresse au retour de la fonction lecture_param ils reprennent leur valeur initiale


Je rappelle que le plantage (quand plantage il y a) a lieu en plein milieu de lecture_param, lors de l'utilisation de fscanf, donc ça ne peut pas être un problème de mauvaise valeur au retour de lecture_param...le bouquin de C, j'en ai certes besoin, mais suis-je le seul ?...


Message édité par bb charlie le 01-11-2006 à 19:57:07
Reply

Marsh Posté le 01-11-2006 à 20:01:09    

bb charlie a écrit :

@Sve@r: j'ai opté pour la solution qui m'a semblé la plus naturelle: la solution 2 avec des tableaux. Bon, cependant, y'a un truc assez incroyable qui c'est produit:<...>


STOP !
 
Si ton code a un comportement étrange, c'est qu'il est buggé. Point.
 

  • Code incomplet (ne compile pas)
  • saisie() : i non défini.
  • saisie() : remplissage_blablabla non défini
  • main() : retourne un int. Toujours.
  • main() : MAX non défini
  • main() : l'appel de saisie() est faux. On ne met pas de type dans un appel de fonction.
  • main() : [b]nbr[/b] n'est pas défini.
  • main() : Comportement indéfini. les pointeurs destinataire et smtp ne sont pas initialisés.


Faut-il vraiment que je continue ?


Message édité par Emmanuel Delahaye le 01-11-2006 à 20:17:37

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 01-11-2006 à 20:40:46    

Trap D a écrit :

Ca serait bien que tu initialises les variables destinataire et smtp, comme tu passes les pointeurs par valeurs et non par adresse au retour de la fonction lecture_param ils reprennent leur valeur initiale, problème courant quand on débute avec les pointeurs.
D'autre part, comme on te l'a déjà dit, un des prototypes de main est int main(void).
Enfin, à quoi sert char chaine[MAX_CHAR] = ""; // Chaîne vide de taille MAX_CHAR      dans ta fonction lecture_params(char *smtp, char *destinataire) ?


 
ah, heuu, mais je pensais pas que tu chercherai à le compiler, c'est normal que tu ais des erreurs, c'est du code "abrégé" que j'ai mis là pour ne pas surcharger le truc et être plus lisible...je n'ai pas d'erreur de compilation de ce genre, tu penses bien que je n'aurais pas posté ce genre d'erreur sur le forum !  
MAX est défini par un define, nbr est défini au début du main, etc...Pour l'appel de saisie, erreur de copier coller désolé, mais sur mon fichier ce n'est pas comme ça, y'a pas de int dans l'appel (sinon j'aurais eu des erreurs de compil et je l'aurais trouvé  ;) .  
 
Bon, je vais mettre le main en int et pas void, initialiser mes pointeurs à NULL par contre --> ça plante toujours
 
merci pour ton aide !

Message cité 2 fois
Message édité par bb charlie le 01-11-2006 à 20:45:12
Reply

Marsh Posté le 01-11-2006 à 20:48:01    

Pour compléter ce que je disais car il est vrai que je me suis mal exprimé, les valeurs de destinataire et smtp n'étant pas initialisée pointent sur n'importe quoi. Donc le scanf lit les données dans le fichier et les rangent à l'adresse indiquée par ces pointeurs destinataire et smtp (je croyais comme j'avais lu en travers que tu initialisais ces valeurs dans la fonction lecture_param).  
C'est une des joies du C, on écrit n'importe où dans la mémoire et par chance ça marche, toujours en période de test et ça plante le jour de la présentation.
Bref, ton printf fonctionne bien, mais comme après tu appelles une fonction saisie ça ne marche plus, (mais ça aurait pu tout aussi bien marcher quand même jusqu'au jour où ça n'aurait plus fonctionner, tout comme ça plante parfois dès le début.

Reply

Marsh Posté le 01-11-2006 à 20:50:22    

bb charlie a écrit :

Bon, je vais mettre le main en int et pas void, initialiser mes pointeurs à NULL par contre --> ça plante toujours
 
merci pour ton aide !

Initialise avec un malloc pas avec NULL, et n'oublie pas de libérer à la fin du prog avec un free.

Reply

Marsh Posté le 01-11-2006 à 20:52:13    

Merci pour tes indications.
En fait, ce qui est bizzare, c'est que lorsque ça plante (ie avec la version du prog qui utilise des variables locales pour tab_tm x et y), ça plante dans la fonction lecture_param, lors de l'appel du fscanf, donc c'est même pas une histoire de mauvais pointeur et tout. Et lorsque j'ai des variables globales (ancienne version du prog), tout marche bien ! Le pire c'est que ce sont deux choses apparemment indépendantes !
 
edit: ok je vais faire avec malloc --> c'est fait, c'est pareil, mêmes symptomes...

Message cité 1 fois
Message édité par bb charlie le 01-11-2006 à 21:08:42
Reply

Marsh Posté le 01-11-2006 à 21:08:29    

bb charlie a écrit :

Bon, je vais <...> initialiser mes pointeurs à NULL


Et ça va changer quoi ?
 
Tu définis des pointeurs et tu passes leur valeurs à des fonctions. Il faut que la valeur soit valide. Pour qu'un pointeur soit valide il n'y a pas 36 solutions :  
 

  • adresse d'une variable du même type
  • adresse retournée par malloc() (et ses frères ou fopen() si FILE * ou toute fonction utilisant malloc() ou fopen())
  • valeur d'un pointeur correctement initialisé


Choisis celle qui te semble la plus adaptée à ton problème.


Message édité par Emmanuel Delahaye le 01-11-2006 à 21:10:07

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 01-11-2006 à 21:11:43    

Ok. C'est fait, j'ai initialisé tous mes pointeurs avec malloc() et le problème n'est plus !!!! ;)  
Alors là, je dois vous avouer que pensais que ça ne changerai rien...c'était même pas des tableaux, non, des petits pointeurs sur des char perdus dans le code, j'ai fait avec malloc et voilà. Je sais que c'est idiot de dire que c'est bizzare, mais quand même, ce problème était pourtant tellement incohérent...vous me direz, c'est justement quand c'est à ce point incohérent que c'est sans doute dû à ce genre de choses...En tout cas, merci à tous, maintenant je crois que je ne laisserai jamais plus un pointeur sans initialisation.

Message cité 2 fois
Message édité par bb charlie le 01-11-2006 à 21:16:01
Reply

Marsh Posté le 01-11-2006 à 21:13:36    

bb charlie a écrit :


En fait, ce qui est bizzare, c'est que lorsque ça plante (ie avec la version du prog qui utilise des variables locales pour tab_tm x et y), ça plante dans la fonction lecture_param, lors de l'appel du fscanf, donc c'est même pas une histoire de mauvais pointeur et tout. Et lorsque j'ai des variables globales (ancienne version du prog), tout marche bien ! Le pire c'est que ce sont deux choses apparemment indépendantes !
 
edit: ok je vais faire avec malloc --> c'est fait, c'est pareil, mêmes symptomes...


C'est qu'il y a un bug ailleurs. Poste un code compilable qui montre le problème.
 
Et ne perd pas ton temps à chercher à expliquer les comportements indéfini. Passe plutôt du temps à chercher les bugs dans ton code...


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 01-11-2006 à 21:17:56    

Emmanuel Delahaye a écrit :

Et ne perd pas ton temps à chercher à expliquer les comportements indéfini. Passe plutôt du temps à chercher les bugs dans ton code...


oui, ça rejoint un peu ce que j'ai dait dans mon dernier post, c'est tellement incohérent que je perdais mon temps à chercher des explications introuvables...
 


j'ai tapé un peu vite...corrigé.
 
merci encore


Message édité par bb charlie le 01-11-2006 à 21:18:25
Reply

Marsh Posté le 01-11-2006 à 21:26:22    

bb charlie a écrit :

maintenant je crois que je ne laisserai jamais plus un pointeur sans initialisation.


Tu as compris le B.A. BA du C, c'est bien.


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 01-11-2006 à 21:30:12    

:sweat:  
ouais, c'est quand même un peu fou que l'on puisse apprendre le B.A BA alors qu'on code régulièrement en C (même si c'est pas du tout mon boulot), pourquoi permettre un pointeur sans initialisation si c'est aussi dangeureux...?
Bon, ceci dit, maintenant, j'ai un autre problème qui n'a rien à voir, mais ma fonction lecture_param ne me renvoie plus les bonnes valeurs, "smtp" contient la même valeur que "destinataire" (je régresse ! ça marchait très bien ça !), encore un résultat farfelu ça...je vais corriger ça fissa, j'ai du faire des erreurs dans les malloc  ;)

Message cité 1 fois
Message édité par bb charlie le 01-11-2006 à 21:33:11
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed