question mark operator in expressions [duplicate] - c

This question already has answers here:
What does the question mark character ('?') mean?
(8 answers)
Closed 10 years ago.
K&R Second Edition (page 71)-- I must have missed the explanation:
sign = (s[i] == '-') ? -1 : 1;
The context of this is a function that converts a string to a double. This part in particular comes after the function skips white space. I infer it is checking for positive or negative value, and saving it as either -1 or +1 for sign conversion at the end of the function... return sign * val /power;
I would like to do better than infer... I'm particularly unsure of what the ? and : 1 are doing here (or anywhere, for that matter).
It kind of seems like an abstract if statement. Where ? checks for truth and : is else... is that so? Is it limited to if/else?
I am a beginner and I haven't come across this expression syntax before, so I am wondering if there is a particular reason it seems to often be replaced by a formal if/else--besides, perhaps, readability?

It kind of seems like an abstract if statement, where ? checks for truth and : is else... is that so?
Yeah, almost. It's called the "conditional operator" (sometimes not entirely accurately referred to as "the ternary operator", since it's the only ternary operator in C). It's not a statement though, it's an expression, it has a value. It evaluates to its second argument if the first argument evaluates to true, and to its third argument if it's false. Therefore
sign = (s[i] == '-') ? -1 : 1;
is equivalent to
if (s[i] == '-') {
sign = -1;
} else {
sign = 1;
}

It kind of seems like an abstract if statement.
That's correct. This is called a "ternary conditional operator".
The normal if works on statements, while the conditional operator works on expressions.
I am wondering if there is a particular reason it seems to often be replaced by a formal if/else--besides, perhaps, readability?
There are cases where branching on statements is not enough, and you need to work on the expression level.
For instance, consider initialization:
const int foo = bar ? 5 : 3;
This could not be written using a normal if/else.
Anyway, people who are saying it's equivalent to the if/else are being imprecise. While the generated assembly is usually the same, they are not equivalent and it should not be seen as a shorthand version of if. Simply put, use if whenever possible, and only use the conditional operator when you need to branch on expressions.

This is the ternary operator. (s[i] == '-') ? -1 : 1; returns -1 if s[i] == '-' and 1 otherwise. This value is then assigned to sign. In other words, a longer way to write this would be:
int sign;
if(s[i] == '-')
{
sign = -1;
}
else
{
sign = 1;
}

?: is the conditional operator in C.
In your example it would produce the same result as this if statement:
if (s[i] == '-')
{
sign = -1;
}
else
{
sign = 1;
}

sign = (s[i] == '-') ? -1 : 1;
is shorthand for:
if (s[i] == '-')
{
sign = -1;
}
else
{
sign = 1;
}

Related

How is 0 used in conditional operator in C?

Conditional operator in C is used like this:
condition ? value_if_true : value_if_false
What does 0 mean when it's used in the value_if_false?
I've seen some people using it like this, for example.
a == b ? i++ : 0
It seems like it does nothing. Does this work like return 0 in other functions?
In C language, ternary is shorter version of if statement and it requires both statements, if_true and if_false. It would be like this (in fact it can have multiple statements for one case, separated with comma):
Short:
condition ? if_true : if_false;
Long:
if (condition) {
if_true;
} else {
if_false;
}
You can also assign the value if you put something infront of condition.
Short:
result = condition ? if_true : if_false;
Long:
if (condition) {
result = if_true;
} else {
result = if_false;
}
Now here is the trick. In C language, writing 0; is a valid statement, so your ternary becomes in longer version same as code below:
if (a == b) {
i++;
} else {
0; /* This is valid C statement */
}
Or if you have assignment too, it would be:
if (a == b) {
result = i++;
} else {
result = 0;
}
You can also do this:
int a;
/* Code here ... */
condition ? a = 5: 0;
That is effectively the same as:
if (condition) {
a = 5;
} else {
/* DO not touch a */
}
The ?: operator is a ternary operator, but it is not called "ternary" as some answers and/or comments here suggest. It just is the arity of the operator, just as + is a binary operator or as & is unary. If it has a name at all, it is called "Conditional Expression"-operator
It is not quite equivalent to if/else, because it is a conditional value (with the consequence, that both expressions must have the same type) in the first place, not a conditional execution. Of course, both types can be cast to make them equal.
In the case of what the OP does, a better option (if if shall not be used) is in my opinion:
a == b && i++;
which resembles a bit more logical what happens. But of course it is a matter of style.
The reason why someone might want to write a == b ? i++ : 0; is that s/he probably wants to have an (Caution! You are now entering an opinion-based area) easier and faster alternative to if (a == b) i++; - although this is of course opinion-based and I personally not share the same opinion.
One thing I can think of as a "blocker" at the if statement is the requirement to write the parentheses () which can be omitted by using the conditional operator instead.
"But why the 0?"
The C syntax requires a third operand for the conditional operator. Else if you would want to compile for example:
a == b ? i++;
you will get an error from the compiler:
"error: expected ':' before ';' token"
Or respectively, doing so:
a == b ? i++ : ;
would raise:
"error: expected expression before ';' token"
So they use 0 as kind of "syntax satisfier" to be able to use the conditional operator as replacement for the if statement. You could use any other numeral value here as well, but 0 is the most readable value, which signifies that it has no use otherwise.
To showcase the use at an example:
#include <stdio.h>
int main (void)
{
int a, b, c = 4;
a = 2;
b = 2;
a == b ? c++ : 0;
printf("%d",c);
return 0;
}
The output for c will be 5, because a == b.
Note that a == b ? i++ : 0 is different when used f.e. inside of an assignment like f.e.:
int c = a == b ? i++ : 0;
Here c is either getting assigned by i or 0, dependent upon a == b is true or not. If a == b is true, c is assigned by i. If a == b is wrong, c is assigned by 0.
Side Notes:
To view it from a technical point, ?= is called the "conditional operator". The conditional operator is one of the group of ternary operators.
If you want to learn more about the conditional operator ?=, look at ISO:IEC 9899:2018 (C18), ยง6.5.15 - "Conditional operator" for more information.
There's nothing special about 0 one could write
a == b ? i++ : 1
And it would behave the same way.
Only difference is when you assign the expression to say another variable:
int c = a == b ? i++ : 1;
// a == b -> c will be i++
// a != b -> c will be 1
However it's much cleaner to write
if (a == b) i++;
It helps to think of the ternary operator as a shorthand way or writing an if-else statement.
If(a == b){
i++;
}else{
//if assigned, return 0. Else do nothing.
}

Error in C code error: expression is not assignable

I'm writing a function that is suppose to print out the description of a programs execution. A function in my program uses 0 as a signal for a base-10 numeric conversion.
I would like my program to have friendly output, and tell the user if a number has been converted to base 10, instead of letting the program say the number was converted from base 0.
When I attempt to compile this code, I get an error message which says 'expression is not assignable'.
I'm compiling on command line with cc compiler
Apple LLVM version 7.3.0 (clang-703.0.29)
Any idea what this error means and how to correct?
Thanks.
void foo( int base ){
int theBase;
base == 0 ? theBase = 10: theBase = base;
printf("%s%d\n", "The base is ", theBase)
}
error message:
error: expression is not assignable
base == 0 ? theBase = 10: theBase = base;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
What you are doing here is a conditionnal assignation.
Usually you can do it like that:
if (base == 0)
theBase = 10;
else
theBase = base;
Here you chosed to use a ternary expression. It does work a bit like an if/else structure, but it is really different.
The ternary return a value, it's not made to execute code based on a condition. No, it return a value based on a condition.
So here, you have to do:
theBase = (base == 0 ? 10 : base);
(the parenthesis are not required, but it's a lot better to avoid error).
In fact, you can make a ternary execute code, in a multiple way, like returning a function:
int my_function()
{
printf("Code executed\n");
return (10);
}
/* ... */
theBase = (base == 0 ? my_function() : base);
EDIT:
And yes you can use that code:
base == 0 ? (theBase = 10) : (theBase = base);
But it's pretty useless to use a ternary in that case, because you still have to duplicate the theBase = X code.
Because you need the lvalue, where it belongs, at the left side of the expression, like this
theBase = (base == 0) ? 10 : base;
Note how the compiler considers
base == 0 ? theBase = 10 : theBase
like the "lvalue" in that expression, because of operator precedence.
The ternary operator, is that, an operator, so you can't use it to replace an if statement.
You should use
theBase = (base == 0 ? 10 : base);
instead of
base == 0 ? theBase = 10: theBase = base;
You have to put parenthesis around the assignments
base == 0 ? (theBase = 10) : (theBase = base);
else priority is playing tricks on you. Even better, use the idiomatic syntax:
theBase = base ? base : 10;
Not answering the question, but might be helpful for others who encountered this:
In my case I had legal assignment, like:
int xyz = 5;
I was not aware that somewhere in the included headers there was the following line:
#define xyz 14
I'm not sure why the compiler didn't shout about syntax error before this semantic one. Either way if someone is frustrated enough to reach this answer I would recommend to check if the variable name is not already defined somewhere before as a macro or similar.

How to properly parse numbers in an arithmetic expression, differentiating positive and negative ones?

I have an assignment in my Data Structures class in which I have to program a calculator that solves arithmetic expressions with the 4 basic operations and parenthesis, the input is done via the stdin buffer and the same with the output.
It was easy at the beginning, the teacher provided us the algorithms (how to transform the expression from the infix to the postfix and how to evaluate it) and the only goal was for us to implement our own stack and use it, but the calculator itself does not work quite well, and I think it is because of my parser.
This is the algorithm, and my code, used to parse the numbers, operators and parenthesis while putting them into an array to store the expression in a way that it is easier to evaluate later.
// saida is an array of pairs of integers, the first value of the pair is the value of the info (the number itself or the ASCII value of the operator)
// The second value is an indicator of whether it is a number or a operator
for (i = 0; i < exp_size; i++) {
c = expression[i];
// If the current char is a digit, store it into a helper string and keep going until a non-digit is found
// Then atoi() is used to transform this string into an int and then store it.
if (c >= '0' && c <= '9') {
j = 1, k = i+1;
tempInt[0] = c;
while(expression[k] >= '0' && expression[k] <= '9') {
tempInt[j++] = expression[k];
k++;
}
tempInt[j] = '\0';
saida[saidaIndex][0] = atoi(tempInt);
saida[saidaIndex++][1] = 0;
i = k-1;
}
// If the character is an operator, the algorithm is followed.
else if (c == '+' || c == '-' || c == '*' || c == '/') {
while(pilha->size > 0 && isOpBigger( stack_top(pilha), c )) {
saida[saidaIndex][0] = stack_pop(pilha);
saida[saidaIndex++][1] = 1;
}
stack_push(c, pilha);
}
else if (c == '(') stack_push(c, pilha);
else if (c == ')') {
j = stack_pop(pilha);
while(j != '(') {
saida[saidaIndex][0] = j;
saida[saidaIndex++][1] = 1;
j = stack_pop(pilha);
}
}
}
The problem is, in this code I can't tell if a minus sign indicates a subtraction operator or a negative number (I know that a minus operator is a sum with a negative number, but it didn't helped me solving this problem), I thought of the following, none with success:
Every time there is a minus sign, store a plus sign instead and let the next number be itself * -1. Wouldn't work in case the next number is already a negative one or if the minus sign is before an expression with parenthesis like 1 + 2 - (3 * 4).
If there is a space after the minus sign, it is an operator, if not, it is a negative number. Wouldn't work because there are not those rules on the input.
I have no experience whatsoever in interpreters and I really don't know how to proceed. The code works perfectly with valid expressions without negative numbers, but not with weird ones like () + 3 - (), but that's another problem.
Thanks for any help.
That is the problem called "unary minus" and can in your case (no variables) get solved by substitution.
The operator - is an unary minus if it is
preceded by a left parenthesis
preceded by another operator
the first character of the input
Now instead of storing a - you store a different character like, say m and assign it a higher precedence than the other operators (or the same as the exponentiation operator if you have one).
Another tip: don't use spaces to indicate anything, an arithmetic expression must work without any spaces or it is not correct.

goto not working with ?: operator in C

For learning purposes, I wrote the following code snippet:
for(int i=0;i<10;i++)
{
for(int j = 0;j<5;j++)
{
//(i==j && i==3)? (goto found) : printf("stya here\n");
if(i==j && i==3){goto found;} else {printf("stay here\n");}
}
}
found:
printf("yes I am here");
But I wondered when I discovered the omitted statement inside the inner loop not gives error and now I am confused about if-else is not always replaceable with ?: operator. What is the fact here? Why does the commented statement give an error?
The ?: operator is not replacement for if. It works only for expressions: condition ? expr1 : expr2 where both sub-expressions expr1 and expr2 are of the same type (and the whole expression then is of the same type).
goto is not expression, it is a statement.
I am not well versed enough in C to explain why this doesn't work syntactically, but in the sense of intent the ?: ternary operator form is intended as a conditional expression (yields a result), not as a control flow mechanism. Using the if statement you can choose a value for a variable or change the flow of the application.
e.g.
//Change flow
if(x ==0)
{
//do this
}
else
{
//goto some label
}
or
//Change value
if(x == 0)
{
y = 1;
}
else
{
y = 2;
}
The ternary is only intended for the second case, as a conditional expression
i.e.
y = (x ==0) ? 1 :2;
Actually, what you're trying to do with goto and the ternary operator is possible if your compiler support the extension Statement Expressions, as it's name said, this extension allow you to write statements inside an expression or sub-expressions, just like this:
(rand() % 2) ? ({goto lbl1;}) : ({goto lbl2;});
Using these statements can be very useful (mostly to optimize macros) but often lead to very dirty code, just like the example i gave :)
So to complement the other answers i'll say that it's not possible in C99/11 without extension but most of the recent compiler support a bunch of extension that allows you to do non-standard cool things.
What would be the result of "goto found" expression? I don't know, neither does the compiler, so the result of ? expression cannot be determined, hence the error.
In general, the ?: operator is no replacement for a classic if() ... else() .... It might be used as such if both operators (and the condition) are values or expressions returning a value. You can't use them with statements like goto, break or continue.
The following would be possible:
condition ? dothis() : dothat(); // there's no assignment, but it's still valid
var = condition ? dothis() : othervar;
condition ? (var=4, othervar=3) : (somevar = 1);
But you can't include anything that's not an expression (i.e. nothing not having some value or result):
condition ? continue : break; // statements letting the execution continue somewhere else
condition ? {var = 4; othervar = 3;} : dothat(); // trying to inline scopes/multiple exressions
var = condition ? while(var) {var--;} : 5; // similar, inlining a complete loop
These last examples can be done, but they'd require you to use if() or function bodys to call:
if (condition) continue; else break;
condition ? (var = 4, var = 3) : dothat();
var = condition ? dotheloop(var) : 5; // ok, this could be 'var = condition ? 0 : 5;' but... example code

What is the meaning of '==' in C?

What is the meaning of == and how does it differ from =?
How do I know which one to use?
== is a test for equality. = is an assignment.
Any good C book should cover this (fairly early on in the book I would imagine).
For example:
int i = 3; // sets i to 3.
if (i == 3) printf("i is 3\n"); // prints it.
Just watch out for the heinous:
if (i = 4) { }
which is valid C and frequently catches people out. This actually assigns 4 to the variable i and uses that as the truth value in the if statement. This leads a lot of people to use the uglier but safer:
if (4 == i) {}
which, if you accidentally use = instead of ==, is a compile-time error rather than something that will bite you on the backside while your program is running :-)
The logical-or operator is two vertical bar characters, one after the other, not a single character. Here it is lined up with a logical-and, and a variable called b4:
||
&&
b4
No magic there.
a == b is a test if a and b are equal.
a = b is called an assignment, which means to set the variable a to having the same value as b.
(You type | with Shift-\ in the US keyboard layout.)
== tests equality
= assigns a value
neither are related to ||
I might add that in Finnish and Swedish keyboards. Pipe symbol; |; of OR is AltGr (the right alt) and < key. IF you are using Mac on the other hand it is Alt-7 key.
Gave me a lot of sweat when I first started typing on these keyboards.
Now that you know the difference between '==' and '=", let me put you some words of caution. Although '==' is used as a standard test of equality between comparable variables and '=' used as an internally type-casted assignment, the following programming error is quiet common.
In the below example and similar codes, '=' is know as "Always true" conditional operator.
#include<stdio.h>
int main()
{
int i = 10, j = 20;
if ( i = j )
printf("Equal\n");
else
printf("NOT Equal\n");
return 0;
}
So, the word of caution is "Never use '=' in if statements, unless you have something evil in your mind."

Resources