web-dev-qa-db-fra.com

Comment puis-je lire une chaîne d'entrée de longueur inconnue?

Si je ne sais pas combien de temps le mot est, je ne peux pas écrire char m[6];,
La longueur du mot est peut-être dix ou vingt . Comment puis-je utiliser scanf pour obtenir une entrée au clavier?

#include <stdio.h>
int main(void)
{
    char  m[6];
    printf("please input a string with length=5\n");
    scanf("%s",&m);
    printf("this is the string: %s\n", m);
    return 0;
}

veuillez saisir une chaîne de longueur = 5
Bonjour
c'est la chaîne: bonjour 

54

Entrez en sécurisant dynamiquement une zone

PAR EXEMPLE.

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

char *inputString(FILE* fp, size_t size){
//The size is extended by the input with the value of the provisional
    char *str;
    int ch;
    size_t len = 0;
    str = realloc(NULL, sizeof(char)*size);//size is start size
    if(!str)return str;
    while(EOF!=(ch=fgetc(fp)) && ch != '\n'){
        str[len++]=ch;
        if(len==size){
            str = realloc(str, sizeof(char)*(size+=16));
            if(!str)return str;
        }
    }
    str[len++]='\0';

    return realloc(str, sizeof(char)*len);
}

int main(void){
    char *m;

    printf("input string : ");
    m = inputString(stdin, 10);
    printf("%s\n", m);

    free(m);
    return 0;
}
77
BLUEPIXY

Avec les ordinateurs d’aujourd’hui, vous pouvez vous permettre d’allouer de très grosses chaînes (des centaines de milliers de caractères) sans trop altérer l’utilisation de RAM. Donc, je ne m'inquiéterais pas trop.

Cependant, jadis, lorsque la mémoire était précieuse, la pratique courante consistait à lire les chaînes de caractères en morceaux. fgets lit jusqu'à un nombre maximal de caractères depuis l'entrée, mais laisse le reste du tampon d'entrée intact, afin que vous puissiez lire le reste comme bon vous semble.

dans cet exemple, j'ai lu des blocs de 200 caractères, mais vous pouvez utiliser la taille de bloc de votre choix, bien sûr.

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

char* readinput()
{
#define CHUNK 200
   char* input = NULL;
   char tempbuf[CHUNK];
   size_t inputlen = 0, templen = 0;
   do {
       fgets(tempbuf, CHUNK, stdin);
       templen = strlen(tempbuf);
       inputlen += templen;
       input = realloc(input, inputlen+1);
       strcat(input, tempbuf);
    } while (templen==CHUNK-1 && tempbuf[CHUNK-2]!='\n');
    return input;
}

int main()
{
    char* result = readinput();
    printf("And the result is [%s]\n", result);
    free(result);
    return 0;
}

Notez qu'il s'agit d'un exemple simplifié sans vérification d'erreur. dans la vie réelle, vous devrez vous assurer que la saisie est correcte en vérifiant la valeur de retour de fgets.

Notez également qu'à la fin de la routine readinput, aucun octet n'est gaspillé. la chaîne a la taille de mémoire exacte dont elle a besoin.

12
Mr Lister

Je n'ai vu qu'un seul moyen simple de lire une chaîne arbitrairement longue, mais je ne l'ai jamais utilisée. Je pense que ça va comme ça:

char *m = NULL;
printf("please input a string\n");
scanf("%ms",&m);
if (m == NULL)
    fprintf(stderr, "That string was too long!\n");
else
{
    printf("this is the string %s\n",m);
    /* ... any other use of m */
    free(m);
}

m entre % et s indique à scanf() de mesurer la chaîne, d'allouer de la mémoire, de la copier dans cette chaîne et de stocker l'adresse de cette mémoire allouée dans l'argument correspondant. Une fois que vous avez fini, vous devez free() it.

Toutefois, cela n’est pas pris en charge pour chaque implémentation de scanf().

Comme d'autres l'ont fait remarquer, la solution la plus simple consiste à limiter la longueur de l'entrée. Si vous souhaitez toujours utiliser scanf(), vous pouvez le faire de la manière suivante:

char m[100];
scanf("%99s",&m);

Notez que la taille de m[] doit être supérieure d'au moins un octet au nombre compris entre % et s.

Si la chaîne entrée dépasse 99, les caractères restants attendent d'être lus par un autre appel ou par le reste de la chaîne de format transmise à scanf().

En règle générale, scanf() n'est pas recommandé pour gérer les entrées de l'utilisateur. Cela s'applique mieux aux fichiers texte structurés de base créés par une autre application. Même dans ce cas, vous devez être conscient du fait que l'entrée peut ne pas être formatée comme prévu, car quelqu'un aurait pu l'interférer pour essayer de casser votre programme.

7
sh1

Si je peux suggérer une approche plus sûre:

Déclarez un tampon assez grand pour contenir la chaîne:

char user_input[255];

Obtenir la saisie de l'utilisateur de manière sûre :

fgets(user_input, 255, stdin);

Un moyen sûr d’obtenir l’entrée, le premier argument étant un pointeur sur une mémoire tampon dans laquelle l’entrée sera stockée, le deuxième l’entrée maximale que la fonction doit lire et le troisième un pointeur sur l’entrée standard - c’est-à-dire où l’utilisateur entre de.

La sécurité, en particulier, provient du deuxième argument limitant le nombre de lectures qui empêchent les dépassements de mémoire tampon. De plus, fgets prend en charge la terminaison nulle de la chaîne traitée.

Plus d'infos sur cette fonction ici .

ÉDITER: si vous avez besoin de formater (par exemple, convertir une chaîne en un nombre), vous pouvez utiliser atoi une fois que vous avez saisi l’entrée.

5
Nobilis

Version plus sûre et plus rapide (capacité doublée):

char *readline(char *Prompt) {
  size_t size = 80;
  char *str = malloc(sizeof(char) * size);
  int c;
  size_t len = 0;
  printf("%s", Prompt);
  while (EOF != (c = getchar()) && c != '\r' && c != '\n') {
    str[len++] = c;
    if(len == size) str = realloc(str, sizeof(char) * (size *= 2));
  }
  str[len++]='\0';
  return realloc(str, sizeof(char) * len);
}
3
KIM Taegyoon

Prenez un pointeur de caractère pour stocker la chaîne requise.Si vous avez une idée de la taille possible de la chaîne, utilisez la fonction

char *fgets (char *str, int size, FILE* file);`

sinon, vous pouvez aussi allouer de la mémoire à l'exécution en utilisantmalloc ()function qui fournit dynamiquement la mémoire demandée.

1
Dayal rai

Lisez directement dans l'espace alloué avec fgets().

Un soin particulier est nécessaire pour distinguer une lecture réussie, une fin de fichier, une erreur d'entrée et une mémoire insuffisante. Une bonne gestion de la mémoire est nécessaire sur EOF.

Cette méthode conserve le '\n' d'une ligne.

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

#define FGETS_ALLOC_N 128

char* fgets_alloc(FILE *istream) {
  char* buf = NULL;
  size_t size = 0;
  size_t used = 0;
  do {
    size += FGETS_ALLOC_N;
    char *buf_new = realloc(buf, size);
    if (buf_new == NULL) {
      // Out-of-memory
      free(buf);
      return NULL;
    }
    buf = buf_new;
    if (fgets(&buf[used], (int) (size - used), istream) == NULL) {
      // feof or ferror
      if (used == 0 || ferror(istream)) {
        free(buf);
        buf = NULL;
      }
      return buf;
    }
    size_t length = strlen(&buf[used]);
    if (length + 1 != size - used) break;
    used += length;
  } while (buf[used - 1] != '\n');
  return buf;
}

Utilisation de l'échantillon

int main(void) {
  FILE *istream = stdin;
  char *s;
  while ((s = fgets_alloc(istream)) != NULL) {
    printf("'%s'", s);
    free(s);
    fflush(stdout);
  }
  if (ferror(istream)) {
    puts("Input error");
  } else if (feof(istream)) {
    puts("End of file");
  } else {
    puts("Out of memory");
  }
  return 0;
}
0
chux

Je sais que je suis arrivé après 4 ans et qu'il est trop tard, mais je pense que je peux utiliser un autre moyen. J'avais utilisé getchar() Function comme ceci: -

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

//I had putten the main Function Bellow this function.
//d for asking string,f is pointer to the string pointer
void GetStr(char *d,char **f)
{
    printf("%s",d);

    for(int i =0;1;i++)
    {    
        if(i)//I.e if i!=0
            *f = (char*)realloc((*f),i+1);
        else
            *f = (char*)malloc(i+1);
        (*f)[i]=getchar();
        if((*f)[i] == '\n')
        {
            (*f)[i]= '\0';
            break;
        }
    }   
}

int main()
{
    char *s =NULL;
    GetStr("Enter the String:- ",&s);
    printf("Your String:- %s \nAnd It's length:- %lu\n",s,(strlen(s)));
    free(s);
}

voici l'exemple de test pour ce programme: -

Enter the String:- I am Using Linux Mint XFCE 18.2 , eclispe CDT and GCC7.2 compiler!!
Your String:- I am Using Linux Mint XFCE 18.2 , eclispe CDT and GCC7.2 compiler!! 
And It's length:- 67
0
user8677351

j'ai aussi une solution avec des entrées et des sorties standard

#include<stdio.h>
#include<malloc.h>
int main()
{
    char *str,ch;
    int size=10,len=0;
    str=realloc(NULL,sizeof(char)*size);
    if(!str)return str;
    while(EOF!=scanf("%c",&ch) && ch!="\n")
    {
        str[len++]=ch;
        if(len==size)
        {
            str = realloc(str,sizeof(char)*(size+=10));
            if(!str)return str;
        }
    }
    str[len++]='\0';
    printf("%s\n",str);
    free(str);
}
0
Priyanshu Agrawal