It is because your terminal inputs are buffered in the I/O queue of the kernel.
Input and output queues of a terminal device implement a form of buffering within the kernel independent of the buffering implemented by I/O streams.
The terminal input queue is also sometimes referred to as its typeahead buffer. It holds the characters that have been received from the terminal but not yet read by any process.
The size of the input queue is described by the MAX_INPUT and _POSIX_MAX_INPUT parameters;
By default, your terminal is in Canonical mode.
In canonical mode, all input stays in the queue until a newline character is received, so the terminal input queue can fill up when you type a very long line.
Now to answer your questions:
Is there a way to instruct scanf
to read more than 2 line?
That 2 line concept is wrong. Anyways, you can't instruct scanf
to read more than 4096 bytes if the maximum size of I/O queue of the terminal is set to 4096 bytes.
Is there any other function which we can use which doesn't have this limitation ?
No you can't even with any other function. It's not a limitation of scanf
.
EDIT: Found a rather standard way of doing it
We can change the input mode of terminal from canonical mode to non-canonical mode.
To change the input mode we have to use low level terminal interface.
We can do the task as follows:
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
int clear_icanon(void)
{
struct termios settings;
int result;
result = tcgetattr (STDIN_FILENO, &settings);
if (result < 0)
{
perror ("error in tcgetattr");
return 0;
}
settings.c_lflag &= ~ICANON;
result = tcsetattr (STDIN_FILENO, TCSANOW, &settings);
if (result < 0)
{
perror ("error in tcsetattr");
return 0;
}
return 1;
}
int main()
{
clear_icanon(); // Changes the input mode of terminal from canonical mode to non canonical mode.
char input_array[5000];
int len;
printf("Enter key: ");
scanf("%s",input_array);
len = strlen(input_array);
printf("Message: %s\n",input_array);
printf("Message Len: %d\n",len);
return 0;
}
In case you want to know how to do it from terminal
$ stty -icanon (changes the input mode to non-canonical)
$ stty icanon (changes it back to canonical)
Earlier answer was: (This technique is older)
I don't know whether it is the best way or not, but It can be done by changing the terminal mode from cooked
(default) to cbreak
or to raw
mode.
When the terminal is in cbreak
mode, It works with single characters at a time, rather than forcing a wait for a whole line and then feeding the line in all at once.
either you can use stty cbreak
in terminal before executing the program.
or
To use cbreak mode programatically
First install the curses
package by running
$ sudo apt-get install libncurses5-dev
Next edit the program as follows:
#include <stdio.h>
#include <string.h>
#include <curses.h>
int main()
{
initscr(); //start curses mode
cbreak(); //change the terminal mode to cbreak. Can also use raw();
endwin(); //end curses mode
char input_array[5000];
int len;
printf("Enter key:");
scanf("%s",input_array);
len = strlen(input_array);
printf("Message:%s\n",input_array);
printf("Message Len:%d\n",len);
return 0;
}
Now compile with the -lcurses
option
$ gcc 1.c -lcurses