2017-04-02 6 views
2

Früher habe ich gets benutzt, aber dann habe ich gehört, dass es von c11 entfernt wurde und dass es insgesamt sehr gefährlich ist. Also habe ich ein wenig gesucht und herausgefunden, dass Sie mit fgets() dasselbe machen können.Alternative zu bekommen?

Das Problem ist, dass, wenn ich fgets() benutze, es auch das Ende der Zeile zu kopieren scheint, was zu einer zusätzlichen unerwünschten Zeile führt.

Ihnen zu zeigen, was ich meine:

//if I have 
char key[30]; 
fgets(key, sizeof(key), stdin); 

//now if ender for instance: Doggo and do: 
printf("The key is:%s|hozaah!\n", key); 

//I expect it to print: 
The key is:Doggo|hozaah! 

//Instead it prints: 
The key is:Doggo 
|hozaah! 

Gibt es eine Möglichkeit, dies zu umgehen? Oder gibt es eine andere Funktion, die ich stattdessen verwenden kann?

+1

gefunden der Schlüssel [strcspn (Schlüssel, "\ n")] = 0; funktioniert wie ein Zauber, danke! – Mathue24

+0

@Kerrek Chill Kumpel, er hat nur versucht zu helfen, keine Notwendigkeit, so groß zu sein lol – Mathue24

+0

@ Mathue24: Ja, Entschuldigung, fair genug.Ich bin ein wenig überempfindlich gegenüber schlechtem Cargo-Culture in C-Strings, da die meisten Software-Schwachstellen auf schlechtes Verständnis von Strings und von Off-by-Ones zurückzuführen sind. Ich möchte, dass die Leute sorgfältig darüber nachdenken. –

Antwort

4

Es gibt keinen Standard direkter Ersatz für gets(), aber es gibt viele einfache Möglichkeiten des Newline, falls vorhanden, um loszuwerden:

  • Die einfachste Verwendung strcspn (in <string.h> erklärt):

    if (fgets(buf, sizeof buf, fp)) { 
        buf[strcspn(buf, "\n")] = '\0'; 
    } 
    
  • Der Klassiker mit strlen:

    if (fgets(buf, sizeof buf, fp)) { 
        size_t len = strlen(buf); 
        if (len > 0 && buf[len - 1] == '\n') 
         buf[--len] = '\0'; 
    } 
    
  • Ein weiterer Klassiker mit strchr:

    if (fgets(buf, sizeof buf, fp)) { 
        char *p = strchr(buf, '\n'); 
        if (p != NULL) 
         *p = '\0'; 
    } 
    

Eine Alternative ist die POSIX-Funktion getline(), die auf Ihrem System verfügbar sein könnten:

#include <stdio.h> 
ssize_t getline(char **lineptr, size_t *n, FILE *stream); 

Der Puffer mit malloc() zugewiesen oder neu zugewiesen wird und dessen Größe wird in *n aktualisiert. Die Anfangswerte sollten lineptr = NULL und n = 0 sein.

1

Die Antwort liegt in der Tatsache, dass fgets so viele Zeichen wie fit in den Puffer liest, ein Nullabschluss einschließlich, aber nur aus Datei oder eine neue Zeile zu beenden, und es wird speichern die Newline in der Zeichenfolge, too: man 3 fgets

Wenn Sie also die Eingabe am Terminal eingeben, wird auch der Zeilenumbruch an den Standard-Eingang übertragen und von fgets gelesen. Dies unterscheidet sich von der alten gets, die die Newline durch ein Nullbyte ersetzt.

Wenn Sie also Zeilen lesen und die potenzielle Zeilenschaltung nicht möchten, streichen Sie sie aus. Leider fgets nicht sagen, wie viele Zeichen gelesen wurden, so müssen Sie erneut die Zeichenfolge scannen, ihn auszuführen:

char* p = fgets(key, sizeof(key), stdin); 

if (!p) { /* error */ } 

size_t n = strlen(key); 

if (n > 0 && key[n - 1] == '\n') { 
    key[n - 1] = '\0'; 
} else { 
    /* buffer too short or EOF reached without newline */ 
} 

printf("The line was: '%s'\n", key); 

Es lohnt Alternativen erwägen sein kann: Wenn Sie nur einen Eingang benötigen, nicht tun Geben Sie den Zeilenumbruch an erster Stelle ein. Wenn Sie viele Zeilen benötigen, verwenden Sie fread in einem Puffer fester Größe und suchen Sie selbst nach Zeilenvorschüben.

+0

[Demo] (https://wandbox.org/permlink/AwlDxatyy7fnSuXF), versuchen Sie es mit und ohne Eingabe Newline. –