2010-10-26 8 views
38

ich den Namen von meinem Benutzer unter Verwendung von C-Programmenwie Zeichenfolge durch den Benutzer in c

Dazu schrieb ich eingegeben lesen möchten eingegeben lesen:

char name[20]; 

printf("Enter name:"); 
gets(name); 

aber mit gets ist nicht gut, so machen Sie mir ein besserer Weg.

Antwort

65

Sie sollten nie Verwendung gets (oder scanf mit unbeschränkter Stringgröße) da, dass Sie überläuft bis puffern öffnet. Verwenden Sie die fgets mit einem stdin Griff, da es Ihnen, die Daten beschränken kann, die in Ihrem Puffer platziert werden.

Hier ist ein kleiner Ausschnitt I für Zeile Eingabe vom Benutzer verwenden:

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

#define OK  0 
#define NO_INPUT 1 
#define TOO_LONG 2 
static int getLine (char *prmpt, char *buff, size_t sz) { 
    int ch, extra; 

    // Get line with buffer overrun protection. 
    if (prmpt != NULL) { 
     printf ("%s", prmpt); 
     fflush (stdout); 
    } 
    if (fgets (buff, sz, stdin) == NULL) 
     return NO_INPUT; 

    // If it was too long, there'll be no newline. In that case, we flush 
    // to end of line so that excess doesn't affect the next call. 
    if (buff[strlen(buff)-1] != '\n') { 
     extra = 0; 
     while (((ch = getchar()) != '\n') && (ch != EOF)) 
      extra = 1; 
     return (extra == 1) ? TOO_LONG : OK; 
    } 

    // Otherwise remove newline and give string back to caller. 
    buff[strlen(buff)-1] = '\0'; 
    return OK; 
} 

Dies ermöglicht es mir, um die maximale Größe gesetzt ist, wird erkennen, ob zu viele Daten auf der Zeile eingegeben werden, und wird den Rest bündig von der Linie, so dass es die nächste Eingabeoperation nicht beeinflusst.

Sie können es testen mit so etwas wie:

// Test program for getLine(). 

int main (void) { 
    int rc; 
    char buff[10]; 

    rc = getLine ("Enter string> ", buff, sizeof(buff)); 
    if (rc == NO_INPUT) { 
     // Extra NL since my system doesn't output that on EOF. 
     printf ("\nNo input\n"); 
     return 1; 
    } 

    if (rc == TOO_LONG) { 
     printf ("Input too long [%s]\n", buff); 
     return 1; 
    } 

    printf ("OK [%s]\n", buff); 

    return 0; 
} 
+1

nicht die Systembibliotheken, die scanf implementieren verhindern einen Überlauf des Befehls (ich verstehe, dass innerhalb des Programms, wenn der Entwickler die Eingabe nicht überprüft hat, könnte es einen Überlauf geben, aber die Systembibliothek ist sicher oder?). – Marm0t

+8

Nein, wenn Sie "scanf" ("% s") in einen 20-Byte-Puffer und der Benutzer eine 40-Byte-Zeile eingibt, werden Sie abgespritzt. Der ganze Punkt von 'scanf' ist scan-formatiert und es gibt wenig mehr _unformatted_ als Benutzereingabe :-) – paxdiablo

+5

@ Marm0t - Denken Sie auf diese Weise durch die Betrachtung der folgenden Frage: Wie kann die Implementierung einen Überlauf verhindern, wenn alles es ist ein Zeiger auf eine Scheibe des Gedächtnisses (typecasted als char *) 'ohne irgendeinen Parameter, der der Implementierung über die Größe des Zielpuffers sagt'? –

5

Auf einem POSIX-System, sollten Sie wahrscheinlich getline verwenden, wenn es verfügbar ist.

Sie können auch Chuck Falconer Public Domain ggets Funktion verwenden, die Syntax näher an gets bietet, aber ohne die Probleme. (Chuck Falconer Webseite ist nicht mehr verfügbar, obwohl archive.org has a copy, und ich habe my own page for ggets gemacht.)

+0

Mit dem Vorbehalt, dass es nicht wie erwartet mit Dateien funktioniert, die nur in einer CR enden. Das ist nicht so ungewöhnlich, wie du dir vielleicht vorstellen kannst (sagt er, nachdem er einen Ordner voll mit ihnen gefunden hat). Es ist eine verpasste Chance, dass getdelim/getline nicht eine Liste von Trennzeichen statt eines einzigen int übernommen hat. –

+0

@MauryMarkowitz Es würde auf einem System funktionieren, das CR als sein natives Zeilenende-Format verwendet. Textmodus-Streams konvertieren den nativen Zeilenende-Typ in '\ n'. – jamesdlin

15

Ich denke, die beste und sicherste Weg, Strings vom Benutzer eingegeben lesen verwendet getline()

Hier ist ein Beispiel, wie man Dazu:

#include <stdio.h> 
#include <stdlib.h> 
int main(int argc, char *argv[]) 
{ 
    char *buffer = NULL; 
    int read; 
    unsigned int len; 
    read = getline(&buffer, &len, stdin); 
    if (-1 != read) 
     puts(buffer); 
    else 
     printf("No line read...\n"); 

    printf("Size read: %d\n Len: %d\n", read, len); 
    free(buffer); 
    return 0; 
} 
+1

lesen = getline (& buffer, & len, stdin); gibt GCC-Warnungen zB: gcc -Wall -c "getlineEx2.c" getlineEx2.c: In Funktion main: getlineEx2.c: 32: 5: Warnung: übergeben Argument 2 von getline aus inkompatiblen Zeigertyp [standardmäßig aktiviert] lesen = getline (& buffer, & len, stdin); ^ In der Datei enthalten von/usr/include/stdio.h:29: von getlineEx2.c: 24: /usr/include/sys/stdio.h:37:9: Hinweis: erwartete size_t * aber Das Argument ist vom Typ unsigned int * ssize_t _EXFUN (getline, (char **, size_t *, FILE *)); ^ Kompilierung erfolgreich abgeschlossen. – rpd

+1

Nur die Aktualisierung dieser getline erfordert jetzt len ​​size_t oder unsigned long – Wes

+0

Nachteil: POSIX, aber nicht ANSI C. –

1

Sie scanf Funktion Zeichenfolge zu lesen

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

ich weiß nicht verwenden können, über andere bessere Möglichkeiten Zeichenfolge zu erhalten,

2

fand ich eine einfache und schöne Lösung:

char*string_acquire(char*s,int size,FILE*stream){ 
    int i; 
    fgets(s,size,stream); 
    i=strlen(s)-1; 
    if(s[i]!='\n') while(getchar()!='\n'); 
    if(s[i]=='\n') s[i]='\0'; 
    return s; 
} 

es basiert auf fgets aber frei von ‚\ n‘ und stdin zusätzlichen Zeichen (ersetzen fflush (stdin), dass funktioniert nicht auf allen Betriebssystemen, nützlich, wenn Sie danach Zeichenfolgen erfassen müssen).

0

Auf BSD-Systemen und Android können Sie auch fgetln verwenden:

#include <stdio.h> 

char * 
fgetln(FILE *stream, size_t *len); 

Wie so:

size_t line_len; 
const char *line = fgetln(stdin, &line_len); 

Die line ist null \n nicht beendet und enthält (oder was auch immer Ihre Plattform verwendet) in das Ende. Es wird nach dem nächsten E/A-Vorgang im Stream ungültig. Sie dürfen den zurückgegebenen line Puffer ändern.