122 votes

Comment lire une ligne de la console en C ?

Quel est le moyen le plus simple de lire une ligne complète dans un programme C en console ? Le texte saisi peut avoir une longueur variable et nous ne pouvons pas faire d'hypothèse sur son contenu.

91voto

Johannes Schaub - litb Points 256113

Vous avez besoin d'une gestion dynamique de la mémoire, et vous utilisez le fgets pour lire votre ligne. Cependant, il ne semble pas y avoir de moyen de voir combien de caractères elle a lus. Vous utilisez donc fgetc :

char * getline(void) {
    char * line = malloc(100), * linep = line;
    size_t lenmax = 100, len = lenmax;
    int c;

    if(line == NULL)
        return NULL;

    for(;;) {
        c = fgetc(stdin);
        if(c == EOF)
            break;

        if(--len == 0) {
            len = lenmax;
            char * linen = realloc(linep, lenmax *= 2);

            if(linen == NULL) {
                free(linep);
                return NULL;
            }
            line = linen + (line - linep);
            linep = linen;
        }

        if((*line++ = c) == '\n')
            break;
    }
    *line = '\0';
    return linep;
}

Nota : N'utilisez jamais gets ! Il ne vérifie pas les limites et peut faire déborder votre tampon.

0 votes

Attention - il faut vérifier le résultat de realloc à cet endroit. Mais si cela échoue, alors il y a probablement des problèmes plus graves.

4 votes

Vous pourriez probablement améliorer un peu l'efficacité en faisant fgets avec buffer, et en vérifiant si vous avez le caractère newline à la fin. Si ce n'est pas le cas, réallouez votre tampon d'accumulation, copiez dedans, et refaites fgets.

0 votes

Paul, ce qui me garantit qu'il y a une nouvelle ligne ou ' \0 ' à la fin si fgets n'a pas besoin de plus d'espace ? il aurait pu lire moins que la taille du tampon. Attendez. Vous voulez dire que vous utilisez strlen pour trouver la taille du tampon. \0 et regarder devant ? Je n'étais pas sûr de ce qui était le plus rapide. J'ai donc opté pour la méthode char par char.

34voto

dmityugov Points 2786

Si vous utilisez la bibliothèque GNU C ou une autre bibliothèque conforme à POSIX, vous pouvez utiliser getline() et passer stdin pour le flux de fichiers.

25voto

Une implémentation très simple mais peu sûre de la ligne de lecture pour l'allocation statique :

char line[1024];

scanf("%[^\n]", line);

Une mise en œuvre plus sûre, sans possibilité de dépassement de tampon, mais avec la possibilité de ne pas lire toute la ligne, est la suivante :

char line[1024];

scanf("%1023[^\n]", line);

Pas la "différence de un" entre la longueur spécifiée dans la déclaration de la variable et la longueur spécifiée dans la chaîne de format. Il s'agit d'un artefact historique.

21voto

badbadboy Points 1754

Donc, si vous cherchez des arguments de commande, jetez un coup d'œil à la réponse de Tim. Si vous voulez juste lire une ligne de la console :

#include <stdio.h>

int main()
{
  char string [256];
  printf ("Insert your full address: ");
  gets (string);
  printf ("Your address is: %s\n",string);
  return 0;
}

Oui, il n'est pas sécurisé, vous pouvez faire un dépassement de tampon, il ne vérifie pas la fin du fichier, il ne supporte pas les encodages et beaucoup d'autres choses. En fait, je ne me suis même pas demandé s'il faisait TOUT cela. Je reconnais que j'ai un peu merdé :) Mais...quand je vois une question comme "Comment lire une ligne de la console en C ?", je suppose que la personne a besoin de quelque chose de simple, comme gets() et pas de 100 lignes de code comme ci-dessus. En fait, je pense que si vous essayez d'écrire ces 100 lignes de code dans la réalité, vous feriez beaucoup plus d'erreurs, que si vous aviez choisi gets ;)

1 votes

Cela ne permet pas d'avoir de longues cordes... - ce qui, je pense, est le cœur de sa question.

2 votes

-1, gets() ne doit pas être utilisé car il ne vérifie pas les limites.

0 votes

Gets est une fonction sécurisée

14voto

Ciro Santilli Points 3341

getline Exemple d'exécution

getline a été mentionné sur cette réponse mais voici un exemple.

Il est POSIX 7 alloue de la mémoire pour nous, et réutilise le tampon alloué sur une boucle gentiment.

Les novices du pointeur, lisez ça : Pourquoi le premier argument de getline est un pointeur sur le pointeur "char**" au lieu de "char*" ?

main.c

#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    char *line = NULL;
    size_t len = 0;
    ssize_t read = 0;
    while (1) {
        puts("enter a line");
        read = getline(&line, &len, stdin);
        if (read == -1)
            break;
        printf("line = %s", line);
        printf("line length = %zu\n", read);
        puts("");
    }
    free(line);
    return 0;
}

Compilez et exécutez :

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out

Résultat : cela se voit sur therminal :

enter a line

Alors si vous tapez :

asdf

et appuyez sur entrée, ceci apparaît :

line = asdf
line length = 5

suivi d'un autre :

enter a line

Ou d'un tuyau vers stdin :

printf 'asdf\nqwer\n' | ./main.out

donne :

enter a line
line = asdf
line length = 5

enter a line
line = qwer
line length = 5

enter a line

Testé sur Ubuntu 20.04.

implémentation de la glibc

Pas de POSIX ? Peut-être que vous voulez regarder le Mise en œuvre de la glibc 2.23 .

Elle décide de getdelim qui est un simple sur-ensemble POSIX de getline avec un terminateur de ligne arbitraire.

Il double la mémoire allouée chaque fois qu'une augmentation est nécessaire, et semble sûr pour les threads.

Cela nécessite une certaine extension de la macro, mais il est peu probable que vous puissiez faire beaucoup mieux.

0 votes

Quel est le but de len ici, quand il est lu fournit la longueur trop

1 votes

@Abdul see man getline . len est la longueur du tampon existant, 0 est magique et lui dit d'allouer. Read est le nombre de caractères lus. La taille du tampon peut être supérieure à read .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X