C Operators and Expressions

C Operators and Expressions

C Operators and Expressions, Arithmetic, Ternary, Increment, Decrement...

Operators and Expressions

Operators and expressions are crucial parts of any programming language, but in C they play an even more important role due to the low level of C when compared to other languages.

Arithmetic

I hope you know the basics of arithmetic, otherwise go back a few years to school.

i = i + 3; // Addition (+) and assignment (=) operators, add 3 to i
i = i - 8; // Subtraction, subtract 8 from i
i = i * 9; // Multiplication
i = i / 2; // Division
i = i % 5; // Modulo (division remainder)

C has abbreviations for each of the above. Every one of these lines could be written more concisely as

i += 3; // Same as "i = i + 3"
i -= 8; // Same as "i = i - 8"
i *= 9; // Same as "i = i * 9"
i /= 2; // Same as "i = i / 2"
i %= 5; // Same as "i = i % 5"

You must use the pow function from the <math.h> library to perform exponential operations in C:

#include <stdio.h>
#include <math.h>

int main() {
    double base = 2.0;
    double exponent = 3.0;
    double result;

    result = pow(base, exponent);

    printf("%.2f raised to the power of %.2f is %.2f\n", base, exponent, result);

    return 0;
}

To compile the code:

clang -o expo expo.c -lm

Note the addition of the -lm statement to include the math library…

Ternary Operator

The ternary operator is also included in C. That is, an expression whose value depends on the result of an embedded conditional:

// If x > 10, add 17 to y. Otherwise add 37 to y.
y += x > 10? 17: 37;

That probably sounds a little confusing, so let’s write a simpler equivalent expression:

if (x > 10) {
  y += 17;
} else {
  y += 37;
}

Compare these two until you see each of the components of the ternary operator.

Or, another example that prints out whether a number stored in x is odd or even:

printf("The number %d is %s.\n", x, x % 2 == 0? "even": "odd");

Using %s with printf() means to print a string.

The value of the entire ternary expression evaluates to the string “even” if the expression x % 2 evaluates to 0. Otherwise, it will evaluate to the string “odd”.

Notice that ternaries are not flow control like if statements. It is simply an expression that will be evaluated to a value!

Increment and Decrement

The increment and decrement operators will be used a lot in your C programs!

Post increment and Post decrement

i++; // Add one to i
i--; // Subtract one from i

Post-increment and post-decrement first calculate the value of the expression with the as-is value, and then increment or decrement the value after determining the value of the expression.

Pre increment and Pre decrement

++i; // Add one to i
--i; // Subtract one from i

Pre-increment and pre-decrement increment or decrement the variable’s value before evaluating the expression. Then it evaluates the expression with the new value.

They are often written in simplified form:

i += 1; // Add one to i
i -= 1; // Subtract one from i

Here’s how the post increment can be used:

i = 10;
j = 5 + i++; // Compute 5 + i, _then_ increment i

printf("%d, %d\n", i, j); // Prints 11, 15

Now compare what it would be like with pre-increment:

i = 10;
j = 5 + ++i; // Increment i, _then_ compute 5 + i

printf("%d, %d\n", i, j); // Prints 11, 16

Array and pointer access and manipulation often use this technique. It gives you a way to use the value in a variable, incrementing or decrementing it before or after use.

But by far the place where you’ll see this is in a Forloop:

for (i = 0; i < 10; i++) {
  printf("i is %d\n", i);
}

The Comma Operator

This is a rarely used method to delimit expressions that run from left to right:

x = 10, y = 20; // First assign 10 to x, then 20 to y

Seemed kind of dumb, because you could just replace the comma with a semicolon, right?

x = 10; y = 20; // First assign 10 to x, then 20 to y

But this is something else. It’s… In the second case, we have two separate expressions, whereas in the first case we have a single expression.

With the comma operator, the value of the comma expression is the value of the expression to the right:

x = (1, 2, 3);

printf("x is %d\n", x); // Prints 3, because 3 is rightmost in the comma list

But that’s also quite artificial. A common place to use the comma operator is in for loops to do different things in each part of the statement:

for (i = 0, j = 10; i < 100; i++, j++) {
  printf("%d, %d\n", i, j);
}

Conditional Operators

We have a number of standard operators for Boolean values:

a == b;  // True if a is equivalent to b
a != b;  // True if a is not equivalent to b
a < b;   // True if a is less than b
a > b;   // True if a is greater than b
a <= b;  // True if a is less than or equal to b
a >= b;  // True if a is greater than or equal to b

Don’t confuse assigning (=) with comparing (==)! Use two equal signs for comparison and one for assignment.

With if statements, we can use the comparison expressions:

if (a <= 10) {
  printf("Success!\n");
}

Boolean Operators

We can use Boolean operators for and, or, and not to chain or modify conditional expressions.

Operator Meaning
&& and
|| or
! not

An example of Boolean “and”:

// Do something if x less than 10 and y greater than 20:
if (x < 10 && y > 20) {
  printf("Doing something!\n");
}

An example of Boolean “not”:

if (!(x < 12)) {
  printf("x is not less than 12\n");
}

In this case, we have to use parentheses because “!” has a higher priority than the other Boolean operators.

The sizeof Operator

This operator returns the size (in bytes) that a particular variable or datatype occupies in memory.

In particular, it will tell you the size (in bytes) that a particular expression’s type (which can be just a single variable) uses in memory.

Except for char and its variants (which are always 1 byte), this can be different on different systems.

You might think it would return an int, since it calculates the number of bytes needed to store a type. Or… since it can’t be negative, maybe a unsigned?

But C has a special type for representing the return value of the sizeof function.

It’s called size_t. Pronounced “size tee” . All we know is that it’s an unsigned integer type. It can hold the size in bytes of anything you can pass to sizeof.

size_t appears in many different places where counts of things are passed or returned. You can think of it as a value that represents a count of something.

You can take the size of a variable or an expression:

int a = 999;

// %zu is the format specifier for type size_t
// If your compiler balks at the "z" part, leave it off

printf("%zu\n", sizeof a); // Prints 4 on my system
printf("%zu\n", sizeof(2 + 7)); // Prints 4 on my system
printf("%zu\n", sizeof 3.14); // Prints 8 on my system

// If you need to print out negative size_t values, use %zd

Remember, it’s the size in bytes of the expression’s type, not the expression’s size.

That’s why the size of 2+7 is the same as the size of a; they’re both of type int!

You can take the size of a type (note that the parentheses are required around the name of a type, as opposed to an expression):

printf("%zu\n", sizeof(int));  // Prints 4 on my system
printf("%zu\n", sizeof(char)); // Prints 1 on all systems

It’s important to note that sizeof is compile-time. The expression’s result is determined entirely at compile-time, not runtime.