Module 4 · Operators and Type Conversion
Assignment Shortcuts, ++ and --
In this lesson
- Shorten
total = total + xtototal += x, and know what else that changes. - Say what value
n++has, and how it differs from++n. - Explain why
i = i++is undefined, and write the safe version instead.
David has a counter and wants the next value. He writes i = i++;, because it reads like "i becomes i, increased".
The Playground compiles it without a word. On his machine it leaves i unchanged. A friend runs the same file and gets a different answer.
Neither machine is broken. That line asks C to do two things to one box in one step, and the standard refuses to say which one wins.
Five shortcuts for changing a variable you already have
Adding to a running total is so common that C has a shorter spelling for it.
The compound assignment operators
total += x the same as total = total + x
total -= x the same as total = total - x
total *= x the same as total = total * x
total /= x the same as total = total / x
total %= x the same as total = total % x
- The variable is named once, not twice. A typo in the second name is a bug these forms cannot have.
- The operator goes before the
=, never after.=+is a different, legal and useless thing. - The right side is worked out completely first, then the operator is applied.
#include <stdio.h>
int main(void)
{
int total = 100;
total += 25;
printf("after += %d\n", total);
total -= 5;
printf("after -= %d\n", total);
total *= 2;
printf("after *= %d\n", total);
total /= 7;
printf("after /= %d\n", total);
total %= 10;
printf("after %%= %d\n", total);
return 0;
}
after += 125
after -= 120
after *= 240
after /= 34
after %= 4
Line four is the one to watch. 240 divided by 7 is 34.28, and total is an int, so the answer is 34.
So /= carries lesson 1's integer division with it. The shortcut changed the spelling, not the arithmetic.
The conversion that hides inside the shortcut
total *= 1.5 is not exactly total = total * 1.5. It is total = (int)(total * 1.5), with the cast written in for you.
That last step is silent. It is the reason the two forms are not identical, and the reason a price can quietly lose its fraction.
#include <stdio.h>
int main(void)
{
int price = 7;
price *= 1.5;
printf("%d\n", price);
return 0;
}
10
Seven times 1.5 is 10.5. The multiplication really did happen in double, and then 10.5 was cut down to fit an int.
Nothing is said about it at either command line, and not even under -Wall -Wextra. A local gcc -Wconversion reports warning: conversion from 'double' to 'int' may change value.
So a compound assignment always lands back in the left variable's type. Lesson 6 gives that conversion its proper name.
++ and --, and the value each form hands back
n++ and ++n both add 1 to n. They differ in what the expression is worth while they do it.
n++ is the postfix form. Its value is the old n. ++n is the prefix form, and its value is the new one.
#include <stdio.h>
int main(void)
{
int n = 5;
printf("n++ gives %d\n", n++);
printf("n is now %d\n", n);
int m = 5;
printf("++m gives %d\n", ++m);
printf("m is now %d\n", m);
return 0;
}
n++ gives 5
n is now 6
++m gives 6
m is now 6
Both variables end at 6. The only difference is the number that reached printf.
So the choice matters exactly when you use the value. On a statement of its own, the two forms are the same.
Two changes to one box, in one expression, is undefined
Between two statements, C guarantees everything is finished. Inside one expression, it guarantees far less.
The rule for this track, stated plainly: if one expression changes a variable and also reads or changes it again, the behaviour is undefined. Not unspecified, not compiler-dependent: undefined.
That is what i = i++ does. It assigns to i and increments i, and nothing orders those two events.
Undefined means the standard places no requirement on the program at all. No output of such a line is quoted anywhere in this track, because there is no correct output to quote.
int i = 3;
i = i++;
The Playground says nothing about this, because the check lives behind -Wall. A local gcc -Wall reports warning: operation on 'i' may be undefined, and the word "may" is the compiler being honest about how hard this is to detect.
The rule this track follows
The rule is short: write ++ and -- on a line of their own, never inside a larger expression.
You give up nothing. Every use has a two-line version that says the same thing and is always defined.
#include <stdio.h>
int main(void)
{
int i = 3;
int copy = i;
i++;
printf("copy %d, i %d\n", copy, i);
return 0;
}
copy 3, i 4
Two statements, two ordered steps, one obvious reading. Module 6 puts i++ in the one place the language reserves for it, the third slot of a for header.
So the shortcut is welcome; hiding it inside another expression is not.
One box, three additions, printed once at the end.
#include <stdio.h>
int main(void)
{
int total = 0;
total += 10;
total += 20;
total += 30;
printf("%d\n", total);
return 0;
}
60
Module 6 replaces the three lines with a loop. The operator does not change when that happens.
Run in CompilerA ticket queue. The number you are given is the one before the counter moved.
#include <stdio.h>
int main(void)
{
int next_ticket = 41;
int mine = next_ticket++;
int yours = next_ticket++;
printf("mine %d\n", mine);
printf("yours %d\n", yours);
printf("next %d\n", next_ticket);
return 0;
}
mine 41
yours 42
next 43
Each line touches next_ticket once, so nothing here is undefined. Postfix is the right form: you want the ticket that was free before you took it.
Four marks come in, one total and one count go out, all with compound assignment.
#include <stdio.h>
int main(void)
{
int a = 0;
int b = 0;
int c = 0;
int d = 0;
scanf("%d %d %d %d", &a, &b, &c, &d);
int total = 0;
int count = 0;
total += a;
count++;
total += b;
count++;
total += c;
count++;
total += d;
count++;
printf("total %d over %d marks\n", total, count);
printf("average %.2f\n", total / (double)count);
return 0;
}
total 329 over 4 marks
average 82.25
That output is for the input 75 82 82 90. The (double) is lesson 6's cast, doing lesson 1's job on the last line.
Where this is used
- Every loop you will write. The third slot of a
forheader is almost alwaysi++. Module 6 arrives in two lessons and this is the operator it runs on. - Reference counting. CPython keeps a count on every object and does
++and--on it as names appear and disappear. When the count reaches zero the memory is released. - Byte counters in a server. Nginx adds each written chunk to a running total with
+=. That total is what your bandwidth bill is computed from. - Game scores and health.
score += 10andhealth -= damageare the two most common lines in any game loop, and they are this lesson's first section.
Common mistakes
1. Changing one variable twice in one expression.
int i = 3;
i = i++;
Silent on the Playground; a local gcc -Wall says warning: operation on 'i' may be undefined. This is undefined behaviour, so no output is quoted here. Write i++; on its own line.
2. Writing the operator after the equals sign.
int total = 100;
total =+ 25;
printf("%d\n", total);
No message at either command line, and it prints 25. =+ is an assignment of positive 25, which is legal and is not what you meant. The operator belongs before the =.
3. Expecting /= to keep the fraction.
int total = 7;
total /= 2;
printf("%d\n", total);
No message at either command line, and it prints 3. Both sides are integers, so lesson 1's integer division applies. Use a double variable if the fraction matters.
4. Reading the postfix value as the new one.
int n = 5;
printf("%d\n", n++);
No message at either command line, and it prints 5, not 6. The increment did happen; the value handed to printf was taken before it. Use ++n when you want the new value.
Maria's till adds five sales to one running total and prints the total at the end.
Input. One line with five integers.
Output. One line with their total.
Constraints. Each value is between -1000000 and 1000000.
Sample. Input 10 20 30 40 50 gives 150.
#include <stdio.h>
int main(void)
{
int a = 0;
int b = 0;
int c = 0;
int d = 0;
int e = 0;
scanf("%d %d %d %d %d", &a, &b, &c, &d, &e);
int total = 0;
/* Five += lines, one per value. */
return 0;
}
Graded as running-total. Start total at 0 yourself; an uninitialised box is Module 2's warning.
Zara wants to prove she can predict ++ and -- before running anything.
Write the value of n and of each expression, in this exact sequence of statements, starting from the value read.
Input. One line with one integer n.
Output. Four lines: the value of n++, then n, then --n, then n again.
Constraints. -1000 <= n <= 1000.
Sample. Input 5 gives the four lines 5, 6, 5, 5.
#include <stdio.h>
int main(void)
{
int n = 0;
scanf("%d", &n);
/* Four printf lines. Each one touches n at most once. */
return 0;
}
Not graded in this module. Write the four answers on paper first, then run it.
Run in CompilerKenji is checking that he understands the order of a chain of compound assignments.
Start from the value read, then apply, in order: *= 3, += 17, /= 4, %= 10. Print the value after each step.
Input. One line with one integer n.
Output. Four lines, the value of n after each of the four steps.
Constraints. 0 <= n <= 1000000.
Sample. Input 9 gives the four lines 27, 44, 11, 1.
#include <stdio.h>
int main(void)
{
int n = 0;
scanf("%d", &n);
/* Four steps, four printf lines, all on the same box. */
return 0;
}
Not graded in this module. The third step is where integer division quietly decides the last two answers.
Run in CompilerCommon doubts
Is
++nfaster thann++?In C, on a plain
int, no. The compiler produces the same instructions when the value is not used. The habit matters in C++, where the two forms can call different functions.Can I write
+=on adouble?Yes, and on any arithmetic type.
%=is the one exception, because%itself refuses floating types.Why does
total =+ 25even compile?Because it is a plain assignment of the value
+25. Unary plus is a real operator that does nothing, so C sees nothing wrong.If
i = i++is undefined, why does my compiler not stop?Detecting it in general is impossible, so the standard asks for no message. GCC catches the easy cases under
-Walland the wording is "may be undefined".Is
a[i] = i++also undefined?Yes, and for the same reason. Module 9 brings arrays; the rule you carry there is the one in this lesson.
Key takeaways
+=,-=,*=,/=and%=name the variable once and change it in place.- A compound assignment converts the result back to the left variable's type, silently.
n++hands back the old value;++nhands back the new one.- Both forms change the variable the same way, so on their own line they are identical.
- Changing one variable twice in one expression is undefined behaviour, not a puzzle with an answer.
- This track writes
++and--as statements of their own.
Next you leave whole numbers behind and work on the bits inside them, one at a time.
End of lesson 3
Mark it done, and your progress moves with you.
Next: Bitwise Operators: Working One Bit at a Time