This question already has answers here:
What does the comma operator , do?
(8 answers)
Closed 6 years ago.
I am checking a student's homework.
The assignment is to print the amount of English letters to the console.
For some reason, what he did works (7th line):
int main(void)
{
char first = 'A';
char last = 'Z';
int amount = 0;
amount = ("%d - %d", last - first + 1);
printf("The amount of letters in the English alphabet is %d\n", amount);
return(0);
}
After seeing it, I tried putting other things in the brackets instead of "%d - %d". No matter what I put there and how many commas were there, it'd only take what's after the last comma (which is the correct sentence).
What is actually happening there?
This is one of the examples of usage of comma operator. In case of
("%d - %d", last - first + 1);
the LHS operand of the comma operator ("%d - %d") is evaluated, result is discarded, then RHS (last - first + 1) is evaluated and returned as the result. The result, is then assigned to amount and thus, you have the amount holding the result of the operation last - first + 1.
Quoting C11, chapter ยง6.5.17, comma operator
The left operand of a comma operator is evaluated as a void expression; there is a
sequence point between its evaluation and that of the right operand. Then the right
operand is evaluated; the result has its type and value.
FWIW, in this case, "%d - %d" is just another string literal, it does not carry any special meaning.
Related
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.
I am writing the strcat function
/*appends source string to destination string*/
#include <stdio.h>
int main()
{
char srcstr[100], deststr[100];
char *psrcstr, *pdeststr;
printf("\n Enter source string: ");
gets(srcstr);
printf("\n Enter destination string: ");
gets(deststr);
pdeststr = deststr;
psrcstr = srcstr;
while(*pdeststr++)
;
while(*pdeststr++ = *psrcstr++)
;
printf("%s", deststr);
return 0;
}
For srcstr = " world" and deststr = "hello" I get hello, when I expect to see hello world, which is what I see if I change the first while so
while(*pdeststr);
pdeststr++;
why can't I write all in one line in the first while, just like in the second while?
Your one line loop
while(*pdeststr++);
Is equivalent to
while(*pdeststr)
pdeststr++;
pdeststr++;
Because the postincrement operator is executed before the condition is tested, but after the value for the test is determined.
So you could cater for this with
while(*pdeststr++);
pdeststr--;
Mandatory introduction: do not use gets(), use fgets()!.
Your problem is here:
while(*pdeststr++)
;
The side effect of incrementing is carried out in your last iteration step (when pdeststr points to the NUL terminator), so after this loop, pdeststr points one after your NUL terminator. Write it like this instead:
while(*pdeststr) ++pdeststr;
The boolean value for the while condition is computed before the ++ post-increment.
So when your while loop exits, the post-increment operator is executed one last time, hence pdeststr is pointing right after the null terminator char that follows the word "hello".
Then the rest of the program appends more data after that null char. You end up with the string "hello\0world\0". The print function thinks the string ends at the first null char it encounters.
You have an extra incrementation that point you after the NULL char, and so finally you could print only the first string.
By precedence the postfix increment operator (ptr++) is higher than the indirection (dereference) operator (*ptr). Therefore the
while(*pdeststr++);
will always increment the pdeststr first then evaluate the previously pointed value. As an outcome, when the result of evaluation is 0 the pdeststr actually points to the next element, so there will be a null-terminator character ('\0') between your concatenated words.
As a one-liner solution with while loop you can use the short-circuit evaluation as follows:
while(*pdeststr && pdeststr++);
The code snippet above will stop when *foo results 0 and won't evaluate the foo++ part.
My conclusion is that at the end, deststr = "hello\0 world\0" and because of that printf("%s", deststr); find the first \0 and gives as output hello
This question already has answers here:
What does the comma operator , do?
(8 answers)
How does the Comma Operator work
(9 answers)
Closed 6 years ago.
I have these lines in my program:
printf("%-29s\n",("%s, Capital", CO));
printf("%-29s\n",("%s, Drawing",CO));
and when I run the program, it only shows the %s equivalent (CO) instead of "%s, Drawing"
Please help?
You used the comma operator and the behavior is normal.
An expression with comma operator A, B means that first evaluate A, ignore its result, then evaluate B and the result of comma operator will be its value.
If you want to show "%s, Drawing", print it.
printf("%-29s\n","%s, Drawing");
As MikeCAT has already stated, you have used the comma operator. If you want to left-align the compound string, you can achieve it by first printing to a temporary buffer with snprintf:
char tmp[30];
snprintf(tmp, sizeof(tmp), "%s, Capital", CO);
printf("|%-29s|", tmp);
snprintf(tmp, sizeof(tmp), "%s, Drawing", CO);
printf("|%-29s|", tmp);
Of course, given that you print a newline directly after the string (and the justification is therefore somewhat pointless), you might as well just print the desired format directly:
printf("%s, Capital\n", CO);
printf("%s, Drawing\n",CO);
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.
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.