2016-12-20 2 views
6

Kann ein Benutzer null Terminator in einer Eingabe eingeben, für die scanf verwandt wird, so würde die Länge der Eingabe 0 sein?

Benutzer, der null Terminator in scanf eingibt

char msg[1000]; 
scanf("%1000s",msg); // the user would type nothing: '' or '\0' 
+0

Für das ['scanf'] (http://en.cppreference.com/w/c/io/fscanf) -Format' "% s" 'muss * eine * Nicht-Leerzeichen-Eingabe sein. Wenn Sie eine optionale Eingabe wünschen, verwenden Sie stattdessen ['fgets'] (http://en.cppreference.com/w/c/io/fgets). –

+0

@Someprogrammerdude Ich kann nicht fgets verwenden, es muss scanf sein –

+1

Dann müssen Sie mit den Einschränkungen leben, nicht in der Lage zu sein, eine nicht leere Eingabe zu geben. –

Antwort

8

Auf vielen Systemen ist die Antwort "Ja".

Normalerweise ist die magische Sequenz Control- @.

Der Zeichencode für @ ist normalerweise 64, einer weniger als der von A (65). Control-A ist Zeichencode 1; eine weniger ist Zeichencode 0, auch bekannt als '\0'.

Beachten Sie, dass Sie, um eine Eingabe mit der Länge null zu erhalten, das Nullbyte als erstes Nicht-Leerzeichen eingeben müssen, und Sie müssen immer noch Return drücken, um die Eingabe einzugeben. Ihr Programm würde es schwer finden, zuverlässig zu identifizieren, was sonst nach dem Nullbyte eingegeben wurde.

0

Ja, es ist möglich, weil '\0' ein Nicht-Leerraum ist. scanf() wird berücksichtigen, dass das Ende der Zeichenfolge ist. So %s kann eine leere Zeichenfolge übereinstimmen.

Sie können den Spezifizierer m verwenden, um einen entsprechenden Puffer für die Eingabe zu reservieren. Beachten Sie, dass dies der Standard POSIX 200112L ist.

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

int main(void) { 
    char *str; 
    int n; 
    if (scanf("%ms%n", &str, &n) == 1) { 
     printf("I read %d character(s).\n", n); 
     if (strlen(str) != 0) { 
     printf("str = %s\n", str); 
     } 
     else { 
     printf("str is empty"); 
     } 
     free(str); 
    } 
    else { 
     printf("The user enter nothing"); 
    } 
} 
+0

'frei (str);'?!?! Wo ist das entsprechende 'malloc()'? –

+4

@AndrewHenle In [scanf] (https://linux.die.net/man/3/scanf) siehe Modifikator m. – Stargateur

+2

Schön. Ich habe heute etwas Neues gelernt. Vielen Dank. (Und nein, ich war nicht der Downvoter.) –

4

Einige Systeme ermöglichen es dem Terminalbenutzer ein NUL Byte eingeben, indem Sie Ctrl - @. scanf() würde dann dieses Byte in das Zielarray speichern, würde aber höchstwahrscheinlich nicht berücksichtigen, dass dieses Byte ein Worttrennzeichen darstellt, so dass das Eingabe-Parsing fortgesetzt wird, bis das Ende der Datei oder ein Leerzeichen wie Newline eingegeben wird.

Es gibt keine Möglichkeit, vom Ziel-Array zu unterscheiden, ob ein NUL-Byte nach anderen Zeichen gespeichert wurde oder genau, wie viele weitere Zeichen nach diesem NUL-Byte gelesen wurden. Aber wenn scanf() zurückgegeben 1 und msg hat eine Länge von Null, ist die einzige Möglichkeit, dass der Benutzer ein NUL-Byte nach einer möglicherweise leeren Folge von Leerzeichen eingegeben.

Dies würde auch die einzige Möglichkeit für fgets() sein, einen leeren String zurück, wenn eine Ziel-Array mit einer Größe übergeben größer als 1

Wenn Eingabe aus einer Datei anstelle eines Terminal gelesen wird, ist es immer ein Möglichkeit, dass die Datei NUL-Bytes enthält und Vorsicht geboten ist, um ein undefiniertes Verhalten zu vermeiden, falls dies geschieht. Zum Beispiel, hier ist ein klassischer Fehler:

char msg[1000]; 
if (fgets(msg, sizeof msg, stdin)) { 
    int len = strlen(msg); 
    if (msg[len - 1] == '\n') { // potential undefined behavior! 
     msg[--len] = '\0'  // potential undefined behavior! 
    } 
    ... 
} 

Beachten Sie auch, dass Ihr Code einen Fehler hat: die maximale Anzahl von Zeichen in das Ziel zu speichern, sollte 999, nicht 1000 sein:

char msg[1000]; 
if (scanf("%999s",msg) == 1) { 
    /* word was read from the user */ 
    if (*msg == '\0') { 
     printf("user entered a NUL byte\n"); 
    } 
} 
2

Kann ein Benutzer einen Nullabschluss in eine Eingabe eingeben, für die scanf verwendet wird, sodass die Länge der Eingabe 0 ist?

Zusätzlich zu einem Benutzer typing in a null character könnte stdin re-directed Eingabe verwenden, die Null-Zeichen enthält.

foo < data.bin 

Detail: Wenn das erste gescannte Zeichen ein Null-Zeichen ist oder '\0', es ist wie jedes andere Zeichen und gespeichert wie jede andere nicht-white-space Zeichen gelesen wird. So ist die Länge der Eingabe immer noch mehr als 0, aber der Wert von strlen(msg) gemeldet wird durch das eingebettete Null-Zeichen getäuscht und gibt Null zurück.

fgets() hat das gleiche Problem wie scanf() in dieser Hinsicht: strlen(msg) nicht alway Bericht die Anzahl der Zeichen lesen.

Nicht-Standard getline() gibt die Anzahl der gelesenen Zeichen zurück und ist ein Ausweg daraus.


@Stargateur erwähnt "%n" mit der Anzahl der Zeichen in msg gespeichert zu speichern. Vielleicht wie

char msg[1000 + 1]; 
int start, end; 
if (1 == scanf(" %n%1000s%n", &start, msg, &end)) { 
    printf("%d characters read\n", end - start); 
} 

IAC, versuchen wir, mit einer Ecke Schwäche scanf() und Familie zu bewältigen. Die beste Leseeingabe Lösung hängt von zusätzlichen Faktoren ab, die von OP nicht erwähnt werden.

Verwandte Themen