Wie erlauben Sie die Eingabe von Leerzeichen mit scanf?

Lesezeit: 6 Minuten

Benutzeravatar von Kredns
Kredns

Unter Verwendung des folgenden Codes:

char *name = malloc(sizeof(char) + 256); 

printf("What is your name? ");
scanf("%s", name);

printf("Hello %s. Nice to meet you.\n", name);

Ein Benutzer kann seinen Namen eingeben, aber wenn er einen Namen mit einem Leerzeichen wie eingibt Lucas Aardvark, scanf() schneidet einfach alles danach ab Lucas. Wie mache ich scanf() Leerzeichen zulassen

  • Beachten Sie, dass idiomatischer ‘malloc(sizeof(char) * 256 + 1)’ oder ‘malloc(256 + 1)’ oder noch besser (vorausgesetzt, ‘name’ wird strikt lokal verwendet) ‘char name’ ist[256+1]’. Das ‘+1’ kann als mneumonic für das Null-Terminator dienen, das in die Zuweisung aufgenommen werden muss.

    – Barry Kelly

    8. August 2009 um 4:47 Uhr

  • @Barry – Ich vermute sizeof(char) + 256 war ein Tippfehler.

    – Chris Lutz

    20. Juli 2011 um 22:06 Uhr

Benutzeravatar von paxdiablo
paxdiablo

Leute und besonders Anfänger) sollten niemals verwendet werden scanf("%s") oder gets() oder andere Funktionen, die keinen Pufferüberlaufschutz haben, es sei denn, Sie wissen mit Sicherheit, dass die Eingabe immer ein bestimmtes Format haben wird (und vielleicht nicht einmal dann).

Denken Sie daran, als scanf steht für “scan formatted” und es gibt herzlich wenig weniger formatiert als vom Benutzer eingegebene Daten. Es ist ideal, wenn Sie die vollständige Kontrolle über das Eingabedatenformat haben, aber im Allgemeinen nicht für Benutzereingaben geeignet sind.

Verwenden fgets() (die hat Pufferüberlaufschutz), um Ihre Eingabe in einen String zu bekommen und sscanf() es auszuwerten. Da Sie nur das wollen, was der Benutzer ohne Parsing eingegeben hat, brauchen Sie es nicht wirklich sscanf() jedenfalls in diesem Fall:

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

/* Maximum name size + 1. */

#define MAX_NAME_SZ 256

int main(int argC, char *argV[]) {
    /* Allocate memory and check if okay. */

    char *name = malloc(MAX_NAME_SZ);
    if (name == NULL) {
        printf("No memory\n");
        return 1;
    }

    /* Ask user for name. */

    printf("What is your name? ");

    /* Get the name, with size limit. */

    fgets(name, MAX_NAME_SZ, stdin);

    /* Remove trailing newline, if there. */

    if ((strlen(name) > 0) && (name[strlen (name) - 1] == '\n'))
        name[strlen (name) - 1] = '\0';

    /* Say hello. */

    printf("Hello %s. Nice to meet you.\n", name);

    /* Free memory and exit. */

    free (name);
    return 0;
}

  • Ich wusste nichts davon fgets(). Es sieht dann tatsächlich einfacher zu bedienen aus scanf(). +1

    – Kredns

    8. August 2009 um 6:37 Uhr

  • Wenn Sie nur eine Zeile vom Benutzer erhalten möchten, ist dies einfacher. Es ist auch sicherer, da Sie Pufferüberläufe vermeiden können. Die scanf-Familie ist wirklich nützlich, um einen String in verschiedene Dinge umzuwandeln (wie vier Zeichen und ein int zum Beispiel mit “%c%c%c%c%d”), aber selbst dann sollten Sie fgets und sscanf nicht verwenden scanf, um die Möglichkeit eines Pufferüberlaufs zu vermeiden.

    – paxdiablo

    8. August 2009 um 6:48 Uhr

  • Sie können die maximale Puffergröße in das scanf-Format einfügen, Sie können nur keine zur Laufzeit berechnete Größe einfügen, ohne das Format zur Laufzeit zu erstellen (es gibt kein Äquivalent von * für printf, * ist ein gültiger Modifikator für scanf mit einem anderen Verhalten: Unterdrückung der Zuweisung ).

    – Ein Programmierer

    8. August 2009 um 11:55 Uhr

  • @ JonathanKomar und alle anderen, die dies in Zukunft lesen: Wenn Ihr Professor Ihnen gesagt hat, dass Sie verwenden müssen scanf Bei einer Aufgabe haben sie sich geirrt, und Sie können ihnen sagen, dass ich das gesagt habe, und wenn sie mit mir darüber streiten wollen, ist meine E-Mail-Adresse leicht in meinem Profil zu finden.

    – zol

    30. April 2019 um 18:10 Uhr

  • @Rainning: es soll nicht schön sein, sonst hätten wir es nicht strcscnp oder atoi. Es ist ein funktionaler Name, der wahrscheinlich darauf hinweisen soll gets aus einem Dateihandle. Seine Fähigkeit, das zu tun, was das OP wollte, wird in keiner Weise durch seinen Namen beeinflusst.

    – paxdiablo

    14. März um 10:04 Uhr


Benutzeravatar von Kelly Robins
Kelly Robins

Versuchen

char str[11];
scanf("%10[0-9a-zA-Z ]", str);

Ich hoffe, das hilft.

  • (1) Um Leerzeichen zu akzeptieren, müssen Sie natürlich ein Leerzeichen in die Zeichenklasse einfügen. (2) Beachten Sie, dass 10 die maximale Anzahl von Zeichen ist, die gelesen werden, also muss str mindestens auf einen Puffer der Größe 11 zeigen. (3) Das abschließende s hier ist keine Formatanweisung, aber scanf versucht hier, es genau abzugleichen. Der Effekt wird bei einem Eintrag wie 1234567890s sichtbar, bei dem die s verbraucht, aber nirgendwo abgelegt werden. Ein anderer Buchstabe wird nicht verbraucht. Wenn Sie nach dem s ein anderes Format eingeben, wird es nur gelesen, wenn ein passendes s vorhanden ist.

    – Ein Programmierer

    8. August 2009 um 11:52 Uhr

  • Ein weiteres potenzielles Problem ist die Verwendung von – an einer anderen Stelle als der ersten oder letzten Implementierung definiert. Normalerweise wird es für Bereiche verwendet, aber was der Bereich bezeichnet, hängt vom Zeichensatz ab. EBCDIC hat Löcher in den Buchstabenbereichen und selbst wenn man von ASCII-abgeleiteten Zeichensätzen ausgeht, ist es naiv zu glauben, dass alle Kleinbuchstaben im az-Bereich liegen …

    – Ein Programmierer

    8. August 2009 um 13:35 Uhr

  • “%[^\n]” hat das gleiche Problem wie gets(), Pufferüberlauf. Mit dem zusätzlichen Haken, dass das \n-Finale nicht gelesen wird; dies wird dadurch verdeckt, dass die meisten Formate damit beginnen, Leerzeichen zu überspringen, aber [ isn’t one of them. I don’t understand the instance at using scanf to read strings.

    – AProgrammer

    Aug 9, 2009 at 6:09

  • Removed the s from the end of the input string since it’s both superfluous and incorrect in certain cases (as pointed out in earlier comments). [ is it’s own format specifier rather than some variation of the s one.

    – paxdiablo

    Feb 15, 2015 at 6:23

SVA's user avatar
SVA

This example uses an inverted scanset, so scanf keeps taking in values until it encounters a ‘\n’– newline, so spaces get saved as well

#include <stdio.h>

int main (int argc, char const *argv[]) { Zeichenname[20];  // Puffergröße erreichen - 1 Zeichen (um NULL-Terminator zu berücksichtigen) scanf("%19[^\n]", Name); printf("%s\n", Name); Rückgabe 0; }

  • Vorsicht bei Pufferüberläufen. Wenn der Benutzer einen “Namen” mit 50 Zeichen schreibt, wird das Programm wahrscheinlich abstürzen.

    – Brunoais

    29. Januar 2013 um 15:17 Uhr

  • Da Sie die Puffergröße kennen, können Sie verwenden %20[^\n]s um Pufferüberläufe zu verhindern

    – osven

    11. November 2017 um 20:52 Uhr

  • 45 Punkte und niemand wies auf die offensichtliche Ladungskultivierung hin s dort!

    – Antti Haapala – Слава Україні

    27. Juni 2019 um 5:39 Uhr

Benutzeravatar von Vitim.us
Vitim.us

Sie können dies verwenden

char name[20];
scanf("%20[^\n]", name);

Oder dieses

void getText(char *message, char *variable, int size){
    printf("\n %s: ", message);
    fgets(variable, sizeof(char) * size, stdin);
    sscanf(variable, "%[^\n]", variable);
}

char name[20];
getText("Your name", name, 20);

DEMO

Nicht verwenden scanf() um Strings zu lesen, ohne eine Feldbreite anzugeben. Sie sollten auch die Rückgabewerte auf Fehler überprüfen:

#include <stdio.h>

#define NAME_MAX    80
#define NAME_MAX_S "80"

int main(void)
{
    static char name[NAME_MAX + 1]; // + 1 because of null
    if(scanf("%" NAME_MAX_S "[^\n]", name) != 1)
    {
        fputs("io error or premature end of line\n", stderr);
        return 1;
    }

    printf("Hello %s. Nice to meet you.\n", name);
}

Alternativ verwenden fgets():

#include <stdio.h>

#define NAME_MAX 80

int main(void)
{
    static char name[NAME_MAX + 2]; // + 2 because of newline and null
    if(!fgets(name, sizeof(name), stdin))
    {
        fputs("io error\n", stderr);
        return 1;
    }

    // don't print newline
    printf("Hello %.*s. Nice to meet you.\n", strlen(name) - 1, name);
}

getline()

Jetzt trotzdem Teil von POSIX.

Es kümmert sich auch um das Problem der Pufferzuweisung, nach dem Sie zuvor gefragt haben, obwohl Sie sich darum kümmern müssen freedie Erinnerung.

Jonscas Benutzeravatar
jonska

Du kannst den … benutzen fgets() Funktion zum Lesen einer Zeichenfolge oder Verwendung scanf("%[^\n]s",name); Das Lesen von Zeichenfolgen wird also beendet, wenn ein Zeilenumbruchzeichen auftritt.

  • Achten Sie darauf, dass dies Pufferüberläufe nicht verhindert

    – Brunoais

    29. Januar 2013 um 15:16 Uhr

  • s gehört da nicht hin

    – Antti Haapala – Слава Україні

    27. Juni 2019 um 5:40 Uhr

1424950cookie-checkWie erlauben Sie die Eingabe von Leerzeichen mit scanf?

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

Privacy policy