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
Related
I have this function and it works well, but I was wondering if the usage of getchar is correct. Could I do something else instead? Thanks, guys.
void addRecord (struct record ** start, int account, char name[], char address[ ]);
{
printf("Enter your account number:\n");
scanf("%d", &account);
getchar();
printf("Enter your name:\n");
fgets(name, sizeof name, stdin);
printf("Enter your residential address:\n");
getaddress(address, sizeof address);
}
Assuming names cannot be empty and are not allowed to start with spaces (or tabs), you can read the name with another scanf while skipping over all intervening whitespace.
printf("Enter your account number:\n");
int account;
if(scanf("%d", &account) != 1) { /* error getting account */ }
printf("Enter your name:\n");
char name[80];
if(scanf(" %79[^\n]", name) != 1) { /* error getting name */ }
The breakdown of the " %79[^\n]" format specifier being used is:
the leading space skips over one or more whitespace characters (spaces, tabs, newlines), which consumes the newline left behind by the first scanf, any empty lines, and any leading spaces on the next line;
79 is a width specifier which limits scanf to reading at most 79 characters, leaving room for the terminating \0 nul character in the 80-character destination buffer;
[^\n] directs scanf to read a string up to (and not including) the \n newline character, which saves the name that the user entered into the name argument.
getchar() will only fetch a single character from stdin . To clear stdin buffer, you have use getchar() until you get EOF (end of file) or a new line. So, instead of calling getchar() once, call it a loop like this:
int c;
do {
c = getchar();
} while (c != EOF && c != '\n');
Note that the value of EOF is -1, so you must use int to handle it, as char is limited to 0 to 255 range.
Thanks to David Ranieri, the value of EOF can be (and usually) out of the range supported by char , so you should use int (or short ) to handle EOF.
You can put this code inside a function like clear_stdin if you need to reuse this code several times.
I came across this problem when I want to check what I input is number. The scanf function will return 1 if I successfully input a number. So here is what I wrote:
int argu;
while(scanf("%d",&argu)!=1){
printf("Please input a number!\n");
}
But when I input things like abcd to it, the loop would go forever and not stop for prompt.
I looked it up online and found that it had something to do with the cache and I need to clean it up so scanf can get new data. So I tried fflush but it didn't work.
Then I saw this:
int argu,j;
while(scanf("%d",&argu)!=1){
printf("Please input a number!\n");
while((j=getchar())!='\n' && j != '\n');
}
Then when I input things like 'abcd' it worked well and it prompted for my input. But when I input things like '12ab', it wouldn't work again.
So is there a way I can check the input for scanf("%d", &argu) is actually a number and prompt for another input if it isn't?
EDIT:
I saw the answers and solved my problem by using while(*eptr != '\n').
Notice that the fgets function actually reads '\n' into the array and gets doesn't. So be careful.
It's better to read a full line, using fgets(), and then inspecting it, rather than trying to parse "on the fly" from the input stream.
It's easier to ignore non-valid input, that way.
Use fgets() and then just strtol() to convert to a number, it will make it easy to see if there is trailing data after the number.
For instance:
char line[128];
while(fgets(line, sizeof line, stdin) != NULL)
{
char *eptr = NULL;
long v = strtol(line, &eptr, 10);
if(eptr == NULL || !isspace(*eptr))
{
printf("Invalid input: %s", line);
continue;
}
/* Put desired processing code here. */
}
But when I input things like abcd to it, the loop would go forever and not stop for prompt.
That's because if scanf encounters a character that does not match the conversion specifier, it leaves it in the input stream. Basically, what's happening is that scanf reads the character a from the input stream, determines that it's not a valid match for the %d conversion specifier, and then pushes it back onto the input stream. The next time through the loop it does the same thing. And again. And again. And again.
fflush is not a good solution, because it isn't defined to work on input streams.
For the input "12ab", scanf will read and convert "12", leaving "ab" in the input stream.
The best solution is to read all your input as text, then convert to numeric types using strtol (for integral values) and strtod (for real values). For example:
char input[SIZE]; // assume SIZE is big enough for whatever input we get
int value;
if (fgets(input, sizeof input, stdin) != NULL)
{
char *chk;
int tmp = (int) strtol(input, &chk, 10);
if (isspace(*chk) || *chk == 0)
value = tmp;
else
printf("%s is not a valid integer string\n", input);
}
chk points to the first character in the input stream that isn't a decimal digit. If this character is not whitespace or the 0 terminator, then the input string wasn't a valid integer. This will detect and reject inputs like "12ab" as well as "abcd".
scanf is a good solution if you know your input is always going to be properly formed and well-behaved. If there's a chance that your input isn't well-behaved, use fgets and convert as needed.
I will suggest to get input as a string and check for non-numeric characters in it. If input is valid convert string to int by sscanf(str,"%d",&i); or else diplay error.
Just call scanf("%*[^\n]\n") inside the loop, and it will discard the "cache".
Call scanf("%*[^\n]\n") inside the loop. This should be enough to discard anything associated with the cache.
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
I came across this problem when I want to check what I input is number. The scanf function will return 1 if I successfully input a number. So here is what I wrote:
int argu;
while(scanf("%d",&argu)!=1){
printf("Please input a number!\n");
}
But when I input things like abcd to it, the loop would go forever and not stop for prompt.
I looked it up online and found that it had something to do with the cache and I need to clean it up so scanf can get new data. So I tried fflush but it didn't work.
Then I saw this:
int argu,j;
while(scanf("%d",&argu)!=1){
printf("Please input a number!\n");
while((j=getchar())!='\n' && j != '\n');
}
Then when I input things like 'abcd' it worked well and it prompted for my input. But when I input things like '12ab', it wouldn't work again.
So is there a way I can check the input for scanf("%d", &argu) is actually a number and prompt for another input if it isn't?
EDIT:
I saw the answers and solved my problem by using while(*eptr != '\n').
Notice that the fgets function actually reads '\n' into the array and gets doesn't. So be careful.
It's better to read a full line, using fgets(), and then inspecting it, rather than trying to parse "on the fly" from the input stream.
It's easier to ignore non-valid input, that way.
Use fgets() and then just strtol() to convert to a number, it will make it easy to see if there is trailing data after the number.
For instance:
char line[128];
while(fgets(line, sizeof line, stdin) != NULL)
{
char *eptr = NULL;
long v = strtol(line, &eptr, 10);
if(eptr == NULL || !isspace(*eptr))
{
printf("Invalid input: %s", line);
continue;
}
/* Put desired processing code here. */
}
But when I input things like abcd to it, the loop would go forever and not stop for prompt.
That's because if scanf encounters a character that does not match the conversion specifier, it leaves it in the input stream. Basically, what's happening is that scanf reads the character a from the input stream, determines that it's not a valid match for the %d conversion specifier, and then pushes it back onto the input stream. The next time through the loop it does the same thing. And again. And again. And again.
fflush is not a good solution, because it isn't defined to work on input streams.
For the input "12ab", scanf will read and convert "12", leaving "ab" in the input stream.
The best solution is to read all your input as text, then convert to numeric types using strtol (for integral values) and strtod (for real values). For example:
char input[SIZE]; // assume SIZE is big enough for whatever input we get
int value;
if (fgets(input, sizeof input, stdin) != NULL)
{
char *chk;
int tmp = (int) strtol(input, &chk, 10);
if (isspace(*chk) || *chk == 0)
value = tmp;
else
printf("%s is not a valid integer string\n", input);
}
chk points to the first character in the input stream that isn't a decimal digit. If this character is not whitespace or the 0 terminator, then the input string wasn't a valid integer. This will detect and reject inputs like "12ab" as well as "abcd".
scanf is a good solution if you know your input is always going to be properly formed and well-behaved. If there's a chance that your input isn't well-behaved, use fgets and convert as needed.
I will suggest to get input as a string and check for non-numeric characters in it. If input is valid convert string to int by sscanf(str,"%d",&i); or else diplay error.
Just call scanf("%*[^\n]\n") inside the loop, and it will discard the "cache".
Call scanf("%*[^\n]\n") inside the loop. This should be enough to discard anything associated with the cache.
i write a little code to simply read a char from the keyboard but the program fails, why? How must i read a char?
int main(int argc, char** argv)
{
char op;
do
{
printf("¿Sigues?");
scanf("%c",&op);
}while(op=='s' || op=='S');
return 0;
}
Your problem is that the %c conversion specifier doesn't cause scanf() to skip leading whitespace. You need to handle the newline character that's still in the stream after reading your input.
The input stream is empty when scanf() is called the first time through the loop, so it waits for you to type something. You type s and hit the Enter key, so the input stream contains the characters s and \n (newline). scanf() removes the s from the input stream and assigns it to op. When scanf() is called the second time, the input stream is not empty; it still has the \n character in it, so scanf() reads it and assigns it to op, which causes the loop condition to fail, so your loop exits.
There are several ways to get around this problem. I'm going to recommend reading strings as opposed to individual characters using fgets(), as follows:
char op[3] = {0}; // input character + newline character + 0 terminator
do
{
printf("¿Sigues?");
if (fgets(op, sizeof op, stdin))
{
/**
* Check for a newline character in the input. If it's not there
* then the user typed in too many characters. In order to keep
* the input stream from getting clogged up with bad input, read
* until we find a newline character.
*/
char tmp[3];
char *newline = strchr(op, '\n');
while (!newline && fgets(tmp, sizeof tmp, stdin))
{
newline = strchr(tmp, '\n');
}
}
else
{
printf("Error while reading input\n");
op[0] = 0;
}
} while (tolower(op[0]) == 's');
op = getc(stdin);
scanf flushes only after reading a newline. it cant be done in platform independent way
You're seeing the line "Sigues" twice because there's a \n still in the input stream. If you type in a character and hit enter there are now two characters in your input stream. Your scanf formatter only specifies one char, so scanf reads in one char and then advances. However, the next character in the stream is a \n, hence the exit from the loop on the second go.
NB. #eduffy's technique of getc(stdin) will do the exact same thing, there's still a \n in stdin. You need to advance past that \n somehow.
How about reading in your char, and then chomping the rest of the stream up to the \n char? I tried this and it works for me:
char op;
do
{
printf("¿Sigues?");
scanf("%c",&op);
while(getchar() != '\n') continue;
}while(op=='s'|| op=='S');