A "Feild" Guide to Programming with C++
Introductory programming notes by Henry FeildChapter 2: Variables and Constants
Important takeaways
- Programs keep track of data in memory using variables and constants
- variables can change throughout a program; may be unknown until run time
- constants remain unchanged throughout a program; must be known at compile time
- Think of variables and constants as named buckets in memory
- In C++, each bucket must be of a specific type, and only data of that
type can be stored in the bucket; e.g.,
int
buckets can only hold whole integers between -231 and 231 - An example variable declaration and assignment is:
int age = 100;
- An example constant declaration is:
const int PI = 3.14;
- Literals are values of a particular type that are used directly in a program, not through a variable or constant; e.g., 100 and 3.14 in the above assignments
Contents
Types
When programming, we usually need to keep track of data throughout the life of the program. For example, if we are programming a calculator program, we need to keep track of the operator, the operands, and the result. Each piece of data can be classified as a particular type, such as a whole number (e.g., 10), a real number (e.g., 2.93), a character (e.g., 'h'), or a string of characters (e.g., "hello"). In this section we will discuss the specifics of the most basic and common types available in C++. In later chapters, we'll see how we can create our own custom types using C++ structs and classes.
\ref lists the most common C++ types we'll use, along with examples.
Type | Description | Examples |
---|---|---|
int | Whole integers, up to ±32767 | 5 , 10 , -2039 |
long | Whole integers up to ±2147483647 | -5 , 10000000 |
float | Floating point (decimals) | 4.5 , 3 , 9.139482 |
double | Longer decimals | 39929391.9103 |
char | Single character (a whole integer between 0–255) | '+' , 'Z' , 127 |
string | A string of characters | "Hello there!" |
bool | Boolean (true or false) | true , false , 1 , 0 |
The key with types is to choose the one that best fits the data you want to
store. For example, if you are trying to keep track of a person's age, then an
int
is the best fit, since you can reasonably expect the age won't go outside of the range
and you don't need a decimal. If you need to keep track of a name, then you
should use a string
, since names are sequences of characters. An
initial or individual symbol (like '*') is best represented using a
char
, though you could also use a string
. Use a bool
when you need to keep track of a
binary state, e.g., whether a game is over or not.
Variables
When we want to store data that we don't know at the beginning of our program (because we want to read it in from the user or base it on a computation), or if the data might change throughout the course of a program, we can store it in a variable. A variable stores values that can vary. The value of a variable can be set over and over again.
There are several parts to using variables: declaring, initializing, accessing, and reassigning. We talk about these below, as well as scope.
Declaring variables
In order to use a variable in C++, we must first declare it. A declaration is a line of code that tells the
compiler that we want to set aside a box of memory of a certain type and
identified by a name. It consists of the type followed by the name of our
variable (the name is also called an identifier
), and ends with a
semi-colon (as do all statements in C++). This must be done before we can ever
use a variable or assign a value to it. For example, to declare a variable to
hold an age, we can do the following:
Here are a few more examples:
There are rules about identifiers, however. For instance, they may not start with any character other than a-z, A-Z, and _. In addition, no reserved C++ keywords can be used, which include the following:
alignas, alignof, and, and_eq, asm, auto, bitand, bitor, bool, break, case, catch, char, char16_t, char32_t, class, compl, const, constexpr, const_cast, continue, decltype, default, delete, do, double, dynamic_cast, else, enum, explicit, export, extern, false, float, for, friend, goto, if, inline, int, long, mutable, namespace, new, noexcept, not, not_eq, nullptr, operator, or, or_eq, private, protected, public, register, reinterpret_cast, return, short, signed, sizeof, static, static_assert, static_cast, struct, switch, template, this, thread_local, throw, true, try, typedef, typeid, typename, union, unsigned, using, virtual, void, volatile, wchar_t, while, xor, xor_eq
While the C++ compiler doesn't really care what you name your variables, you
should. The style I recommend is to avoid all but the most common abbreviations
and use camelCasing when your identifiers consist of multiple words. For
example, if I have a variable to store my brother's age, I would name it:
brothersAge
, rather than broAge
,
brother_age
, or, worst of all, ba
. There are certain
situations when a single letter identifier is okay, but in general, you should
avoid it. Identifiers that are easy to read and understand improve code
comprehension. That's good for you, for me, and for anyone else who ends up
looking at your code.
Assigning values to variables
Once a variable has been declared (so the compiler knows about it), we can store data in the variable via an assignment. Assignments come in to flavors: the very first assignment to a variable is called an initialization (since we're setting the variable's initial value); any assignment thereafter is referred to as a reassignment.
In C++, we use the =
sign to mean "gets", or "is assigned". The
variable that is getting the value is on the left, and the value that is being
gotten is on the right. For example, age = 5;
will assign the value
5
to the variable age
. We read this "age gets the
value 5" or "age is set to 5". It is quite common to think of =
the
way it is used in math—it's different in programming! In programming, it's
an assignment operator, not a test of equality. The thing on the left always
gets the value of whatever is on the right.
Initialization can take place either at the same time a variable is declared or sometime after the declaration. For example, here's an example of separating the two steps:
And here's the version where they happen at the same time:
Here are the assignments for the variables we declared in the previous subsection:
The right hand side of an assignment can also be a variable or complex
expression. For instance, if we have another variable, say,
brothersAge
, and I want to set age
to the value stored
in brothersAge
, then I could do that with this assignment:
age = brothersAge;
. This assumes, of course, that both variables
have been declared and that brothersAge
has been initialized.
E.g.,:
At the end, the value stored in age
is 10 and the value stored in
brothersAge
is 11. Why? In memory, the assignment operator
copies the value stored in the variable on the right at that point
in the program and stores it in the variable on the left. They are not
being linked—the data is being copied.
Expressions
Expressions are segments of code that can be evaluated by the computer
and replaced with a resulting value. A variable by itself constitutes an
expression. A literal (e.g., 10
) is an expression, too.
However, expressions can be longer and involve any number of operators and
function calls. An example of a more
complex expression would be a mathematical one, e.g.,:
Here we've initialized brothersAge
to 11. We then assign
brothersAge-1
to age, which is 10. So the final value of
age
is 10. For numerical types, like int
,
long
, float
, and double
, we can use a
series of operators between them: +, -, /, *.
Numerical-type variables can also use short cuts for reassigning their values, as shown in the table below:
Operator | Description | Example | Equivalent to |
---|---|---|---|
+= | Increments the variable on the left by the value on the right | age += 10; | age = age + 10; |
-= | Decrements the variable on the left by the value on the right | age -= 10; | age = age - 10; |
*= | Multiplies and updates the variable on the left by the value on the right | age *= 10; | age = age * 10; |
/= | Divides and updates the variable on the left by the value on the right | age /= 10; | age = age / 10; |
++ | Increments the variable on the left by one | age++; | age = age + 1; |
-- | Decrements the variable on the left by one | age--; | age = age - 1; |
Whole number integers (e.g., of type int
and long
) can
make use of the modulo operator, represented as %
. Modulo yields
the remainder after dividing the right operand by the left operand.
E.g., 10 % 7
is 3, because 7 goes into 10 once, with a remainder of
3. So the assignment int age = 10 % 7;
will assign 3 to the
variable age
.
Other types of variables can be used with operators, as well. For instance, if we have two strings, we can concatenate them (glue them together) as in the following program:
Here the variable messageFull
is given the value "Hello there"
as a result of the expression messageFirstHalf + messageSecondHalf
.
Here's another example that makes use of a string function length()
(we'll actually call these "methods" later in the semester):
In this example, we first declare a string variable named name
,
then assign it the string literal "George Washington". On line 2,
we declare an integer variable nameLength
and set it to the number
of characters contained in the value stored in name
. Double quotes
are not part of the string, so the length is 17.
Scope
Where variables are declared in a program also matters. Variables must be
declared in the scope in which they are used. Until we
learn about functions, main
will be our primary scope. So, we
should declare all the variables we need at the top of the main
function:
What if we did the following?
The variable age
has a global scope in
this example because it can be accessed everywhere—in every single
function in your code. Global scope should almost always be avoided with
variables. There is no situation in this class where you should declare a
variable in the global scope. The primary reason for this is that you have no
control over what functions modify the value stored in global variables. There
are better ways to pass values within your code. (In certain types of
programming, such as for game development or graphical user interface
development, global variables are considered okay and even sometimes required;
we will not be doing any such development in this class.)
Two variables in the same scope cannot share the same name. If an identifier exists as a higher scope (e.g., in the global scope), then a variable of the same name may be declared in a lower scope (e.g., in main). When this happens, we say that the variable in the lower scope shadows the other identifier. Here's an example:
While we will shy away from global variables in this class, we will find that constructs such as loops also have a lower scope that the function in which they reside, causing shadowing issues.
(Back to top)Constants
Variables are perfect when we have data that might vary during the lifetime of
the program. Sometimes, however, we need a value that we know will never change
during a program. For example, π (3.14...) or the minimum drinking age in the
US. C++ gives us a special keyword to stick in front of our declaration to say
"this value will never change": const
. This is then followed by the
type, the identifier, and the initialization. Unlike variables, constants
must be initialized when they are declared and we can never reassign
a value to a constant. Here's an example of declaring a constant for π and
the minimum drinking age:
Notice that constants' names are all upper case, and spaces are represented as underscores. This is not a requirement of C++, but rather the convention we (and most other programmers) will use for constants in C++ (and many other languages). It makes it extremely easy to tell what values are constants later on in the program.
Also unlike variable, the most appropriate place for constants are in the global space. So add them to the header of your C++ programs. One of our reasons for not wanting variables to be global is that we lose control over what code can reassign values to global variables. However, since constants cannot be changed, we don't have that worry. Moreover, constants are always hard coded, whereas variables are usually read in from a user, file, or are the result of a calculation (our early examples are an exception to this generalization). Because constants are hard coded, having them at the top of the program makes them easy for a programmer to update as needed and recompile the program (e.g., if we needed more precision for PI, or if the minimum drinking age changed). Here's an example of a program with our constants declared:
(Back to top)Literals vs. variables vs. constants
Now that you've learned about variables and constants, it's time to learn about some nomenclature that will make it easier for us to talk about them and the data we store in them.
A variable is a C++ entity that allows us to label a
box of memory for storing data of a given type (like an int
or
string
). The value stored in that box can change during the
lifetime of a program.
A constant is like a variable, except that its value must be initialize when the constant is declared, and it can never change during the lifetime of a program.
A literal is a value of a given type. For example, a
string
literal consists of a pair of double quotes with text in
between (like "Hello!"
). Examples of int
literals are:
5
, 20093
, and -13
.
A few things about string and char literals
We use strings a lot. Therefore, it's helpful for you to know a few
extra things about them so that you'll get the most out of using them. As we saw
in the examples above, string literals are surrounded by double quotes. like
"Hello!"
. That's all well and good, but what happens when you want
to use a double quote in the string itself? Or what if you want to represent
some kind of whitespace character like a tab or new line? What other things can
you embed in strings?
Here's a table with some character combinations and what they will do within a
string. Notice that they all start with a backslash (\
).
Backslashes are used in C++ as what's called an escape
character. A backslash tells the C++ compiler that the character (or
characters) that follow should be treated specially and not taken at face value.
Escape sequence | Meaning |
---|---|
\" |
Embeds a double quote (as opposed to marking the end of a string literal). |
\n |
Embeds a new line character (ASCII character 10). |
\t |
Embeds a tab character (ASCII character 9). |
\b |
Embeds a backspace character (ASCII character 8), which causes the cursor to back up one spot when printed to a CLI. |
\a |
Causes an audible bell when printed to most CLIs. |
\' |
Embeds a single (this is necessary only in char literals). |
These can be used within char
literals, as well. You can find
out more about string and character literals on this Wikipedia
page.