Wie kann ich eine Eingabezeichenfolge unbekannter Länge lesen?

Lesezeit: 9 Minuten

Benutzeravatar von showkey
Showkey

Wenn ich nicht weiß, wie lang das Wort ist, kann ich nicht schreiben char m[6];,
Die Länge des Wortes beträgt vielleicht zehn oder zwanzig. Wie kann ich verwenden scanf um Eingaben von der Tastatur zu erhalten?

#include <stdio.h>
int main(void)
{
    char  m[6];
    printf("please input a string with length=5\n");
    scanf("%s",&m);
    printf("this is the string: %s\n", m);
    return 0;
}

Bitte geben Sie einen String mit Länge=5 ein
Eingabe: Hallo
Dies ist die Zeichenfolge: hallo

  • Verwenden Sie die Realloc-Kombination des Zeigers

    – Pinker Panther

    1. Juni 2013 um 10:00 Uhr

  • Die kannst du fallen lassen & in scanf("%s",&m) seit m ist bereits ein Zeiger auf das erste Element von m[] in diesem Ausdruck.

    – Jens

    1. Juni 2013 um 11:10 Uhr

  • Du solltest benutzen "%5s" um einen Pufferüberlauf zu vermeiden.

    – Jonathan Leffler

    10. Juli um 14:11 Uhr

Benutzeravatar von BLUEPIXY
BLUEPIXY

Treten Sie ein, während Sie einen Bereich dynamisch sichern

Z.B

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

char *inputString(FILE* fp, size_t size){
//The size is extended by the input with the value of the provisional
    char *str;
    int ch;
    size_t len = 0;
    str = realloc(NULL, sizeof(*str)*size);//size is start size
    if(!str)return str;
    while(EOF!=(ch=fgetc(fp)) && ch != '\n'){
        str[len++]=ch;
        if(len==size){
            str = realloc(str, sizeof(*str)*(size+=16));
            if(!str)return str;
        }
    }
    str[len++]='\0';

    return realloc(str, sizeof(*str)*len);
}

int main(void){
    char *m;

    printf("input string : ");
    m = inputString(stdin, 10);
    printf("%s\n", m);

    free(m);
    return 0;
}

  • Multiplizieren mit sizeof(char)? Pfui.

    – Jens

    1. Juni 2013 um 11:06 Uhr

  • @Jens Pfff, das wird wohl wegoptimiert. Keine Probleme. Aber wenn Sie ein globales Suchen und Ersetzen von durchführen würden char mit wchar_tdiese Lösung würde immer noch funktionieren, im Gegensatz zu anderen Lösungen, die mehr Basteln erfordern würden!

    – Herr Lister

    1. Juni 2013 um 11:12 Uhr


  • @MrLister Weshalb der richtige Weg, wenn überhaupt, ist, mit zu multiplizieren sizeof (*str) also musst du das auch gar nicht bearbeiten die Multiplikation, wenn sich der Typ ändert.

    – Jens

    1. Juni 2013 um 12:11 Uhr


  • Das ist definitiv so str[len]='\0'; return realloc(str, len); führt dazu, dass der Terminator verworfen wird. Ich glaube du meintest str[len++] = '\0'.

    – sch1

    1. Juni 2013 um 12:12 Uhr

  • @germanfr Nein. Ich sagte ungefähr realloc(NULL, sizeof(char)*size); the same as malloc(sizeof(char) * size). Ich sage nicht dasselbe von malloc und realloc.

    – BLUEPIXY

    16. Oktober 2016 um 15:01 Uhr

Benutzeravatar von Herrn Lister
Herr Lister

Mit den heutigen Computern können Sie sehr große Zeichenfolgen (Hunderttausende von Zeichen) zuweisen, ohne die RAM-Nutzung des Computers zu beeinträchtigen. Ich würde mir also nicht allzu viele Sorgen machen.

In früheren Zeiten, als der Speicher knapp war, war es jedoch üblich, Zeichenfolgen in Blöcken zu lesen. fgets liest bis zu einer maximalen Anzahl von Zeichen aus der Eingabe, lässt aber den Rest des Eingabepuffers intakt, sodass Sie den Rest daraus lesen können, wie Sie möchten.

In diesem Beispiel lese ich Blöcke von 200 Zeichen ein, aber Sie können natürlich jede beliebige Blockgröße verwenden.

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

char* readinput()
{
#define CHUNK 200
   char* input = NULL;
   char tempbuf[CHUNK];
   size_t inputlen = 0, templen = 0;
   do {
       fgets(tempbuf, CHUNK, stdin);
       templen = strlen(tempbuf);
       input = realloc(input, inputlen+templen+1);
       strcpy(input+inputlen, tempbuf);
       inputlen += templen;
    } while (templen==CHUNK-1 && tempbuf[CHUNK-2]!='\n');
    return input;
}

int main()
{
    char* result = readinput();
    printf("And the result is [%s]\n", result);
    free(result);
    return 0;
}

Beachten Sie, dass dies ein vereinfachtes Beispiel ohne Fehlerprüfung ist; im wirklichen Leben müssen Sie sicherstellen, dass die Eingabe in Ordnung ist, indem Sie den Rückgabewert von überprüfen fgets.

Beachten Sie auch, dass am Ende der readinput-Routine keine Bytes verschwendet werden; Die Zeichenfolge hat genau die Speichergröße, die sie haben muss.

  • Benötigt Fehlerbehandlung für realloc() Rückkehr NULL (und folglich z readinput() Rückkehr NULL).

    – sch1

    1. Juni 2013 um 12:29 Uhr


  • Sie müssen den Rückgabewert von überprüfen fgets()sonst kann der Code in eine Endlosschleife eintreten.

    – chux – Wiedereinsetzung von Monica

    6. Dezember 2015 um 20:18 Uhr

  • Ich denke, es gibt ein Problem damit beim ersten Realloc (Realloc, wenn die Eingabe NULL ist). Dies könnte auf einen willkürlichen Speicher hinweisen, und daher hat strcat möglicherweise nicht das beabsichtigte Ergebnis (dh die Eingabe sollte nur der Inhalt des Puffers sein). Anstatt zu versuchen, eine zugewiesene Zeichenfolge der Länge templen zu speichern, versucht es stattdessen, eine Zeichenfolge von strlen(beliebige Daten) + templen zu speichern, und gibt einen Fehler “malloc() Speicherbeschädigung” aus.

    – Brendan Hart

    15. Oktober 2019 um 17:47 Uhr


  • @BrendanHart Ach, das hat in sechs Jahren niemand gesehen. Behoben durch Ausführen eines strcpy anstelle eines strcat.

    – Herr Lister

    15. Oktober 2019 um 19:03 Uhr

  • Um den Zeilenvorschub zu verlieren, fügen Sie hinzu tempbuf[strcspn(tempbuf, "\n")] = 0; nach fgets Linie.

    – Nö

    22. November 2020 um 17:25 Uhr

Benutzeravatar von sh1
sch1

Ich habe nur einen gesehen einfach Möglichkeit, eine beliebig lange Zeichenfolge zu lesen, aber ich habe sie noch nie verwendet. Ich denke es geht so:

char *m = NULL;
printf("please input a string\n");
scanf("%ms",&m);
if (m == NULL)
    fprintf(stderr, "That string was too long!\n");
else
{
    printf("this is the string %s\n",m);
    /* ... any other use of m */
    free(m);
}

Das m zwischen % und s erzählt scanf() um die Zeichenfolge zu messen und Speicher dafür zuzuweisen und die Zeichenfolge dorthin zu kopieren und die Adresse dieses zugewiesenen Speichers im entsprechenden Argument zu speichern. Sobald Sie damit fertig sind, müssen Sie free() es.

Dies wird nicht bei jeder Implementierung von unterstützt scanf()obwohl.

Wie andere bereits betont haben, besteht die einfachste Lösung darin, die Länge der Eingabe zu begrenzen. Wenn Sie noch verwenden möchten scanf() dann kannst du das so machen:

char m[100];
scanf("%99s",&m);

Beachten Sie, dass die Größe von m[] muss mindestens ein Byte größer sein als die Zahl dazwischen % und s.

Wenn die eingegebene Zeichenfolge länger als 99 ist, warten die verbleibenden Zeichen darauf, von einem anderen Aufruf oder dem Rest der übergebenen Formatzeichenfolge gelesen zu werden scanf().

Allgemein scanf() wird für die Verarbeitung von Benutzereingaben nicht empfohlen. Es wird am besten auf einfache strukturierte Textdateien angewendet, die von einer anderen Anwendung erstellt wurden. Selbst dann müssen Sie sich darüber im Klaren sein, dass die Eingabe möglicherweise nicht so formatiert ist, wie Sie es erwarten, da jemand daran eingegriffen haben könnte, um zu versuchen, Ihr Programm zu beschädigen.

  • Beachten Sie, dass "%ms" ist kein Standard-C — es ist wahrscheinlich entweder eine POSIX-Erweiterung oder eine GNU-Erweiterung.

    – Tim Čas

    12. Februar 2015 um 21:36 Uhr

  • @ TimČas: Es ist Teil von Posix 2008, was ein Standard ist. Es gab früher eine ähnliche GNU-Erweiterung und eine ähnliche BSD-Erweiterung; der Posix-Standard soll die verschiedenen Implementierungen vereinheitlichen. Gut möglich, dass es in eine zukünftige C-Norm Einzug hält.

    – Rici

    12. Februar 2015 um 22:37 Uhr

Es gibt eine neue Funktion im C-Standard, um eine Zeile zu erhalten, ohne ihre Größe anzugeben. getline Die Funktion ordnet die Zeichenfolge automatisch der erforderlichen Größe zu, sodass die Größe der Zeichenfolge nicht erraten werden muss. Der folgende Code demonstriert die Verwendung:

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


int main(void)
{
    char *line = NULL;
    size_t len = 0;
    ssize_t read;

    while ((read = getline(&line, &len, stdin)) != -1) {
        printf("Retrieved line of length %zu :\n", read);
        printf("%s", line);
    }

    if (ferror(stdin)) {
        /* handle error */
    }

    free(line);
    return 0;
}

Benutzeravatar von Nobilis
Nobilis

Wenn ich einen sichereren Ansatz vorschlagen darf:

Deklarieren Sie einen Puffer, der groß genug ist, um die Zeichenfolge aufzunehmen:

char user_input[255];

Holen Sie sich die Benutzereingabe in a sicher Weg:

fgets(user_input, 255, stdin);

Ein sicherer Weg, um die Eingabe zu erhalten, wobei das erste Argument ein Zeiger auf einen Puffer ist, in dem die Eingabe gespeichert wird, das zweite die maximale Eingabe, die die Funktion lesen soll, und das dritte ein Zeiger auf die Standardeingabe – dh wo die Benutzereingabe erfolgt aus.

Sicherheit ergibt sich insbesondere aus dem zweiten Argument, das begrenzt, wie viel gelesen wird, wodurch Pufferüberläufe verhindert werden. Ebenfalls, fgets kümmert sich um die Nullterminierung der verarbeiteten Zeichenfolge.

Weitere Informationen zu dieser Funktion hier.

BEARBEITEN: Wenn Sie eine Formatierung vornehmen müssen (z. B. eine Zeichenfolge in eine Zahl konvertieren), können Sie verwenden atoi sobald Sie die Eingabe haben.

  • aber das OP fragt, er weiß nicht, wie viel er eingeben wird, wenn er zufällig mit> 255 eingeben möchte

    – Pinker Panther

    1. Juni 2013 um 10:01 Uhr

  • Meiner Meinung nach fgets(user_input, sizeof user_input, stdin); ist sicherer.

    – chux – Wiedereinsetzung von Monica

    6. Dezember 2015 um 19:56 Uhr

  • @chux-ReinstateMonica Bis Sie einen Zeiger anstelle eines Arrays verwenden;)

    – klutt

    26. Februar 2021 um 14:45 Uhr

  • aber nehmen wir an, Sie schreiben eine Shell. Möchten Sie wirklich auf 255 oder einen festen Wert begrenzen? Die erste Antwort scheint besser geeignet zu sein, Zeichenfolgen mit unbekannter Größe zur Kompilierzeit zu handhaben.

    – Et7f3XIV

    30. Mai 2021 um 9:41 Uhr

Sicherere und schnellere Version (Verdopplung der Kapazität):

char *readline(char *prompt) {
  size_t size = 80;
  char *str = malloc(sizeof(char) * size);
  int c;
  size_t len = 0;
  printf("%s", prompt);
  while (EOF != (c = getchar()) && c != '\r' && c != '\n') {
    str[len++] = c;
    if(len == size) str = realloc(str, sizeof(char) * (size *= 2));
  }
  str[len++]='\0';
  return realloc(str, sizeof(char) * len);
}

  • aber das OP fragt, er weiß nicht, wie viel er eingeben wird, wenn er zufällig mit> 255 eingeben möchte

    – Pinker Panther

    1. Juni 2013 um 10:01 Uhr

  • Meiner Meinung nach fgets(user_input, sizeof user_input, stdin); ist sicherer.

    – chux – Wiedereinsetzung von Monica

    6. Dezember 2015 um 19:56 Uhr

  • @chux-ReinstateMonica Bis Sie einen Zeiger anstelle eines Arrays verwenden;)

    – klutt

    26. Februar 2021 um 14:45 Uhr

  • aber nehmen wir an, Sie schreiben eine Shell. Möchten Sie wirklich auf 255 oder einen festen Wert begrenzen? Die erste Antwort scheint besser geeignet zu sein, Zeichenfolgen mit unbekannter Größe zur Kompilierzeit zu handhaben.

    – Et7f3XIV

    30. Mai 2021 um 9:41 Uhr

Nehmen Sie einen Zeichenzeiger, um die erforderliche Zeichenfolge zu speichern. Wenn Sie eine Vorstellung von der möglichen Größe der Zeichenfolge haben, verwenden Sie die Funktion

char *fgets (char *str, int size, FILE* file);`

Andernfalls können Sie auch zur Laufzeit Speicher zuweisen malloc() Funktion, die angeforderten Speicher dynamisch bereitstellt.

1418940cookie-checkWie kann ich eine Eingabezeichenfolge unbekannter Länge lesen?

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

Privacy policy