Как прочитать строку фиксированной длины, не ожидая дальнейших вводов / новой строки? - PullRequest
0 голосов
/ 07 апреля 2020

Моя проблема:

Моя цель - прочитать строку фиксированной длины из stdin, сохранить ее в буфере и сразу же продолжить выполнение следующего кода, но ни fgets(), ни scanf() перестать ждать получения большего ввода, даже если фиксированное количество символов для чтения фиксировано -> scanf("%5s",c); и fgets(b,6,stdin);.

Я написал этот пример, чтобы проиллюстрировать проблему:

#include <stdio.h>
#include <string.h>

int main(void)
{
    char b[6];
    char c[6];

    printf("Enter a string of 5 characters (b):\n");
    fgets(b, sizeof(b), stdin);   
    getchar();                    // catch the left newline in stdin because in 
                                  // b was not enough space.

    printf("\nEnter a string of 5 characters (c):\n");    
    scanf("%5s", c);
    //getchar();                  // catch the left newline. important if there is any 
                                  // read operation thereafter.
    printf("\nb: %s\n", b);
    printf("c: %s\n", c);

    return 0;
}

Выполнение:

/a.out
Enter a string of 5 characters (b):
hello

Enter a string of 5 characters (c):
world

b: hello
c: world

Оба, fgets() и scanf(), ждут перехода на новую строку. В качестве примечания: в случае scanf() с указателем формата %s любой пробел остановит использование директивы; В случае scanf() с указателем формата %[ и отрицательным набором сканирования %[^N] вхождение N остановит потребление.

В любом случае он ожидает большего ввода, хотя и указан для чтения всего 5 символов.

Как прочитать строку, не ожидая ввода большего числа?


Мои исследования:

Я нашел способ достичь того, что я хочу, но это довольно большой обходной путь: я мог бы поймать каждый символ отдельно и использовать производную getch() для Linux (потому что я работаю с Linux и conio.h здесь не topi c), которые предоставляются в ответах на Что эквивалентно getch () & getche () в Linux? в for -l oop и после этого присваивает завершающий нулевой символ последнему элементу, например, fe :

#include <termios.h>
#include <stdio.h>

static struct termios old, current;

/* Initialize new terminal i/o settings */
void initTermios(int echo) 
{
  tcgetattr(0, &old); /* grab old terminal i/o settings */
  current = old; /* make new settings same as old settings */
  current.c_lflag &= ~ICANON; /* disable buffered i/o */
  if (echo) {
      current.c_lflag |= ECHO; /* set echo mode */
  } else {
      current.c_lflag &= ~ECHO; /* set no echo mode */
  }
  tcsetattr(0, TCSANOW, &current); /* use these new terminal i/o settings now */
}

/* Restore old terminal i/o settings */
void resetTermios(void) 
{
  tcsetattr(0, TCSANOW, &old);
}

/* Read 1 character - echo defines echo mode */
char getch_(int echo) 
{
  char ch;
  initTermios(echo);
  ch = getchar();
  resetTermios();
  return ch;
}

/* Read 1 character without echo */
char getch(void) 
{
  return getch_(0);
}

/* Read 1 character with echo */
char getche(void) 
{
  return getch_(1);
}

int main(void)
{
    char b[6];
    int c;

    printf("Enter a string of 5 characters (b):\n");

    for(int i = 0; i < 5; i++)
    {
        if((c = getch_(1)) == EOF)
        {
            if(ferror(stdin))
            {

            }
            else if(feof(stdin))
            {
                fprintf(stderr,"End of file reached!"); 
            }          
        }
        else
        {
            b[i] = c;
        }
    }

    b[5] = '\0';

    printf("\n\n");

    puts(b);

    return 0;
}

Но этот метод довольно большой обходной путь. Есть ли способ добиться этого более простым способом?

...