TU ACM logo.

Variables and Basic Arithmetic

We're going to learn how to play around with values in this article.
Posted 15 January 2020 at 1:26 PM
By Joseph Mellor

This is the fifth article in the Making Sense of C series.

So far, we've determined that we're going to talk to the compiler by telling it the name of the file we want it to read and we've determined how to tell the compiler to ignore parts of the file we don't want it to read. We've also established that our code is going to consist of a bunch of statements, but we've never established what a valid statement should look like. In this article, we're going to discuss the most basic statements in C: variables and basic arithmetic.

Topics Covered

Value Manipulation

For C to be a programming language, you'll need to be able to write more than comments. While there are some complicated things you should be able to do in any programming language, we'll focus on the simplest thing we can do: arithmetic. You should also be able to store values for later use, otherwise you would have to type the entire expression on one line, even if you repeat things. In this section, we're going to discuss how to manipulate values using some of the basic operators in C, how to store the results in variables, and how to use those results later on.


Variables store values for later use. To access a variable, we need some way of identifying it, so we'll need to give it a name. Since explicit types are more efficient than variables, we also need to specify the type. Since we don't need to specify anything besides the type and the name, our statement to declare a variable should just be the name of the variable and its type.

We will use the syntax [type] [variable_name]; to declare a variable. I will discuss types more later in the series, but for now we're just going to use one: int, which represents an signed integer (positive whole numbers, negative whole numbers, and zero). Since we're only dealing with ints, our variable declarations will look like int a;. You can only use a variable after it's declared (remember that the compiler reads your code top to bottom, left to right) and you can only declare a variable once. Once a variable is defined, it cannot change its type for reasons we'll specify later.

int a;
int a;          // ERROR: redeclaration of a

You can also declare multiple variables of the same type on one line.

int a, b, c;
Naming Variables

We can't use a semicolon, /*, */, //, or a space since they're already reserved. For now, let's just say that we can use any letters or digits to name a variable. We also can't use any reserved symbols like +-/*% in our names or use any reserved words, like int. We can use something like sum_of_ints, we just can't use the name int. Since we also might want spaces, we can use the underscore (_) to represent a space. Lastly, we don't want numbers at the beginning of variables, since someone could see something like 4x and think that x is the variable and it's getting multiplied by four, so the first character can't be a number.

Here are a list of valid variables names:

Naming Conventions

In general, I use snake_case when I name my variables, meaning each word is separated with underscores, like in the first three examples above. A lot of people prefer to not use underscores because it's extra typing, so they use camelCase, in which the first letter of every word except the first is capitalized and every variable only contains letters.

I find snake_case easier to read, so I use it.

You should make sure to always give anything you can name a descriptive name, including variables. For example, what do you think the first four variables store in the list above? What if you see something in your code that looks like number_of_apples + distance_from_sun? Would it make sense to add those variables? On the other hand, what if you saw fsadlj + x3? Does it make sense to add those variables? How could you tell?

Giving things descriptive names will save you a lot of headache in the future. Of course, there is a balance between descriptiveness and verboseness. For example, I could have called sum_of_squares, sum_of_the_first_one_hundred_squares_counting_one_hundred_squared, but that's way too much to type and all I need to know to not confuse it with other variables or to recognize when I'm using it when I shouldn't is that the variable stores a sum of squares.

Arithmetic Operators

Since you're programming, you probably want to do some math operations like addition, subtraction, etc., so let's just reserve the normal math symbols for these basic operations right off the bat.

and they all have the syntax 15 • 12, where is one of the arithmetic operators.

You probably also want to be able to use negative numbers, so let's say that if a - shows up before a number, we'll make the number negative. The - also functions just like a negative sign does in normal math, where -13 * 5-65.

The last basic arithmetic operation you'll likely need is the ability to get the remainder of a division. Remember that we're looking for unused, unpaired (parentheses, curly brackets, less than, greater than, and square brackets are out) printable characters that will be on everyone's keyboards. After assigning everything else, we find that our only choices to represent the remainder division are @ and %. Since % is more related to arithmetic than an @ symbol, we'll use %.

The % operator is specifically defined so that, for any two whole numbers, (a / b) * b + (a % b) must equal a. Since the remainder is only defined for integer division, % only works on whole numbers. For example:

From the last four, we can see that the remainder has the same sign as what comes before the % regardless of the sign of what comes after %.

Now that you can do some basic arithmetic in C, let's look into how to store the results.

Assignment Operators

First and foremost, = stores the value on the right in the variable on the left. Things that can be assigned in C are called lvalues (left values) and thing that cannot be assigned in C are called rvalues (right values) because rvalues cannot appear on the left side of an assignment operator and lvalues can appear on the left side of an assignment operator.

For example:

int a;
a = 7;              // a now contains 7

// You can also declare and use = on the same line, like so
int b = 2 * 3;      // b now contains 6
int c = a + b;      // a is replaced with 7 and b is replaced with 6, so now
                    // c contains 13
                    // Notice that variables (lvalues) can show up on the right
                    // side of an assignment operator

6 = c;              // Throws an error and won't compile

a = 15;             // a now contains 15, c still contains 13
c = c * 10;         // c contains 130

The last line can be shortened to c *= 10;.

In fact, all the other assignment operators work identically. a •= [rvalue]; is exactly equivalent to a = a • ([rvalue]);, where a is a variable, is +, -, *, /, or %, and [rvalue] is any expression that results in a number. It's just a little syntactic sugar to save you some typing.

The last thing to note is that [lvalue] • [rvalue] (where represents one of the assignment operators) actually returns the [rvalue], so you could write something like

int a, b;
a = 7 + (b = 5 + 1);        // b is set to 6, then (b = 6) is replaced with 6,
                            // so the right hand side becomes 7 + 6
Just Because You Can Doesn't Mean You Should

When you write code, you aren't just writing code for the computer, you're writing code for everyone who reads your code, including yourself. You should write code that you'll be able to understand a year from now, which generally means that you shouldn't write bad code that uses obscure or surprising features of the language just to be clever.

Using clever tricks in your code is like using big words. If you use them because using anything else would be more inefficient, more complicated, or impossible, then using them is fine. If you use them because you want to impress people, then you're going to look like an idiot when you mess up and people won't want to interact with you.

In the case of using the fact that a = b returns b, I wouldn't recommend using it.

Operator Precedence

Say that you have this code:

int a = 17;
a += 1 + 30 / 3 - 3 * 50;

To determine the value of a, we need to have some sort of order in which to do the operations. For example, we could do the operations left to right, but then we would calculate 1 + 30 / 3 as (1 + 30) / 331 / 310 (it gets rounded to zero because we're using integer division). If we were using the regular order of operations, we would evaluate 1 + 30 / 3 as 1 + (30 / 3)1 + 1011. In C, there is a strict order of operations listed here.

In practice:

The less energy you have to spend on figuring out the result of an expression, the better.


Up to this point, we've established that we're going to give our compiler a file with a series of statements without giving examples of these statements. In this article, we've established what some statements will look like. Our file should now look like

int a;                  // I could have combined these lines into "int a = 7;"
a = 7;
int a_cubed = a * a * a;    // Just some basic multiplication

other statement;        // We still haven't established what other statements
                        // would look like.
int b = (a + 7) * a;
b /= -6;

other statement;

What's Next

Before we go onto the next topic in C, we need to take a detour to explain how computers handle memory, as we're going to introduce types that won't appear to have any use cases unless you understand how your computer handles memory. I strongly recommend that you read the article before moving on.

We also can also discuss how computers represent integral types and how computers represent floating point types, but knowing how to represent them isn't as important for understanding C. Without the knowledge about how computers represent numbers, you're just going to have to accept that the language is the way it is without any explanation why.

Once we've covered those two detours, we'll move on to dealing with the fundamental types in C.

A picture of Joseph Mellor, the author.

Joseph Mellor is a Senior at TU majoring in Physics, Computer Science, and Math. He is also the chief editor of the website and the author of the tumd markdown compiler. If you want to see more of his work, check out his personal website.
Credit to Allison Pennybaker for the picture.