Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 18/02/2011, à 18:58

darkgilson

[Résolu]Problèmes avec les boucles en C

Bonsoir smile

Je suis en train d'essayer de réaliser un programme en C pour les cours.
A l'école, on travaille sur du windows (devc++) et mon programme tourne correctement.

Cependant, lorsque j'essaye de faire tourner ce meme programme sur ubuntu, j'ai des problèmes de boucles.
Regardez plutôt :

capturejax.png

Au lieu de me demander la couleur 1, ça passe directement à la 2. Et c'est assez aléatoire.
Sur windows, aucun souci et le programme s'arrête bien à chaque fois pour encoder les paramètres. J'ai l'impression qu'il y a une erreur de buffer, mais j'utilise pourtant des fflush (stdin).

Comme IDE, j'utilise Netbeans et j'ai essayé avec codeblocks et geany, meme résultat sad
Le compilateur est GNU (gcc)

Que faire ?

Voici mon code source pour ceux que ça intéresse :

#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "math.h"




typedef struct tabres
{
    char c1;
    char c2;
    char c3;
    double valeur;
}tabres;

void garnir (tabres[], int);
double calcul (tabres[], int);
double calculserie (tabres[], int);
double calculparallele (tabres[], int);

int main (void)
{
    int nbres, i=0;
    double serie, parralele;
    printf("Hello world\n"
            "Combien de resistances avez-vous? (max 10)\n");
    fflush(stdin);
    scanf("%d", &nbres);
    fflush(stdin);
    tabres tableaudesresistances[nbres];
    while (i<nbres)
    {
        printf("Resistance numero %d :\n", i+1);
        garnir (tableaudesresistances, i);
        printf("Resistance %d stockee.\n", i+1);
        i++;
        if (i==nbres)
            printf("Nous avons fini de tout garnir !\n");
    }
    /*
     * tableaudesresistances est un tableau de structure qui comprend les codes
     * couleur des resistances ainsi que le résultat du calcul de leur valeur.
     */
    calcul (tableaudesresistances, nbres);
    printf("Nous avons calcule touuuuutes les resistances !!\n");
    serie=calculserie(tableaudesresistances, nbres);
    printf("La valeur des resistances en serie vaut %f", serie);
    parralele=calculparallele(tableaudesresistances, nbres);
    return 0;
}



void garnir (tabres tab[], int i)
{
    int cpt=0;
    while (cpt<3)
    {
        printf("Entrez la couleur numero %d de la resistance %d :\n", cpt+1, i+1);
        fflush(stdin);
        scanf("%c", &tab[i].c1);
        fflush(stdin);
        cpt++;
    }
}

double calcul (tabres fr[] , int a)
{
       double valeur=5216456;
       return valeur;
}
double calculserie (tabres tab[], int nb)
{
       double valeur=5216456;
       return valeur;

}
double calculparallele (tabres tab[], int nb)
{
       double valeur=5216456;
       return valeur;

}

Merci !

Dernière modification par darkgilson (Le 18/02/2011, à 20:53)

Hors ligne

#2 Le 18/02/2011, à 19:32

grim7reaper

Re : [Résolu]Problèmes avec les boucles en C

Salut,

Erreur classique : ne jamais, au grand jamais, faire de fflush sur un flux entrant (comme stdin).
Les profs qui enseignent fflush(stdin) devraient être pendus haut et court mad !
Le comportement est indéfini (ça peut aussi bien fonctionner que faire planter ton programme, tuer des bébés chats ou invoquer Satan tongue).

Extrait de la norme du langage C

ISO/IEC 9899:TC3 a écrit :

If stream points to an output stream or an update stream in which the most recent
operation was not input, the fflush function causes any unwritten data for that stream
to be delivered to the host environment to be written to the file; otherwise, the behavior is
undefined.

Tu peux aussi jeter un œil ici.

En fait, quand tu lis le clavier, tu lis un buffer qui contient le texte tapé. Donc toi tu tapes "3" puis tu appuie sur la touche Entrée.
Ton premier scanf (avec le %d) lit le nombre 3 et ton second scanf (avec le %c) lit la touche Entrée ('\n' en général, c'est un caractère comme un autre donc il est lu avec %c).
La solution est bien de vider le buffer, mais surtout pas avec fflush(stdin) !
Pour vider proprement le buffer de stdin, regarde ici.
Sinon, inutile de vider le buffer stdin après les printf comme tu le fais, le faire après les scanf est suffisant.


Sinon, on utilise <> pour l'inclusion des headers système (comme ceux de la bibliothèques standards). Ça donne ça

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

Dernière modification par grim7reaper (Le 18/02/2011, à 19:34)

Hors ligne

#3 Le 18/02/2011, à 19:58

Le Farfadet Spatial

Re : [Résolu]Problèmes avec les boucles en C

Salut à tous !

grim7reaper a écrit :

Erreur classique : ne jamais, au grand jamais, faire de fflush sur un flux entrant (comme stdin).
Les profs qui enseignent fflush(stdin) devraient être pendus haut et court mad !

   C'est sans doute l'erreur la plus importante ici, mais je pense que ce n'est pas la seule chose qui t'aura fait tiquer, me trompais-je ?

Le comportement est indéfini (ça peut aussi bien fonctionner que faire planter ton programme, tuer des bébés chats ou invoquer Satan tongue).

   En passant, je constate que tu es toujours très créatif lorsqu'il s'agit d'envisager des effets non défini.

Sinon, on utilise <> pour l'inclusion des headers système (comme ceux de la bibliothèques standards). Ça donne ça

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

   Tout-à-fait. On peut également ajouter qu'il n'est pas utile d'ajouter tous les en-têtes dont on connait le nom : je conseille plutôt d'ajouter les en-têtes au fur-et-à-mesure du besoin. Ce n'est pas très important lorsqu'il ne s'agit que de la bibliothèque standard, mais je pense que c'est une bonne habitude à prendre.

   Sinon, es-tu au courant de l'existence de « for » ? Globalement, ton code me fait fortement penser à : « pourquoi faire simple quand on peut faire compliqué ? » Je suis trop bon, ça me perdra, mais je te propose une version corrigée de ton code – profites-en, je ne le fais pas souvent. Comme tu ne fais visiblement pas du C ANSI, j'ai produit du C99 :

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

typedef struct tabres {
    char c1;
    char c2;
    char c3;
    double valeur;
} tabres;

void clean_stdin (void) {
  int c;
    
  do {
    c = getchar();
  } while (c != '\n' && c != EOF);
}  // clean_stdin

void garnir (tabres tab[], size_t i) {
  for (size_t cpt = 0; cpt < 3; ++cpt) {
    printf("Entrez la couleur numero %zu de la resistance %zu : ",
       cpt + 1, i + 1);
    scanf("%c", &tab[i].c1);
    clean_stdin();
  }
}  // garnir

double calcul (tabres fr[] , int a) {
  double valeur = 5216456;
  return valeur;
}  // calcul

double calculserie (tabres tab[], int nb) {
  double valeur = 5216456;
  return valeur;
}  // calculserie

double calculparallele (tabres tab[], int nb) {
  double valeur = 5216456;
  return valeur;
}  // calculparallele

int main (void) {
  size_t nbres;
  double serie, parralele;

  printf("Combien de resistances avez-vous (max 10) ? ");
  scanf("%zu", &nbres);
  clean_stdin();

  tabres tableaudesresistances [nbres];

  for (size_t i = 0; i < nbres; ++i) {
    printf("Resistance numero %zu :\n", i + 1);
    garnir (tableaudesresistances, i);
    printf("Resistance %zu stockee.\n", i + 1);
  }
  printf("Nous avons fini de tout garnir !\n");

  /*
   * tableaudesresistances est un tableau de structure qui comprend les codes
   * couleur des resistances ainsi que le résultat du calcul de leur valeur.
   */

  calcul (tableaudesresistances, nbres);
  printf("Nous avons calcule touuuuutes les resistances !!\n");
  serie=calculserie(tableaudesresistances, nbres);
  printf("La valeur des resistances en serie vaut %f\n", serie);
  parralele=calculparallele(tableaudesresistances, nbres);
  return 0;
}  // main

   Ce qui donne par exemple cette trace d'exécution :

$ gcc -std=c99 darkgilson.c -o darkgilson
$ ./darkgilson 
Combien de resistances avez-vous (max 10) ? 3
Resistance numero 1 :
Entrez la couleur numero 1 de la resistance 1 : r
Entrez la couleur numero 2 de la resistance 1 : j
Entrez la couleur numero 3 de la resistance 1 : b
Resistance 1 stockee.
Resistance numero 2 :
Entrez la couleur numero 1 de la resistance 2 : v
Entrez la couleur numero 2 de la resistance 2 : v
Entrez la couleur numero 3 de la resistance 2 : r
Resistance 2 stockee.
Resistance numero 3 :
Entrez la couleur numero 1 de la resistance 3 : b
Entrez la couleur numero 2 de la resistance 3 : b
Entrez la couleur numero 3 de la resistance 3 : n
Resistance 3 stockee.
Nous avons fini de tout garnir !
Nous avons calcule touuuuutes les resistances !!
La valeur des resistances en serie vaut 5216456.000000

   À bientôt.

Le Farfadet Spatial

Hors ligne

#4 Le 18/02/2011, à 20:16

darkgilson

Re : [Résolu]Problèmes avec les boucles en C

Un ÉNORME merci à vous big_smile:D

J'ignorais totalement la méthode adéquate pour vider le buffer d'entrée.

Sinon, on utilise <> pour l'inclusion des headers système

Oui, d'habitude j'utilise aussi des <> mais là netbeans a voulu prendre une ou l'autre liberté... Curieux. Mais ça compilait quand même, heureusement smile

Le comportement est indéfini (ça peut aussi bien fonctionner que faire planter ton programme, tuer des bébés chats ou invoquer Satan ).

tongue tongue

Sinon, es-tu au courant de l'existence de « for » ?

Oui, je l'utilise surtout pour faire des recherches dans des tableaux par exemple. Personnellement, je trouve qu'une boucle classique while est plus claire niveau lisibilité. Question de goût smile
Aussi, je sais que ça peut paraître bizarre d'écrire des prototypes, puis le void, puis seulement les fonctions, mais c'est une démarche qu'on nous encourage à utiliser à l'école. Je sais utiliser l'autre qui consiste à mettre les fonctions avant le main, mais je me suis habitué à la première méthode.

Encore merci à vous, je vais tenter de terminer ce programme smile
Puis peut-être essayer de sauvegarder tous les résultats dans un fichier, mais là c'est une autre histoire avec tous ces fopen, fread et compagnie tongue

Hors ligne

#5 Le 18/02/2011, à 20:20

grim7reaper

Re : [Résolu]Problèmes avec les boucles en C

Le Farfadet Spatial a écrit :
grim7reaper a écrit :

Erreur classique : ne jamais, au grand jamais, faire de fflush sur un flux entrant (comme stdin).
Les profs qui enseignent fflush(stdin) devraient être pendus haut et court mad !

   C'est sans doute l'erreur la plus importante ici, mais je pense que ce n'est pas la seule chose qui t'aura fait tiquer, me trompais-je ?

J'avoue que je n'ai pas vraiment regardé le code car j'avais diagnostiqué le problème assez rapidement. Je suis donc allé directement à sa cause. Il y a un autre point que j'aurais dû aborder ?

Tout-à-fait. On peut également ajouter qu'il n'est pas utile d'ajouter tous les en-têtes dont on connait le nom : je conseille plutôt d'ajouter les en-têtes au fur-et-à-mesure du besoin. Ce n'est pas très important lorsqu'il ne s'agit que de la bibliothèque standard, mais je pense que c'est une bonne habitude à prendre.

Très juste. Tu fais bien de le préciser.


[HS]Au fait, pour ton livre sur le C++ as-tu pu remettre le serveur en ligne ?[/HS]



darkgilson a écrit :

Aussi, je sais que ça peut paraître bizarre d'écrire des prototypes, puis le void, puis seulement les fonctions, mais c'est une démarche qu'on nous encourage à utiliser à l'école. Je sais utiliser l'autre qui consiste à mettre les fonctions avant le main, mais je me suis habitué à la première méthode.

À mon sens la méthode la plus propre, en général, est de séparer les déclarations (dans un fichier d'en-tête, extension .h en général) de l'implémentation (dans un fichier source).

Sinon pense à passer ton sujet en résolu wink

Dernière modification par grim7reaper (Le 18/02/2011, à 20:25)

Hors ligne

#6 Le 18/02/2011, à 20:42

Pylades

Re : [Résolu]Problèmes avec les boucles en C

darkgilson a écrit :

[…]
Aussi, je sais que ça peut paraître bizarre d'écrire des prototypes, puis le void, puis seulement les fonctions, mais c'est une démarche qu'on nous encourage à utiliser à l'école. Je sais utiliser l'autre qui consiste à mettre les fonctions avant le main, mais je me suis habitué à la première méthode.
[…]

Si tu voulais dire main à la place de void, non ce n'est pas bizarre, c'est même une très bonne façon de faire (mais comme l'a dit grim7reaper, c'est bien de placer les includes et les prototype dans un fichier d'en-tête à part).


grim7reaper a écrit :

J'avoue que je n'ai pas vraiment regardé le code car j'avais diagnostiqué le problème assez rapidement. Je suis donc allé directement à sa cause. Il y a un autre point que j'aurais dû aborder ?

On pourrait parler de l'usage abusif de printf à la place de puts, par exemple…

Les identificateur sont difficiles à lire et en français, donc ce n'est pas agréable à lire.

Je n'aime aussi pas voir de crochets dans un prototype, mais ça c'est une question de style qui m'est strictement personnelle (c'est pour bien mettre en évidence que lorsque l'on passe un tableau comme argument, il est converti en pointeur).

Point de détail, il y a des fautes d'orthographe et les lettres ne sont pas accentuées, mais ce dernier point peut se comprendre si l'on travaille dans un environnement où il vaut mieux n'utiliser que le set ASCII.

Dernière modification par Pylade (Le 18/02/2011, à 20:44)


“Any if-statement is a goto. As are all structured loops.
“And sometimes structure is good. When it’s good, you should use it.
“And sometimes structure is _bad_, and gets into the way, and using a goto is just much clearer.”
                Linus Torvalds – 12 janvier 2003

Hors ligne

#7 Le 18/02/2011, à 20:52

grim7reaper

Re : [Résolu]Problèmes avec les boucles en C

Pylade a écrit :

On pourrait parler de l'usage abusif de printf à la place de puts, par exemple…

En effet, pour une chaîne sans formatage il faut privilégier puts (ou fputs).

Les identificateur sont difficiles à lire et en français, donc ce n'est pas agréable à lire.

Je suis aussi plutôt favorable aux codes en anglais, mais sur ce point je laisse le développeur faire ce qu'il veut.

les lettres ne sont pas accentuées, mais ce dernier point peut se comprendre si l'on travaille dans un environnement où il vaut mieux n'utiliser que le set ASCII.

Pour les accents, je n'en utilise jamais dans les fichiers sources même si mon environnement les supporte. J'ai eu trop de mauvaises surprises en me déplaçant d'un environnement à l'autre (car je ne travaille pas toujours sur ma machine).

Dernière modification par grim7reaper (Le 18/02/2011, à 20:52)

Hors ligne

#8 Le 18/02/2011, à 21:27

Le Farfadet Spatial

Re : [Résolu]Problèmes avec les boucles en C

Salut à tous !

darkgilson a écrit :

Sinon, es-tu au courant de l'existence de « for » ?

Oui, je l'utilise surtout pour faire des recherches dans des tableaux par exemple. Personnellement, je trouve qu'une boucle classique while est plus claire niveau lisibilité. Question de goût smile

   Il n'y a pas qu'une question de goût. Pour l'instant, tes boucles sont simples, mais avec des boucles plus complexes, tu risques fort d'oublier de mettre à jour le compteur, où de le faire à un mauvais moment. Dès lors, le débogage va devenir compliqué. La logique du code doit être la plus évidente possible, donc, quand la logique est une boucle « pour », il faut utiliser « for ».

   Cela étant dit, les boucles « tant que » ne sont pas plus classiques que les boucles « pour ».

grim7reaper a écrit :

[HS]Au fait, pour ton livre sur le C++ as-tu pu remettre le serveur en ligne ?[/HS]

   Le serveur est en service, mais je me bats avec la configuration d'OBM. Du coup, le reste des services n'est pas activé. En plus, je reçois des amis cette semaine, donc je n'avance pas. Cela dit, tu as raison de me relancer, il faut que je me bouscule un peu, cela fait trop longtemps que ça traine.

Pylade a écrit :

Si tu voulais dire main à la place de void, non ce n'est pas bizarre, c'est même une très bonne façon de faire (mais comme l'a dit grim7reaper, c'est bien de placer les includes et les prototype dans un fichier d'en-tête à part).

   À mon sens, elle n'est ni meilleure ni plus mauvaise que l'autre. J'ai changé l'organisation un peu par habitude, parce que je n'ai pas fait le copier-coller d'un bloc et que par habitude j'évite les déclarations « forward » s'il n'y a pas une raison de récursivité (toujours dans l'idée de faire apparaître la logique du code). Cela dit, ça n'impacte en rien le code produit par le compilateur et ce n'est pas plus lisible. De toute façon, la bonne façon de faire, comme tout le monde l'a dit, c'est de répartir le code dans divers fichiers (toujours en faisant ressortir la logique du code).

grim7reaper a écrit :

Pour les accents, je n'en utilise jamais dans les fichiers sources même si mon environnement les supporte. J'ai eu trop de mauvaises surprises en me déplaçant d'un environnement à l'autre (car je ne travaille pas toujours sur ma machine).

   C'est d'ailleurs pour cela qu'existent différents outils pour localiser les codes.

   À bientôt.

Le Farfadet Spatial

Hors ligne

#9 Le 19/02/2011, à 14:39

ehmicky

Re : [Résolu]Problèmes avec les boucles en C

grim7reaper a écrit :
Pylade a écrit :

On pourrait parler de l'usage abusif de printf à la place de puts, par exemple…

En effet, pour une chaîne sans formatage il faut privilégier puts (ou fputs).

Je crois avoir vu récemment (par hasard) que gcc optimise et compile (en x86) :

printf("message");

avec un call puts, et pas printf, non ? (ce qui veut pas dire que printf("message") soit correct), mais j'ai pas de Linux sous la main pour vérifier.

Dernière modification par ehmicky (Le 19/02/2011, à 14:57)


Stego++, bibliothèque libre de stéganographie (avec cryptographie), à venir !
Besoin de votre aide :
Stats sur les compilateurs C++ les plus utilisés
Comment utiliser les archetypes C++ ?

Hors ligne

#10 Le 19/02/2011, à 14:48

grim7reaper

Re : [Résolu]Problèmes avec les boucles en C

Oui tout à fait, mais il ne vaut mieux pas compter sur les optimisations des compilateurs pour ce genre de choses (ça peut varier d'un compilo à l'autre, voire d'une version à l'autre d'un même compilo).

D'un point de vue sémantique (f)puts est plus juste que printf. Comme son nom l'indique printf est là pour produire des sorties formatées et (f)puts des simples chaînes de caractères. Autant écrire un code « correct » dès le départ smile

Dernière modification par grim7reaper (Le 19/02/2011, à 14:52)

Hors ligne