#define MAX_COMMAND_LEN 32
char command[MAX_COMMAND_LEN];
while (1) {
if (fgets(command, MAX_COMMAND_LEN, stdin) == NULL) {
perror("Error: standard function fgets has failed\n");
break;
}
if (command[strlen(command) -1] != '\n') {
printf("Error: command length must be less than or equal to 30 characters\n");
continue;
}
else {
printf("Error: command not found\n");
}
}
quit();
I have couple of problems which I'm not able to handle:
When I press Enter, it stops the loop and doesn't print the command not found message.
When I enter a command with a size bigger than 30 characters it prints both the command not found and the command length must be less than or equal to 30 characters messages.
When I enter a 64 size command it prints twice the 30-length message.
I believe it divides the input to 30-length segments and input each one of them, how do I overcome it? I tried to flush stdin, it does not work. I want to get rid of the rest of the input. How do I overcome all these problems?
For your second problem, it's because fgets fetches the 31 (MAX_COMMAND_LEN, minus space for the terminating '\0' character) first characters, you notice it's no newline and the next time around the loop fgets fetches the remaining characters.
When I enter a command with a size bigger than 30 characters it prints both the 'command not found' and the 'command length must be less than or equal to 30 characters' messages.
fgets reads a maximum of MAX_COMMAND_LEN - 1 characters as it leaves room for a '\0'.
This is why for any message of more than 30 character, the first 31 characters that fgets reads don't contain a '\n' and so the 30-length message is displayed.
As the second part of the command has a '\n' in the end, the command not found is also printed.
When I enter a 64 size command it prints twice the 30-length message.
fgets is called 3 times for this command. The first 31-length chunk is read, then the second 31-length chunk is read, and then the remaining characters. Both 31-length chunks don't contain a '\n' character and therefore the 30-length message is displayed twice.
You may have misunderstood how fgets actually works:
char * fgets ( char * str, int num, FILE * stream );
Reads characters from stream and stores them as a C string into str
until (num-1) characters have been read or either a newline or the
End-of-File is reached, whichever comes first. A newline character
makes fgets stop reading, but it is considered a valid character and
therefore it is included in the string copied to str. A null
character is automatically appended in str after the characters read
to signal the end of the C string.
So,
when you press "Enter" - it inputs newline and that is not exceptional case in your code.
when you input a string bigger than 30 characters fget reads it for multiple times.
same with the 60 characters - newline is NOT the last character of the string, thus you get an error twice.
For question (i), sorry, I don't know why, because my program gives the correct output.
For question (ii), you give the second argument of fgets is 32, the function will read at most 32 characters including the '\n' and '\0'; what's left is still in the stdin buffer, and when your program continues after printing the error, the fgets will read the leftover characters in the stdin buffer until it reads '\n'.
If you want to flush the stdin, you need fpurge(stdin) function to purge the stdin buffer.
Related
I want to read exactly N bytes from stdin or a file multiple times, then read less than N bytes once and then read EOF. I expected this to work:
char s[5] = "11111";
while (scanf("%4c", s) != EOF) {
printf("%s", s);
}
However, when I type 1234567890, it prints 1234156781. This is because with c type modifier it doesn't put \0 after read chars.
Other things I tried:
"%4s" reads until first whitespace
"%4[^\n]" and fgets do read until first end of line
"%4[^\0]" doesn't work (why?)
"%4[]" doesn't work
"%4" doesn't work
Is there a way to scanf up to N characters including spaces and new lines, and store them as a zero-terminated string
No, not with a single scanf() call.
The below comes close, except it does not consume the '\n', nor does it assign anything (including a null character) to buff[] when the first character is '\n'.
#define N 100
char buf[N+1];
if (scan("%100[^\n]", buf) == 1) {
"%4[^\0]" doesn't work (why?)
scanf("%4[^\0]", s) is like scanf("%4[^", s).
Both are UB because the format "%4[^" is invalid. The format parsing stops at the first null character.
Perhaps something pathologic like scanf("%4[\001-\377]", s) will "work", yet scanf() is just not the right solution for this task.
fgets() readily reads 1 line, including the '\n'.
#define N 100
char buf[N+1];
if (fgets(buf, sizeof buf, stdin)) {
...
#Timofey X How does fgets() not meet the function needs?
If OP wants to read past '\n', then use fread().
#define N 100
char buf[N+1];
size_t len = fread(buf, 1, N, stdin);
buf[len] = 0;
I want to read exactly N bytes from stdin or a file multiple times, then read less than N bytes once and then read EOF.
You will generally not encounter end-of-file on stdin when it is connected to a terminal/console, unless the user presses a certain OS-specific key combination, such as CTRL+D on Linux or CTRL+Z on Microsoft Windows.
You probably want the loop to end when you encounter the end of the line (which is when you encounter the newline character).
When using %4c with scanf, it will attempt to match exactly 4 characters. However, you want it to match up to 4 characters. Also, in the title of your question, you stated that you want scanf to write a terminating null character.
One way of solving this is to use "%4[^\n]" instead of "%4c", which will match 1 to 4 characters, instead of exactly 4 characters, and will write a terminating null character.
char s[5];
while ( scanf( "%4[^\n]", s ) == 1 ) {
printf( "%s", s );
}
However, this will not read the newline character into the buffer, so that must be done separately, if you want it.
I am trying to make a program that gets user input for a username in an array of characters and is able to call any letter from the array but if I enter more than 20 characters or none at all how do I add an error message like "Try again" without the program automatically closing when I enter too many or stopping if I enter none at all pressing just enter?
int main(void)
{
char name[20];
printf(": ");
fgets (name, 20, stdin);
printf("%c", name[2]);
}
The program automatically closes because you reach the end of main routine.
The behaviour of fgets when you don't provide enough buffer to hold the full string is to fill it as much as possible (and this is the full buffer size, less one char to put the final string terminator), put the last '\0' to end the string, and return what you have. The rest of the line will be returned in the next fgets (again, if it fills completely, or you will need another read to handle it)
Had you checked the returned value of fgets you would see that it returned a normal string and the return value was != NULL.
The way to detect that you got more characters than requested is to search for the last character of the returned string to be a '\n' character. If it is, then the read ended at the line terminator. If it is not, then the buffer is full, and it filled it completely (but be careful, that the last char of the buffer will be a '\0', I'm talking about the previous to last)
If you just press <ENTER> you'll get one character (not none), the '\n' itself. The only way to get a NULL return value from fgets is to have no more input at all (and end of file condition) which, from the terminal, can be issued by pressing Ctrl-D at the beginning of the line.
I would like to have a better understanding of using fgets() and stdin.
The following is my code:
int main()
{
char inputBuff[6];
while(fgets(inputBuff, 6, stdin))
{
printf("%s", inputBuff);
}
return 0;
}
Let's say my input is aaaabbbb and I press Enter. By using a loopcount, I understand that actually the loop will run twice (including the one I input aaaabbbb) before my next input.
Loop 1: After I have typed in the characters, aaaabbbb\n will be stored in the buffer of stdin file stream. And fgets() is going to retrieve a specific number of data from the file stream and put them in inputBuff. In this case, it will retrieve 5 (6 - 1) characters at a time. So that when fgets() has already run once, inputBuff will store aaaab, and then be printed.
Loop 2: Then, since bbb\n are left in the file stream, fgets() will execute for the second time so that inputBuff contains bbb\n, and then be printed.
Loop 3: The program will ask for my input (the 2nd time) as the file stream has reached the end (EOF).
Question: It seems that fgets() will only ask for my keyboard input after stdin stream has no data left in buffer (EOF). I am just wondering why couldn't I use keyboard to input anything in loop 2, and fgets() just keep on retrieving 5 characters from stdin stream and left the excess data in the file stream for next time retrieval. Do I have any misunderstanding about stdin or fgets()? Thank you for your time!
The behavior of your program is somewhat more subtle than you expect:
fgets(inputBuff, 6, stdin) reads at most 5 bytes from stdin and stops reading when it gets a newline character, which is stored into the destination array.
Hence as you correctly diagnose, the first call reads the 5 bytes aaab and prints them and the second call reads 4 bytes bbb\n and prints them, then the third call gets an empty input stream and waits for user input.
The tricky part is how stdin gets input from the user, also known as console input.
Both console input and stdin are usually line buffered by default, so you can type a complete line of input regardless of the size of the buffer passed to fgets(). Yet if you can set stdin as unbuffered and console input as uncooked, the first fgets() would indeed read the first 5 bytes as soon as you type them.
Console input is an intricate subject. Here is an in depth article about its inner workings: https://www.linusakesson.net/programming/tty/
Everything is there in manual page of fgets() whatever you are asking. Just need to read it properly, It says
char *fgets(char *s, int size, FILE *stream);
fgets() reads in at most one less than sizecharacters
from stream and stores them into the buffer pointed to by s. Reading
stops after an EOF or a newline. If a newline is read, it is
stored into the buffer. A terminating null byte (aq\0aq) is stored
after the last character in the buffer.
If input is aaaabbbb and in fgets() second argument you specified size as 6 i.e it will read one less 5 character and terminating \0 will be added so first time inputBuff holds aaaab and since still EOF or \n didn't occur so next time inputBuff holds bbb\n as new line also get stored at last.
Also you should check the return type of fgets() and check if \n occurs then break the loop. For e.g
char *ptr = NULL;
while( (ptr = fgets(inputBuff, 6, stdin))!= NULL){
if(*ptr == '\n')
break;
printf("%s", inputBuff);
}
fgets() does only read until either '\n' or EOF. Everything after that will be left in stdin and therefore be read when you call fgets() again. You can however remove the excess chars from stdin by for example using getc() until you reach '\0'. You might want to look at the manpages for that.
What does %[^\n] mean in C?
I saw it in a program which uses scanf for taking multiple word input into a string variable. I don't understand though because I learned that scanf can't take multiple words.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
int main() {
char line[100];
scanf("%[^\n]",line);
printf("Hello,World\n");
printf("%s",line);
return 0;
}
[^\n] is a kind of regular expression.
[...]: it matches a nonempty sequence of characters from the scanset (a set of characters given by ...).
^ means that the scanset is "negated": it is given by its complement.
^\n: the scanset is all characters except \n.
Furthermore fscanf (and scanf) will read the longest sequence of input characters matching the format.
So scanf("%[^\n]", s); will read all characters until you reach \n (or EOF) and put them in s. It is a common idiom to read a whole line in C.
See also §7.21.6.2 The fscanf function.
scanf("%[^\n]",line); is a problematic way to read a line. It is worse than gets().
C defines line as:
A text stream is an ordered sequence of characters composed into lines, each line consisting of zero or more characters plus a terminating new-line character. Whether the last line requires a terminating new-line character is implementation-defined.
The scanf("%[^\n]", line) has the specifier "%[^\n]". It scans for unlimited number of characters that match the scan-set ^\n. If none are read, the specifier fails and scanf() returns with line unaltered. If at least one character is read, all matching characters are read and saved and a null character is appended.
The scan-set ^\n implies all character that are not (due to the '^') '\n'.
'\n' is not read
scanf("%[^\n]",.... fails to read a new line character '\n'. It remains in stdin. The entire line is not read.
Buffer overflow
The below leads to undefined behavior (UB) should more than 99 characters get read.
char line[100];
scanf("%[^\n]",line); // buffer overflow possible
Does nothing on empty line
When the line consists of only "\n", scanf("%[^\n]",line); returns a 0 without setting line[] - no null character is appended. This can readily lead to undefined behavior should subsequent code use an uninitialized line[]. The '\n' remains in stdin.
Failure to check the return value
scanf("%[^\n]",line); assumes input succeeded. Better code would check the scanf() return value.
Recommendation
Do not use scanf() and instead use fgets() to read a line of input.
#define EXPECTED_INPUT_LENGTH_MAX 49
char line[EXPECTED_INPUT_LENGTH_MAX + 1 + 1 + 1];
// \n + \0 + extra to detect overly long lines
if (fgets(line, sizeof line, stdin)) {
size_t len = strlen(line);
// Lop off potential trailing \n if desired.
if (len > 0 && line[len-1] == '\n') {
line[--len] = '\0';
}
if (len > EXPECTED_INPUT_LENGTH_MAX) {
// Handle error
// Usually includes reading rest of line if \n not found.
}
The fgets() approach has it limitations too. e.g. (reading embedded null characters).
Handling user input, possible hostile, is challenging.
scanf("%[^\n]",line);
means: scan till \n or an enter key.
scanf("%[^\n]",line);
Will read user input until enter is pressed or a newline character is added (\n) and store it into a variable named line.
Question: what is %[^\n] mean in C?
Basically the \n command prints the output in the next line, but in
case of C gives the Null data followed by the above problem only.
Because of that to remove the unwanted data or null data, need to add
Complement/negotiated symbol[^\n]. It gives all characters until the next line
and keeps the data in the defined expression.
Means it is the Complemented data or rewritten data from the trash
EX:
char number[100]; //defined a character ex: StackOverflow
scanf("%[^\n]",number); //defining the number without this statement, the
character number gives the unwanted stuff `���`
printf("HI\n"); //normaly use of printf statement
printf("%s",number); //printing the output
return 0;
NOTE: Please notice this is not a duplicate of Why is scanf() causing infinite loop in this code? , I've already seen that question but the issue there is that he checks for ==0 instead of !=EOF. Also, his problem is different, the "infinite loop" there still waits for user input, it just does not exit.
I have the following while loop:
while ((read = scanf(" (%d,%d)\n", &src, &dst)) != EOF) {
if(read != 2 ||
src >= N || src < 0 ||
dst >= N || dst < 0) {
printf("invalid input, should be (N,N)");
} else
matrix[src][dst] = 1;
}
The intention of which is to read input in the format (int,int), to stop reading when EOF is read, and to try again if an invalid input is received.
The probelm is, that scanf works only for the first iteration, after that there is an infinite loop. The program does not wait for user input, it just keeps assuming that the last input is the same.
read, src, and dst are of type int.
I have looked at similar questions, but they seem to fail for checking if scanf returns 0 instead of checking for EOF, and the answers tells them to switch to EOF.
You need to use
int c;
while((c=getchar()) != '\n' && c != EOF);
at the end of the while loop in order to clear/flush the standard input stream(stdin). Why? The answer can be seen below:
The scanf with the format string(" (%d,%d)\n") you have requires the user to type
An opening bracket(()
A number(For the first %d)
A comma(,)
A number(For the last %d)
The space(First character of the format string of your scanf) and the newline character(\n which is the last character of the format string of your scanf) are considered to be whitespace characters. Lets see what the C11 standard has to say about whitespace characters in the format string of fscanf(Yes. I said fscanf because it is equivalent to scanf when the first argument is stdin):
7.21.6.2 The fscanf function
[...]
A directive composed of white-space character(s) is executed by reading input up to the first non-white-space character (which remains unread), or until no more characters can be read. The directive never fails
So, all whitespace characters skips/discards all whitespace characters, if any, until the first non-whitespace character as seen in the quote above. This means that the space at the start of the format string of your scanf cleans all leading whitespace until the first non-whitespace character and the \n character does the same.
When you enter the right data as per the format string in the scanf, the execution of the scanf does not end. This is because the \n hadn't found a non-whitespace character in the stdin and will stop scanning only when it finds one. So, you have to remove it.
The next problem lies when the user types something else which is not as per the format string of the scanf. When this happens, scanf fails and returns. The rest of the data which caused the scanf to fail prevails in the stdin. This character is seen by the scanf when it is called the next time. This can also make the scanf fail. This causes an infinite loop.
To fix it, you have to clean/clear/flush the stdin in each iteration of the while loop using the method shown above.
scanf prompts the user for some input. Assuming the user does what's expected of them, they will type some digits, and they will hit the enter key.
The digits will be stored in the input buffer, but so will a newline character, which was added by the fact that they hit the enter key.
scanf will parse the digits to produce an integer, which it stores in the src variable. It stops at the newline character, which remains in the input buffer.
Later, second scanf which looks for a newline character in the input buffer. It finds one immediately, so it doesn't need to prompt the user for any more input.