Comment lire une ligne de la console en C?

Quelle est la manière la plus simple de lire une ligne complète dans un programme de console C? Le texte saisi peut avoir une longueur variable et nous ne pouvons pas en déduire le contenu.

Vous avez besoin d’une gestion dynamic de la mémoire et utilisez la fonction fgets pour lire votre ligne. Cependant, il semble y avoir aucun moyen de voir combien de caractères il a lu. Donc, vous utilisez 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; } 

Note : Ne jamais utiliser obtient! Il ne fait pas de vérification des limites et peut déborder de votre tampon

Si vous utilisez la bibliothèque GNU C ou une autre bibliothèque compatible POSIX, vous pouvez utiliser getline() et lui transmettre stdin pour le stream de fichiers.

Vous devrez peut-être utiliser une boucle caractère par caractère (getc ()) pour vous assurer de ne pas avoir de débordement de tampon et ne pas tronquer l’entrée.

Une implémentation très simple mais peu sûre pour lire une ligne pour une allocation statique:

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

Une implémentation plus sûre, sans possibilité de débordement de la mémoire tampon, mais avec la possibilité de ne pas lire toute la ligne, est:

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

Pas la «différence par un» entre la longueur spécifiée déclarant la variable et la longueur spécifiée dans la chaîne de format. C’est un artefact historique.

Donc, si vous cherchiez des arguments de commande, jetez un oeil à la réponse de Tim. Si vous voulez juste lire une ligne de la console:

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

Oui, ce 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 pensais même pas si cela avait été le cas. Je suis d’accord que je suis un peu foutu 🙂 Mais … quand je vois une question comme “Comment lire une ligne de la console en C?”, Je suppose qu’une personne a besoin de quelque chose de simple, comme get () et pas 100 lignes de code comme ci-dessus En fait, je pense que si vous essayez d’écrire ces 100 lignes de code en réalité, vous commetsortingez beaucoup plus d’erreurs que vous ne l’auriez fait si vous aviez choisi;)

getline

Mentionné sur cette réponse, mais voici un exemple.

Il s’agit de POSIX 7 , alloue de la mémoire pour nous et réutilise joliment le tampon alloué.

Pointeur newbs, lisez ceci: Pourquoi le premier argument de getline est-il un pointeur sur le pointeur “char **” au lieu de “char *”?

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

implémentation glibc

Pas de POSIX? Peut-être que vous voulez regarder l’ implémentation de la glibc 2.23 .

Il se getdelim à 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 sans risque.

Cela nécessite une expansion de la macro, mais il est peu probable que vous fassiez beaucoup mieux.

Comme suggéré, vous pouvez utiliser getchar () pour lire depuis la console jusqu’à ce qu’une fin de ligne ou un EOF soit renvoyé, en construisant votre propre tampon. Un tampon dynamic croissant peut se produire si vous ne pouvez pas définir une taille de ligne maximale raisonnable.

Vous pouvez également utiliser fgets comme un moyen sûr d’obtenir une ligne en tant que chaîne C terminée par null:

 #include  char line[1024]; /* Generously large value for most situations */ char *eof; line[0] = '\0'; /* Ensure empty line if no input delivered */ line[sizeof(line)-1] = ~'\0'; /* Ensure no false-null at end of buffer */ eof = fgets(line, sizeof(line), stdin); 

Si vous avez épuisé l’entrée de la console ou si l’opération a échoué pour une raison quelconque, eof == NULL est renvoyé et le tampon de ligne peut être inchangé (ce qui explique pourquoi définir le premier caractère sur ‘\ 0’ est pratique).

fgets ne dépassera pas la ligne [] et garantira la présence d’un null après le dernier caractère accepté lors d’un retour réussi.

Si la fin de ligne a été atteinte, le caractère précédant la terminaison ‘\ 0’ sera un ‘\ n’.

S’il n’y a pas de terminaison ‘\ n’ avant la fin ‘\ 0’, il se peut qu’il y ait plus de données ou que la requête suivante signalera la fin du fichier. Vous devrez en faire un autre pour déterminer lequel est qui. (À cet égard, la boucle avec getchar () est plus facile.)

Dans l’exemple de code (mis à jour) ci-dessus, si la ligne [sizeof (line) -1] == ‘\ 0’ après avoir réussi un object, vous savez que le tampon a été complètement rempli. Si cette position est suivie d’un «\ n», vous savez que vous avez eu de la chance. Sinon, il y a plus de données ou une fin de fichier dans stdin. (Lorsque le tampon n’est pas complètement rempli, vous pouvez toujours être à la fin du fichier et il peut également ne pas y avoir de ‘\ n’ à la fin de la ligne en cours. Puisque vous devez parsingr la chaîne pour trouver et / ou éliminer tout ‘\ n’ avant la fin de la chaîne (le premier ‘\ 0’ dans le tampon), je préfère préférer utiliser getchar ().)

Faites ce que vous devez faire pour que la ligne soit toujours plus grande que le montant que vous lisez en premier. Les exemples de croissance dynamic d’un tampon peuvent être utilisés avec getchar ou fgets. Il y a quelques cas difficiles à surveiller (comme si vous vous rappeliez que l’entrée suivante commencerait à être stockée à la position du “0” qui mettait fin à l’entrée précédente avant que le tampon ne soit étendu).

Beaucoup de gens, comme moi, viennent à ce post avec le titre correspondant à ce qui est recherché, bien que la description parle de la longueur variable. Pour la plupart des cas, nous connaissons la longueur au préalable.

Si vous connaissez la longueur avant la main, essayez ci-dessous:

 char str1[1001] = { 0 }; fgets(str1, 1001, stdin); // 1000 chars may be read 

source: https://www.tutorialspoint.com/c_standard_library/c_function_fgets.htm

Comment lire une ligne de la console en C?

  • Construire votre propre fonction est l’un des moyens qui vous aideront à lire une ligne depuis la console en C.

  • J’utilise l’ allocation dynamic de mémoire pour allouer juste la quantité de mémoire suffisante requirejse pour contenir tous les caractères d’une ligne avec le caractère '\0' .

  • Et ici, j’utilise une boucle pour parsingr chaque caractère de la chaîne un par un en utilisant la getchar() jusqu’à ce que l’utilisateur entre le caractère '\n' ou EOF

     //the function to read lines of variable length char* scan_line(char *line) { int ch; //as getchar() returns `int` if( (line = malloc(sizeof(char))) == NULL) //allocating memory { //checking if allocation was successful or not printf("unsuccessful allocation"); exit(1); } line[0]='\0'; for(int index = 0; ( (ch = getchar())!='\n' ) && (ch != EOF) ; index++) { if( (line = realloc(line, (index + 2)*sizeof(char))) == NULL ) { //checking if reallocation was successful or not printf("unsuccessful reallocation"); exit(1); } line[index] = (char) ch; //type casting `int` to `char` line[index + 1] = '\0'; //inserting null character at the end } return line; } 
  • Maintenant, vous pouvez lire une ligne complète de cette façon:

     char *line = NULL; line = scan_line(line); 

Voici un exemple de programme utilisant la fonction scan_line() :

 #include  #include  //for dynamic allocation functions char* scan_line(char *line) { .......... } int main(void) { char *a = NULL; a = scan_line(a); //function call to scan the line printf("%s\n",a); //printing the scanned line free(a); //don't forget to free the malloc'd pointer } 

échantillon d’entrée:

 Twinkle Twinkle little star.... in the sky! 

sortie de l’échantillon:

 Twinkle Twinkle little star.... in the sky! 

J’ai rencontré le même problème il y a quelque temps, c’était ma solution, j’espère que ça m’aidera.

 /* * Initial size of the read buffer */ #define DEFAULT_BUFFER 1024 /* * Standard boolean type definition */ typedef enum{ false = 0, true = 1 }bool; /* * Flags errors in pointer returning functions */ bool has_err = false; /* * Reads the next line of text from file and returns it. * The line must be free()d afterwards. * * This function will segfault on binary data. */ char *readLine(FILE *file){ char *buffer = NULL; char *tmp_buf = NULL; bool line_read = false; int iteration = 0; int offset = 0; if(file == NULL){ fprintf(stderr, "readLine: NULL file pointer passed!\n"); has_err = true; return NULL; } while(!line_read){ if((tmp_buf = malloc(DEFAULT_BUFFER)) == NULL){ fprintf(stderr, "readLine: Unable to allocate temporary buffer!\n"); if(buffer != NULL) free(buffer); has_err = true; return NULL; } if(fgets(tmp_buf, DEFAULT_BUFFER, file) == NULL){ free(tmp_buf); break; } if(tmp_buf[strlen(tmp_buf) - 1] == '\n') /* we have an end of line */ line_read = true; offset = DEFAULT_BUFFER * (iteration + 1); if((buffer = realloc(buffer, offset)) == NULL){ fprintf(stderr, "readLine: Unable to reallocate buffer!\n"); free(tmp_buf); has_err = true; return NULL; } offset = DEFAULT_BUFFER * iteration - iteration; if(memcpy(buffer + offset, tmp_buf, DEFAULT_BUFFER) == NULL){ fprintf(stderr, "readLine: Cannot copy to buffer\n"); free(tmp_buf); if(buffer != NULL) free(buffer); has_err = true; return NULL; } free(tmp_buf); iteration++; } return buffer; } 

Sur les systèmes BSD et Android, vous pouvez également utiliser fgetln :

 #include  char * fgetln(FILE *stream, size_t *len); 

Ainsi:

 size_t line_len; const char *line = fgetln(stdin, &line_len); 

La line n’est pas terminée par null et contient \n (ou tout ce que votre plate-forme utilise) à la fin. Il devient invalide après la prochaine opération d’E / S en cours.

Quelque chose comme ça:

 unsigned int getConsoleInput(char **pStrBfr) //pass in pointer to char pointer, returns size of buffer { char * strbfr; int c; unsigned int i; i = 0; strbfr = (char*)malloc(sizeof(char)); if(strbfr==NULL) goto error; while( (c = getchar()) != '\n' && c != EOF ) { strbfr[i] = (char)c; i++; strbfr = (void*)realloc((void*)strbfr,sizeof(char)*(i+1)); //on realloc error, NULL is returned but original buffer is unchanged //NOTE: the buffer WILL NOT be NULL terminated since last //chracter came from console if(strbfr==NULL) goto error; } strbfr[i] = '\0'; *pStrBfr = strbfr; //successfully returns pointer to NULL terminated buffer return i + 1; error: *pStrBfr = strbfr; return i + 1; } 

Cette fonction devrait faire ce que vous voulez:

 char* readLine( FILE* file ) { char buffer[1024]; char* result = 0; int length = 0; while( !feof(file) ) { fgets( buffer, sizeof(buffer), file ); int len = strlen(buffer); buffer[len] = 0; length += len; char* tmp = (char*)malloc(length+1); tmp[0] = 0; if( result ) { strcpy( tmp, result ); free( result ); result = tmp; } strcat( result, buffer ); if( strstr( buffer, "\n" ) break; } return result; } char* line = readLine( stdin ); /* Use it */ free( line ); 

J’espère que ça aide.