Why this fgets() behaving in a weird way? - c

I'm using strstr() function to search a string given by the user in some other string.
Problem is that when I use fgets() to take input, the strstr() function is giving zero(false) even if the string entered by user is there.
For Example:
char search[20]; //MAX size of search term is 20 bytes
puts("Enter search term: ");
fgets(search,20,stdin); //suppose user enters: photographer (12 characters long)
if(strstr("I'm no photographer but I can picture us together",search))
puts("Found!");
else
puts("No luck!");
Output: No luck!
Even tough "photographer" is there in the string
However, if I use scanf() to take search input.
scanf("%19s",search); //like this
Output: Found!
Why is this happening ?

This is happening because fgets() stores a trailin newline \n at the end of the string read. So the string you read in search is basically "photographer\n"
Either use scanf() or overwrite a null character \0 on the newline.
To overwrite on the newline, you can do something like this
l=strlen(search)-1;
if(search[l]=='\n')
search[l]='\0';

from the manual:
fgets() reads in at most one less than size characters 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 ('\0') is stored after the last character in the buffer.
beware that none of those functions are safe to use because they don't check the size of the buffer.

Related

Why won't this scanf format-string work? "%[^\n]\n"

I've seen a few examples where people give scanf a "%[^\n]\n" format string to read a whole line of user input. If my understanding is correct, this will read every character until a newline character is reached, and then the newline is consumed by scanf (and not included in the resulting input).
But I can't get this to work on my machine. A simple example I've tried:
#include <stdio.h>
int main(void)
{
char input[64];
printf("Enter some input: ");
scanf("%[^\n]\n", input);
printf("You entered %s\n", input);
}
When I run this, I'm prompted for input, I type some characters, I hit Enter, and the cursor goes to the beginning of the next line but the scanf call doesn't finish.
I can hit Enter as many times as I like, and it will never finish.
The only ways I've found to conclude the scanf call are:
enter \n as the first (and only) character at the prompt
enter Ctrl-d as the first (and only) character at the prompt
enter some input, one or more \n, zero or more other characters, and enter Ctrl-d
I don't know if this is machine dependent, but I'm very curious to know what's going on. I'm on OS X, if that's relevant.
According to the documentation for scanf (emphasis mine):
The format string consists of whitespace characters (any single whitespace character in the format string consumes all available consecutive whitespace characters from the input), non-whitespace multibyte characters except % (each such character in the format string consumes exactly one identical character from the input) and conversion specifications.
Thus, your format string %[^\n]\n will first read (and store) an arbitrary number of non-whitespace characters from the input (because of the %[^\n] part) and then, because of the following newline, read (and discard) an arbitrary number of whitespace characters, such as spaces, tabs or newlines.
Thus, to make your scanf stop reading input, you either need to type at least one non-whitespace character after the newline, or else arrange for the input stream to end (e.g. by pressing Ctrl+D on Unix-ish systems).
Instead, to make your code work as you expect, just remove the last \n from the end of your format string (as already suggested by Umamahesh P).
Of course, this will leave the newline still in the input stream. To get rid of it (in case you want to read another line later), you can getc it off the stream, or just append %*c (which means "read one character and discard it") or even %*1[\n] (read one newline and discard it) to the end of your scanf format string.
Ps. Note that your code has a couple of other problems. For example, to avoid buffer overflow bugs, you really should use %63[^\n] instead of %[^\n] to limit the number of characters scanf will read into your buffer. (The limit needs to be one less than the size of your buffer, since scanf will always append a trailing null character.)
Also, the %[ format specifier always expects at least one matching character, and will fail if none is available. Thus, if you press enter immediately without typing anything, your scanf will fail (silently, since you don't check the return value) and will leave your input buffer filled with random garbage. To avoid this, you should a) check the return value of scanf, b) set input[0] = '\0' before calling scanf, or c) preferably both.
Finally, note that, if you just want to read input line by line, it's much easier to just use fgets. Yes, you'll need to strip the trailing newline character (if any) yourself if you don't want it, but that's still a lot easier and safer that trying to use scanf for a job it's not really meant for:
#include <stdio.h>
#include <string.h>
void chomp(char *string) {
int len = strlen(string);
if (len > 0 && string[len-1] == '\n') string[len-1] = '\0';
}
int main(void)
{
char input[64];
printf("Enter some input: ");
fgets(input, sizeof(input), stdin);
chomp(input);
printf("You entered \"%s\".\n", input);
}
Whitespace characters in format of scanf() has an special meaning:
Whitespace character: the function will read and ignore any whitespace
characters encountered before the next non-whitespace character
(whitespace characters include spaces, newline and tab characters --
see isspace). A single whitespace in the format string validates any
quantity of whitespace characters extracted from the stream (including
none).
Thus, "%[^\n]\n" is just equivalent to "%[^\n] ", telling scanf() to ignore all whitespace characters after %[^\n]. This is why all '\n's are ignored until a non-whitespace character is entered, which is happened in your case.
Reference: http://www.cplusplus.com/reference/cstdio/scanf/
Remove the the 2nd new line character and the following is sufficient.
scanf("%[^\n]", input);
To answer the original one,
scanf("%[^\n]\n", input);
This should also work, provided you enter a non white space character after the input. Example:
Enter some input: lkfjdlfkjdlfjdlfjldj
t
You entered lkfjdlfkjdlfjdlfjldj

How Can I Scan a File in a Way That Doesn't Discard Newlines

I am relatively new to C programming, but, from what I understand, fscanf skips any whitespace when scanning input for every type beside characters. What other means do I have to scan integers while keeping any newline character that may be attached to them within the file (as I actually want to do something with these newline characters)?
You can use fgets in the following format:
char *fgets(char *s, int size, FILE *stream);
and as it's man page says:
fgets() reads in at most one less than size characters 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 ('\0') is
stored after the last character in the buffer.
It will read a newline character, however it will stop reading after that and terminate with the null character.
You could use fcanf(file,"%[^\n]") which takes everything up to user hit enter.

Difference between fgets and fscanf?

I have a question concerning fgets and fscanf in C. What exactly is the difference between these two? For example:
char str[10];
while(fgets(str,10,ptr))
{
counter++;
...
and the second example:
char str[10];
while(fscanf(ptr,"%s",str))
{
counter++;
...
when having a text file which contains strings which are separated by an empty space, for example: AB1234 AC5423 AS1433. In the first example the "counter" in the while loop will not give the same output as in the second example. When changing the "10" in the fgets function the counter will always give different results. What is the reason for this?
Can somebody please also explain what the fscanf exactly does, how long is the string in each while loop?
The function fgets read until a newline (and also stores it). fscanf with the %s specifier reads until any blank space and doesn't store it...
As a side note, you're not specifying the size of the buffer in scanf and it's unsafe. Try:
fscanf(ptr, "%9s", str)
fgets reads to a newline. fscanf only reads up to whitespace.
In your example, fgets will read up to a maximum of 9 characters from the input stream and save them to str, along with a 0 terminator. It will not skip leading whitespace. It will stop if it sees a newline (which will be saved to str) or EOF before the maximum number of characters.
fscanf with the %s conversion specifier will skip any leading whitespace, then read all non-whitespace characters, saving them to str followed by a 0 terminator. It will stop reading at the next whitespace character or EOF. Without an explicit field width, it will read as many non-whitespace characters as are in the stream, potentially overruning the target buffer.
So, imagine the input stream looks like this: "\t abcdef\n<EOF>". If you used fgets to read it, str would contain "\t abcdef\n\0". If you usedfscanf, str could contain "abcdef\0" (where \0 indicates the 0 terminator).
fgets read the whole line. fscanf with %s read a string, separate by space (or \n,\t,etc...).
Anyway, you should not use them unless you sure that the array you read to is big enough to contain the input.
You wrote When changing the "10" in the fgets function the counter will always give different results. Note that fgets and scanf don't know how much bytes to read. you should tell them. changing the "10" just enlarge the buffer these functions write to.

How this program has this output In C

i have a piece of code in C .But i am not able to understand its output
#include<stdio.h>
main()
{
char a1[20];
char a2[30];
char a3[40];
scanf("%s",&a1);
gets(a2);
fgets(a3,sizeof(a3),stdin);
printf("%d,%d,%d\n",strlen(a1),strlen(a2),strlen(a3));
}
When i enter my input like
amit
singh
output comes out to be 4,0,6 and fgets doest not allow me to enter any string ,i am able to enter only 2 inputs?
input is "amit\nsingh\n"
the scanf consumes "amit" (and writes that into a1)
the gets consumes "\n" (and writes empty string to a2)
the fgets consumes "singh\n" (which it writes to a3)
The output is correct.
Do not EVER use gets!
http://pubs.opengroup.org/onlinepubs/9699919799/functions/fscanf.html
http://pubs.opengroup.org/onlinepubs/9699919799/functions/gets.html
http://pubs.opengroup.org/onlinepubs/9699919799/functions/fgets.html
scanf() takes amit and stores it in array a1.
Since functions of the scanf() family leave the newline character in the input buffer and gets() reads up to a newline character (which it finds immediately), it stores an empty string into a2.
So the call to fgets() reads singh into a3. fgets() puts also the newline character into the target variable - this is why you see 6 characters as string length for a3.
Since there are no more input commands, no 3rd line is read.
scanf leaves a '\n' in the stream which is read by gets.
gets doesn't count \n in the length. Hence you get a 0 there.
Then your fgets reads "singh" and as it does take into account the newline character, it outputs 6.
Have a look at the following references for better understanding:
http://www.cplusplus.com/reference/clibrary/cstdio/fgets/
http://www.cplusplus.com/reference/clibrary/cstdio/gets/

c, gets(),fgets()

char s1[100];
char s2[100];
gets(s1);
fgets(s2,sizeof(s2),stdin);
printf("%d,%d\n",strlen(s1),strlen(s2));
after run, I input "abcd" two times,
and the result i got is : 4,5
why is that?
From the gets / fgets man page:
The fgets() function reads at most one less than the number of characters
specified by n from the given stream and stores them in the string s.
Reading stops when a newline character is found, at end-of-file or error.
The newline, if any, is retained. If any characters are read and there
is no error, a `\0' character is appended to end the string.
The gets() function is equivalent to fgets() with an infinite n and a
stream of stdin, except that the newline character (if any) is not stored
in the string. It is the caller's responsibility to ensure that the
input line, if any, is sufficiently short to fit in the string.
fgets keeps the newline, which is character number 5, but gets doesn't.
Also, get into a habit of using fgets always, as it is impossible to prevent buffer overflows when using gets.
Because fgets returns the string with '\n' at the end while gets not.
From the gets() man page:
The gets() function is equivalent to fgets() with an infinite n and a stream of stdin, except that the newline character (if any) is not stored in the string.

Resources