Was ist der einfachste Weg, Benutzereingaben in C zu erhalten?

Lesezeit: 8 Minuten

Benutzer-Avatar
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.

  • Mögliches Duplikat stackoverflow.com/questions/314401/…

    – Ray Total

    20. Oktober 2011 um 6:11 Uhr

Benutzer-Avatar
HostileFork sagt, vertraue SE nicht

Das einfachste “Korrekt” Weg ist wahrscheinlich dieser, entnommen aus Bjarne Stroustrups Aufsatz Lernstandard C++ als neue Sprache.

(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

Benutzer-Avatar
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.

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

char * prompt_and_read(const char * prompt) {
  char * response;
  char * bufsize;

  printf("%s", prompt);
  asprintf(&bufsize, "%%%us", BUFSIZ);

  if((response = malloc(BUFSIZ + 1)) == NULL) {
    fprintf(stderr,"out of memory\n");
    exit(1);
  }
  scanf(bufsize, response);
  free(bufsize);
  return response;
}

int main ( void ) {
  char * pathname;

  pathname = prompt_and_read("Enter a file name: ");
  printf("You entered: [%s]\n", pathname);
  free(pathname);

  return 0;
}

  • 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.

    – Karrick

    20. Oktober 2011 um 6:38 Uhr

  • Feindliche Version gerade gepostet. 🙂

    – Karrick

    20. Oktober 2011 um 7:27 Uhr

#include <stdio.h>
int main(void)
{
    char file[100];
    printf("File Name?: \n");
    fgets(file, 100, stdin);
    printf("Your input: %s", file);
}

  • Siehe auch: stackoverflow.com/questions/1252132/…

    – HostileFork sagt, vertraue SE nicht

    20. Oktober 2011 um 6:29 Uhr

#include <iostream>
#include <string>

using namespace std;

int main()
{
    cout << "Enter a file name:";

    string filepath;
    cin >> filepath;
}

Benutzer-Avatar
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

Benutzer-Avatar
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

1245760cookie-checkWas ist der einfachste Weg, Benutzereingaben in C zu erhalten?

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

Privacy policy