strstr not functioning - c

Why does this particular piece of code return false on the strstr() if I input "test"?
char input[100];
int main()
{
fgets(input, 100, stdin);
printf("%s", input);
if(strstr("test message", input))
{
printf("strstr true");
}
}
I thought strstr searched the first param for instances of the second param? It works when I replace input with some text or just assign it something directly, but it seems to not work with fgets.

It's because fgets stores the newline character so when strstr does a comparison it fails.
From the man page:
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 '\0' is stored after the last character in the buffer.

Add input[strlen(input) - 1] = '\0'; after the fgets. fgets reads in the newline char ('\n'). There is no '\n' in "test message" so input will never be contained within it.
You should really check to see if the newline is at the end of the buffer after calling fgets to know if the whole line was able to actually fit into it, and also to obviously remove it.

Related

fgets() goes newline when storing string but gets() no issue about newline

fseek(fPtr, 0, SEEK_END);
fflush(stdin);
printf("\n\t\t\t ENTERID : ");
fgets(user.id, ID_SIZE, stdin);
fflush(stdin);
printf("tENTER FIRST NAME: ");
fgets(user.fname, MAX_FNAME_SIZE, stdin); //automatic added newline
printf("ENTER LAST NAME: ");
fgets(user.lname, MAX_LNAME_SIZE, stdin); //automatic added newline
I was using fgets() for reading the input of the string and store into the text file using the fwrite.
But why does fgets() automatically enter a newline for each input of string.
"...but gets() no issue about newline"
Note, that although your observation about gets() being preferable in this case over fgets() for handling newline, the unfavorable behaviors that come with gets() make it dangerous to use, with the result that "it was officially removed by the 2011 standard." (credit) Even without the \n mitigations mentioned below, fgets() is highly preferred over gets().
"fgets() goes newline when storing string..." and "...why does fgets() automatically enter a newline for each input of string"
fgets() does not enter the newline upon reading the line, rather if one exists, the newline is picked up as part of the line when fgets() called. For example in this case, when using stdin as the input method, the user clicks the <return> to finish inputting text. Upon hitting the <return> key, a \n is entered just like any other character, and becomes the last character entered. When the line is read using fgets(), if the \n is seen before any of its other stop reading criteria, fgets() stops reading, and stores all characters, including \n, terminates line with \0 and stores into the buffer. (If sizeof(buffer) - 1 or EOF is seen first, fgets() will never see the newline.)
To easily eliminate the \n, (or other typical unwanted line endings), use the following single line statements after each of your calls to fgets():
fgets(user.id, ID_SIZE, stdin);
user.id[strcspn(user.id, "\n")] = 0;
//fflush(stdin);//UB, should not be called
...
fgets(user.fname, MAX_FNAME_SIZE, stdin);
user.fname[strcspn(user.fname, "\n")] = 0;
...
fgets(user.lname, MAX_LNAME_SIZE, stdin);
user.lname[strcspn(user.lname, "\n")] = 0;
...
This technique works for truncating any string by searching for the unwanted char, whether it be "\n", "\n\r", "\r\n", etc. When using more than one search character, eg "\r\n", it searches until it reaches either the \r or the \n and terminates at that position.
"This [method] handles the rare buffer than begins with '\0', something that causes grief for the buffer[strlen(buffer) - 1] = '\0'; [method]." (#Chux - comment section of link below.)
Credit here
Quoting from the man page,
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.
So, after providing the input from the terminal, you press the ENTER key which adds a newline to the input buffer. That same newline is scanned and stored in the destination provided to fgets().
If you want to remove the trailing newline, use the solution mentioned in the answer: Removing trailing newline character from fgets() input
That said, read:
Why is the gets function so dangerous that it should not be used?
How is the working of fflush(stdin) changing the output in below code?

C: error replacing gets() with fgets()

I am currently having an issue replacing gets() with fgets(). I have looked at multiple examples of doing this and it seems very straight forward however I am getting unexpected output in doing so. Using the gets() method in comments below, I get good behavior from my shell program I am writing, however when I change to the fgets() call, I get output ": no such file or directory" when giving input "ls". Like I said, with the gets() call it is working fine. code below:
int main(void) {
while(1) {
int i = 0;
printf("$shell: ");
scanf("%s", first);
/* gets(input);*/
fgets(input, sizeof(input), stdin);
//...parse input into tokens for exec system call...
execvp(first, args);
}
return 0;
}
Unlike gets, fgets will read the newline and store it in the string.
From the man page:
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 '\0' is stored after the last character in the
buffer.
You can remove the newline (if it is present) by replacing it will a null byte:
fgets(input, sizeof(input), stdin);
if (input[strlen(input)-1] == '\n') input[strlen(input)-1] = '\0';

Why fgets takes cursor to next line?

I have taken a string from the keyboard using the fgets() function. However, when I print the string using printf(), the cursor goes to a new line.
Below is the code.
#include<stdio.h>
int main()
{
char name[25];
printf("Enter your name: ");
fgets(name, 24, stdin);
printf("%s",name);
return 0;
}
And below is the output.
-bash-4.1$ ./a.out
Enter your name: NJACK1 HERO
NJACK1 HERO
-bash-4.1$
Why is the cursor going to the next line even though I have not added a \n in the printf()?
However, I have noticed that if I read a string using scanf(), and then print it using printf() (without using \n), the cursor does not go to next line.
Does fgets() append a \n in the string ? If it does, will it append \0 first then \n, or \n first and then \0?
The reason printf is outputting a newline is that you have one in your string.
fgets is not "adding" a newline --- it is simply reading it from the input as well. Reading for fgets stops just after the newline (if any).
Excerpt from the manpage, emphasis mine:
The fgets() function reads at most one less than the number of characters specified by size from the given stream and stores them in the string str. 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.
An easy way to check if there's a newline is to use the help of one of my favorite little-known functions --- strcspn():
size_t newline_pos = strcspn(name, "\r\n");
if(name[newline_pos])
{
/* we had a newline, so name is complete; do whatever you want here */
//...
/* if this is the only thing you do
you do *not* need the `if` statement above (just this line) */
name[newline_pos] = 0;
}
else
{
/* `name` was truncated (the line was longer than 24 characters) */
}
Or, as an one-liner:
// WARNING: This means you have no way of knowing if the name was truncated!
name[strcspn(name, "\r\n")] = 0;
Because if there is a '\n' in the read text it will be taken by fgets(), the following was extracted from the 1570 draft §7.21.7.2 ¶ 2
The fgets function reads at most one less than the number of characters specified by n
from the stream pointed to by stream into the array pointed to by s. No additional
characters are read after a new-line character (which is retained) or after end-of-file. A
null character is written immediately after the last character read into the array.
I highlighted by making bold the part which says that the '\n' is kept by fgets().

strlen() returns the string count with the null terminator

normally, strlen() does not count the null terminator at the end of the string. But, below code prints the string count with the null terminator. Can anyone explain me why? Thanks
char str2[100];
printf("\nEnter a string: ");
fgets (str2, sizeof(str2), stdin);
printf("\n%d",strlen(str2));
I am assuming the preceding fgets prompt picked up the newline character.
For example:
You put in apple.
Internally your string was stored as apple\n\0.
strlen then returned 6 for apple + '\n'
The fgets() function accepts the input when a newline character(Enter key when using stdin) is encountered, and the newline character \n is considered a valid character by the function and included in the string copied to your str2.Hence when you pass it as a parameter to strlen() it gives one more than the original number of characters in your string to account for the additional \n character.
If you want the original number of characters or don't want a \n to be added, use the gets() function as it doesn't copy the newline character.And further, you only need to pass the string as argument,no need to pass the stream (stdin) as the default stream for gets() is stdin.
char str2[100];
printf("\nEnter a string: ");
gets(str2);
printf("\n%d",strlen(str2));
Here you have used fgets() function to take input. When you take input by fgets() function then an additional new line character('\n') will be added with your sting. suppose your input is : "hello" . after typing this sting you must press ENTER key for which new line character will be added with your string. Hence its seems to you that strlen() counts the null terminator. But if you take input using scanf() function it will not add additional new line character('\n') when ENTER is pressed. So you will see the exact number of character you string contains. Run the following code to see my explanation.
#include<stdio.h>
#include<string.h>
void main()
{
char str2[100];
printf("\nEnter a string: ");
scanf("%s",str2);
//fgets (str2, sizeof(str2), stdin);
printf("\n%d",strlen(str2));
}
as stated by others, the fgets() will read the newline(\n) character and store it in your array.
after every call to fgets() I always use strcspn() to search the array/pointer to find the newline character and replace it with the null character.
char str2[100];
printf("\nEnter a string: ");
fgets (str2, sizeof(str2), stdin);
//new line of code to replace '\n' with '\0'
str2[strcspn(str2, "\n")] = '\0';
printf("\n%d",strlen(str2));
fgets() reads until \n is encountered.
If the user enters anshul then str2 will contain anshul\n\0.
strlen() will return 7 because strlen() searches until it finds the NULL('\0') character.
gets(s) does not include the '\n' when you hit the enter key after being done entering the string.But, fgets() does include the '\n' while reading from a file.
As per the man page(use: man fgets) on linux terminal,
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.

Why is my output formatted, i.e. '\n' automatically in fgets?

Here is my code
#include<stdio.h>
int main()
{
FILE* fp;
int i;
fp=fopen("newfile","r");
if(fp==NULL)
{
printf("hhaha");
return 0;
}
char str[20];
for(i=0;i<2;i++)
{
fgets(str,20,fp);
printf("%s",str);
}
return 0;
}
Now if my newfile has text
my name
is xyz
then how come when i print the two lines are printed in two newlines?
where does the newline character come from?
fgets sets the pointer to a char * representing the line of the file including the \n at the end of the line. (As is the case with most strings, it will also be '\0' terminated)
A file with this:
Thisismyfile
Will have this from fgets:
This\n\0,is\n\0,my\n\0,file\n\01
1The final value may not be include \n. That will depend on whether it is a \n terminated file.
from man fgets
gets() reads a line from stdin into the buffer pointed to
by s until either a terminating newline or EOF, which it replaces with
'\0'. No check for buffer overrun is performed
(see BUGS below).
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 '\0' is stored after the last
character in the buffer.
and thus fgets behaviour is different from what you might expect
From the linux man page for fgets():
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 '\0' is stored after the last character in thebuffer.
fgets() includes the newline when reading into the string - that's how fgets() is defined to work. From the standard:
No additional characters are read after a new-line character (which is retained) or after end-of-file.

Resources