2009-12-02 6 views
1

Je suis actuellement en train de faire un projet pour une classe de programmation Beginner C où je suis supposé faire un système de commande de base pour une entreprise. J'ai un problème avec l'une de mes fonctions, cela fonctionne très bien en tant que programme séparé, mais en tant que fonction dans le programme de commande, il ne me laisse pas entrer un nouvel élément avant qu'il ne quitte la fonction. Il semble cependant parcourir tout après le get (item); comme je l'ai ajouté \ n chaque fois que je l'exécute.C Fonction sortant avant la saisie

Voici mon code:

do{ 
printf("Menu here"); 
scanf("%c", &menu); 
switch(menu) 
{ 
    case 'A': 
     listItem(); 
     break; 

    case 'B': 
     addItem(); 
     break; 

    ... 

    case 'X': 
     break; 
} 

printf("Press Enter to continue."); 
scanf("%c%c", &enter, &enter); 
system("cls"); 

}while(menu != 'X'); 


void addItem() 
{ 
    char item[30]; 
    printf("\nAdd new item: "); 
    gets(item); 
    FILE * output; 
    output = fopen("items.txt", "a"); 
    fputs(item, output); 
    fprintf(output, "\n"); 
    fclose(output); 
} 

les choses après que l'interrupteur est ce que ma pensée des enseignants serait un moyen laid mais efficace pour résoudre le fait que nous ne fouillons pas plus profondément dans ce qu'il a appelé les « bizarreries d'entrée C "dans ce cours.

Je suis reconnaissant pour tous les conseils et réponses et fournira plus de mon code si nécessaire.

+3

NE JAMAIS UTILISER GETS. DÉJÀ. –

Répondre

5

Ce qui se passe est la suivante:

  1. programme imprime le menu.
    • Types d'utilisateurs "B <enter>".
    • scanf lit le caractère B. Le <enter> attend toujours dans le flux d'entrée.
    • addItem est appelée.
    • gets() est appelée, lit le <enter> qui est toujours en attente et renvoie une ligne vide.

Vous pouvez corriger en lisant et en rejetant tout jusqu'au prochain saut de ligne après avoir lu le caractère de sélection de menu avec scanf:

int c; 

printf("Menu here"); 
scanf("%c", &menu); 
do { 
    c = getchar(); 
} while (c != EOF && c != '\n'); 
1

Une chose immédiate j'ai remarqué. Votre boucle do while vérifie val pour "X" alors que cette valeur est réellement dans menu.

Autre que cette possibilité (val peut être "X" pour commencer, ce qui pourrait provoquer la sortie de la boucle indépendamment de la valeur entrée), rien ne saute comme provoquant évidemment une sortie prématurée d'une fonction ou d'une boucle. Je pense que vous feriez mieux de poster votre base de code complet afin que nous ne devinions pas trop.

Mise à jour:

Ne pas utiliser les éléments suivants pour les devoirs - vous aurez presque certainement échoué pour le plagiat (puisque vos éducateurs, en supposant qu'ils ne sont pas fous au total, sera à la recherche de travail pris à partir de ces sites). Je voulais juste vous donner une idée de ce que vous pouvez utiliser pour les E/S de l'utilisateur afin de rendre vos programmes un peu plus robustes. Comme une âme utile l'a fait remarquer, vous ne devriez jamais utiliser les routines d'entrée qui n'ont pas de protection de dépassement de tampon en option car cela va certainement permettre à des intrusions malveillantes de bloquer votre code (c'est le cas le plus prendra en charge votre ordinateur).

Cela signifie non gets, vous devez utiliser fgets à la place, car il peut limiter la quantité d'informations réellement entrées. En outre, j'ai tendance à éviter l'utilisation de scanf et fscanf car toute défaillance de ces fonctions laisse en fait le pointeur du fichier d'entrée à un emplacement indéterminé.

Je trouve qu'il est préférable d'utiliser fgets pour obtenir une ligne entière, vérifiez que vous avez réellement obtenu une ligne entière, utilisez sscanf sur cette ligne. De cette façon, vous pouvez être sûr que vous êtes sur une limite de ligne, que vous avez une ligne entière et que vous pouvez alors sscanf cette ligne au contenu de votre coeur jusqu'à ce que vous le fassiez correspondre avec quelque chose.

À cette fin, vous pouvez regarder par-dessus le code suivant:

#include <stdio.h> 

#define FSPEC "file.txt" 

// Skip to the end of the line. This is used in some 
// places to ensure there's no characters left in the 
// input buffer. It basically discards characters 
// from that buffer until it reaches the end of a line. 

static void skipLine (void) { 
    char ch = ' '; 
    while ((ch != '\n') && (ch != EOF)) 
     ch = getchar(); 
} 

 

// Get a line of input from the user (with length checking). 

static char *getLine (char *prompt, char *line, int sz) { 
    // Output prompt, get line if available. 
    // If no line available (EOF/error), output newline. 

    printf ("%s", prompt); 
    if (fgets (line, sz, stdin) == NULL) { 
     printf ("\n"); 
     return NULL; 
    } 

    // If line was too long (no '\n' at end), throw away 
    // rest of line and flag error. 

    if (line[strlen (line) - 1] != '\n') { 
     skipLine(); 
     return NULL; 
    } 

    // Otherwise line was complete, return it. 

    return line; 
} 

 

// Output the menu and get a choice from the user. 

static char doMenu (void) { 
    char cmd[1+2]; // need space for char, '\n' and '\0'. 

    // Output the menu. 

    printf ("\n"); 

    printf ("\n"); 
    printf ("Main menu\n"); 
    printf ("---------\n"); 
    printf ("1. Input a line\n"); 
    printf ("2. Output the file\n"); 
    printf ("3. Clear the file\n"); 
    printf ("\n"); 
    printf ("x. Exit\n"); 
    printf ("\n"); 

    // Get the user input and return it. 

    if (getLine ("Enter choice (1,2,3,x): ", cmd, sizeof(cmd)) == NULL) 
     return '\n'; 

    printf ("\n"); 

    return cmd[0]; 
} 

 

static void doOption1 (void) { 
    FILE *fh; 
    char *ln; 
    char buff[15+2]; // need space for line, '\n' and '\0'. 

    // Get and check line, add to file if okay. 

    if ((ln = getLine ("Enter line: ", buff, sizeof(buff))) == NULL) { 
     printf ("Bad input line\n"); 
    } else { 
     fh = fopen (FSPEC, "a"); 
     if (fh != NULL) { 
      fputs (ln, fh); 
      fclose (fh); 
     } 
    } 
} 

 

static void doOption2 (void) { 
    FILE *fh; 
    int intch; 

    // Output the file contents. 

    printf ("=====\n"); 
    fh = fopen (FSPEC, "r"); 
    if (fh != NULL) { 
     while ((intch = fgetc (fh)) != EOF) 
      putchar (intch); 
     fclose (fh); 
    } 
    printf ("=====\n"); 
} 

 

static void doOption3 (void) { 
    FILE *fh; 

    // Clear the file. 

    fh = fopen (FSPEC, "w"); 
    if (fh != NULL) 
     fclose (fh); 
} 

 

// Main program basically just keeps asking the user for input 
// until they indicate they're finished. 

int main (void) { 
    char menuItem; 

    // Get asking for user input until exit is chosen. 

    while ((menuItem = doMenu()) != 'x') { 
     switch (menuItem) { 
      case '1': doOption1(); break; 
      case '2': doOption2(); break; 
      case '3': doOption3(); break; 
      default: printf ("Invalid choice\n"); break; 
     } 
    } 

    return 0; 
} 
+0

La coupure ne sortira que de l'instruction switch et non de la boucle while. – Lucas

+0

@Lucas, votre déclaration est correcte, mais je ne peux pas localiser où j'ai effectivement fait cette contention. J'ai déclaré que la boucle se terminerait si val avait la valeur "X", rien sur les instructions break qui sortent de la boucle. – paxdiablo

+0

le menu et le problème de val est moi foutant ma traduction de mes variables en anglais, j'ai manqué de changer le dernier val au menu, la condition de boucle est valide dans mon code original –

1

Vous lisez un caractère à la fois, et scanf() est en train de faire une mise en mémoire tampon. Si je tape "ABC" et appuyez sur Entrée, votre programme va lire "A", faire l'action pour "A", imprimer "Appuyez sur Entrée pour continuer", lire "B" et "C" dans le scanf qui suit immédiatement. Alors, bien sûr, ça va revenir tôt; vous lui avez déjà donné des informations, à savoir 'B' et 'C'.

Je vous suggère d'utiliser une autre méthode de saisie. Par exemple, vous pouvez passer aux commandes basées sur des lignes (en utilisant peut-être fgets()), ce qui vous oblige à appuyer sur Entrée à chaque étape. Ou vous pouvez utiliser curses ou toute autre chose spécifique à la plate-forme dont vous avez besoin pour faire une entrée non-bufférisée, de sorte que vous réagissez aux touches enfoncées et non à la mémoire tampon fournie par stdio.