Unwanted double repetition in C - c

Let's say I am writing this piece of code:
char c; // c from choise.
do{
printf("Please choose one of the following operators:\n");
printf("+ for Addition\n- for Subtraction\n* for Multiplication\n/ for Division\n");
printf("= for Assignment and\nE to check if two variables have the same type and value.\n");
scanf("%c", &c);
}while(c!='+' && c!='-' && c!='*' && c!='/' && c!='=' && c!='E');
The main problem is, when the user inserts numbers or letters, everything else other than the above operators, each message inside the printf appears twice on the screen.
For example, if c='A' we have:
Please choose one of the following operators:
+ for Addition
- for Subtraction
* for Multiplication
/ for Division
= for Assignment and
E to check if two variables have the same type and value.
A //wrong answer, the loop continues...
Please choose one of the following operators:
+ for Addition
- for Subtraction
* for Multiplication
/ for Division
= for Assignment and
E to check if two variables have the same type and value.
Please choose one of the following operators:
+ for Addition
- for Subtraction
* for Multiplication
/ for Division
= for Assignment and
E to check if two variables have the same type and value.
//here the program awaits the new value of c.
But, if c='-' or c='+' etc., of course we have
Please choose one of the following operators:
+ for Addition
- for Subtraction
* for Multiplication
/ for Division
= for Assignment and
E to check if two variables have the same type and value.
- // or +
//the program goes to the next line.
Same thing happened when I tried to convert the do_while loop in the while or for loop.

Add a space before %c: scanf(" %c", &c);. This is because the newline entered from previous input might get stored in c. You can also clear the input buffer using a getchar() after the scanf().

After the user types an incorrect character, there is still (at least) a newline in the stdin buffer.
The comment by #haccks is one way to fix the problem.
Another way is to follow the scanf by a short loop that calls getchar until EOF is received.

Related

Use sscanf to process variable-format output

This is a program ,15.5,in the book called Pointers On C.I can't understand what this program want to do.
#include<stdio.h>
#include<stdlib.h>
#define DEFAULF_A 1
#define DEFAULF_B 2
void function(char *buffer)
{
int a,b,c;
if(sscanf(buffer,"%d %d %d",&a,&b,&c)!=3)
{
a=DEFAULF_A;
if(sscanf(buffer,"%d %d",&b,&c)!=2)
{
b=DEFAULF_B;
if(sscanf(buffer,"%d",&c)!=1)
{
fprintf(stderr,"Bad input:%s",buffer);
exit(EXIT_FAILURE);
}
}
}
}//***the title of the program is Use sscanf to process variable-format output***
If I suppose the first three number in buffer is 1,2 and 3.
List item
The sscanf at the second if assigns 1 to B that should have been assigned to A and assigns 2 to C that should have been assigned to B.So why not just throw out the &c and leave the &a in sscanf,like this
c=DEFAULF_A;
if(sscanf(buffer,"%d %d",&a,&b)!=2)
List item
And why does the exit(EXIT_FAILURE) appear in the third if?When the exit(EXIT_FAILURE) appear in the third if,it mean there is a problem with the first read and the second and the third reads don't know.But when it comes this case sscanf(buffer,"%d %d %d",&a,&b,&c)!=3,the program is also wrong.
List item
So what this program want to do?
Due to I just started to learn CS,I only konw a little about C language,and lack other basic computer knowledge,please answer in a way that is easy to understand.Thanks in advance.
This is a example in Pointers On C .This program might correspond to this sentence that "the latter is used to convert the expected number of values.
[] The sscanf at the second if assigns 1 to B that should have been assigned to A and assigns 2 to C that should have been
assigned to B.So why not just throw out the &c and leave the &a in
sscanf,like this
c=DEFAULF_A;
if(sscanf(buffer,"%d %d",&a,&b)!=2)
Because that's (apparently) not the desired behavior. The program is assigning read values to the rightmost subset of variables (a, b, c), so if only two values are provided then they go to b and c, and if only one is provided then it goes to c. The variables that don't get read values assigned to them are assigned default values instead. Your proposed alternative does not achieve the same thing.
And this is in fact the distinguishing characteristic of the function presented -- the "trick", if you will. It would indeed be simpler to write a straight left-to-right style matchup of values to variables.
Nevertheless, the function is needlessly complicated. Myself, I would not write it with three separate sscanf calls, because you can get everything you need from just one. I would write the function something like this:
#define DEFAULT_A 1
#define DEFAULT_B 2
void function(char *buffer) {
int a, b, c, num_fields;
num_fields = sscanf(buffer, "%d %d %d", &a, &b, &c);
switch (num_fields) {
case 3:
// three values read and assigned. nothing to see here.
break;
case 2:
// only two values read (into variables 'a' and 'b')
// shift them to the correct variables and assign a default to 'a'
c = b;
b = a;
a = DEFAULT_A;
break;
case 1:
// only one value read (into variable 'a')
// shift it to the correct variable and assign defaults to the others
c = a;
b = DEFAULT_B;
a = DEFAULT_A;
break;
default:
fprintf(stderr, "Bad input: %s\n", buffer);
exit(EXIT_FAILURE);
}
}
[] And why does the exit(EXIT_FAILURE) appear in the third if?When the exit(EXIT_FAILURE) appear in the third if,it mean there is
a problem with the first read and the second and the third reads don't
know.But when it comes this case sscanf(buffer,"%d %d %d",&a,&b,&c)!=3,the program is also wrong.
The return value of sscanf reports on two things:
how many scanf directives resulted in values being successfully read from the input, converted to the indicated data type, and assigned to variables; and
whether any kind of system error was encountered (very unlikely for sscanf(), but this is shared with scanf(), for which it is a genuine possibility).
You seem to have the second one in mind, but it is the first that the program is mainly relying upon. It is using the return value to determine how many of the variables were assigned values. That the first attempt does not assign all three does not imply that the second will not assign two, or the third, one. But of course you're right that the program is somewhat redundant. As I demonstrate above, only one sscanf() call is needed.
[] So what this program want to do?
Nitpick: it's just one function, not a complete program.
Technically, because it doesn't do anything with the values it parses out of the string, all it does is report on whether the string pointed to by the function argument starts with a text representation of at least one decimal integer, optionally preceded by any number of whitespace characters (spaces, tabs, etc.). If so, it prints nothing. If not, it prints an error message.
But what you're probably looking for is the explanation I provided in response to your first numbered question.
Seeing how you are essentially asking 'What does this program' do: It is essentially performing a 'default initialization for not entered values'.
Another (more efficient) way to achieve (much) the same thing is:
#include<stdio.h>
#include<stdlib.h>
#define DEFAULF_A 1
#define DEFAULF_B 2
void function(char *buffer)
{
int a,b,c;
switch (sscanf(buffer,"%d %d %d",&a,&b,&c))
{
case 1:
b = DEFAULF_B; //Only one has been entered, assign default to 'b'.
//Falls through
case 2:
c = DEFAULF_A; //Only two have been entered, assign default to 'c'.
//Falls through.
case 3: break; //All three have been entered, do nothing.
default:
exit(EXIT_FAILURE); //None have been entered -> Abort the program.
break;
}
}
If buffer contained 3 numbers, all three numbers are kept and no defaults are applied.
If buffer contained 2 numbers, the two numbers are kept (in your code that's b and c, in mine it's a and b) and DEFAULF_A is assigned to the remaining variable.
If buffer contained 1 number, that number is kept (c for you, a in my example) and the other two get assigned DEFAULF_A and DEFAULF_B respectively.
If buffer contained no number at all, your program gets terminated with the return code 'EXIT_FAILURE', which a calling program could fetch.
The program examines contents from a buffer, and tries to read three values from it, for example:
1 2 3
If the first sscanf finds three numbers, it reads them all. If only two are found, it assigns default value to a and tried to read two numbers. If only one is found, it assigns default value to b and tries to read one number. If there are no numbers, the program exits, because there is no default value for c.
So if we reach exit(), it means there were neither 3, 2, or 1 numbers in the buffer. If one of the if clauses succeeded, further ones are not executed.
It is important to realize that sscanf always starts from the beginning of the buffer. So if it reads for example 1 2 in the first call, but cannot find the third one, the buffer still contains the same data during the second call, and two numbers can be read.
Regarding your question 1: Why are two numbers considered as "b and c", rather than "a and b"? This is simply the way the programmer wanted the program to work. They could have as easily set a default value for c and considered the two numbers as "a and b".
Regarding your question 2: What if the output is completely invalid, and the third read will fail? In that case, we know that the first and second reads will fail as well, so we can safely put the error handling after the third one.

Alternative Solution to repeated digit worked example in chapter 8, KNK C Programming (Arrays & Boolean Values)

I am dealing with my attempted solution to a worked through problem of Chapter 8 in KNK's C Programming, A Modern Approach. I understand the answer they have proposed but would like to know why my one is wrong. I am stumped...
I am trying to write a program using arrays and the getchar() function to read a positive number and check whether it has repeated digits.
My program uses Boolean values to keep track of which digits appear in a number. The array named digit_seen is indexed from 0 to 9 to correspond to the 10 possible digits. Initially every element of the array is false.
I would like to write a program which, when given a number n, examines n's digits one at a time, from left to right. Storing each examined digit into the digit variable and then using it as an index into digit_seen. If digit_seen[digit] is true then digit appears at least twice in n. However if digit_seen[digit] is false then digit has not been seen before and the program will then update digit_seen[digit] to true and keep on going.
Here is my imperfect code:
#include <stdbool.h>
#include <stdio.h>
int main()
{
bool digit_seen[10] = {false};
int digit;
printf("Enter a positive number: ");
while((digit = getchar()) != EOF) {
if(digit_seen[digit])
break;
digit_seen[digit] = true;
}
if(digit == EOF)
printf("No repeated digit\n");
else
printf("Repeated digit\n");
}
Let me briefly explain why I (clearly incorrectly) think it should work. Suppose I type in the number 12 (i.e. n=12). Then getchar() takes 1, puts it in digit. Note that 1 != EOF, so the while loop is executed. We also see that digit_seen[digit] is false so the if statement is never executed and now we assign digit_seen[digit] to true (i.e. the number 1 has been 'seen' now).
The exact process is repeated for the next digit 2. Then all the possible digits have been scanned and we get to EOF. So we assign digit = EOF. At this point the while loop is not executed. We go to the if statement following the while loop, see that it is indeed true and print the words "No repeated digit".
Now suppose instead I type in the number 22 instead of 12 (i.e. n=22). By the time we read the 2 digit for the second time digit_seen[digit] is already
true, so we break out of the while loop. We then encounter if(digit == EOF) and note that in the case where we are breaking out of the while loop (instead of the argument in the while's parenthesis being false) digit must have an integer value between 0 and 9 respectively. Yet EOF is stored as -1 on the computer. So the if(digit == EOF) is not executed, instead the else clause is executed and we have the program correctly telling us that a "Repeated digit" has been typed.
Can someone please tell me what I am missing here? My output is always just "Repeated digit"? Further I would like to add that this is a worked example that KNK provides a solution for BUT the solution does not involve getchar(). It involves scanf() then uses modulo (%) and divide(/) operations to analyse the number's digits from right to left. I understand their solution but I am not content with understanding their alternative approach and not seeing where I failed. I find it curious they didn't use getchar() as this was my first instinct before looking at their solution. Is there a way to solve the problem using my proposed method, by analysing n's digits as they're typed? Or does it require a different approach like the one in the book?
As a self-taught programmer with no one else to ask these sorts of questions any elucidation would be very generous.
ANSWER:
After having taken your considerations on board I am posting my "alternative answer". One small tweak was all that was needed. I am now extra aware of what getchar() does and the ASCII Table. Not that I had a good reason not to be before. I would urge anyone reading to compare with KNK should be they curious.
#include <stdbool.h>
#include <stdio.h>
int main()
{
bool digit_seen[10] = {false};
int digit;
printf("Enter a positive number: ");
while((digit = getchar()) != '\n') {
digit -= '0';
if(digit_seen[digit])
break;
digit_seen[digit] = true;
}
if(digit == '\n')
printf("No repeated digit\n");
else
printf("Repeated digit\n");
}
getchar() does not return a digit. It returns a code for a character.
In the code most commonly used for characters in C implementations, ASCII, the codes for the digit characters “0” through “9” are 48 through 57. Then digit_seen[digit] attempts to access the array using an index that is out of bounds of the array. This may result in accessing some part of memory that contains some unrelated value. If that value is non-zero, then digit_seen[digit] evaluates as true, and the break; is executed to leave the loop.
Then digit == EOF is not true, and “Repeated digit” is printed.
First, after getting a character with getchar, test whether it is a digit character using the isdigit function declared in <ctype.h>. If it is a digit character, convert it to a digit (0-9) using digit -= '0';. Then you can use it as an index into the array.
If it is not a digit character, you might ignore it or print a warning to the user. For example, “white space” characters (detected using the isspace function) may be ignored. This includes the new-line character that is generated when the user presses enter or return.

Reading from a file in C, how "%*lf" work?

While reading from a file in C, I was told that I can add an * after the % to disregard that input. For example:
fscanf(inputfile, "%lf %lf %*lf", &num1, &num2);
In this example the pointer reads three double values, but only two of them need to be stored (the ones without the * sign after the % sign).
Could someone explain how it works, because as far as I know the * sign is used to initialize or step into a pointer?
The use of * is just a string constant chosen arbitrarily. It has no relation to pointer dereferencing. How it "works" is that the parser in scanf simply parses the type as it would normally then throws away the value rather than looking for a parameter to put it in.

incompatible types in assignment of `float' to `char[3]'

trying to figure out what is going on here. I'm just learning C, so go easy on me. :P I was assigned to create a unit converter from centimeters to inches. I've got it. Now I want to spice it up a little by creating options. My compiler isn't enjoying what I have. this is the first few lines....
main(void)
{
float centimeter;
char cnv[3];
float entry;
float oz;
float lb;
float cm;
float lb1;
centimeter=2.54;
lb1=2.2;
printf("Hello. Please type exactly, the type of conversion you would like to do.\n\n1. cm to in\n\n2. lb to kg\n");
scanf("%3c",&cnv);
if (strcmp(cnv=cm));
{
printf("Please enter your length in centimeters:\n");
scanf("%f",&entry);
printf("with %.0f centimeters in length, that converts to %.2f inches.",entry,entry/centimeter);
}
if (strcmp(cnv=lb));
{
printf("Please enter your weight in pounds:\n");
scanf("%f",&entry);
printf("with %.0f Pound(s) of weight, that converts to %.2f Kilogram(s).",entry,entry/lb1);
}
}
and it's giving me the error in the title. How can I fix this?
1) You're confusing = (assignment) with == (test for equality)
2) You can't compare a numeric value directly to a character array. You need to convert one or the other to a type which can be compared -- convert the number to string, if your using strcmp() (and understand how that function returns its results, which aren't what you've assumed here), or convert the string to a numeric type and compare that way.
The '=' operator is used for assigning values not comparison. You should use '==' for comparisons.
The values that you are of different types. You should convert one of the variables to the other type to compare.
Strings must be compared with some string comparison function like strcmp() as you have done, but strcmp() is a function and therefore the you should pass the parameters in with a comma separating them.
As an aside strcmp() returns 0 when the strings that you pass in are equivalent, so using a syntax more like this would be appropriate: if(!strcmp(cnv, cm)) or if(strcmp(cnv, cm) == 0)
If I might take a guess what you really were looking to do was something like: if(strcmp(cnv, "cm") == 0) cm is a name of a variable whereas "cm" is a zero terminated string with the characters 'c' and 'm'
The next thing that you will need to worry about is reading in the 3 characters from scanf, because if the input was "cm" and the user pressed enter to enter the text. The program scanned 3 characters one of which was the newline character '\n'. So when you go to do the strcmp() the program will compare each character up till it reaches a byte that has been zeroed out. With just 3 characters being read I am not sure if the string you are capturing is zero terminated, but I am sure that the string could contain a '\n' which would throw the results of strcmp() way off.
Thestrcmp syntax is not correct. For more about string compare function please check this link
http://www.tutorialspoint.com/ansi_c/c_strcmp.htm

C, reading simple formula strings from input

for a homework, we need to input simple formulas (such as 3*2, 4+10, 50/16, etc.) and calculate the result (and rest) using only addition, subtraction, and bit shifting. Anyway, I could use three subsequent input reading, however I thought I'd try getting the formula in one pass using fgets() and sscanf(). Here is what I have :
int *v; // value (left side)
int *m; // modifier (right side)
char *o; // operant
int res = sscanf(buffer,"%d%s%d",v,o,m);
But naturally, this does not work, because o gets all the remaining portion of the string, leaving m with nothing (m equals whatever value is where and when it is declared)
Now, what would be the proper way to accomplish this?
NOTE : I'm using a trim function to trim extra spaces.
Try %c instead of %s. If the operator is always a single character, and there are no spaces between the operator and the operands, this should work.
By the way, are you initializing v, m, and o to actually point to something? It would be much better to do this:
int v;
int m
char o;
int res = sscanf(buffer, "%d%c%d", &v, &o, &m);
As my "Intro to Programming in C" professor used to say: "C is dangerous. Practice safe C!".
You may use %[-+*/] (with your set of operators) to ensure, that operator string gets only operator characters.
Since you don't have extraneous spaces and operators are all one character long, you could use %c to fill in o.

Resources