fscanf problems, taking a char a time - c

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.

Related

What is the use of scanf("\n"); statement before scanf("%[^\n]%*c", s)?

What is the use of scanf("\n"); statement before scanf("%[^\n]%*c", s) ?
int main()
{
char ch;
char str [100];
char s[100];
scanf("%c",&ch);
printf("%c",ch);
scanf("%s",&str);
printf("\n%s",str);
scanf("\n"); // <<< what is the purpose of this line
scanf("%[^\n]%*c",s);
printf("\n%s",s);
return 0;
}
So what is the use of scanf("\n"); statement before scanf("%[^\n]%*c", s) ?
What is the use of scanf("\n");
The true answer is probably that the original author of this code was flailing, desperately trying to get scanf to work, despite scanf's various foibles.
Other evidence that the original author was having problems:
scanf("%c", &ch);
When reading individual characters, the %c often does not work as expected or as desired. Most of the time, at least in code like this, it is necessary to add a space, like this: " %c".
scanf("%[^\n]%*c", s);
This line, also, is difficult to understand. It is attempting to read one full line of text, a task which scanf is not well-suited for.
Overall the code appears to be attempting to read one single character, followed by one string (not containing whitespace), followed by one full line of text (possibly containing whitespace).
Given its shortcomings (and scanf's shortcomings), I'd say it's not even worth trying to figure out what the original code will do. A considerably cleaner way of accomplishing this task (still using scanf) would be
if(scanf(" %c", &ch) != 1) exit(1);
printf("%c\n",ch);
if(scanf("%99s", str) != 1) exit(1);
printf("%s\n", str);
if(scanf(" %99[^\n]", s) != 1) exit(1);
printf("%s\n", s);
Note these changes:
checking return value of scanf
extra space in " %c", as mentioned
%99s instead of plain %s, to avoid array overflow
no & before str with %s
extra space with %[…] also
length modifier 99 with %[…] also
no %*c after %[…]
(cosmetic/stylistic) printing \n at the end of each line
If you're trying to do anything at all fancy, it's often much easier to just skip scanf, and go with more powerful techniques. I might use something like this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char chbuf[5];
char ch;
char str [100];
char s[100];
printf("enter a character:\n");
if(fgets(chbuf, 5, stdin) == NULL) exit(1);
ch = *chbuf;
printf("%c\n", ch);
printf("enter a string:\n");
if(fgets(str, 100, stdin) == NULL) exit(1);
str[strcspn(str, "\n")] = 0; /* strip \n */
printf("%s\n", str);
printf("enter a line:\n");
if(fgets(s, 100, stdin) == NULL) exit(1);
s[strcspn(s, "\n")] = 0;
printf("%s\n", s);
}
This simply used fgets to read all input, one line at a time. To fetch a single character, it then grabs the first character of a short line. (Also it's printing explicit prompts, since that helps to avoid confusion.)
One small drawback of fgets is that it always leaves the \n in the buffer. I've used a common albeit somewhat obscure trick to strip it back off; see this question for an explanation.
This modified program works, although it is different from the original in one significant respect: it will allow whitespace in the first string read as well as the second.
Also, the modified program insists that the three inputs be on three separate lines, while the original would have accepted them all on the same line (or on two lines, or on three lines). Whether that is an improvement or a disimprovement, I can't say. :-)
If you want to limit yourself to a subset of scanf's full complexity, using simple invocations of it for the simple uses it's well-suited for, and avoiding it for the more complicated problems that it's dreadfully painful to use for, you might read the suggestions at this answer.
After this incorrect call of scanf
scanf("%s",&str);
where the second parameter shall be
scanf("%s",str);
the input buffer can contain the new line character '\n' and the next call of scanf
scanf("%[^\n]%*c",s);
can read as a result an empty string.
So this call
scanf("\n");
is an attempt to remove the new line character from the input buffer.
However it will be better just to write
scanf(" %[^\n]%*c",s);
See the leading space in the format string. It allows to skip white space characters in the input buffer.

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.

Filtering lines using fscanf

I am trying to read a file of the form
A number,number
A number,number
[space] B number,number
etc
where I want to read only the lines that do start with a space (ie, in the example above, the last line only). I wrote this loop:
while ((g = fscanf(fp," %c %x,%d\n",&a,&b,&c) != EOF){
printf("%c %x,%d\n",a,b,c);
}
but despite the space I put at the beginning of the string, it still outputs all the lines. I know I can filter them inside the loop, but is it possible to specify it in the fscanf?
OP: it possible to specify it in the fscanf?
A: Yes, but its ugly. Use the best tool for the job.
Use fgets(), then scan with sscanf().
char buf[100];
char a;
unsigned b;
int c;
while (fgets(buf, sizeof buf, fp) != NULL) {
// Thank-you #Chris Dodd
if ((buf[0] == ' ') && (sscanf(buf, " %c%x,%d", &a,&b,&c) == 3)) {
printf("%c %x,%d\n",a,b,c);
}
}
One way to achieve what you want is to use getc and check for space , if space is found call ungetc and read the line using fgets else read the line and skip it

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.

fgets and sscanf getting list value twice

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();
}

Resources