Introduction to C: variables, types and operators
The structure of a C program, int/char/double, scope, integer division, ++/--, logical and bitwise operators, precedence. The foundation of “What is printed?” questions.
The last four weeks of the semester are C. Why C? Because C sits right above the level you have learned so far: a C variable is a location in memory, a C expression is a few LC-3 instructions, a function call is JSR and stack operations. That is why the textbook builds C on top of the LC-3. Most of the C questions on the exam are of the “What is printed?” type: you run the code in your head and write the output.
Golden rules:
- int / int = int, the fraction is truncated.
- True = nonzero, false = 0. Comparisons produce 1 or 0.
- x++ gives the old value, ++x gives the new value.
- && and || short-circuit.
- A variable declared inside a block shadows the one outside.
The first program
#include <stdio.h>
int main(void) {
int count = 3;
printf("count = %d\n", count);
return 0;
}
count = 3
#include <stdio.h>: a preprocessor command for printf/scanf. Before compiling, the contents of that file are inserted here.main: the program starts here.- Every statement ends with
;. Blocks are{ }.
A C program is compiled: source code → preprocessor → compiler → assembly/machine code → linker → executable file. On the LC-3 this means producing assembly of the kind you wrote in week 10.
Variables and types
Every variable has a type, a name and a value. The type says how many bits will be reserved in memory and how the bits will be read (week 2).
| Type | What does it hold? | Example | printf |
|---|---|---|---|
int | signed integer (2’s complement) | int n = -5; | %d |
char | a single character (ASCII code, small integer) | char c = 'A'; | %c or %d |
double | a number with a fraction (IEEE 754) | double x = 2.5; | %f |
In LC-3 C, int is 16 bits; on your computer it is usually 32 bits. The numbers used in the exam fit in both.
Constants: 17 is decimal, 0x1F is hex (31), 017 is octal (15). Putting a zero in front makes the number octal: watch out.
Scope
- A local variable is declared inside a function or block and is seen only there. In the LC-3 it lives on the stack (runtime stack).
- A global variable is declared outside all functions and is seen everywhere. In the LC-3 it lives in the global data region (R4 points to this region).
A variable with the same name in an inner scope shadows the outer one:
int g = 10;
void show(void) {
int g = 3; /* a new, local g */
printf("show: %d\n", g);
}
int main(void) {
show();
printf("main: %d\n", g);
return 0;
}
show: 3
main: 10
PITFALL · a local with no initial value. If you write
int x;and use x, its value is undefined (whatever was left in that memory location). Global variables, on the other hand, start automatically at 0.
Arithmetic operators
printf("%d %d %d %d\n", 7 / 2, -7 / 2, 7 % 3, -7 % 3);
3 -3 1 -1
- Division truncates toward zero: -3.5 → -3.
- The sign of the result of
%is that of the left number. - If one is a double, the division is a real division:
7 / 2.0= 3.5.
Assignment and compound assignment
int n = 10;
n -= 3; /* 7 */
n *= 2; /* 14 */
n /= 4; /* 3 */
n %= 3; /* 0 */
printf("%d\n", n);
0
Increment and decrement
| Expression | Value | x afterwards |
|---|---|---|
x++ | old x | x + 1 |
++x | x + 1 | x + 1 |
x-- | old x | x - 1 |
--x | x - 1 | x - 1 |
int i = 3;
int k = i++ * 2; /* 3 * 2, then i = 4 */
printf("%d %d\n", i, k);
4 6
If you had written ++i * 2, i would become 4 first, and k = 8.
PITFALL · changing the same variable twice in one expression. Expressions like
x = x++ + ++x;are undefined in C (undefined behavior). They give different results depending on the compiler. If you meet them in exam questions, the answer may be “undefined”.
Relational and logical operators
< <= > >= == != give 1 (true) or 0 (false) as the result. && (and), || (or), ! (not) count every nonzero value as true.
int a = 3, b = 0;
printf("%d %d %d %d\n", a && b, a || b, !b, a == 3);
0 1 1 1
Short-circuit: in A && B, if A is false, B is not computed. In A || B, if A is true, B is not computed. This makes guarded expressions like (i != 0) && (10 / i > 1) possible.
The conditional operator: condition ? a : b. If the condition is true, a; otherwise b.
Bitwise operators
| Operator | Meaning | Example (12 = 1100, 10 = 1010) |
|---|---|---|
& | AND | 12 & 10 = 8 |
| | OR | 12 | 10 = 14 |
^ | XOR | 12 ^ 10 = 6 |
~ | NOT (every bit) | ~5 = -6 |
<< | shift left | 5 << 2 = 20 |
>> | shift right | 40 >> 3 = 5 |
~x = -x - 1 (2’s complement). Do not mix up & and &&: 12 & 10 = 8, 12 && 10 = 1.
char arithmetic
Since a char is an integer, you can calculate with it:
char c = 'b';
c = c - 'a' + 'A'; /* lowercase → uppercase */
printf("%c\n", c);
printf("%d\n", '7' - '0');
B
7
Precedence and associativity
| Level | Operators | Direction |
|---|---|---|
| 1 | () [] -> . x++ x-- | left to right |
| 2 | ++x --x ! ~ -x *p &x (type) | right to left |
| 3 | * / % | left to right |
| 4 | + - | left to right |
| 5 | << >> | left to right |
| 6 | < <= > >= | left to right |
| 7 | == != | left to right |
| 8 | & | left to right |
| 9 | ^ | left to right |
| 10 | | | left to right |
| 11 | && | left to right |
| 12 | || | left to right |
| 13 | ?: | right to left |
| 14 | = += -= … | right to left |
If you are not sure, use parentheses; in the exam, solve step by step according to the table:
2 + 3 * 4 % 5
2 + 12 % 5 * and % are at the same level, the left one first
2 + 2
4
From C to the LC-3
a = b + c; (all three local) is roughly translated by the compiler like this (R5 is the frame pointer, week 12):
LDR R0, R5, #-1 ; R0 = b
LDR R1, R5, #-2 ; R1 = c
ADD R0, R0, R1
STR R0, R5, #0 ; a = R0
So every C variable is a memory location, and every operation is one or a few instructions.
Common mistakes
| Wrong idea | The truth |
|---|---|
7 / 2 = 3.5 | 3; for a fraction use 7 / 2.0 |
double d = 7 / 2; → 3.5 | 3.0 |
y = x++ → y is the new value | y is the old value |
10 > 5 > 1 is true | (10>5)=1, 1>1 = 0 |
& and && are the same | & is bitwise, && is logical |
!5 = -5 | 0; for -5 write -5, for -6 ~5 |
017 = 17 | Octal: 15 |
| A local variable starts at 0 | Undefined; a global starts at 0 |
Test yourself
Exam-style questions. Solve them on paper first, then reveal the answer.
What is printed?
printf("%d %d\n", 17 / 5, 17 % 5);Show answer
If two ints are divided the result is an int, the fraction is truncated: 17 / 5 = 3. The remainder: 17 = 3·5 + 2 → 2.
What is printed?
int x = 5;
int y = x++;
printf("%d %d\n", x, y);Show answer
x++ (post-increment) first gives the old value, then increments. y = 5, x = 6.
What is printed?
int x = 5;
int y = ++x;
printf("%d %d\n", x, y);Show answer
++x (pre-increment) first increments, then gives the new value. x = 6, y = 6.
What is printed?
double d = 7 / 2;
printf("%.1f\n", d);Show answer
The right side is computed first: 7 / 2 is two ints → 3. Assigned to a double it becomes 3.0. For 3.5 you must write 7 / 2.0 or (double) 7 / 2.
What is printed?
printf("%d\n", 10 > 5 > 1);Show answer
In C a comparison produces 1 (true) or 0 (false) and is evaluated from left to right: (10 > 5) = 1, then 1 > 1 = 0. It is not read as a chain like in mathematics.
What is printed? Does the program crash?
int i = 0;
int r = (i != 0) && (10 / i > 1);
printf("%d\n", r);Show answer
&& short-circuits: if the left side is 0 the right side is never computed. So 10 / 0 does not run. The result is 0.
What is printed?
printf("%d %d %d\n", 12 & 10, 12 | 10, 12 ^ 10);Show answer
12 = 1100, 10 = 1010. AND: 1000 = 8. OR: 1110 = 14. XOR: 0110 = 6. The same as the mask operations in week 2.
What is printed?
printf("%d %d\n", 5 << 2, 40 >> 3);Show answer
Shifting left by k bits multiplies by : 5 · 4 = 20. Shifting right (for a positive number) divides by : 40 / 8 = 5.
What is printed?
char c = 'A' + 2;
printf("%c %d\n", c, c);Show answer
A char is an integer: 'A' = 65, 65 + 2 = 67. %c prints it as a character ('C'), %d prints it as a number (67).
What is printed?
printf("%d\n", 2 + 3 * 4 % 5);Show answer
* and % are at the same level, left to right: 3 * 4 = 12, 12 % 5 = 2. Then 2 + 2 = 4.
What is printed?
int x = 4;
printf("%d %d %d\n", !x, !!x, x > 3 ? 10 : 20);Show answer
Every nonzero value is true. !4 = 0, !!4 = !0 = 1. The conditional operator: x > 3 is true → 10.
What is printed?
int g = 10;
void show(void) {
int g = 3;
printf("show: %d\n", g);
}
int main(void) {
show();
printf("main: %d\n", g);
return 0;
}Show answer
The int g inside show is a new local variable and shadows the global g. The global g is not touched. main sees the global g: 10.
Verification: Every code snippet was compiled and run as C99 with Zig cc (clang), and the outputs were copied exactly (verify/SEN2201/c/w11a.c; the first program and the char example are at the start of w11b.c; node verify/SEN2201/c/run.mjs w11).