Как прочитать строку из консоли в C? - PullRequest
97 голосов
/ 24 ноября 2008

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

Ответы [ 13 ]

75 голосов
/ 24 ноября 2008

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

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

27 голосов
/ 24 ноября 2008

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

15 голосов
/ 25 ноября 2008

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

char line[1024];

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

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

char line[1024];

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

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

11 голосов
/ 24 ноября 2008

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

8 голосов

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 с произвольным ограничителем строки.

Удваивает выделенную память всякий раз, когда необходимо увеличение, и выглядит поточно-ориентированным.

Это требует некоторого расширения макроса, но вряд ли у вас получится намного лучше.

8 голосов
/ 24 ноября 2008

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

#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?", Я предполагаю, что человеку нужно что-то простое, например, get (), а не 100 строк кода, как указано выше. На самом деле, я думаю, что если бы вы попытались написать эти 100 строк кода на самом деле, вы бы совершили гораздо больше ошибок, чем сделали бы, если бы вы выбрали;)

5 голосов
/ 26 ноября 2008

Как и предполагалось, вы можете использовать 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 и линейный буфер может быть неизменным (вот почему установка первого символа '\ 0' удобна).

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

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

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

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

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

3 голосов
/ 02 октября 2015

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

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

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

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

1 голос
/ 21 июля 2016

Как прочитать строку из консоли в 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!
0 голосов
/ 25 мая 2017

Примерно так:

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