2010-10-12 9 views
21

J'ai écrit le code suivant pour lire une ligne à partir d'une fenêtre de terminal, le problème est que le code est bloqué dans une boucle infinie. La ligne/phrase est de longueur indéfinie, donc j'ai l'intention de la lire en partie dans la mémoire tampon, puis de la concaténer à une autre chaîne qui peut être étendue par realloc en conséquence. S'il vous plaît quelqu'un peut repérer mon erreur ou suggérer une meilleure façon d'y parvenir?Comment lire depuis stdin avec fgets()?

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

#define BUFFERSIZE 10 

int main (int argc, char *argv[]) 
{ 
    char buffer[BUFFERSIZE]; 
    printf("Enter a message: \n"); 
    while(fgets(buffer, BUFFERSIZE , stdin) != NULL) 
    { 
     printf("%s\n", buffer); 
    } 
    return 0; 
} 
+0

Cela semble plutôt correct, quand voulez-vous que la boucle se termine? Comme il est maintenant, vous pouvez le terminer en appuyant sur ctrl + d sur * nix ou ctrl + z sur Windows. – nos

+1

Je ne vois rien de mal dans le code - quand vous dites "coincé dans une boucle infinie", que voulez-vous dire exactement? –

+0

Ma boule de cristal me dit que Paul R a cloué le problème. La solution consiste à placer 'printf' dans la boucle. – pmg

Répondre

14

ici une solution de concaténation:

char *text = calloc(1,1), buffer[BUFFERSIZE]; 
printf("Enter a message: \n"); 
while(fgets(buffer, BUFFERSIZE , stdin)) /* break with ^D or ^Z */ 
{ 
    text = realloc(text, strlen(text)+1+strlen(buffer)); 
    if(!text) ... /* error handling */ 
    strcat(text, buffer); /* note a '\n' is appended here everytime */ 
    printf("%s\n", buffer); 
} 
printf("\ntext:\n%s",text); 
4

Vous avez une mauvaise idée de ce que retourne fgets. Jetez un oeil à ceci: http://www.cplusplus.com/reference/clibrary/cstdio/fgets/

Il renvoie null lorsqu'il trouve un caractère EOF. Essayez d'exécuter le programme ci-dessus et appuyez sur CTRL + D (ou quelle que soit la combinaison est votre caractère EOF), et la boucle se terminera avec succès.

Comment voulez-vous détecter la fin de l'entrée? Nouvelle ligne? Dot (vous avez dit la phrase xD)?

+0

la fin de l'entrée devrait être une nouvelle ligne – robdavies35

+0

Scannez votre tampon pour les retours à la ligne, puis :) – slezica

1

En supposant que vous ne souhaitez que lire une seule ligne, utilisez LINE_MAX, qui est défini dans <limits.h>:

#include <stdio.h> 
... 
char line[LINE_MAX]; 
... 
if (fgets(line, LINE_MAX, stdin) != NULL) { 
... 
} 
... 
+3

LINE_MAX n'est pas C89 ou C99, son seul compilateur spécifique – user411313

+1

Funny vous montrer un code en utilisant 'LINE_MAX' sans inclure' limits.h' –

0

Si vous voulez concaténer la entrée, puis remplacez printf("%s\n", buffer); par strcat(big_buffer, buffer);. Créez également et initialisez le grand tampon au début: char *big_buffer = new char[BIG_BUFFERSIZE];big_buffer[0] = '\0';. Vous devez également empêcher un dépassement de mémoire tampon en vérifiant la longueur du tampon en cours et la longueur du nouveau tampon ne dépasse pas la limite: if ((strlen(big_buffer) + strlen(buffer)) < BIG_BUFFERSIZE). Le programme modifié ressemblerait à ceci:

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

#define BUFFERSIZE 10 
#define BIG_BUFFERSIZE 1024 

int main (int argc, char *argv[]) 
{ 
    char buffer[BUFFERSIZE]; 
    char *big_buffer = new char[BIG_BUFFERSIZE]; 
    big_buffer[0] = '\0'; 
    printf("Enter a message: \n"); 
    while(fgets(buffer, BUFFERSIZE , stdin) != NULL) 
    { 
     if ((strlen(big_buffer) + strlen(buffer)) < BIG_BUFFERSIZE) 
     { 
      strcat(big_buffer, buffer); 
     } 
    } 
    return 0; 
} 
+0

'new' est C++ mais la question est à propos de C –

1

Quitte la boucle si la ligne est vide (Amélioration du code).

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

// The value BUFFERSIZE can be changed to customer's taste . Changes the 
// size of the base array (string buffer)  
#define BUFFERSIZE 10 

int main(void) 
{ 
    char buffer[BUFFERSIZE]; 
    char cChar; 
    printf("Enter a message: \n"); 
    while(*(fgets(buffer, BUFFERSIZE, stdin)) != '\n') 
    { 
     // For concatenation 
     // fgets reads and adds '\n' in the string , replace '\n' by '\0' to 
     // remove the line break . 
/*  if(buffer[strlen(buffer) - 1] == '\n') 
      buffer[strlen(buffer) - 1] = '\0'; */ 
     printf("%s", buffer); 
     // Corrects the error mentioned by Alain BECKER.  
     // Checks if the string buffer is full to check and prevent the 
     // next character read by fgets is '\n' . 
     if(strlen(buffer) == (BUFFERSIZE - 1) && (buffer[strlen(buffer) - 1] != '\n')) 
     { 
      // Prevents end of the line '\n' to be read in the first 
      // character (Loop Exit) in the next loop. Reads 
      // the next char in stdin buffer , if '\n' is read and removed, if 
      // different is returned to stdin 
      cChar = fgetc(stdin); 
      if(cChar != '\n') 
       ungetc(cChar, stdin); 
      // To print correctly if '\n' is removed. 
      else 
       printf("\n"); 
     } 
    } 
    return 0; 
} 

Quitter lorsque vous appuyez sur Entrée.

#include <stdio.h> 
#include <stdbool.h> 
#include <string.h> 
#include <assert.h> 

#define BUFFERSIZE 16 

int main(void) 
{ 
    char buffer[BUFFERSIZE]; 
    printf("Enter a message: \n"); 
    while(true) 
    { 
     assert(fgets(buffer, BUFFERSIZE, stdin) != NULL); 
     // Verifies that the previous character to the last character in the 
     // buffer array is '\n' (The last character is '\0') if the 
     // character is '\n' leaves loop. 
     if(buffer[strlen(buffer) - 1] == '\n') 
     { 
      // fgets reads and adds '\n' in the string, replace '\n' by '\0' to 
      // remove the line break . 
      buffer[strlen(buffer) - 1] = '\0'; 
      printf("%s", buffer); 
      break; 
     } 
     printf("%s", buffer); 
    } 
    return 0; 
} 

Concaténation et allocation dynamique (liste chaînée) en une seule chaîne.

/* Autor : Tiago Portela 
    Email : [email protected] 
    Sobre : Compilado com TDM-GCC 5.10 64-bit e LCC-Win32 64-bit; 
    Obs : Apenas tentando aprender algoritimos, sozinho, por hobby. */ 

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

#define BUFFERSIZE 8 

typedef struct _Node { 
    char *lpBuffer; 
    struct _Node *LpProxNode; 
} Node_t, *LpNode_t; 

int main(void) 
{ 
    char acBuffer[BUFFERSIZE] = {0}; 
    LpNode_t lpNode = (LpNode_t)malloc(sizeof(Node_t)); 
    assert(lpNode!=NULL); 
    LpNode_t lpHeadNode = lpNode; 
    char* lpBuffer = (char*)calloc(1,sizeof(char)); 
    assert(lpBuffer!=NULL); 
    char cChar; 


    printf("Enter a message: \n"); 
    // Exit when Enter is pressed 
/* while(true) 
    { 
     assert(fgets(acBuffer, BUFFERSIZE, stdin)!=NULL); 
     lpNode->lpBuffer = (char*)malloc((strlen(acBuffer) + 1) * sizeof(char)); 
     assert(lpNode->lpBuffer!=NULL); 
     strcpy(lpNode->lpBuffer, acBuffer); 
     if(lpNode->lpBuffer[strlen(acBuffer) - 1] == '\n') 
     { 
      lpNode->lpBuffer[strlen(acBuffer) - 1] = '\0'; 
      lpNode->LpProxNode = NULL; 
      break; 
     } 
     lpNode->LpProxNode = (LpNode_t)malloc(sizeof(Node_t)); 
     lpNode = lpNode->LpProxNode; 
     assert(lpNode!=NULL); 
    }*/ 

    // Exits the loop if the line is empty(Improving code). 
    while(true) 
    { 
     assert(fgets(acBuffer, BUFFERSIZE, stdin)!=NULL); 
     lpNode->lpBuffer = (char*)malloc((strlen(acBuffer) + 1) * sizeof(char)); 
     assert(lpNode->lpBuffer!=NULL); 
     strcpy(lpNode->lpBuffer, acBuffer); 
     if(acBuffer[strlen(acBuffer) - 1] == '\n') 
      lpNode->lpBuffer[strlen(acBuffer) - 1] = '\0'; 
     if(strlen(acBuffer) == (BUFFERSIZE - 1) && (acBuffer[strlen(acBuffer) - 1] != '\n')) 
     { 
      cChar = fgetc(stdin); 
      if(cChar != '\n') 
       ungetc(cChar, stdin); 
     } 
     if(acBuffer[0] == '\n') 
     { 
      lpNode->LpProxNode = NULL; 
      break; 
     } 
     lpNode->LpProxNode = (LpNode_t)malloc(sizeof(Node_t)); 
     lpNode = lpNode->LpProxNode; 
     assert(lpNode!=NULL); 
    } 


    printf("\nPseudo String :\n"); 
    lpNode = lpHeadNode; 
    while(lpNode != NULL) 
    { 
     printf("%s", lpNode->lpBuffer); 
     lpNode = lpNode->LpProxNode; 
    } 


    printf("\n\nMemory blocks:\n"); 
    lpNode = lpHeadNode; 
    while(lpNode != NULL) 
    { 
     printf("Block \"%7s\" size = %lu\n", lpNode->lpBuffer, (long unsigned)(strlen(lpNode->lpBuffer) + 1)); 
     lpNode = lpNode->LpProxNode; 
    } 


    printf("\nConcatenated string:\n"); 
    lpNode = lpHeadNode; 
    while(lpNode != NULL) 
    { 
     lpBuffer = (char*)realloc(lpBuffer, (strlen(lpBuffer) + strlen(lpNode->lpBuffer)) + 1); 
     strcat(lpBuffer, lpNode->lpBuffer); 
     lpNode = lpNode->LpProxNode; 
    } 
    printf("%s", lpBuffer); 
    printf("\n\n"); 

    // Deallocate memory 
    lpNode = lpHeadNode; 
    while(lpNode != NULL) 
    { 
     lpHeadNode = lpNode->LpProxNode; 
     free(lpNode->lpBuffer); 
     free(lpNode); 
     lpNode = lpHeadNode; 
    } 
    lpBuffer = (char*)realloc(lpBuffer, 0); 
    lpBuffer = NULL; 
    if((lpNode == NULL) && (lpBuffer == NULL)) 
    { 

     printf("Deallocate memory = %s", (char*)lpNode); 
    } 
    printf("\n\n"); 

    return 0; 
} 
+0

Ai-je tort, ou la boucle n'est-elle terminée que si la ligne vide vient juste après une limite BUFFERSIZE? –

+0

@Alain BECKER J'ai amélioré le code (je suppose), vraiment hors de la boucle dans cet événement, mais ne laisse maintenant que si la ligne est vide (en appuyant sur Entrée sans rien taper), j'ai testé avec TDM-GCC et LCC. – sapitando

+0

Il n'y a vraiment pas grand intérêt à (a) afficher un mur de code (b) sans explication à (c) une question vieille de 6 ans qui (d) a déjà de bonnes réponses. –

Questions connexes