This program works as long as the "major" variable is only one word. For example, CIS is a valid input but Computer Information Systems is not. How do I fix this?
#include<stdio.h>
int main()
{
char major [51];
int classes;
printf("What is your major? ");
scanf("%50s", major);
printf("How many classes are you taking this semester? ");
scanf("%d", &classes);
printf("Your major is %s and you are taking %d classes this semester.\n", major, classes);
}
You can use %50[^\n] to match up to 50 characters until a newline is encountered, and store them in major[]. The newline will be left behind in the input stream, but the %d conversion specifier automatically skips over leading whitespace characters.
Note that if the user enters more than 50 characters, there will be extra characters in the input stream to discard before calling scanf() to get the number of classes.
Your problem is scanf stops at the first white space. What you need to do is keep reading until you read the end line character.
It's possible to do this with scanf but there are better options. fgets() comes to mind immediately. https://www.tutorialspoint.com/c_standard_library/c_function_fgets.htm
A few searches on Stack overflow will yield a ton of topics about the scanf() vs fgets() vs others.
Using fscanf() vs. fgets() and sscanf()
Related
I’m new to C programming language, I have wrote a simple code that reads two “char” values and prints them on the screen but the second one got empty value for a strange reason. What’s going wrong with my code?
Char c;
Scanf(“%c”,&c);
Printf(“Value:%c”,c);
Scanf(“%c”,&c);
Printf(“Value:%c”,c);
Output:
Value:g
Value:
(This is a comment, but comments are hard to format)
There's nothing wrong with your code (other than the failure to check the value returned by scanf and deal with errors or incorrect input). Consider:
#include <stdio.h>
int
main(void)
{
char c;
scanf("%c",&c);
printf("Value:%c",c);
scanf("%c",&c);
printf("Value:%c",c);
return 0;
}
$ gcc a.c
$ printf 'abc' | ./a.out
Value:aValue:b
Perhaps what's "wrong" is that you have newlines in your input. (eg, you are entering data interactively and forgetting that when you hit "return" a newline is inserted into the input stream.)
If your goal was to read two "interesting" characters, and if you don't think that whitespace characters like space and newline are "interesting", you've been tripped up by number six out of the seventeen things about scanf that are designed to trip up the unwary: %c does read whitespace characters.
If you want scanf to skip over whitespace characters, so that %c will read the next, non-whitespace or "interesting" character, simply include a space character in the format string before the %c:
char c;
scanf(" %c", &c);
printf("Value: %c\n",c);
scanf(" %c", &c);
printf("Value: %c\n",c);
In a scanf format string, the presence of a whitespace character indicates that you want scanf to skip over all whitespace at that point in the input.
Normally you don't have to worry about skipping whitespace with scanf, because most of the other format specifiers -- %d, %f, %s, etc. -- automatically skip over any whitespace, if necessary, before they start parsing their input. But %c is special: someone thought you might want to use it to read whitespace characters, so it doesn't skip them, so if you don't want to read them, you have to skip them yourself, with that space character in the format string first.
I am currently attempting to obtain a user character input which proceeds a user non-character input, such as integer, float/double, etc. I've read several Stack overflow solutions, and not a single one seems to work for me. Here are the six different ways I attempted to write this code:
#include <stdio.h>
int main(void)
{
int integer;
char character;
scanf("%d", &integer);
fflush(stdin);
scanf("%c", &character);
printf("The ASCII Code of %c is %d", character, character);
This gave an ASCII Code of 10 (\n, i.e. line feed character) implying fflush(stdin) did not flush the line feed whitespace. Then, from this, it would be more relevant and convenient if we looked at lines 7-8. Now, I deleted fflush(stdin) and added a space before %c conversion specifier in scanf(), i.e.
scanf(" %c", &character) This also did not work, thus I tried the following:
scanf("%c\n", &character) This did allow me to input a value, unlike the previous scenarios, albeit the character was not the same as that inputted because the ASCII code generated was still 10. I also attempted to manipulate the code using getchar() but the ASCII code was either 0 or 10 (space or line feed) and not the actual character input. Thus, I would very much appreciate it if anyone knows a way to resolve this issue. Thank you!
This question already has answers here:
What is the effect of trailing white space in a scanf() format string?
(4 answers)
Closed 6 years ago.
#include <stdio.h>
int main() {
float change = 0.0;
printf("O hai! ");
while (change <= 0) {
printf("How much change is owed?\n");
scanf("%f\n", &change);
}
return 0;
}
and the result if input is a negative is endless "How much change is owed?"
scanf is actually entered, but due to the \n in format string "%f\n", after having entered a number, scanf waits for the next non-whitespace character to return. Note that a white space in format specifier lets scanf consume a sequence of any white space characters, not only one, and so it "hangs" as long as only white space characters are provided by the stream.
Change scanf("%f\n",&change) into scanf("%f",&change).
When you ask a computer to discard whitespace, how does it know what it's done? Answer: As soon as it reads something that's not whitespace.
You asked it to discard whitespace after reading a number. Thus it's not done until it reads the number and then reads some non-whitespace.
That really doesn't make any sense since there's no reason anyone would enter non-whitespace after entering the number.
Here's a tip though that will save you pain in the future: If what you really want to do is read a line of input then parse it, use a function that reads a line and then some code to parse that input.
I want to ask a specific question and get a Y/N answer read in by the user. I will need to use the character Y or N to change the outcome of the next question eventually, which is why I need the character to be saved so I can retrieve it later. I don't want to use a string or a for/while loop. Also, why do I need to include the * after "%c*"?
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int avgTemp, lowestTemp, temperature;
char choice ='Y';
char decision ='N';
printf("What is the average temperature?\n");
scanf("%d", &avgTemp);
printf("What is the lowest temperature in last 24 hours?\n");
scanf("%d", &lowestTemp);
printf("Has the temperature been over 99 degrees F for more than 30 minutes?
Please answer Y for yes and N for no.\n");
scanf("%c*", &choice);
printf("choice is %c", choice);
return 0;
}
Also, why do I need to include the * after "%c*"?
%c* means to scan for a character and then a * (which it will discard). Maybe you meant %*c which means do the scan but discard it. You don't need either of them.
scanf is a very problematic function and should be avoided. Your program illustrates the problem. scanf does not read a whole line. scanf will only scan stdin up to what you asked for and then stop. This means extra input and newlines can sometimes be left on the input stream for the next unsuspecting scanf. From the man page...
Each successive pointer argument must correspond properly with each
successive conversion specifier (but see the * conversion below). All
conversions are introduced by the % (percent sign) character. The format string may also contain other characters. White space (such as blanks, tabs, or newlines) in the format string match any
amount of white space, including none, in the input. Everything else matches only
itself. Scanning stops when an input character does not match such a format character. Scanning also stops when an input conversion cannot be made (see below).
This makes it very easy to accidentally leave characters on the input buffer. Each of your scanf("%d") will read in the number and stop. This leaves a newline on the input buffer. This is fine for %d because...
Before conversion begins, most conversions skip white space
...but not for %c.
Matches a sequence of width count characters (default 1); the next pointer must be a pointer to char, and there must be enough room for all the characters (no terminating NUL is added). The usual skip of leading white space is suppressed. To skip white space first, use an explicit space in the format.
So you need scanf(" %c") to make it work at all.
scanf is to be avoided because it's very, very vulnerable to unexpected input. Try giving "foo" to the first question. All the scanf("%d") will silently fail. And scanf("%c") will read f.
Instead, read the whole line with getline (preferred as it handles memory allocation for you) or fgets and then use sscanf on the resulting string. This avoids all the above problems.
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