web-dev-qa-db-fra.com

Quel est le moyen le plus simple d’obtenir une entrée utilisateur en C?

Il semble y avoir beaucoup de façons d'obtenir une entrée utilisateur en C. 

Quel est le moyen le plus simple qui nécessite peu de code?

En gros, j'ai besoin d'afficher ceci:

Enter a file name: Apple.text

En gros, je dois demander à l'utilisateur un nom de fichier. J'ai donc besoin de quelque chose qui obtienne simplement ce mot que l'utilisateur saisira. 

20
antonpug

Le plus simple "correct" est probablement celle-ci, tirée du document de Bjarne Stroustrup Learning Standard C++ comme nouvelle langue .

(Remarque: j'ai modifié le code de Bjarne pour qu'il vérifie isspace() au lieu de simplement la fin de la ligne. Aussi, à cause du commentaire de @ matejkramny, utiliser while(1) au lieu de while(true)... et tant que nous sommes assez hérétiques pour éditer celui de Stroustrup code, j’ai sous-classé dans les commentaires C89 au lieu du style C++ aussi. :-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;
}

Cela couvre:

  • sauter des espaces jusqu'à la saisie de caractères
  • extension dynamique du tampon de chaîne pour l'adapter à des chaînes de taille arbitraire
  • conditions de traitement lorsque la mémoire ne peut pas être allouée

Existe-t-il des solutions plus simples mais brisées, qui pourraient même aller un peu plus vite? Absolument!!

Si vous utilisez scanf dans un tampon sans limite de taille de lecture, votre saisie dépasse la taille du tampon, ce qui créera une faille de sécurité et/ou un crash.

Limiter la taille de la lecture à, disons, seulement 100 caractères uniques d'un nom de fichier pourrait sembler préférable à un crash. Mais cela peut être pire. Par exemple, si l'utilisateur voulait dire (...)/dir/foo/bar.txt mais que vous finissez par mal interpréter sa saisie et écrasez un fichier appelé bar.t dont il se souciait peut-être.

Il est préférable de prendre de bonnes habitudes tôt dans le traitement de ces problèmes. Mon avis est que si vos exigences justifient une approche proche du métal et du style "C-like", cela vaut la peine d'envisager le passage au C++. Il a été conçu pour gérer précisément ces problèmes - avec des techniques robustes et extensibles, tout en offrant de bonnes performances.

23
HostileFork

scanf semble fonctionner dans un environnement non hostile. En d'autres termes, vous créez un programme utilitaire simple pour vous-même.

BUFSIZ dépasse généralement de loin les limites de noms de chemin UNIX.

#include <stdio.h>

int main(void) {
  char str[BUFSIZ];                                                                                                                                                                             

  printf("Enter a file name: ");                                                                                                                                                                
  scanf("%s", str);                                                                                                                                                                             

  printf("You entered: %s\n", str);                                                                                                                                                             
}

Si vous devez accumuler des données dans un programme pouvant être la cible d'un dépassement de mémoire tampon, vous aurez peut-être besoin d'un peu plus.

#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;
}
7
karrick
#include <stdio.h>
int main(void)
{
    char file[100];
    printf("File Name?: \n");
    fgets(file, 100, stdin);
    printf("Your input: %s", file);
}
3
Tio Pepe

vous devriez écrire votre propre fonction wrapper fgets () qui lit une ligne d’entrée dans un tampon d’une taille spécifiée et qui supprime le caractère de nouvelle ligne que fgets () lit également. vous pouvez également renvoyer un statut indiquant si la ligne entière a ou non pu s'intégrer dans la mémoire tampon (c'est-à-dire que la nouvelle ligne se trouve à la fin de la mémoire tampon). vous ne devriez jamais vraiment utiliser scanf ou get sauf si vous voulez des débordements.

EDIT: pensé que je pourrais fournir un code de base:

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;
}
1
AusCBloke
#include <iostream>
#include <string>

using namespace std;

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

    string filepath;
    cin >> filepath;
}
1
Ayjay

Utilisez ce code simple

#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);
      }                                                                                                                             
0
Q_SaD