fgets and sscanf getting list value twice - c

I'm having trouble with sscanf and fgets where it seems to be getting the last value input and re reading it back through even though we have come to the end of the file. My code:
while (won == 0) {
char command, input[MAX_LENGTH];
fgets(input, MAX_LENGTH, stdin);
sscanf(input, " %c\n", &command);
printf('%c\n', command);
check_won();
}

Your sscanf pattern is %c %s, but you're only ever reading command. Is that intentional? You should consider checking the return value of fgets to ensure that it is still actually reading input, and the return value of sscanf to ensure that it is indeed reading two elements (and discarding the second one). If your input is not being parsed and collected correctly, and your check_won function is dependent on that input, you will see repeated input because your array will not be being re-initialized.
Try something like this instead?
if(fgets(input, MAX_LENGTH, stdin) == NULL) {
break;
}

In the format string you have specified 2 elements but you have passed only one argument &command.
sscanf(input, " %c %s\n", &command);

What's happening is even though fgets fails at the EOF, your sscanf is reading the last value of input fetched by fgets. So do not do sscanf if fgets fails.
Try this
char command, input[MAX_LENGTH];
while ( won == 0 && fgets(input, MAX_LENGTH, stdin) ) {
sscanf(input, " %c\n", &command);
printf('%c\n', command);
check_won();
}

Related

getline and fgets failed to get input on first attempt

void someFunction(){
char *buffer;
size_t bufsize = 32;
int bytes_read;
for (;;) {
buffer = (char *) malloc(bufsize * sizeof(char));
if (buffer == NULL) {
perror("Unable to allocate buffer");
exit(1);
}
FILE *ptr;
ptr = fopen("sample.txt", "a");
printf("Enter Stuff to write down:\n");
//getline(&buffer,&bufsize,stdin);
//fgets(buffer, 30, stdin);
//scanf("%[^\n]%*c", buffer);
//scanf("%s", buffer);
if (buffer[0] == '0') {
break;
}
WriteWithFprintf(ptr, buffer);
free(buffer);
fclose(ptr);
}
}
The problem is: if I use
getline(&buffer,&bufsize,stdin);
or
fgets(buffer, 30, stdin);
then it escapes the first like so:
Enter Stuff to write down:
Enter Stuff to write down:
0
If I use:
scanf("%[^\n]%*c", buffer);
then I get an infinite loop.
It does work with:
scanf("%s", buffer);
but I want input with space so this is not an option for me.
All of the behaviors described for different variations on your code are consistent with the next character available to be read from stdin being a newline, presumably from a preceding line of input.
In that case,
the getline() and fgets() alternatives will read the newline (and any preceding characters) as a line, and then loop to read the line you actually want on the second pass.
the first scanf() variation will read nothing on account of a matching failure for the %[^\n] field (leading whitespace is not skipped for %[ directives). Not having matched anything to that, there will be no attempt to match anything to the %*c.
the second scanf() alternative will work as you describe, because scanf will automatically consume leading whitespace when processing a %s directive, including any newline.
There is a variety of things you could do, depending on exactly how want to handle input. Here is one:
int c = fgetc(stdin);
if (c == EOF) {
// handle eof ...
} else if (c != '\n') {
ungetc(c, stdin);
}
// your choice for reading the wanted data ...
That will consume up to one leading newline from stdin to get it out of your way.
getline and fgets failed to get input on first attempt
Neither failed. Both simply read a '\n' and immediately returned. This '\n' was left-over from a previous input function like scanf("%s", ...), that did not consume the entire line. getline() is not part of the standard C library.
scanf("%[^\n]%*c", buffer); fails to read anything when the first available character is '\n'.
scanf("%s", buffer); consumes all optional leading white space like '\n'. This may appear to work for OP.
scanf("%[^\n]%*c", buffer); and scanf("%s", buffer); are both poor code as they do not have a width limit, risking buffer overflow.
I recommend for a learner to not use scanf() at all and perform all input with fgets(), including the part of code not posted.

Don't understand how to input/print and compare string in loop in C

I'm newcomer to C and I am stuck. I want to write simple program, which will take input from keyboard and output it if it isn't an 'exit' word. I've tried few different approaches and none of them works. Almost in all cases I get infinite output of the first input.
Here is one of my approaches:
#include <stdio.h>
int main() {
char word[80];
while (1) {
puts("Enter a string: ");
scanf("%79[^\n]", word);
if (word == "exit")
break;
printf("You have typed %s", word);
}
return 0;
}
I thought after it finish every loop it should give me prompt again, but it doesn't.
What I am doing wrong.
Please if you know give me some advice.
Thanks in advance. Really, guys I will be so happy if you help me to understand what I am doing wrong.
Oh, by the way I've noticed that when I typed some word and press 'Enter', the result string also include Enter at the end. How can I get rid of this ?
Improper string compare - use strcmp().
if (word == "exit") simply compares 2 address: the address of the first char in word and the address of the first char in string literal "exit". Code needs to compare the content beginning at those addresses: strcmp() does that.
Left-over '\n' from the previous line's Enter. Add a space to scanf() format to consume optional leading white-space. Also check scanf() results.
scanf() specifiers like "%d", "%u" and "%f" by themselves consume optional leading white-space. 3 exceptions: "%c", "%n" and "%[".
Add '\n' at end of printf() format. # Matt McNabb
#include <stdio.h>
int main() {
char word[80];
while (1) {
puts("Enter a string: ");
// v space added here
if (scanf(" %79[^\n]", word) != 1)
break; // Nothing saved into word or EOF or I/O Error
if (strcmp(word, "exit") == 0)
break;
printf("You have typed %s\n", word);
}
return 0;
}
Nice that OP used a proper width limited value of 79 in scanf()
Oh, by the way I've noticed that when I typed some word and press 'Enter', the result string also include Enter at the end. How can I get rid of this ?
This is because you don't output a newline after printf("You have typed %s", word);. The next statement executed is puts("Enter a string: "); . So you will see You have typed helloEnter a string:. To fix this, change to printf("You have typed %s\n", word);
As others have mentioned, use strcmp to compare strings in C.
Finally, the scanf format string "%79[^\n]" does not match a newline. So the input stream still contains a newline. Next time you reach this statement the newline is still in the stream , and it still doesn't match because you specifically excluded newlines.
You will need to discard that newline (and any other input on the line) before getting the next line. One way to do that is to change the input to scanf("%79[^\n]%*[^\n]", word); getchar(); That means:
Read up to 79 non-newlines
Read all the non-newline things , and don't store them
Read a character (which must be a newline now) and don't store it
Finally it would be a good idea to check the return value of scanf so that if there is an error then you can exit your program instead of going into an infinite loop.
The specifier [^\n] will abort scanf if the next character is a newline (\n), without reading the newline. Because of that, the scanf calls after the first one won't read any input.
If you want to read single words, use the %79s specifier and the following code to remove the \n at the end of your string:
if(word[strlen(word)]=='\n')
word[strlen(word)]='\0';
If you want to read whole lines, you can remove the newline from the input buffer this way:
char line[80];
int i;
while(1)
{
puts("Enter a string:");
i=-1;
scanf("%79[^\n]%n",line,&i);
//%n returns the number of characters read so far by the scanf call
//if scanf encounters a newline, it will abort and won't modify i
if(i==-1)
getchar(); //removes the newline from the input buffer
if(strcmp(line,"exit")==0)
break;
printf("You have typed %s\n",line);
}
return 0;
It is better to clear (to have a reproducible content) with memset(3) the memory buffer before reading it, and you should use strcmp(3) to compare strings. Also, consider using fflush(3) before input (even if it is not actually necessary in your case), don't forget to test result of scanf(3), also most printf(3) format control strings should end with a \n -for end-of-line with flushing- so:
#include <stdio.h>
int main() {
char word[80];
while(1) {
puts("Enter a string: ");
memset (word, 0, sizeof(word)); // not strictly necessary
fflush(stdout); // not strictly necessary
if (scanf("%79[^\n]", word)<=0) exit(EXIT_FAILURE);
if (!strcmp(word,"exit"))
break;
printf("You have typed %s\n", word);
};
return 0;
}
I would suggest reading a whole line with fgets(3) and getting rid of its ending newline (using strchr(3)). Also read about getline(3)
Don't forget to compile with all warnings and debug info (e.g. gcc -Wall -g) and learn how to use the debugger (e.g. gdb)
Your first problem is that you can't compare a string with '=='. So:
if (word == "exit")
should be
if ( strncmp( word, "exit", 4 ) == 0 )
(You could also use strncmp( word, "exit", strlen(word) ) if you know that word is zero-terminated and safe from bad values. There's a few other options also.)
Your second problem is that scanf() is not consuming the input, probably because it's not matching what you've told it to expect. Here is a good explanation of how to do what you want to do:
http://home.datacomm.ch/t_wolf/tw/c/getting_input.html

How to take inputs for strings one by one in C

I have to take inputs like below, and print the same (only the sentences):
2
I can't believe this is a sentence.
aarghhh... i don't see this getting printed.
Digit 2 shows the number of lines to be followed (2 lines after this here).
I used all the options scanf and fgets with various regex used.
int main() {
int t;
char str[200];
scanf ("%d", &t);
while (t > 0){
/*
Tried below three, but not getting appropriate outputs
The output from the printf(), should have been:
I can't believe this is a sentence.
aarghhh... i don't see this getting printed.
*/
scanf ("%[^\n]", str);
//scanf("%200[0-9a-zA-Z ]s", str);
//fgets(str, 200, stdin);
printf ("%s\n", str);
t--;
}
}
I am sorry, i have searched all related posts, but I am not able to find any answer to this:
All versions of scanf() produce no results, and fgets() prints only the first sentence.
Thanks in advance.
You should just use fgets(). Remember that it will keep the linefeed, so you might want to remove that manually after reading the line:
if(scanf("%d", &t) == 1)
{
while(t > 0)
{
if(fgets(str, sizeof str, stdin) != NULL)
{
const size_t len = strlen(str);
str[len - 1] = '\0';
printf("You said '%s'\n", str);
--t;
}
else
printf("Read failed, weird.\n");
}
}
To make it easier let's say the input is "2\none\ntwo\n".
When you start your program, before the first scanf() the input buffer has all of it and points to the beginning
2\none\ntwo
^
After the first scanf(), the "2" is consumed leaving the input buffer as
2\none\ntwo
^^
And now you attempt to read everything but a newline ... but the first thing in the buffer is a newline, so nothing gets read.
Suggestion: always use fgets() to read full lines, and then parse the input as you think is better.
To use regex in C you must include regex.h. In this case, you do not need regex. Where you have "%[^\n]", replace it with "%s". Make sure that you include stdio.h.

Requiring scanf to recognise no input

im very new to C programming, and i am looking for the simplest possible solution to getting scanf to recognise no input, by that i mean pressing the enter key with nothing typed and it knowing nothing has been entered and returning to the main menu. Iv looked about on here and i found a similar problem but scanf was taking an integer value, whereas i require a string for a filename. My code is:
FILE *Fpacket;
char filename[20];
puts("Please declare a name for the file"); // request filename
scanf("%s", filename); // store text in filename string
I have tried a combination of fgets, getchar and afew others but i just cant get it to take the newline character as input. I am aware scanf ignores preceding whitespace, any help greatly appreciated!
Thanks
There is no solution using %s in scanf("%s", filename) as the format specifier consumes whitespace, including \n before attempting to fill filename. scanf() will not return until non-whitespace (or EOF or IO Error) occurs.
Much better to use fgets()/sscanf()
char buf[MAXPATH + 2];
if (fgets(buf, sizeof buf, stdin) == NULL) handle_EOF_IOError();
if (buf[0] == '\n')
handle_OnlyEnterKeyPressed();
else
sscanf(buf, "%s", filename);
If you want to take a Newline(Enter) character from the keyboard as input, then you need to use another key to terminate the string
//press Esc to terminate the string.
int main() {
char filename[20];
char ch;
int i;
i=0;
while ((filename[i] = std::cin.get()) != 27 && i<20) {
i++;
}
return 0;
}
If you press enter on your keyboard, it will take it as character and store it on filename[i], the while loop will never terminate until you press Esc or i<20

fscanf problems, taking a char a time

When I try to use fscanf to read a text file that contains
PIZZA CHIPS BURGERS as one of the lines. I am trying to add them to a variable, but instead it only takes one letter at a time.
if (infile) {
while (fscanf(infile, "%c", &cit) > 0) {
printf("%c\n",cit);
How do I make it take the word PIZZA instead of P I Z Z A?
char word[256];
if (infile)
{
while (fscanf(infile, "%255s", word) == 1)
printf("Word: %s\n", word);
}
Note that if you want a whole line read in at a time, spaces and all, then you'll use fgets():
char line[4096];
if (infile)
{
while (fgets(line, sizeof(line), infile) != 0)
printf("Line: %s", line);
}
NB: fgets() keeps the newline unless the line is so long that it has to be truncated, so the printf() format doesn't need a newline of its own. Generally, it is easier to control input if you use fgets() and sscanf() than if you use just scanf() or fscanf(). In particular, you can usually give better error diagnostics because you have all of what the user typed. You can also try alternative formats if that's necessary.

Resources