Learning C – Part 1 Variables

“One man’s constant is another man’s variable”
-Alan Perlis, Epigrams on Programming, 1982

To kick off our C series, I figured we should go over one of the most common pieces of language design there is: variables. Variables initially got their start in Mathematics as many pieces of language design did. At their core, variables are not complicated. They’re essentially giving a name to some kind of value like A = 5, B = “hello” or C = 1/2. However, with programming in general this can become more complex. In time we will get to more abstract usage of variables, but for now we need to cover the basic types in C.

In C, C++, Java, and many other explicit languages the programmer will have to specify what data type for a variable. This means that they must specify if what they’re feeding the variable is a number, a letter, a piece of memory, and more. C has a number of different data types with their own purpose:

Data Type Explanation Size
int A number of some kind: …, -50, -1, 0, 1, 50, … Takes up 2-4 bytes of memory, 16 (2*8) to 32 (4*8) bits.Ranges from -32,768 to 32,767 or −2,147,483,648 to 2,147,483,647
char A character of some kind: ‘a’, ‘b’, ‘A’, ‘B’ Takes up 1 byte of memory, 8 (1*8) bits.Ranges from 0 to 255.
float A decimal number: 1.000000, 2.123456, 3.999999 Takes up 4 bytes of memory, 32 (4*8) bits.Ranges from 1.2E-38 to 3.4E+38Allows up to 6 decimal places of accuracy.
double A decimal number: 1.000000000000000, 2.123456789123456, 3.999999999999999 Takes up 8 bytes of memory, 64 (8*8) bits.Ranges from 2.3E-308 to 1.7E+308Allows up to 15 decimal places of accuracy.
void Typeless data, can refer to memory location in certain circumstance (explained later). N/A, 1 byte, 8 (1*8) bits with some flags.void does not have an actual size.
short A number of some kind: …, -50, -1, 0, 1, 50, … Takes up 2 bytes of memory, 16 (2*8) bits.Ranges from -32,768 to 32,767.
long A number of some kind: …, -50, -1, 0, 1, 50, … Takes up 4 bytes of memory, 32 (4*8) bits.Ranges from −2,147,483,648 to 2,147,483,647.

Each of these variables have their own unique uses which we will see through the course of this tutorial. The byte specifics are not important at the moment, but they will be very useful when we begin to cover memory management. However, this is not the end of the variable types. Variable modifiers also exist within C which can cause the above variables to change properties. First, we need a quick crash course in binary before we can move on to the variable modifiers.

Binary Crash Course

For an integer (int), there are anywhere from 2 to 4 bytes depending on the compiler that the code is compiled with and what system the code is run on. Assuming an integer has 4 bytes, that means we have 32 (4*8) bits.

32 bit integer:
00000000000000000000000000000000

With binary, we count from right to left and we add powers of two as we go. For example:
0000 = 0
0001 = 2^0 = 1.
0010 = 2^1 = 2.
0100 = 2^2 = 4.
1000 = 2^3 = 8.
1111 = 2^3 + 2^2 + 2^1 + 2^0 = 8 + 4 + 2 + 1 = 15.

Not all bits contribute the same way to the final number when it comes to computing. Here we introduced the concept of signed and unsigned values. To tell if a number is negative the most significant bit (farthest left bit) will be 1 (negative) or 0 (positive). If the most significant bit is 1, then we count all 0s as if they were 1s and vice versa and subtract 1 from the total value. This means if our example above was signed it would be the following:

0000 = 0
0001 = 2^0 = 1.
0010 = 2^1 = 2.
0100 = 2^2 = 4.
1000 = -1 * (2^2 + 2^1 + 2^0) – 1 = -1 * (4 + 2 + 1) – 1 = -8.
1111 = -1 * 0 – 1 = -1.

With this we’re now able to express negative numbers, but we run into a big issue: our range has been cut down from 0 – 15 to -8 – 7. Our original form where our range was from 0 to 15 is referred to as unsigned and our new form where the range was from -8 to 7 is referred to as signed. In C, integers, shorts, and longs are all signed unless specified otherwise.

Applying these steps to our 4 byte integer, we can show that the maximum value is:
01111111111111111111111111111111 = 2,147,483,647

and the minimum value is:
10000000000000000000000000000000 = −2,147,483,648

Now that we know this, we can move on to variable modifiers.

Back to modifiers

In C there are 4 type modifiers: unsigned, signed, long, and short. While long and short can be used as their own data types shown above, they can also be used to be explicit about the format of some data (long long, short short) or they can modify another data type (long int, short int). Note that not all combinations of these modifiers and the above data types exist such as long/short void.

Modifier Effect
unsigned X Do not allow negative numbers, use full binary range.
signed X Allow negative numbers, cut down binary range.
long X Extend to 64 bits (8 bytes)
short X Shrink to 16 bits (2 bytes)

These are all of the major data types and type modifiers, but with these types a programmer can create more abstract types such as structs, unions, and classes (C++) which we will discuss later. For now, let’s take a look at an example of some of these variables in action. Shown below is an example written in C to demonstrate assigning values to variables of these datatypes and measuring the size of them in bytes. We’ll talk more about the printf function and its syntax in the next part.

We get the values that we assigned like a = 5, b = ‘b’, and so on. Also, since we printed the size of each variable, we were able to figure out the size in bytes according to GCC. Variables are a key tool in any programming language and they will only get more complex from here. In future parts we will discuss operators on variables like * and & which can drastically change how variables act. For now we’ll move on to operators and demonstrate the different major operators.

Operators

C has a large amount of operators that are usually divided into few categories: Arithmetic, Bitwise, Logical, Memory, Comparison, Assignment, and Incremental.

Operator Category Effect
+ Arithmetic Adds two values
Arithmetic Subtracts two values
* Arithmetic Multiplies two values
/ Arithmetic Divides two values
% Arithmetic Gets the remainder of two values
^ Bitwise XORs two values
For every bit in each value, the new value will have a 1 if one of the bits is 1, but not both (exclusive OR).
A = 1011, B = 1110, A ^ B = 0101
& Bitwise ANDs two values
For every bit in each value, the new value will have a 1 if both bits are a 1.
| Bitwise ORs two values
For every bit in each value, the new value will have a 1 if one of the bits is 1.
~ Bitwise NOTs a value
For every bit in the value, flip the bit to 0 if it is 1 and vice versa.
>> Bitwise Right shifts a value
For every bit in the value, shift it right that many places.
A = 1000, A >> 2 = 0010.
<< Bitwise Left shifts a value
For every bit in the value, shift it left that many places.
A = 0001, A << 2 = 0100.
! Logical Negation operator
Inverses a particular value such as a 0 –> 1 or 1 –> 0.
&& Logical Logical AND
Evaluates if two variables are both 1 (true).
|| Logical Logical OR
Evaluates if one variable is 1 (true).
& Memory Reference operator
Get the address of a variable.
* Memory Star / Pointer operator
Point to a location in memory.
> Comparison Greater than
< Comparison Less than
>= Comparison Greater than or equal
< Comparison Less than or equal
!= Comparison Not equal
== Comparison Equal
? Comparison Conditional / Ternary operator
If a condition is met, assign one of two values.
A = (B>C ? B : C)
A = B if B>C is true and A = C is B>C is false.
= Assignment Assign a value
+= Assignment Add and assign a value
A = 1, B = 2, A += B, A == 3
-= Assignment Substract and assign a value
A = 2, B = 1, A -= B, A == 1
*= Assignment Multiply and assign a value
A = 1, B = 2, A *= B, A == 2
/= Assignment Divide and assign a value
A = 4, B = 2, A /= B, A == 2
|= Assignment OR and assign a value
A = 4, B = 2, A |= B, A == 6
&= Assignment AND and assign a value
A = 4, B = 2, A &= B, A == 0
^= Assignment XOR and assign a value
A = 4, B = 2, A ^= B, A == 6
%= Assignment Modulo and assign a value
A = 4, B = 2, A %= B, A == 0
++ Incremental Increments a value.
A = 5, A = A++, A == 6
−− Incremental Decrements a value.
A = 5, A = A–, A == 4.

We’ll be able to see all of these in use later over some of the example projects. Although, just because C offers this vast amount of operators, it is not uncommon to find C programmers who have not used every one of these operators.