scanf and strcmp with c string - c

I found a nice example of how to use strcmp, but it's only working with fgets(), and i need to make it work with scanf. So, here's the code:
int main(void) {
char fruit[] = "apple\n";
char ans[80];
do {
printf ("Guess my favorite fruit? ");
scanf ("%s",ans);
} while (strcmp (fruit, ans) != 0);
puts ("Correct answer!");
return 0;
}
Even when I write the correct answear ("apple") it stays in the loop and keeps asking me what is the favorite fruit... I'm guessing it has something to do with the chars that are not written at ans[80](I need it to be a char array with 80chars at max). I'm not getting this...
Thanks in advance.

Scanf will ignore "\n", so you should init char fruit[] = "apple", since ans will never end with '\n'.
P.S: An explain for scanf: Any number of non-whitespace characters, stopping at the first whitespace character found. A terminating null character is automatically added at the end of the stored sequence.

scanf() does not write the trailing newline character(s) into ans. strcmp() does consider newline characters in its comparison, so it's not matching your literal, which includes the newline.

"scanf" does take newline "\n" character as input. So you are not able to equal the both strings. if you want to equal both strings you need to remove newline"\n" form the first string ("apple" is fine).

Related

Scanf function inside of while runs only one time?

Why did my scanf function inside while runs only one time?
#include<stdio.h>
#include<stdlib.h>
int main()
{
char s[9999];
while(scanf("%[^\n]s",s)>0)
{
int count=0, prev=0;
for (int i=0;i<strlen(s);i++)
{
if(s[i]==' ')
{
count=i-prev;
prev=i+1;
printf("%c", (char) (96+count));
}
else if(strlen(s)-1==i)
{
count=i-prev+1; printf("%c", (char) (96+count)); }
}
printf(" ");
}}
my test case and output:
Input is considered as a string with a maximum length 1000
Unless you understand scanf, you shouldn't use it. When you understand scanf, you will not use it. There are several problems with
while(scanf("%[^\n]s",s)>0)
scanf will read the input stream, writing characters into the variable s until it sees a newline. It will then try to match a literal s in the input stream. Clearly, the next character is not an s (it is a newline), so the s in the format string does not match. (This is not really a problem, but is certainly bizarre that you have asked scanf to match a literal s when an s is certainly not there. If you had tried to do further matches with something like "%[^\n]s%d", you might be confused as to why scanf never matches an integer. It is because scanf stops scanning as soon as the input stream does not match the format string, and the s in the format string will not match.) On the second iteration of the loop, the first character scanf sees is that newline, so it makes no conversions and returns 0. If you want to discard that newline and are okay with removing leading whitespace, you can simply use " %[\n]" as a conversion specifier. If you do not want to discard leading whitespace, you can discard the newline with " %[\n]%*c" Note that you really ought to protect against overwriting s, so you should use either:
while(scanf(" %9998[^\n]", s) > 0)
or
while(scanf("%9998[^\n]%*c", s) > 0)
Here, during the first iteration, s stores the first line, and at the second iteration s read \n. Since I used %[^\n], scanf will stop scanning.
Now here, the number of elements scanned is zero. So the while loop condition is failed. Hence, the loop is iterated only for one line.
We can change the condition as:
while(scanf("%[^\n]\n",s)>0)
This will skip scanning \n, and desired output is printed.

C Program won't terminate after compared to empty string

I am attempting to terminate my C program by checking for an empty string ("") but it seems not to work. I have tried to compare to "\0" as well but it was to no avail.
#include <stdio.h>
#include <string.h>
int main(void) {
char nameInput[128];
for(;;) {
printf("Enter nation name: ");
scanf("%s", nameInput);
if(!strcmp(nameInput, "")){
break;
}
printf("Got nation named \"%s\"\n", nameInput);
}
printf("All done getting nations!\n");
return 0;
}
The "%s" specifier in scanf("%s", nameInput); first consumes1 and discards leading white-space including all '\n' from the Enter before scanning and saving to nameInput.
That is why repeated entries of empty lines do not advance the scan. "%s" is waiting for some non-white-space input.
A better alternative to scanf() is to read all user input with fgets() and then parse the string.
fgets() reads a line and saves the result as a string - usually including the line's ending '\n'.
// scanf("%s", nameInput);
if (fgets(nameInput, sizeof nameInput, stdin)) {
// Success at reading input.
nameInput[strcspn(nameInput, "\n")] = '\0'; // lop off the potential trailing \n
if(!strcmp(nameInput, "")){ // or simply `if(nameInput[0] == '\0')
break;
}
...
have tried to compare to "\0" as well but it was to no avail.
if(!strcmp(nameInput, "")) and if(!strcmp(nameInput, "\0")) do the same thing. strcmp() is comparing strings.
"" is a string literal of 1 char: the null character.
"\0" is a string literal of 2 char: two null characters.
The string compare stops at the first null character.
"%s" by itself also lacks a width limit. Code has no safe guard against input like "BlahBlah...(120_some_more)Blah" and can lead to undefined behavior due a buffer overrun of char nameInput[128];. Code could use "%127s" to prevent that, yet that only handles one of the short-comings of scanf().
1
Input white-space characters (as specified by the isspace function) are skipped, unless the specification includes a [, c, or n specifier. C17dr § 7.21.6.2 8
It's not that it won't terminate, it is awaiting the input that wasn't (yet) typed in.
scanf is not using the right pattern string to scan in anything (including nothing) before the carriage return. You'll need to look into scanf patterns, and alter your pattern from "%s" to something that scanf will accept as input.
If you test out your program, you will see that after pressing "enter" you can type in a word and press enter again, and since you now have a word in the input, the scanf picks it up (discarding the whitespace, as it should with "%s").

What does gets() save when it reads just a newline

Here's the description of gets() from Prata's C Primer Plus:
It gets a string from your system's standard input device, normally
your keyboard. Because a string has no predetermined length, gets()
needs a way to know when to stop. Its method is to read characters
until it reaches a newline (\n) character, which you generate by
pressing the Enter key. It takes all the characters up to (but not
including) the newline, tacks on a null character (\0), and gives the
string to the calling program.
It got my curious as to what would happen when gets() reads in just a newline. So I wrote this:
int main(void)
{
char input[100];
while(gets(input))
{
printf("This is the input as a string: %s\n", input);
printf("Is it the string end character? %d\n", input == '\0');
printf("Is it a newline string? %d\n", input == "\n");
printf("Is it the empty string? %d\n", input == "");
}
return 0;
}
Here's my interaction with the program:
$ ./a.out
This is some string
This is the input as a string: This is some string
Is it the string end character? 0
Is it a newline string? 0
Is it the empty string? 0
This is the input as a string:
Is it the string end character? 0
Is it a newline string? 0
Is it the empty string? 0
The second block is really the thing of interest, when all I press is enter. What exactly is input in that case? It doesn't seem to be any of my guesses of: \0 or \n or "".
This part in the description of gets might be confusing:
It takes all the characters up to (but not including) the newline
It might be better to say that it takes all the characters including the newline but stores all characters not including the newline.
So if the user enters some string, the gets function will read some string and the newline character from the user's terminal, but store only some string in the buffer - the newline character is lost. This is good, because no one wants the newline character anyway - it's a control character, not a part of the data that user wanted to enter.
Therefore, if you only press enter, gets interprets it as an empty string. Now, as noted by some people, your code has multiple bugs.
printf("This is the input as a string: %s\n", input);
No problem here, though you might want to delimit your string by some artificial characters for better debugging:
printf("This is the input as a string: '%s'\n", input);
printf("Is it the string end character? %d\n", input == '\0');
Not good: you want to check 1 byte here, not the whole buffer. If you try to compare the whole buffer with 0, the answer is always false because the compiler converts \0 to NULL and interprets the comparison like "does the buffer exist at all?".
The right way is:
printf("Does the first byte contain the string end character? %d\n", input[0] == '\0');
This compares just 1 byte to \0.
printf("Is it a newline string? %d\n", input == "\n");
Not good: this compares the address of the buffer with the address of "\n" - the answer is always false. The right way to compare string in C is strcmp:
printf("Is it a newline string? %d\n", strcmp(input, "\n") == 0);
Note the peculiar usage: strcmp returns 0 when the strings are equal.
printf("Is it the empty string? %d\n", input == "");
The same bug here. Use strcmp here too:
printf("Is it the empty string? %d\n", strcmp(input, "") == 0);
BTW as people always say, gets cannot be used in a secure way, because it doesn't support protection from buffer overflow. So you should use fgets instead, even though it's less convenient:
char input[100];
while (fgets(input, sizeof input, stdin))
{
...
}
This leads to possible confusion: fgets doesn't delete the newline byte from the input it reads. So if you replace gets in your code by fgets, you will get different results. Fortunately, your code will illustrate the difference in a clear way.
It sets the string to "", that is, {'\0'}. Don’t use gets(), though. It causes buffer overflows.

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 does scanf handle white space?

I am new to Cstring, sorry for asking dumb question, please help.
char string[10];
printf("Give me your last name:\n");
scanf ("%s", string); //if i type 123 123
printf("Original string:%s\n", string); //it shows 123
Compare to:
char string[] = "123 123";
printf("Original string:%s\n", string); //it shows 123 123
The problem is scanf. When you use scanf with %s it reads until it hits whitespace.
To read the entire line you may want to consider using fgets().
scanf treats space as the end of the string.
So it stops reading once it encounters a space character.
While in case of c style array \0 is considered the end of the array.
When you initialize,
char string[] = "123 123";
A \0 is implicitly added at the end of 7th character 3, and it marks the end of this array.
scanf scans for a string until any whitespace. If you need to read until a newline, then use fgets():
char string[64];
fgets(string, sizeof(string), stdin);
printf("%s", string); // should now contain any whitespace in the string.
This is the right behaviour. By default scanf reads the string until it reaches a whitespace.
From scanf manpage:
s
Matches a sequence of non-white-space characters;
the next pointer must be a pointer to character array that is long enough
to hold the input sequence and the terminating
null character ('\0'), which is added automatically.
The input string stops at white space or at the maximum field width,
whichever occurs first.
Sometimes gets() also creates some warnings. If you are so determined to use scanf(), you can use it like scanf("%[^\n]", character_array_variable);
#include<stdio.h>
#include<string.h>
void main()
{
char FullName[20];
scanf("%[^\n]s",FullName);
printf("%s",FullName);
}
The output image:
What you see here happens due to the way scanf() works. You can print strings with any character inside (no matter whether it's a whitespace or not). scanf() just stops once it encounters a whitespace as it considers this variable "done".

Resources