Was ist der einfachste Weg, Benutzereingaben in C zu erhalten?
Lesezeit: 8 Minuten
antonpug
Es scheint viele Möglichkeiten zu geben, Benutzereingaben in C zu erhalten.
Was ist der einfachste Weg, der wenig Code erfordert?
Grundsätzlich muss ich dies anzeigen:
Enter a file name: apple.text
Grundsätzlich muss ich den Benutzer nach einem Dateinamen fragen. Ich brauche also etwas, das nur dieses eine Wort erhält, das der Benutzer eingeben wird.
(Hinweis: Ich habe Bjarnes Code geändert, um nach isspace() statt nur Zeilenende. Auch aufgrund des Kommentars von @matejkramny zu verwenden while(1) Anstatt von while(true)… und solange wir ketzerisch genug sind, um Stroustrups Code zu bearbeiten, habe ich auch C89-Kommentare anstelle von C++-Kommentaren eingefügt. :-P)
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
void quit() /* write error message and quit */
{
fprintf(stderr, "memory exhausted\n");
exit(1);
}
int main()
{
int max = 20;
char* name = (char*) malloc(max); /* allocate buffer */
if (name == 0) quit();
printf("Enter a file name: ");
while (1) { /* skip leading whitespace */
int c = getchar();
if (c == EOF) break; /* end of file */
if (!isspace(c)) {
ungetc(c, stdin);
break;
}
}
int i = 0;
while (1) {
int c = getchar();
if (isspace(c) || c == EOF) { /* at end, add terminating zero */
name[i] = 0;
break;
}
name[i] = c;
if (i == max - 1) { /* buffer full */
max += max;
name = (char*) realloc(name, max); /* get a new and larger buffer */
if (name == 0) quit();
}
i++;
}
printf("The filename is %s\n", name);
free(filename); /* release memory */
return 0;
}
Das umfasst:
Leerzeichen überspringen, bis Sie zur Zeicheneingabe gelangen
Dynamisches Erweitern des Zeichenfolgenpuffers, um Zeichenfolgen beliebiger Größe aufzunehmen
Umgang mit Bedingungen, wenn Speicher nicht zugewiesen werden kann
Gibt es einfachere, aber kaputte Lösungen, die vielleicht sogar etwas schneller laufen? Unbedingt!!
Wenn Sie scanf in einen Puffer ohne Begrenzung der Lesegröße verwenden, überschreitet Ihre Eingabe die Größe des Puffers, es entsteht eine Sicherheitslücke und/oder ein Absturz.
Das Begrenzen der Größe des Messwerts auf beispielsweise nur 100 eindeutige Zeichen eines Dateinamens scheint besser zu sein als ein Absturz. Aber es kann schlimmer sein; zum Beispiel wenn der Benutzer meinte (...)/dir/foo/bar.txt aber am Ende interpretieren Sie ihre Eingabe falsch und überschreiben eine Datei namens bar.t was ihnen vielleicht wichtig war.
Es ist am besten, früh gute Gewohnheiten im Umgang mit diesen Problemen anzunehmen. Meine Meinung ist, dass es sich lohnt, den Sprung zu C++ in Betracht zu ziehen, wenn Ihre Anforderungen etwas Nahestehendes und “C-ähnliches” rechtfertigen. Es wurde entwickelt, um genau diese Bedenken zu bewältigen – mit Techniken, die robust und erweiterbar sind und dennoch eine gute Leistung erbringen.
Selbst wenn Ihre Klasse möchte, dass Sie scannen und weitermachen, würde ich vorschlagen, überall dort Notizen zu machen, wo Sie wissentlich etwas kaputtes / zweckmäßiges tun. Also fügen Sie neben Ihren Lesevorgängen einfach einen Kommentar wie ein /* REVIEW: input correctness, see http://stackoverflow.com/questions/7831755/what-is-the-simplest-way-of-getting-user-input-in-c/ */ Es zeigt, dass Sie Ihre Recherchen durchführen, und behält den Link zum späteren Lesen bei. Außerdem kann jeder, der eine Codebasis debuggt und einen mysteriösen Absturz bekommt, seine Aufmerksamkeit erregen – er sieht nicht nur die Warnung, sondern auch einen Hinweis auf eine Diskussion über die richtige Lösung.
– HostileFork sagt, vertraue SE nicht
20. Oktober 2011 um 7:03 Uhr
Übrigens fragt die Frage nach C, nicht nach C++
– Matej
23. September 2014 um 21:32 Uhr
@matejkramny In dem Artikel, den ich zitiere und zitiere, stellt Bjarne Stroustrup den “C-Weg” dem “C++-Weg” gegenüber. Dies ist sein “C-Weg”-Code, den ich vorstelle. Es ist kein C++-Code. Der Punkt des Papiers ist, dass dieser “korrekte” C-Code in C++ deutlicher und ohne Effizienzverlust ausgedrückt werden kann; was eingefleischte C-Programmierer überraschen könnte. Ich versichere Ihnen, dass ich die Frage lesen kann; Ich dachte nur, dass eine der besten Antworten, die ich zum Schreiben der “korrekten” C-Version dessen, was C++ standardmäßig für Sie tut, gelesen habe, aus einem Artikel stammt, der ein Werk der C++-Evangelisation war. Du solltest die Zeitung lesen, obwohl sie alt ist.
– HostileFork sagt, vertraue SE nicht
23. September 2014 um 22:38 Uhr
In C++ sind boolesche Werte definiert, die (standardmäßig) in C nicht vorhanden sind. Deshalb dachte ich, dies sei C++-Code für eine C-Frage
– Matej
23. September 2014 um 22:44 Uhr
Ich würde auch gerne wissen, warum es zwei While-Schleifen gibt, es scheint, dass Sie nur eine brauchen? (entschuldige meine Unwissenheit)
– Matej
23. September 2014 um 22:45 Uhr
Karrik
scanf scheint in einer nicht-feindlichen Umgebung zu funktionieren. Mit anderen Worten, Sie erstellen ein einfaches Dienstprogramm für sich selbst.
BUFSIZ überschreitet normalerweise die Größenbeschränkungen von UNIX-Pfadnamen bei weitem.
#include <stdio.h>
int main(void) {
char str[BUFSIZ];
printf("Enter a file name: ");
scanf("%s", str);
printf("You entered: %s\n", str);
}
Wenn Sie Daten in einem Programm sammeln müssen, die das Ziel eines Pufferüberlaufs sein könnten, benötigen Sie möglicherweise etwas mehr.
Was passiert also, wenn die Zeichenfolge BUFSIZ überschreitet …?
– HostileFork sagt, vertraue SE nicht
20. Oktober 2011 um 6:26 Uhr
Das ist wirklich möglich, aber ich hatte den Eindruck, dass er Dateinamen in einer nicht feindlichen Umgebung eingeben wollte. 😉 Wenn es feindselig wäre, müsste er sich etwas umständlicher verhalten. Und er bat um eine Lösung, die nur wenig Code beinhaltete.
#include <iostream>
#include <string>
using namespace std;
int main()
{
cout << "Enter a file name:";
string filepath;
cin >> filepath;
}
AusCBloke
Sie sollten Ihre eigene fgets()-Wrapper-Funktion schreiben, die eine Eingabezeile in einen Puffer einer bestimmten Größe liest und das Zeilenumbruchzeichen entfernt, das fgets() ebenfalls liest. Sie könnten auch einen Status zurückgeben, ob die gesamte Zeile in den Puffer gepasst hat oder nicht (dh ist der Zeilenumbruch am Ende des Puffers). Sie sollten niemals scanf oder gets verwenden, es sei denn, Sie möchten Überläufe.
BEARBEITEN: Dachte, ich könnte einen grundlegenden Code bereitstellen:
typedef unsigned char BOOL;
#define TRUE 1
#define FALSE 0
/* wraps fgets, returns FALSE if the whole line couldn't fit into the buffer */
BOOL read_input(char *dest, size_t len)
{
/* our temp buffer needs to hold the extra new line char (len + 1)
* should also add error checking to malloc */
BOOL bSuccess = TRUE;
size_t total_len = len + 1;
char *temp = (char*) malloc( total_len * sizeof(char) );
fgets(temp, total_len, stdin);
/* if the whole line wasn't read, we'll return FALSE but still copy temp into dest */
if (temp[strlen(temp) - 1] != '\n')
bSuccess = FALSE;
else
temp[strlen(temp) - 1] = '\0'; /* overwrite the '\n' if it does infact exist */
strcpy(dest, temp);
free(temp);
return bSuccess;
}
Nun, das ist für eine einfache (na ja, nicht so einfache) Programmieraufgabe. Ich möchte an dieser Stelle nur die Klasse bestehen. Nicht zu kompliziert werden. Trotzdem danke!
– Antonpug
20. Oktober 2011 um 6:34 Uhr
Das obige kann leicht in weniger als 10 Zeilen erledigt werden, es hängt wirklich davon ab, wie oft Sie die Funktionalität wiederholen müssen. Abhängig von der Verwendung Ihrer Eingabe kann dieses Zeilenumbruchzeichen auch manchmal Probleme verursachen. Und es ist auch erwähnenswert, dass Sie, wenn fgets nicht in der Lage ist, die gesamte Zeile in Ihren Puffer zu passen, die zusätzliche Eingabe entfernen möchten, bis Sie auf einen Zeilenumbruch stoßen (fgetc in einer Schleife).
– AusCBloke
20. Oktober 2011 um 6:40 Uhr
scanf hat Zeichenbeschränkungen, wie z scanf("%99s", mySize100Buffer);. Aber nicht wie fgets Die Grenze wird durch eine Ziffernzeichenfolge angegeben, sodass zum Erfassen der BUFSIZE-1-Beziehung das Generieren einer benutzerdefinierten Formatzeichenfolge erforderlich ist. Etwas unpraktisch…
– HostileFork sagt, vertraue SE nicht
20. Oktober 2011 um 7:00 Uhr
BEARBEITEN: Hier ist ein Code, der zeigt, wie einfach Sie es haben könnten (kopieren Sie ihn nicht, damit Sie nicht wegen Plagiats erwischt werden).
– AusCBloke
20. Oktober 2011 um 7:01 Uhr
Q_SaD
Verwenden Sie diesen einfachen Code
#include"stdio.h"
#include"stdlib.h"
main()
{
int i=0,j=0;
char c,buf[100];
start:
printf("Enter the name:");
while ( (c=getchar()) != '\n' )
{
buf[i++]=c;
buf[i]='\0';
}
if ( buf[0] == '\0')
{
printf("invalid name\n");
goto start;
}
else
printf("Your name is valid\nName = %s\n",buf);
}
Nun, das ist für eine einfache (na ja, nicht so einfache) Programmieraufgabe. Ich möchte an dieser Stelle nur die Klasse bestehen. Nicht zu kompliziert werden. Trotzdem danke!
– Antonpug
20. Oktober 2011 um 6:34 Uhr
Das obige kann leicht in weniger als 10 Zeilen erledigt werden, es hängt wirklich davon ab, wie oft Sie die Funktionalität wiederholen müssen. Abhängig von der Verwendung Ihrer Eingabe kann dieses Zeilenumbruchzeichen auch manchmal Probleme verursachen. Und es ist auch erwähnenswert, dass Sie, wenn fgets nicht in der Lage ist, die gesamte Zeile in Ihren Puffer zu passen, die zusätzliche Eingabe entfernen möchten, bis Sie auf einen Zeilenumbruch stoßen (fgetc in einer Schleife).
– AusCBloke
20. Oktober 2011 um 6:40 Uhr
scanf hat Zeichenbeschränkungen, wie z scanf("%99s", mySize100Buffer);. Aber nicht wie fgets Die Grenze wird durch eine Ziffernzeichenfolge angegeben, sodass zum Erfassen der BUFSIZE-1-Beziehung das Generieren einer benutzerdefinierten Formatzeichenfolge erforderlich ist. Etwas unpraktisch…
– HostileFork sagt, vertraue SE nicht
20. Oktober 2011 um 7:00 Uhr
BEARBEITEN: Hier ist ein Code, der zeigt, wie einfach Sie es haben könnten (kopieren Sie ihn nicht, damit Sie nicht wegen Plagiats erwischt werden).
– AusCBloke
20. Oktober 2011 um 7:01 Uhr
12457600cookie-checkWas ist der einfachste Weg, Benutzereingaben in C zu erhalten?yes
Mögliches Duplikat stackoverflow.com/questions/314401/…
– Ray Total
20. Oktober 2011 um 6:11 Uhr