Wie liest man von stdin mit fgets()?

Lesezeit: 8 Minuten

Benutzeravatar von robdavies35
robdavies35

Ich habe den folgenden Code geschrieben, um eine Zeile aus einem Terminalfenster zu lesen. Das Problem ist, dass der Code in einer Endlosschleife hängen bleibt. Die Zeile/der Satz hat eine undefinierte Länge, daher plane ich, sie in Teilen in den Puffer einzulesen und sie dann mit einer anderen Zeichenfolge zu verketten, die über erweitert werden kann realloc entsprechend. Kann bitte jemand meinen Fehler erkennen oder einen besseren Weg vorschlagen, dies zu erreichen?

#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;
}

  • Scheint ziemlich ok, wann soll die Schleife enden? So wie es jetzt ist, können Sie es beenden, indem Sie Strg + D auf * nix oder Strg + Z unter Windows drücken.

    – Nr

    12. Oktober 2010 um 21:08 Uhr

  • Ich sehe nichts offensichtlich Falsches am Code – wenn Sie “in einer Endlosschleife stecken” sagen, was meinen Sie genau?

    – PaulR

    12. Oktober 2010 um 21:09 Uhr

Benutzeravatar von user411313
Benutzer411313

hier eine Verkettungslösung:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFERSIZE 10

int main() {
  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);
  return 0;
}

  • Warum zum +1 auf dieser Zeile: text = realloc( text, strlen(text)+1+strlen(buffer) ); ?

    – Gonidelis

    10. Januar 2019 um 13:23 Uhr


  • @johngonidelis eine Zeichenfolge wird als eine Reihe von ASCII-Werten der Zeichen gespeichert, mit einem einzelnen Zeichen am Ende mit dem Binärwert ‘0’. strlen() zählt nur die tatsächlichen Buchstaben, aber wenn Sie Platz für Ihren eigenen String anlegen, müssen Sie ein weiteres einzelnes Leerzeichen für das Nullbyte einfügen. Diese Zeile enthält die Anzahl der Zeichen, die bereits im Text enthalten sind, plus die Anzahl der Zeichen im Puffer, plus Platz für ein einzelnes Null-Byte, um das Ende der Zeichenfolge anzuzeigen.

    – Wilhelm

    9. Mai 2019 um 21:33 Uhr

Sie haben eine falsche Vorstellung davon, was fgets zurückgibt. Schau dir das an: http://www.cplusplus.com/reference/clibrary/cstdio/fgets/

Es gibt null zurück, wenn es ein EOF-Zeichen findet. Versuchen Sie, das obige Programm auszuführen und STRG+D zu drücken (oder welche Kombination auch immer Ihr EOF-Zeichen ist), und die Schleife wird erfolgreich beendet.

Wie möchten Sie das Ende der Eingabe erkennen? Neue Zeile? Dot (Du sagtest Satz xD)?

  • Das Ende der Eingabe sollte ein Zeilenumbruch sein

    – robdavies35

    12. Oktober 2010 um 21:19 Uhr

  • Scannen Sie Ihren Puffer nach Zeilenumbrüchen, dann 🙂

    – sležica

    12. Oktober 2010 um 21:21 Uhr

Benutzeravatar von sapitando
sapitando

Beendet die Schleife, wenn die Zeile leer ist (Verbesserungscode).

#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;
}

Beenden, wenn die Eingabetaste gedrückt wird.

#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;
}

Verkettung und dynamische Zuordnung (verkettete Liste) zu einer einzelnen Zeichenfolge.

/* 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;
}

  • Liege ich falsch, oder wird die Schleife nur verlassen, wenn die leere Zeile direkt nach einer BUFFERSIZE-Grenze kommt?

    – Alain Becker

    12. September 2016 um 15:30 Uhr

  • @Alain BECKER Ich habe den Code verbessert (glaube ich), wirklich aus der Schleife in diesem Ereignis, aber jetzt verlässt er nur, wenn die Zeile leer ist (Drücken der Eingabetaste, ohne etwas einzugeben), ich habe mit TDM-GCC und LCC getestet.

    – Sapitando

    13. September 2016 um 17:39 Uhr

  • Es macht wirklich nicht viel Sinn, (a) eine Wand mit Code (b) ohne Erklärung zu (c) einer 6 Jahre alten Frage zu posten, die (d) bereits gute Antworten hat.

    – PaulR

    14. September 2016 um 6:12 Uhr

  • @ Paul R Wenn Sie den Code ausführen, werden Sie sehen, dass er selbsterklärend ist und keine Antwort zufriedenstellend ist (Schleife mit Ctrl + Z verlassen) oder so, und ich bin Neuling darin, ich habe diese Frage als Übungsweg verwendet.

    – Sapitando

    14. September 2016 um 6:30 Uhr

Benutzeravatar von Steve Emmerson
Steve Emmerson

Angenommen, Sie möchten nur eine einzige Zeile lesen, dann verwenden Sie LINE_MAXdie in definiert ist <limits.h>:

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

Wenn Sie die Eingabe verketten möchten, ersetzen Sie sie printf("%s\n", buffer); mit strcat(big_buffer, buffer);. Erstellen und initialisieren Sie auch den großen Puffer am Anfang: char *big_buffer = new char[BIG_BUFFERSIZE]; big_buffer[0] = '\0';. Sie sollten auch einen Pufferüberlauf verhindern, indem Sie überprüfen, ob die aktuelle Pufferlänge plus die neue Pufferlänge das Limit nicht überschreiten: if ((strlen(big_buffer) + strlen(buffer)) < BIG_BUFFERSIZE). Das modifizierte Programm würde wie folgt aussehen:

#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;
}

  • new ist C++, aber die Frage bezieht sich auf C

    – Spikatrix

    16. März 2017 um 3:19 Uhr

Benutzeravatar von Sohit Gore
Sohit Gore

Überprüfen Sie die Länge der Zeichenfolge, die jedes Mal in den Puffer eingelesen wird, und verwenden Sie diese, um aus der Schleife auszubrechen.

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

#define LEN 10

int main()
{
        char buffer[LEN];
        char *str = calloc(LEN,sizeof(char));
        short flag = 0;
        while(!flag && fgets(buffer, LEN, stdin))       
        {
                str = realloc(str, strlen(str)+strlen(buffer)+1);
                if(!str) exit(1);
                if(strlen(buffer) != LEN-1)
                        flag = 1;
                strcat(str,buffer);
        }
        printf("%s",str);
        return 0;
}

  • new ist C++, aber die Frage bezieht sich auf C

    – Spikatrix

    16. März 2017 um 3:19 Uhr

1406500cookie-checkWie liest man von stdin mit fgets()?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy