fgets funktioniert nicht nach scanf [duplicate]

Lesezeit: 9 Minuten
#include <stdio.h>
#include <string.h>
#include <ctype.h>

void delspace(char *str);

int main() {
    int i, loops;
    char s1[101], s2[101];

    scanf("%d", &loops);

    while (loops--) {
        fgets(s1, 101, stdin);
        fgets(s2, 101, stdin);
        s1[strlen(s1)] = '\0';
        s2[strlen(s2)] = '\0';

        if (s1[0] == '\n' && s2[0] == '\n') {
            printf("YES\n");
            continue;
        }

        delspace(s1);
        delspace(s2);

        for (i = 0; s1[i] != '\0'; i++)
            s1[i] = tolower(s1[i]);

        for (i = 0; s2[i] != '\0'; i++)
            s2[i] = tolower(s2[i]);

        if (strcmp(s1, s2) == 0) {
            printf("YES\n");
        }
        else {
            printf("NO\n");
        }
    }

    return 0;
}

void delspace(char* str) {
    int i = 0;
    int j = 0;
    char sTmp[strlen(str)];

    while (str[i++] != '\0') {
        if (str[i] != ' ') {
            sTmp[j++] = str[i];
        }
    }
    sTmp[j] = '\0';
    strcpy(str, sTmp);
}

Nachdem ich “loops” eingegeben habe, wurde “s1” automatisch eine Leerzeile zugewiesen. Wie passiert es? Ich bin mir sicher, dass meine Tastatur einwandfrei funktioniert.

  • “Ich bin sicher, meine Tastatur funktioniert gut.” Lol!

    – orlp

    6. Mai 2011 um 23:38 Uhr

  • Eine Variante dieser Frage scheint hier jeden Tag oder so gestellt zu werden.

    – Jim Balter

    7. Mai 2011 um 0:10 Uhr

  • Die Funktion delspace ist definitiv falsch! Dies wird konvertieren abc\0 zu bc\0.

    – TrueY

    17. Februar 2016 um 23:29 Uhr

  • Faustregel: Bei interaktiven Eingaben immer lesen Linien.

    – Karoly Horvath

    3. September 2016 um 11:06 Uhr

  • Siehe auch: stackoverflow.com/questions/5240789/…

    – Melpomen

    1. Oktober 2019 um 17:54 Uhr

scanf() liest genau das, worum Sie es gebeten haben, und hinterlässt das Folgende \n vom Ende dieser Zeile im Puffer wo fgets() werde es lesen. Entweder etwas tun, um den Zeilenumbruch zu verbrauchen, oder (meine bevorzugte Lösung) fgets() und dann sscanf() aus dieser Saite.

  • Wenn ich verwenden möchte scanf(), wie kann ich die neue Leitung konsumieren? Vielen Dank.

    – Vain

    6. Mai 2011 um 23:59 Uhr

  • Verwenden Sie so etwas wie %*[^\n]%*c am Ende des Formats, um alle Zeichen bis zum Zeilenumbruch zu überspringen, gefolgt vom Zeilenumbruch selbst.

    – Geekosaurier

    7. Mai 2011 um 0:07 Uhr

  • @geekosaur: Nur heften %*[^\n]%*c an das Ende des Formats funktioniert nicht wirklich, wenn nach dem vorherigen gelesenen Ding und vor dem Zeilenumbruch KEINE Zeichen stehen, wie dann das %*[^\n] wird nicht übereinstimmen, so dass die %*c wird übersprungen und der Zeilenumbruch bleibt bei der Eingabe. Sie müssen das tun %*c in einem separaten Scanf-Aufruf, damit es funktioniert.

    – Chris Dodd

    16. Mai 2016 um 1:59 Uhr


Benutzer-Avatar
Umarmung

scanf hinterlässt Leerzeichen im Eingabepuffer, einschließlich Zeilenumbruchzeichen. Um fgets zum Lesen der nächsten Zeile zu verwenden, müssen Sie den Rest der aktuellen Zeile manuell entfernen:

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

  • Ja, das wird auch funktionieren, aber ich persönlich verwende nur fgets und dann sscanf (wie von geekosaur vorgeschlagen), weil es “einheitlich” für alle Arten von Daten funktioniert … nicht nur für einzelne Zeichen. Und ich mag “generische Mehrzwecklösungen”. Prost. Keith.

    – corlettk

    7. Mai 2011 um 0:32 Uhr

  • Dies funktioniert jedoch für mehr als einen Charakter – dafür ist die Schleife da;)

    – Umarmung

    7. Mai 2011 um 1:22 Uhr

  • while(c != EOF && c != '\n'); ist nicht gut. c ist außerhalb des Geltungsbereichs.

    – chux – Wiedereinsetzung von Monica

    23. Februar 2018 um 0:50 Uhr

  • Ich wollte mich entschuldigen, indem ich sagte, dass ich C- und Lua-Scoping-Regeln gemischt haben muss, aber anscheinend stammt diese Antwort, bevor ich Lua gelernt habe, hahaha.

    – Umarmung

    23. Februar 2018 um 2:45 Uhr


Benutzer-Avatar
Shubham Pawar

Dies ist eine einfachere Lösung

scanf("%d",&loops);
while ((getchar()) != '\n'); //This will consume the '\n' char
//now you're free to use fgets
fgets(string,sizeof(string),stdin);

Benutzer-Avatar
corlettk

Geekosaur hat Ihre Frage gut beantwortet, ich weise nur auf ein anderes “Problem” mit Ihrem Code hin.

Die Linie s1[strlen(s1)] = '\0'; ist ein no-op wenn s1 ist bereits richtig nullterminiert, BEVOR es ausgeführt wird.

Doch wenn s1 NICHT bereits ordnungsgemäß nullterminiert ist, BEVOR diese Zeile ausgeführt wird (und Sie Pech haben), wird dies Folgendes verursachen:

  • a SIGSEGV auf einem POSIX (*nix)-System.
  • a GPF unter Windows.

Das ist weil strlen findet im Grunde den Index der vorhandener Nullterminator und gibt es zurück! Hier ist eine gültige, nicht optimierte Implementierung von strlen:

int strlen(char *string) {
    int i = 0;
    while(string[i] != '\0') {
        ++i;
    }
    return i;
}

Also … Wenn Sie WIRKLICH besorgt sind, dass Strings NICHT nullterminiert sind, dann würden Sie so etwas tun:

  • string[sizeof(string)]='\0'; an lokal automatische Zeichenfolgen (wobei der Compiler die Größe der Zeichenfolge „kennt“);
  • oder string[SIZE_OF_STRING] für alle anderen Saiten, wo SIZE_OF_STRING ist (am häufigsten) a #define‘d-Konstante oder eine Variable, die Sie speziell pflegen, um die aktuelle Größe (nicht die Länge) einer dynamisch zugewiesenen Zeichenfolge zu speichern.

Und wenn Sie WIRKLICH, WIRKLICH, WIRKLICH besorgt sind, dass Zeichenfolgen nicht nullterminiert sind (als ob Sie es mit “schmutzigen” Bibliotheksmethoden (wie zum Beispiel ATMI von Tuxedo) zu tun haben) Sie AUCH “löschen” Sie Ihre “Rückgabezeichenfolgen”, bevor Sie sie an die verdächtigen Bibliotheksmethoden übergeben, mit:

  • Vor:memset(string, NULL, SIZE_OF_STRING);
  • aufrufen: DirtyFunction(/*out*/string);
  • nach: string[SIZE_OF_STRING]='\0'

SIG11’s sind ein komplettes Biatch zu finden, weil (es sei denn, Sie “haken” sie mit einem Signalprozessor und anders sagen, sie veranlassen Unix, Ihr Programm hart zu beenden, sodass Sie (im Nachhinein) nichts protokollieren können, um herauszufinden, woher zum Teufel das kam … besonders wenn man bedenkt dass in vielen Fällen die Codezeile, die das SIG11 auslöst, bei weitem nicht die eigentliche Ursache dafür ist, dass die Zeichenfolge ihren Nullterminator verliert.

Macht das für Sie Sinn?

PS: ACHTUNG: strncpy beendet NICHT immer null … Sie meinten wahrscheinlich strlcpy stattdessen. Ich habe das auf die harte Tour gelernt … als ein 60-Millionen-Dollar-Abrechnungslauf zusammenbrach.


BEARBEITEN:

FYI: Hier ist eine “sichere” (nicht optimierte) Version von strlen, die ich aufrufen werde strnlen (Ich denke, das sollte drin sein string.h. Seufzen.).

// retuns the length of the string (capped at size-1)
int strnlen(char *string, int size) {
    int i = 0;
    while( i<size && string[i]!='\0' ) {
        ++i;
    }
    return i;
}

Benutzer-Avatar
phantom_ab

einfach setzen
scanf("%d\n",&loops);

Anstatt von
scanf("%d",&loops);

  • Während diese Antwort ein wichtiges Phänomen des ursprünglichen Problems abdeckt, bietet sie keinen Einblick in das Problem selbst. Daher ist es bestenfalls hilfreich, um das ursprüngliche Problem zu ermitteln, und auf lange Sicht nicht wirklich hilfreich. Bitte fügen Sie weitere Erklärungen hinzu, damit Ihre Antwort für spätere Leser hilfreich ist, die nach ähnlichen Problemen suchen.

    – rpi

    12. September 2016 um 13:48 Uhr

  • Fügen Sie keine abschließenden Leerzeichen am Ende von a ein scanf() format string – es unterbricht die UI/UX vollständig, da die Eingabe nicht aufhört, bis Sie etwas anderes als Leerzeichen eingeben (und Zeilenumbrüche sind Leerzeichen). Das bedeutet, dass der Benutzer vorhersagen muss, was die nächste Eingabe sein muss. Sehen [What is the effect of trailing white space in a scanf() format string?](stackoverflow.com/q/19499060/10ths 5168)

    – Jonathan Leffler

    8. Januar um 15:22 Uhr

Benutzer-Avatar
ChandanK

Eine andere Möglichkeit, das folgende Zeilenumbruchzeichen (aufgrund des Drückens der EINGABETASTE) nach dem Scannen der Ganzzahl in variablen Label-Schleifen zu ignorieren, ist:

scanf ("%d%*c", &loops);

Wo, gemäß den Manpages:

* Unterdrückt die Zuweisung. Die folgende Konvertierung erfolgt wie gewohnt, es wird jedoch kein Zeiger verwendet; das Ergebnis der Konvertierung wird einfach verworfen.

Dies ist sehr unwahrscheinlich, aber eine gute Angewohnheit, während scanf nach Fehlern zu suchen:

errno = 0
scanf ("%d%*c", &loops);
if (errno != 0) perror ("scanf");
// act accordingly to avoid un-necessary bug in the code

In Ihrem Code ist loops beispielsweise eine lokale, nicht initialisierte Variable, die Datenmüll enthält. Wenn scanf den gewünschten Wert nicht füllt, kann die folgende While-Schleife willkürlich ausgeführt werden.

  • Während diese Antwort ein wichtiges Phänomen des ursprünglichen Problems abdeckt, bietet sie keinen Einblick in das Problem selbst. Daher ist es bestenfalls hilfreich, um das ursprüngliche Problem zu ermitteln, und auf lange Sicht nicht wirklich hilfreich. Bitte fügen Sie weitere Erklärungen hinzu, damit Ihre Antwort für spätere Leser hilfreich ist, die nach ähnlichen Problemen suchen.

    – rpi

    12. September 2016 um 13:48 Uhr

  • Fügen Sie keine abschließenden Leerzeichen am Ende von a ein scanf() format string – es unterbricht die UI/UX vollständig, da die Eingabe nicht aufhört, bis Sie etwas anderes als Leerzeichen eingeben (und Zeilenumbrüche sind Leerzeichen). Das bedeutet, dass der Benutzer vorhersagen muss, was die nächste Eingabe sein muss. Sehen [What is the effect of trailing white space in a scanf() format string?](stackoverflow.com/q/19499060/10ths 5168)

    – Jonathan Leffler

    8. Januar um 15:22 Uhr

scanf() Lassen Sie das folgende \n vom Ende dieser Zeile im Puffer wo fgets() werde es lesen. Um dies zu verlangsamen, müssen wir etwas tun, um den Zeilenumbruch zu verbrauchen. Sehen wir uns das Problem an.

Das Problem

#include<stdio.h>
void main()
{
    char input[10];
    printf("Enter in fgets: ");
    scanf("%s", input);
    getchar();
    printf("Enter in scanf: ");
    fgets(input, 10, stdin);
}

Ausgabe:

Enter in scanf: Hello
Enter in fgets:

Wie Sie sehen können, wird der fgets-Teil nicht angezeigt. Sehen wir uns die Lösung an.

Stellen getchar() zwischen scanf und fgets()

#include<stdio.h>
void main()
{
    char input[10];
    printf("Enter in fgets: ");
    scanf("%s", input);
    getchar();
    printf("Enter in scanf: ");
    fgets(input, 10, stdin);
}

Ausgabe:

Enter in scanf: Hello
Enter in fgets: Hello

Wenn es möglich ist, verwenden scanf() nach dem fgets()

#include<stdio.h>
void main()
{
    char input[10];
    printf("Enter in fgets: ");
    fgets(input, 10, stdin);
    getchar();
    printf("Enter in scanf: ");
    scanf("%s", input);
}

Ausgabe:

Enter in fgets: Hello
Enter in scanf: Hello

Stellen fget() 2 mal (Diese Methode funktioniert einige Zeit nicht)

#include<stdio.h>
void main()
{
    char input[10];
    printf("Enter in fgets: ");
    scanf("%s", input);
    getchar();
    printf("Enter in scanf: ");
    fgets(input, 10, stdin);
    fgets(input, 10, stdin)
}

Ausgabe:

Enter in scanf: Hello
Enter in fgets: Hello

Stellen sscanf() eingefügt von scanf()

#include<stdio.h>
void main()
{
    char input[10];
    printf("Enter in fgets: ");
    sscanf(hello, "%s", input);
    getchar();
    printf("Enter in scanf: ");
    fgets(input, 10, stdin);
}

Ausgabe:

Enter in sscanf: Hello
Enter in fgets: Hello

  • Würden Sie darauf näher eingehen? ZB ein Beispiel geben.

    – Elis Byberi

    3. März 2020 um 18:37 Uhr

1215520cookie-checkfgets funktioniert nicht nach scanf [duplicate]

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

Privacy policy