Ternary operator inside printf - c

After reading this I started thinking that I have learned a loot about printf(). Suddenly I found following code snippet from this book:
int main()
{
char str[]="Hello";
int i=5,j=10;
printf(i>j?"%50s":"%s",str); //unable to understand this
return 0;
}
Surprisingly above code is running without errors and it prints Hello.
As per my knowledge following is syntax of printf():
int printf(const char *format,argument_list);
So according to this syntax, printf() should start with format string. But as you can see in above code printf() is starting with i>j.
Does it mean I am wrong in interpreting syntax of printf()?
Does placing ternary operator inside printf() is a special case?
EDIT
I know about ternary operator I am asking about first argument of printf() which should be const char* which I seem not in my example.

The conditional operator:
i>j?"%50s":"%s"
is an expression and it has to be evaluated before the function call itself can be evaluated. We can see this by going to the draft C99 standard section 6.5.2.2 Function calls which says:
An argument may be an expression of any object type. In preparing for
the call to a function, the arguments are evaluated, and each
parameter is assigned the value of the corresponding argument.81)
So what is the result of the evaluation of the conditional operator? If we go to section 6.5.15 Conditional operator it says (emphasis mine):
The first operand is evaluated; there is a sequence point after its
evaluation. The second operand is evaluated only if the first compares
unequal to 0; the third operand is evaluated only if the first
compares equal to 0; the result is the value of the second or third
operand (whichever is evaluated), converted to the type described
below.95
so in either case the result is a string literal which will decay to pointer to char which satisfies the requirement for the first argument to printf.

This code is normal and is not any special case. The requirement for printf is that the first argument should be of the type const char*, but it does not necessarily mean that it needs to be a string literal like "%s". All it means that you need to pass as the first argument an expression of the type const char*. And i>j?"%50s":"%s" fulfils this requirement.

I think you well understood the printf syntax but i think you are missing something about C syntax.
It exist a form of "compact IF like" statement formatted like that : ( condition ? true : false )
For example you can do :
int a=5;
int b=(a==5 ? 128 : 256);
int c=(a!=5 ? 8 : 9);
In this case, b=128 and c=9.
An other example :
int flag=1;
printf("The value is: %s", (flag!=0 ? "true" : "false) );
In this case you can see : The value is true
On your example :
printf(i>j?"%50s":"%s",str);
if i is upper than j you use "%50s" format and, if i is lower you use "%s" format
It can be view like :
if (i>j)
printf("%50s",str);
else
printf("%s",str);
You can see the advantage of compact test.

It is a ternary operator and in this the condition i>j is false so %s will be passed as parameter to printf which will print the value of character array which is hello.

Does it mean I am wrong in interpreting syntax of printf()?
No you are not interpreting it wrong.
Does placing ternary operator inside printf() is a special case?
In C, you can say that its an expression instead of a statement
Your code is equivalent to:
if (i > j)
printf("%50s", str);
else
printf("%s", str);

The ternary operator is simply an inline if that's used as an expression (while a regular if is used to create a block). Your line is equal to this:
if (i > j)
printf("%50s", str);
else
printf("%s", str);

if(i>j)
printf("%50s",str);
else
printf("%s",str);
Therefore, Hello gets printed in both situations

Q: Does it mean I am wrong in interpreting syntax of printf()?
A: No, just need to expand what is allowable.
Q: Does placing ternary operator inside printf() is a special case?
A: No ?: is not special, but sometimes confusing at first glance.
The format supplied to printf() does not need to be a literal. It may be any string variable.
int main() {
char str[]="Hello";
char *format;
int i,j;
i = 5; j = 10;
format = i > j ? "%50s" : "%s";
printf(format, str);
i = 10; j = 5;
format = i > j ? "%50s" : "%s";
printf(format, str);
return 0;
}

There is a statement of the form: condition?consequent:alternative.
The condition is checked, and if it's true you'll get the consequent. otherwise you'll get the alternative.
For example:
5>3 ? 10 : 5
5>3 is true, so you'll get 10.

Related

Unexpected output in C program when printing

Assuming that all the header files are included.
void main() {
int i;
clrscr();
printf("india"-'A'+'B');
getch(); }
The Output of the following function is : ndia
Can anyone please explain me this output?
int printf(const char *restrict format, ...);
When you do format - 'A' + 'B' , it's equal to format + 1 considering the ASCII values of A and B.
format is the base address and when you do format + 1 it points to second memory location of this character string and from there it starts printing which is ndia.
The expression "india"-'A'+'B' does not make sense in any sane code. But it will (but see below) result in a pointer to the second element, because 'B' - 'A' will evaluate to 1.
However, the subexpression "india"-'A' will invoke undefined behavior, because the resulting pointer will point outside the array. This is explained here: Why is pointing to one before the first element of an array not allowed in C?
If we rewrite a bit and add parenthesis: "india"+('B'-'A') the expression is well defined and equal to "india" + 1

Why does the OR statement evaluate only one even if both are true? [duplicate]

This question already has an answer here:
Is an if statement guaranteed to not be evaluated more than necessary? [duplicate]
(1 answer)
Closed 3 years ago.
Consider the following C code, according to what I have learnt the OR statement should evaluate both the printf. But in actual output I see only "XX". Why is this happening?
#include<stdio.h>
int main() {
int a;
a = (printf("XX")||printf("YY"));
printf("%d\n",a);
a = (printf("XX")&&printf("YY"));
printf("%d\n",a);
}
Output -
XX1
XXYY1
OR operator output is true even if one condition is true. And in this case first printf statement returns true. So there is no need to evaluate the second operand of OR operator.
|| operator evaluates to true if any of the operands is true. So if first operand evaluates to true it doesn't check the second. It only checks second operand if first operand was false.
&& operator evaluates to true only when both the operands are true. It would check the second operand iff the first one is not false.
As stated in the manpage:
Upon successful return, these functions return the number of characters printed (excluding the null byte used to end output to strings).
The functions snprintf() and vsnprintf() do not write more than size bytes (including the terminating null byte ('\0')). If the output was truncated due to this limit then the return value is the number of characters (excluding the terminating null byte) which would have been written to the final string if enough space had been available. Thus, a return value of size or more means that the output was truncated. (See also below under NOTES.)
Say you have a code like:
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("%d", printf(""));
return 0;
}
This would print 0 just as explained in the manpage.
If your statement is:
printf("") && printf("XX");
It won't print anything because first operand evaluated to 0.
Whereas,
printf("") || printf("YY");
Would print YY.
In your case,
a = (printf("XX")||printf("YY"));
would evaluate printf("YY") only when the first operand failed to print anything.
a = (printf("XX")&&printf("YY"));
Would print XXYY when both printf were successful.
Say you're trying to answer this question "Is it raining or is it after 7 PM?". Once you see that it's raining, you know the answer is "yes". You have no need to check if it's after 7 PM or not.
a = (printf("XX")||printf("YY"));
You asked it an "OR" question. Once it evaluates the first printf, it knows that the answer to your question is yes, so it has no need to evaluate the second part.
The || or OR operator doesn't evaluate its right part if the left part has been determined to be true. Because it does not need to: TRUE || something is "always" true. Even if a potential crash hides on the right. The left part is always checked first.
The return value of printf is not "false" in case of error: it return -1. The "false" value is 0, which would occur if you are trying to print an empty format string, or put a '\0' at the beginning of it. Any value that is not 0 is evaluated as "true" in the general case.

String manipulation in argument

I have got two functions. One function calls the print functions.
Calling function (key is a number between 0 and 42 symbolizing keys of a remote and the keymap just maps names to the keys):
void calling_function(int key){
print_info("[KEY]", ("%#4x %s", key, keymap[key - 1]));
...
}
And the printing function:
print_info(char *prefix, char *message){
print("%s %s\n", prefix, message);
}
But the output looks like this:
[KEY] COLOR_RED
So the int is missing, why is it not inserting the integer? I would like to not work with sprintf()
The second parameter to print_info is char *message. You've passed it ("%#4x %s", key, keymap[key - 1]) which knowing the comma operator evaluates to just the last item keymap[key - 1] which seems to also be a char * lucky enough. You need to use some type of printf function to fill in the printf style format specifiers in "%4x %s"
So the int is missing, why is it not inserting the integer?
Why would it?
I would like to not work with sprintf()
Yet you seem to think that the expression ("%#4x %s", key, keymap[key - 1]) should be a shortcut. It is not. C does not have a Pythonesque syntax for string interpolation. That's what sprintf() is for. The expression you have used employs C's comma operator (,), which evaluates its left operand, discards the result, and then evaluates its right operand, returning that as the value of the expression.
Thus, your print_info() call is equivalent to
print_info("[KEY]", keymap[key - 1]);
(Note that the comma there is not a comma operator; it is part of the syntax of a function call.)
sprintf() is one of the standard ways to produce a formatted string, and it seems the most appropriate for this case. You might approach it like this:
char message[KEYMAP_VALUE_LIMIT + 6];
sprintf(message, "%#4x %s", key, keymap[key - 1]);
print_info("[KEY]", message);
If you do not have and cannot reasonably create an appropriate KEYMAP_VALUE_LIMIT macro then you probably should dynamically allocate the message buffer based on the actual length of the string corresponding to key. In this specific case, however, it looks like you could avoid that by redefining what is considered "prefix" and what "message":
char prefix[13];
sprintf(prefix, "[KEY] %#4x", key);
print_info(prefix, keymap[key - 1]);

c command line int is wrong

Whenever I send in a number from the command line it errors and gives me a wrong number
edgeWidth=*argv[2];
printf("Border of %d pixels\n", edgeWidth);
fileLocation=3;
./hw3 -e 100 baboon.ascii.pgm is what I send in through the command line and when I print the number to the screen I get 49 as the number
int edgeWidth is defined at the beginning of the program.
Why is it not giving me 100?
argv contains an array of strings. So argv[1] is a string, you need to convert it to an integer:
edgeWidth = atoi(argv[1]);
The problem is that by doing
edgeWidth = *argv[2];
you're assigning the first character of "100" to edgeWidth. 49 happens to be the ASCII value for '1'.
If you want 100, you need to use something like atoi or strtol to parse the string into an int.
Addendum: Regarding numeric promotion, part two of 6.5.16.1 in the C99 spec states:
In simple assignment (=), the value of the right operand is converted
to the type of the assignment expression and replaces the value stored
in the object designated by the left operand.
so it does appear that numeric promotion happens here.
Because command line arguments are by default as char* (or may be char** somewhere) not int. you need proper conversion like atoi() to use it as int.
You should use edgeWidth = atoi(argv[2]) to get expected output.

Using ( ) in printf argument list. What does this syntax mean?

I run into a code:
printf("\tout:\t%-14.14s\n", (sprintf(tmpbuf[0], "[%s]", mystring), tmpbuf[0]));
What does those sentence in () with sprintf mean?
It is an expression involving the comma operator, to put the following into a single line:
sprintf(tmpbuf[0], "[%s]", mystring);
printf("\tout:\t%-14.14s\n", tmpbuf[0]);
The comma operator evaluates both arguments and returns its right argument, i.e. tmpbuf[0].

Resources