Domanda

Qual è il modo più semplice per leggere una riga completa in un programma della console C. Il testo inserito potrebbe avere una lunghezza variabile e non possiamo ipotizzare il suo contenuto.

È stato utile?

Soluzione

È necessaria la gestione dinamica della memoria e utilizzare la funzione fgets per leggere la riga. Tuttavia, non sembra esserci modo di vedere quanti personaggi legge. Quindi usi 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 : non usare mai get! Non esegue il controllo dei limiti e può sovraccaricare il buffer

Altri suggerimenti

Se si utilizza la libreria GNU C o un'altra libreria conforme a POSIX, è possibile utilizzare getline () e passaci stdin per il flusso di file.

Un'implementazione molto semplice ma non sicura per leggere la riga per l'allocazione statica:

char line[1024];

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

Un'implementazione più sicura, senza la possibilità di overflow del buffer, ma con la possibilità di non leggere l'intera riga, è:

char line[1024];

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

Non la 'differenza di uno' tra la lunghezza specificata che dichiara la variabile e la lunghezza specificata nella stringa di formato. È un manufatto storico.

Potrebbe essere necessario utilizzare un ciclo carattere per carattere (getc ()) per assicurarsi di non avere buffer overflow e di non troncare l'input.

Quindi, se stavi cercando argomenti di comando, dai un'occhiata alla risposta di Tim. Se vuoi solo leggere una riga dalla 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;
}

Sì, non è sicuro, è possibile eseguire il sovraccarico del buffer, non controlla la fine del file, non supporta la codifica e molte altre cose. In realtà non pensavo nemmeno se avesse fatto QUALSIASI di queste cose. Sono d'accordo che ho fatto un casino :) Ma ... quando vedo una domanda come " Come leggere una riga dalla console in C? & Quot ;, presumo che una persona abbia bisogno di qualcosa di semplice, come gets () e non 100 righe di codice come sopra. In realtà, penso che, se provassi a scrivere quelle 100 righe di codice in realtà, faresti molti più errori di quanti avresti fatto se avessi scelto ottiene;)

getline esempio eseguibile

Menzionato su questa risposta ma ecco un esempio.

È POSIX 7 , alloca memoria per noi e riutilizza correttamente il buffer allocato su un ciclo.

Puntatori newbs, leggi questo: Perché il primo argomento di getline è un puntatore al puntatore " char ** " invece di " char * " ;?

#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 (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;
}

implementazione glibc

Nessun POSIX? Forse vuoi dare un'occhiata a implementazione glibc 2.23 .

Si risolve in getdelim , che è un semplice superset POSIX di getline con un terminatore di riga arbitrario.

Raddoppia la memoria allocata ogni volta che è necessario un aumento e sembra thread-safe.

Richiede una certa espansione macro, ma è improbabile che tu faccia molto meglio.

Come suggerito, puoi usare getchar () per leggere dalla console fino a quando non viene restituito un end-of-line o un EOF, costruendo il tuo buffer. Il buffer crescente può verificarsi in modo dinamico se non si è in grado di impostare una dimensione massima della linea ragionevole.

Puoi usare anche i fgets come un modo sicuro per ottenere una linea come stringa con terminazione nulla C:

#include <stdio.h>

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);

Se hai esaurito l'input della console o se l'operazione non è riuscita per qualche motivo, viene restituito eof == NULL e il buffer di linea potrebbe essere invariato (motivo per cui è utile impostare il primo carattere su '\ 0').

i budget non riempiranno eccessivamente la riga [] e assicurerà che ci sia un valore nullo dopo l'ultimo carattere accettato su un reso riuscito.

Se è stata raggiunta la fine della riga, il carattere che precede la fine '\ 0' sarà un '\ n'.

Se non esiste alcuna terminazione '\ n' prima della fine '\ 0', è possibile che ci siano più dati o che la richiesta successiva riporterà la fine del file. Dovrai fare un altro budget per determinare quale è quale. (A questo proposito, eseguire il ciclo con getchar () è più semplice.)

Nel codice di esempio (aggiornato) sopra, se la riga [sizeof (riga) -1] == '\ 0' dopo i budget riusciti, sai che il buffer è stato riempito completamente. Se quella posizione è seguita da un '\ n' sai che sei stato fortunato. Altrimenti, ci sono più dati o una fine del file più avanti in stdin. (Quando il buffer non è completamente compilato, potresti essere ancora alla fine del file e potrebbe anche non esserci un '\ n' alla fine della riga corrente. Dato che devi scansionare la stringa per trovare e / o eliminare qualsiasi '\ n' prima della fine della stringa (il primo '\ 0' nel buffer), sono propenso a preferire usare getchar () in primo luogo.)

Fai ciò che devi fare per gestire la presenza di più righe rispetto all'importo che leggi come primo blocco. Gli esempi di espansione dinamica di un buffer possono essere fatti funzionare con getchar o fgets. Ci sono alcuni casi limite difficili da tenere d'occhio (come ricordare di avere il prossimo input che inizia a memorizzare nella posizione dello '\ 0' che ha terminato l'input precedente prima che il buffer fosse esteso).

Molte persone, come me, vengono a questo post con il titolo corrispondente a ciò che viene cercato, anche se la descrizione parla di lunghezza variabile. Nella maggior parte dei casi, conosciamo in anticipo la lunghezza.

Se conosci la lunghezza prima, prova di seguito:

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

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

  

Come leggere una riga dalla console in C?

  • Costruisci la tua funzione , è uno dei modi per aiutarti a ottenere la lettura di una riga dalla console in C .

  • Sto usando allocazione dinamica della memoria per allocare solo la quantità sufficiente di memoria richiesta per contenere tutti i caratteri di una riga insieme al carattere '\ 0' .

  • E qui sto usando un ciclo per scansionare ogni carattere della stringa uno per uno usando la funzione getchar () fino a quando l'utente inserisce '\ n' o EOF carattere

    //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;
    }  
    
  • Ora puoi leggere una riga intera in questo modo:

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

Ecco un programma di esempio usando la funzione scan_line () :

#include <stdio.h>
#include <stdlib.h> //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
}

input di esempio:

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

output di esempio:

<*>

Qualche tempo fa ho riscontrato lo stesso problema, questa era la mia soluzione, spero che sia d'aiuto.

/*
 * 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;
}

Su sistemi BSD e Android puoi anche usare fgetln :

#include <stdio.h>

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

In questo modo:

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

La linea non ha una terminazione nulla e contiene \ n (o qualunque sia la piattaforma utilizzata) alla fine. Diventa non valido dopo la successiva operazione I / O sullo stream.

Qualcosa del genere:

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;
}

Questa funzione dovrebbe fare quello che vuoi:

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 );

Spero che questo aiuti.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top