Как читать строку с консоли в C?

Каков самый простой способ прочитать полную строку в программе на консоли C Введенный текст может иметь переменную длину, и мы не можем делать никаких предположений о его содержании.

Ответ 1

Вам необходимо динамическое управление памятью и используйте функцию fgets для чтения вашей строки. Однако, похоже, нет способа увидеть, сколько символов он читает. Поэтому вы используете 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;
}

Примечание. Никогда не используйте get! Он не выполняет проверку границ и может переполнять ваш буфер

Ответ 2

Если вы используете библиотеку GNU C или другую библиотеку, совместимую с POSIX, вы можете использовать getline() и передать stdin в это для потока файлов.

Ответ 3

Возможно, вам потребуется использовать цикл символа (getc()), чтобы убедиться, что у вас нет переполнения буфера и не усекайте ввод.

Ответ 4

Очень простая, но небезопасная реализация для чтения строки для статического распределения:

char line[1024];

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

Более безопасная реализация без возможности переполнения буфера, но с возможностью не читать всю строку:

char line[1024];

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

Не "разница на единицу" между указанной длиной, объявляющей переменную, и длиной, указанной в строке формата. Это исторический артефакт.

Ответ 5

Итак, если вы искали аргументы команды, взгляните на ответ Тима. Если вы просто хотите прочитать строку с консоли:

#include <stdio.h>

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

Да, это не безопасно, вы можете перегрузить буфер, он не проверяет конец файла, он не поддерживает кодировки и много других вещей. На самом деле я даже не думал, сделал ли это ЛЮБОЙ из этого. Я согласен, что я немного испортил:) Но... когда я вижу такой вопрос, как "Как читать строку с консоли в C?", Я предполагаю, что человеку нужно что-то простое, например gets(), а не 100 строк кода, как указано выше. На самом деле, я думаю, если вы попытаетесь написать эти 100 строк кода в реальности, вы сделали бы еще много ошибок, чем вы бы сделали, если бы вы выбрали get;)

Ответ 6

getline пример выполнения

Указано в этом ответе, но вот пример.

Это POSIX 7, выделяет нам память и повторно использует выделенный буфер в цикле.

Указатель newbs, прочитайте следующее: Почему первый аргумент getline указывает на указатель "char **" вместо "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;
}

реализация glibc

Нет POSIX? Возможно, вы хотите посмотреть glibc 2.23.

Он разрешает getdelim, что является простым надмножеством POSIX getline с произвольным терминатором строк.

Он удваивает выделенную память, когда требуется увеличение, и выглядит в потоковом режиме.

Для этого требуется некоторое расширение макроса, но вряд ли вы сделаете гораздо лучше.

Ответ 7

Как и было предложено, вы можете использовать getchar() для чтения с консоли до тех пор, пока не будет возвращен конец строки или EOF, создав собственный буфер. Динамический динамический рост может возникать, если вы не можете установить разумный максимальный размер строки.

Вы также можете использовать fgets как безопасный способ получить строку в виде строки с нулевым символом:

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

Если вы исчерпали вход в консоль или если по какой-то причине операция завершилась неудачно, возвращается eof == NULL и буфер строки может не измениться (именно поэтому установка первого char в '\ 0 "удобна).

fgets не будет переполнять строку [], и это гарантирует, что после успешного приема возвращается нуль.

Если конец линии был достигнут, символ, предшествующий завершающему "\ 0" , будет "\n" .

Если до окончания '\ 0' не заканчивается '\n', может быть, есть больше данных или что следующий запрос будет сообщать о конце файла. Вам нужно будет сделать еще один fgets, чтобы определить, что есть. (В этом отношении петля с getchar() проще.)

В приведенном выше (примерном) примере кода, если строка [sizeof (line) -1] == '\ 0' после успешных fgets, вы знаете, что буфер заполнен полностью. Если это положение выполняется "\n" , вы знаете, что вам повезло. В противном случае в stdin есть либо больше данных, либо конец файла. (Когда буфер не заполнен полностью, вы все равно можете быть в конце файла, и в конце текущей строки также может быть не \\n \. Поскольку вам нужно отсканировать строку, чтобы найти и/или исключить любой "\n" до конца строки (первый "\ 0" в буфере), я склонен предпочитать использование getchar() в первую очередь.)

Сделайте то, что вам нужно сделать, чтобы иметь дело с тем, что все еще больше, чем количество, которое вы читали в качестве первого фрагмента. Примеры динамически растущего буфера могут быть созданы для работы с getchar или fgets. Есть несколько сложных случаев краев, на которые следует обратить внимание (например, помнить, что следующий вход начинается с хранения в позиции "\ 0" , которая закончила предыдущий вход, до того, как буфер был расширен).

Ответ 8

Многие люди, такие как я, приходят на этот пост с заголовком, соответствующим тому, что искали, хотя в описании говорится о переменной длине. В большинстве случаев мы знаем длину заранее.

Если вы знаете длину перед рукой, попробуйте ниже:

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

источник: https://www.tutorialspoint.com/c_standard_library/c_function_fgets.htm

Ответ 9

Я бы изменил ответ @litb на

char *getline(void)
{
   char* accumulator = malloc(100);
   char readBuf[100];
   int accumulatorSize = 100;
   *accumulator = '\0';

   while (!feof(stdin))
   {
     fgets(readBuf, 99, stdin);
     strcat(accumulator, readBuf);
     /* possible fencepost error here */
     if (readBuf[strlen(readBuf)] != '\n')
     {
       accumulatorSize += 100;
       accumulator = realloc(accumulator, accumulatorSize);
       /* should probably check for realloc returning null */
     }
     else
       break;
   }
   return accumulator;
}

Помните, что это более голой код C, чем я написал через 11 лет.

Ответ 10

Я столкнулся с той же проблемой некоторое время назад, это было моим решением, надеюсь, что это поможет.

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

Ответ 11

В BSD-системах и Android вы также можете использовать fgetln:

#include <stdio.h>

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

Так же:

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

line не завершается нулем и содержит \n (или что-то, что использует ваша платформа) в конце. Он становится недействительным после следующей операции ввода-вывода в потоке.

Ответ 12

Как читать строку с консоли в C?

  • Создание вашей собственной функции - это один из способов, который поможет вам добиться чтения строки с консоли в C.

  • Я использую распределение динамической памяти, чтобы выделить достаточный объем памяти, необходимый для хранения все символы строки вместе с символом '\0'.

  • И здесь я использую цикл для сканирования каждого символа строки один за другим с помощью функции getchar() до тех пор, пока пользователь не войдет в символ '\n' или 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;
    }  
    
  • Теперь вы можете прочитать полную строку следующим образом:

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

Здесь пример программы с помощью функции 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
}

образец ввода:

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

вывод образца:

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

Ответ 13

Что-то вроде этого:

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

Ответ 14

Эта функция должна делать то, что вы хотите:

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

Надеюсь, это поможет.