I am trying to scan an arithmetic expression like : 4+3-2*6*(3+4/2)#
What I tried is following code. It's running fine and scanning each character properly except '+' and '-'.
Why it is not scanning only two particular characters!
void scan(){
int n,tmp,digit_no;
char c;
scanf("%c",&c);
while(c!='#'){
if(isdigit(c))
{
tmp=c;
scanf(" %d",&n);
digit_no=numPlaces(n);
n=(tmp-48)*ipow(10,digit_no)+n;
push_n(n);
n=0;
}
else if(c=='+' || c=='-' || c=='*' || c=='/' || c=='(' || c==')' || c=='=' || c=='^')
push_o(c);
scanf("%c",&c);
}
}
Do not get a char, test for a digit, scan an int and then try to put them together. This fails the code's intent with input like for input like "3-2", "1 23", "1+23" as well explained by #John Bollinger as scanf("%d",&n) is consuming the + -.
Instead put the digit back into stdin and then scan for the int.
if(isdigit(c)) {
ungetc(c, stdin);
scanf("%d",&n); // cannot fail as first character is a digit - may overflow though
push_n(n);
n=0;
}
Also suggest to detect EOF and use is...() functions correctly.
// char c;
// scanf("%c",&c);
int c;
// while(c!='#'){
while((c = fgetc(stdin)) !='#' && c != EOF) {
...
// scanf("%c",&c);
}
Detail: is...() expects an int in the range of unsigned char and EOF. Calling them with a char is a problem when the value is negative.
You are mistaken: scanf() is scanning the '+' and '-'. It is simply scanning them as part of the decimal number that follows.
With your example input, the program first scans a '4', which is a digit. It then proceeds to execute scanf(" %d",&n);, which scans the next two characters, "+3", as the number 3, because fields described by %d may optionally have a leading sign character, either '-' or '+'. The scanning stops at the first '-', since a decimal number cannot contain an internal or trailing '-', and indeed, the '-' is scanned as the next character. You would see different results for '-' or '+' following a two-digit number or a parenthesis.
Overall, your approach to scanning numbers is fundamentally flawed. Not only does it run aground on the optional sign character, but I see no way it can do the right thing when the second-most-significant digit of the number you are trying to read is a '0'. That is, your approach cannot distinguish "401" from "41". You cannot successfully scan the tail of a number as a number in its own right without losing information you need.
Related
I'm going through lessons at S.Prata book: 'C Primer Plus'. Chapter 6, control question #8:
// Given the input Go west, young man!, what would each of the following
// programs produce for output? (The ! follows the space character in the
// ASCII sequence.)
#include <stdio.h>
int main(void) {
char ch;
scanf("%c", &ch);
while (ch != 'g') {
printf("%c", ch);
scanf("%c", &ch);
}
return 0;
}
The thing is... as far as I know %c in scanf should be used for a single character, not for a phrase like 'Go west, young man!'. Why this program read all the line and stores all of it (except last word), not only first character? Does it automatically store stuff in scanf as an array?
I thought it will print just 'G'... But it actually prints 'Go west, youn'. Why? It's not %s, but %c.
I suppose it could be because %c stores all input to 'char'.. but in specifications it said that it stores only single character, not several ones.
There is a loop, which has the scanf() in it's body
while ( ch != 'g' )
so, it keeps on reading the inputs present in the buffer, until it finds a 'g'.
So, for the input
'Go west, young man!'.
^---------------- here is the 'g'
It'll keep on reading the characters one by one, in each iteration till it reads the 'g' and encounters the exit criteria for the loop.
The character ch will never store a whole string, it only stores one character. The output you're getting is NOT given by a single printf execution, it's by multiple executions of printfs (The loop enters multiple times). You can confirm that by changing the code to:
#include <stdio.h>
int main(void)
{
char ch;
scanf("%c", &ch);
while (ch != 'g')
{
printf("PRINTING: %c\n", ch);
scanf("%c", &ch);
}
return 0;
}
Now, let's see why the loop enters multiple times.
You entered many characters in the scanf outside the loop, then in the loop you expect it to print the first character, which is totally correct. BUT, you think it will wait for the user input again, which is not correct. In the first scanf, when you entered multiple characters, it just read the first one. But there is somehow a hidden cursor in the stdin (standard input) that keeps track of what has been read. When you entered "Go west, young man!", the G is stored in ch and the cursor is put before the o. When you next call scanf, it will look at the cursor position and finds an o, so it won't wait for user input and just reads it. etc.
To summarize, I suspect your problem is that you misunderstand how scanf works. You think that it will always wait for user input whenever called. That is not the case, it may read from the previous input.
If you want the next scanfs to ignore the long first input, you should actually read it (or seek the stdin which will work in Windows but not Linux). Example:
#include <stdio.h>
int main(void)
{
char ch;
scanf("%c", &ch);
while (getchar() != '\n'); // Get to the end of the stdin.
// The previous line can be replaced with fseek(stdin, 0, SEEK_END); but it will work under Windows only.
while (ch != 'g')
{
printf("PRINTING: %c\n", ch);
scanf("%c", &ch);
}
return 0;
}
The program simply reads all characters one by one of the input.
So for an input such as
Go west, young man!
then the first call to scanf reads the single character 'G'. Then in the loop you print that single 'G', followed by reading the single character 'o'. Then in the next iteration of the loop you print the single character 'o' (that you read in the previous iteration) and then read the space ' '. And so on.
Also note that 'G' is not equal to 'g'. Character comparison is case-sensitive.
I want to input a sentence (containing any possible characters) and print it. But there is a catch. If there is a \n in the sentence then only the part of the sentence before \n should be printed out (i.e. \n should signify the end of the inputted sentence). I wrote a code for this situation :
#include <stdio.h>
main()
{
char ch[100];
printf("Enter a sentence");
scanf("%99[^\\n]",&ch);
printf("%s",ch);
}
This code seems to work fine but it fails in a certain situation.
If there is the character n anywhere in the sentence before \n then it prints only the first word of the sentence! Why does this happen? How can I fix this bug?
This case works fine:
But in this case it fails:
Detail from comments:
Q: Do you want to to stop at a newline, or at a backslash followed by n?
A: slash followed by n
The [] conversion specifier of scanf() works by defining an accepted (or, with ^, rejected) set of characters. So %[^\\n] will stop scanning at the first \ or the first n -> You can't solve your problem with scanf().
You should just read a line of input with fgets() and search for an occurence of "\\n" with strstr().
Side note: there's an error in your program:
char ch[100];
scanf("%99[^\\n]",&ch);
ch evaluates as a pointer to the first element of the array (so, would be fine as parameter for scanf()), while &ch evaluates to a pointer to the array, which is not what scanf() expects.
(the difference is in the type, the address will be the same)
OP's calcification negated the first part of this answer.
OP has not formed the desired scan set for the "%[...]" specifier.
"%99[^\\n]" accepts any character except '\\' and 'n'.
Certainly OP wants "%99[^\n]". \\ changed to \ to accept any character except '\n'.
Yet I would like to take the goal up a bit. This part is only for pedantic code.
input a sentence (containing any possible characters)
How would code handle this if the null character '\0' was included in that "any possible character"?
Note that inputting a null character is not often easy from a keyboard.
Interestingly "%99[^\n]" will scan up to 99 characters (except a '\n') including the null character. Yet the below code prints ch as it it were a string and not a general array of characters.
#include <stdio.h>
int main(void) {
char ch[100];
printf("Enter a sentence\n");
if (scanf("%99[^\n]", ch) != 1) {
ch[0] = '\0'; // Handle a line of only `'\n``, EOF, or error
}
printf("%s",ch);
}
To accomplish this esoteric goal with scanf() (not the best tool in the shed), record the length of the scan and then print the array.
int main(void) {
char ch[100];
int n;
printf("Enter a sentence\n");
if (scanf("%99[^\n]%n", ch, &n) != 1) {
n = 0; // If scanning stopped right away, set length `n` to 0
}
// Write as an array
fwrite(ch, sizeof ch[0], n, stdout);
}
I'm trying to use sscanf() to validate commandline input
I want only things like 1, 0.1, 0.111 to go through,
not a12 12a or 1.2a
I tried
if (sscanf(input, "%f", &val) != 1) { // to check for 1 successful conversion
printf("invalid input");
}
but it seems like I'm letting invalid inputs go through as well.
Any advice?
When sscanf(input, "%f", &var) encounters the input 12a or 1.2a, it stops at the invalid input part, leaving the remaining characters available for reading by a subsequent format code.
Consider that the following strings have invalid characters for floating point numbers following a valid number:
1.0 2.0 (a space)
1.0, 2.0 (a comma)
1.0a 2.0 (a letter)
Spaces and commas look OK to our human parsing engine; the machine floating point parsing simply stops when an invalid character is found, whether it is a human acceptable space or comma, or an ugly letter.
If you want to ensure that a floating point number is not immediately followed by garbage, you could use something like:
n = sscanf(input, "%f%c", &var, &ch);
if (n == 1 ||
(n == 2 && (ch == ' ' || ch == ',' || ...))) {
// ...
}
sscanf is not your friend, here. Even if you check the result to
ensure that you read one whole argument successfully, that doesn't
really guarantee that the input is valid in a meaningful sense.
Given input like:
1!!!1!oneone!
the %f parsing will stop (but succeed) after reading the first 1,
and leave the read pointer at the following !. This may not be what
you consider "valid input".
If anything on the same line is to be considered garbage, then it gets
difficult, because scanf doesn't distinguish between spaces and
newlines. Perhaps try something like this:
int main(int argc, char *argv[])
{
float val;
char c;
if (sscanf(argv[1],"%f%c",&val,&c)!=1)
{
printf("invalid input");
}
return 0;
}
now it will validate all commandline input if it's floating number input or not.
how can I enforce following input restriction in c?
First line contains float ,
Second line contains float ,
Third line int,
after pressing enter three times in console, program should be able to read each line and put the contents in respective int,int,float variables.
After three enter key press program should not wait for user input and start validation.
some test cases
line1: 34
line2:4
line3:12
result: ok
line1:
line2:4
line3:12
result: not ok
line1: Hi
line2:4
line3:12
result: not ok
so far I used the basics
scanf("%f",&p);
scanf("%f",&r);
scanf("%d",&t);
it works fine for test case 1 and 3, but fails when I leave an empty line.
You should always check the return value of scanf.
The reason is that the return value is what scanf uses to communicate conversion errors, among other errors. For example, if your program tells scanf to expect a sequence of decimal digits, and scanf encounters something that doesn't match that pattern, the return value will indicate this failure.
The value returned will be the number of items that are successfully assigned to. For example,
char str[128];
int x, y = scanf("%d %127s", &x, str);
If y is 1, then it should be assumed that x is safe to use. If y is 2, then it should be assumed that both x and str are safe to use.
This answers part of your question. The next part is how you can go about ensuring that the input is in the form of lines. scanf doesn't strictly deal with lines; it deals with other units, such as %d being an int encoded as a sequence of decimal digits (and a sign); it'll return once the decimal digit sequence ends... There's no guarantee that the decimal digits will occupy the entirety of the line.
There are actually two problems here: leading and trailing whitespace. All format specifiers, with the exception of [, c, C, and n, will cause leading whitespace to be discarded. If you want to handle leading whitespace differently, you'll need to codify how you expect leading whitespace to be handled.
Consider that discarding user input is almost always (if not always) a bad idea. If you don't care what the remainder of the line contains, you could use something like scanf("%*[^\n]"); getchar(); to discard everything trailing up to and including the '\n' newline character... The first statement would attempt to read as many non-newline characters as possible, and the second would discard the terminating newline character. However, if you want to ensure that the input occupies the entirety of the line, then you need to test the value returned by getchar.
An example using all of these considerations:
/* Test for leading whitespace (including newlines) */
int c = getchar();
if (c != '-' && !isdigit(c)) {
/* Leading whitespace found */
}
ungetc(c);
/* Test for correct data conversion */
int x, y = scanf("%d", &x);
if (y != 1) {
/* Something non-numeric was entered */
}
/* Test for trailing newline */
c = getchar();
if (c != '\n') {
/* Trailing newline found */
}
Armed with this information, perhaps you can come up with an attempt and update your question with some code if you have any problems...
P.S. I noticed in the code you wrote, you seem to have %f and %d confused; %f is for reading into floats, and %d is for reading into ints, not the other way around...
As soon as I read line wise input, I know that fgets + sscanf must be used instead of direct scanf. Of course you can use getc/getchar as a workaround, but you can get corner cases, where I findfgets + sscanf cleaner. Example to get a float alone on a line:
char line[80], dummy[2];
float val;
if (fgets(line, sizeof(line), stdin) == NULL)...
if (sscanf(line, "%f%1s", &val, dummy) != 1)...
// Ok val was alone on the line with optional ignored blanks before and/or after
You could also add a test for loooong lines :
if ((line[0] != 0) && (line[strlen(line)-1 != '\n'))...
I need help understanding what are they really asking here.
I have written part of the program already.
Do I have to print the decimal value for the newline character and the tab character?
Why I can't get 10 pair per line all the time? Sometimes I get 10 pairs and another times not.
The assignment was:
Write a program that reads input as a stream of characters until
encountering EOF. Have the program print each input character and its
ASCII decimal value.
Note that characters preceding the space character in the ASCII
sequence are nonprinting characters. Treat them specially. If the
nonprinting character is a newline or tab, print \n or \t,
respectively. Otherwise, use control-character notation. For instance,
ASCII 1 is Ctrl+A, which can be displayed as ^A. Note that the ASCII
value for A is the value for Ctrl+A plus 64. A similar relation holds
for the other nonprinting characters. Print 10 pairs per line, except
start a fresh line each time a newline character is encountered.
This is what I have written:
#include <stdio.h>
int main(void)
{
int ch;
int i=0;
printf("Please enter some characters.\n\n");
while((ch=getchar()) != EOF)
{
if((i%10) == 0)
printf("\n");
if (ch == '\n')
printf( "\n\\n ");
else if (ch == '\t')
printf("\\t %d ", ch);
else if (ch < ' ')
printf("^%c %d ", ch+64, ch);
else
printf("%c %d ",ch, ch);
i = i+1;
}
return 0;
}
What they're asking for sounds very clear; here is some pseudo-code:
if (ch == '\n') print "\n %d", ch;
else if (ch == '\t') print "\t %d", ch;
else if (ch < ' ') { print "^"; print "%c %d", ch+'A', ch; }
else print "%c %d",ch, ch;
This is exclusive of formatting needed to make it look right; your code already has some formatting.
ASCII 0-31 are non-printing characters. Their respective control-character notations can be found at the ASCII Wikipedia page in the [b] column.
You will want to print the control-character notation for these characters, with the exception of 9 and 10, for which you will print \t and \n (backslash-t and backslash-n), respectively.
Another thing about your loop
if((i%10==0) || (ch == '\n'))
printf("\n");
These should be two separate statements. Make sure to escape your backslashes with an extra backslash beforehand as printf("\\n"); will actually print "\n" (backslash-n) whereas printf("\n") will just print an actual line feed, which I'm almost certain is not what your instructor is asking for here, except after each ten entries.
Have a look at the Wikipedia pages about ASCII, the caret notation (which is similar to control notation). I don't want to post the solution here. :D