COSC 1315

Programming Fundamentals

Expressions and Operators

Revised:  February 3, 2007
By Richard G. Baldwin

File:  Pf00160.htm
Practice Text


Preface

This lesson was written specifically for the benefit of my students in COSC 1315, Fundamentals of Programming.  The lesson was written under the assumption that those students have no prior programming knowledge when they enroll in the course.

Another browser window

I recommend that you open another copy of this document in a separate browser window so that you can view the code and the discussion of that code at the same time.

Introduction

Operators

Operators are the action elements of a computer program.

They perform actions such as:

Operands

Operators operate on operands.

For example, in the following expression, the plus character is an operator while x and y are operands.

x + y

Assuming that x and y are numeric primitive variables, this expression produces the sum of the values stored in the two variables.

The variable x would be called the left operand and the variable y would be called the right operand.

Expressions

C++ programs consist of statements, which in turn, consist of expressions.
(An expression is a specific combination of operators and operands, which evaluates to a particular result.

The operands can be variables, literals, or method calls that return a value.)

In your past experience, you may have referred to expressions by the names formulas or equations.

Although formulas and equations are not exactly the same thing as expressions, they are close enough to help you understand what expressions are and how they are used.

Statements

A statement is a specific combination of expressions terminated by a semicolon.

The following is an example of a statement comprised of expressions.

z = x + y;

Operationally, in the above statement, values are retrieved from the variables named x and y.  These two values are added together.  The result is stored in (assigned to) the variable named z, replacing whatever value may previously have been contained in that variable.

Operators

Unary, binary, and ternary operators

C++ provides operators that can be used to perform an action on one, two, or three operands.

An operator that operates on one operand is called a unary operator.

An operator that operates on two operands is called a binary operator.

An operator that operates on three operands is called a ternary operator.  (I believe that there is only one ternary operator in C++.)

Some operators can be either unary or binary

Some operators can behave either as a unary or as a binary operator.

(The best known operator that can behave either way is the minus sign.)

The minus sign as binary operator

As a binary operator, the minus sign causes its right operand to be subtracted from its left operand (provided that the two operands evaluate to numeric values).

For example, the following code subtracts the variable y from the variable x and assigns the result of the subtraction to the variable z.  After the third statement is executed, the variable z contains the value 1.

int x = 6;
int y = 5;
int z = x - y;

The minus sign as unary operator

As a unary operator, the minus sign causes the algebraic sign of the right operand to be changed.

For example, the following two statements cause a value of -5 to be stored in the variable x.

int y = 5;
int x = -y;

Binary operators use infix notation

To keep you abreast of the jargon, binary operators in C++ use infix notation.  This means that the operator appears between its operands.

Although I won't identify and discuss them in this lesson, there are also some unary operators that use prefix notation and unary operators that use postfix notation.

For prefix notation, the operator appears before (to the left of) its operand. 

For postfix notation, the operator appears after (to the right of) its operand.

General behavior of an operator

As a result of performing the specified action, an operator can be said to return a value (or evaluate to a value) of a given type.

The type of value returned depends on the operator and on the types of the operands.

(To evaluate to a value means that after the action is performed, the operator and its operands are effectively replaced in the expression by the value that is returned.)

Operator categories

There are many different categories of operators that have different purposes.  Microsoft identifies the following categories of C++ operators:

This lesson will not attempt to teach you about, or even to introduce you to all of the different C++ operators.

You will learn about many of the operators in due time if you continue to pursue an education in computer programming using C++, Java, or C#.

(While there are some differences in specific operators among these three object-oriented programming languages, to a large extent, all three languages use the same operators for the same or similar purposes.)

What you will learn in this course

In this course, you will mainly learn about the following operators.  You will learn about the operators shown in boldface in this lesson.  You will learn about many of the remaining operators in other lessons.

Have seen some operators before

You have already seen how some of these operators are used in previous lessons.  For example, you first saw the use of the new operator, the Indirection operator, the Scope Resolution operator, and the Pointer-to-Member operator in the lesson entitled Basic Object-Based Program Structure.

You have seen the use of the Assignment operator in many previous lessons.

You saw the use of the Address-of operator and the Indirection operator in the lesson entitled C++ Variables and Constants.

You have seen the use of the Function call operator in several previous lessons including the lesson entitled C++ Functions.

The sample program in this lesson

I will provide and explain a simple program in this lesson that uses some of the Multiplicative and Additive operators as well as the Cast operator.

The lesson will also illustrate operator precedence.

In addition, this lesson will reinforce some of the operators that you have seen before.

A future lesson will explain the use of Relational and Equality operators as well as Logical operators in selection and loop structures.

Arithmetic Operators

C++ supports various arithmetic operators on all floating point and integer numbers (including type char).

The binary arithmetic operators

The following table lists the binary arithmetic operators supported by C++.

Operator    Description                
   
   +        Adds its operands
   -        Subtracts the right operand
            from the left operand
   *        Multiplies the operands 
   /        Divides the left operand by
            the right operand
   %        Remainder of dividing the 
            left operand by the right 
            operand - modulus operator
 

Sample Program

Mixed data types

There are some subtle issues involved in the use of mixed data types with arithmetic operators.

Generally speaking, however, if you mix the integer types with the floating types, the integer values will be automatically converted to floating values and the arithmetic will be performed using floating arithmetic.

Floating arithmetic produces a floating result.

Integer division

If you perform integer division, the result will consist of only the whole-number part of the quotient.

The remainder or fractional part will be discarded.

If you need the remainder, you can get it by using the modulus operator from the above table.

Precedence of operators

A very important issue has to do with the actual order in which operations are performed when two or more operators are used in the same expression.

For example, consider the following expression:

(2*a + 3)

Two ways to evaluate

There are two different ways that this expression could be evaluated:

The value of the result will depend heavily on the order in which the operations are performed.

Precedence table

Most programming languages provide a table from which you can determine the order of operations for any combination of operators.  However, this table is often long and difficult to memorize.

After many years of programming, about all that I have memorized from the precedence table is that if you combine multiplication (or division) with addition (or subtraction), the multiplication (or division) will occur before the addition (or subtraction).

No need to memorize the precedence table

Fortunately, we don't need to memorize the precedence table.

We can always control the order of operations by grouping terms inside of pairs of matching parentheses.

For example, I could write the above expression in the following two ways:

(2*(a + 3))
((2*a) + 3)

Evaluate from inner-most outward

When you group terms in parentheses like this, the operations inside the inner-most pair of parentheses will be fully evaluated before removing those parentheses and beginning the evaluation within of the next-outer pair of parentheses.

For example, the first form shown above would add a to 3 and multiply the sum by 2.

The second form shown above would multiply a by 2 and add the product to 3.

The main point is ...

The main point is that whenever you are in doubt as to the order that the operations will take place in an expression, you can always control the order by the judicious use of pairs of matched parentheses.

If the parentheses are not needed, they will simply be discarded without causing any problems.

What is a cast operator?

For the moment, suffice it to say that the purpose of a cast operator is to force a conversion from one type to another.

In the sample program to be discussed later, a value of type char will be temporarily converted to type short using a cast operator to control how the value is displayed.

Description of the sample program

The C++ program that I will explain in this lesson illustrates expressions and operators.  In particular, it illustrates the use of:

The program also illustrates the impact of operand types on the result of arithmetic operations.

Interesting Code Fragments

I will discuss this program in fragments and show the output produced by each fragment.  A complete listing of the program is provided in Listing 7.

The Scope Resolution operator

For several lessons, we have been using a global main function that uses the Scope Resolution operator to invoke a static function named classMain belonging to the class named Expressions01 (the name of the class differs from one lesson to the next).

Listing 1 shows the global main function and the use of the Scope Resolution operator for this purpose.

int main(){
  //Note the use of the Scope Resolution
  // operator.
  Expressions01::classMain();
  return 0;
}//end main

Listing 1

The Indirection, new, and Assignment operators

Also, for several lessons, we have been using a static function named classMain that uses the Indirection, new, Assignment and Pointer-to-Member operators to:

That code is shown in Listing 2.

class Expressions01{ 
  public:
  static void classMain(){
    //Instantiate an object in dynamic memory
    // and save its reference in a pointer 
    // variable.  Note the use of the Indirection
    // operator, the new operator, and the
    // Assignment operator.
    Expressions01* ptrToObject = 
                             new Expressions01();

    //Invoke an instance function on the object.
    // Note the use of the Pointer-to-Member
    // operator.
    ptrToObject -> doSomething();
  }//End classMain function
  
Listing 2

The doSomething function

The doSomething function begins in Listing 3.

  void doSomething(){
    cout << "Precedence:\n";
    cout << "  6*3+5 = " << 6*3+5 << endl;
    cout << "  (6*3)+5 = " << (6*3)+5 << endl;
    cout << "  6*(3+5) = " << 6*(3+5) << endl;
    
Listing 3

The code in Listing 3 illustrates the use of Multiplicative and Additive operators along with the use of parentheses to control the order in which the operations are performed.  The output produced by the code in Listing 3 is shown in Figure 1.

Precedence:
  6*3+5 = 23
  (6*3)+5 = 23
  6*(3+5) = 48
  
Figure 1

The order of the operations

The second line of output in Figure 1 shows the default case where multiplication is performed before addition.

The third line of output in Figure 1 shows that using a pair of parentheses to group the multiplicative terms has no effect since it simply reinforces the default behavior.

The fourth line of output in Figure 1 shows that using a pair of parentheses to group the additive terms has a major effect on the output.  In this case, the expression inside the parentheses is evaluated first and the result of that evaluation (8) is multiplied by 6 producing a result of 48.

Effect of type on arithmetic results

The code in Listing 4 illustrates the effect of the type of operands on the result of arithmetic operations.

    cout << "\nTypes of arithmetic" << endl;
    cout << "  Float:   10.0/3.0 = " 
                             << 10.0/3.0 << endl;
    cout << "  Mixed:   10.0/3 = " << 10.0/3 
                                         << endl;
    cout << "  Integer: 10/3 = " << 10/3 << endl;
    
Listing 4

The output produced by the code in Listing 4 is shown in Figure 2.

Types of arithmetic
  Float:   10.0/3.0 = 3.33333
  Mixed:   10.0/3 = 3.33333
  Integer: 10/3 = 3
  
Figure 2

Floating-point arithmetic

The second line of output in Figure 2 shows that when a floating-point value is divided by another floating-point value, the result is a floating-point value with the fractional part preserved.

Mixed type arithmetic

The third line of output in Figure 2 shows that when a floating-point value is divided by an integer value, the integer is automatically converted to a floating-point type.  The result is a floating-point value with the fractional part preserved.

Integer arithmetic

The fourth line of output in Figure 2 shows that when an integer value is divided by another integer value, the result is also an integer value.  Since an integer value doesn't have a fractional part, the fractional part of the result is simply discarded.  This can often lead to logical errors, which produce incorrect results, and which are difficult to find and fix.

Getting a remainder

The code in Listing 5 illustrates the use of the modulus operator to get and display the remainder produced by an integer division.

    cout << "\nThe modulus operator" << endl;
    cout << " For 11/3:\n";
    cout << "  Quotient = " << 11/3 << endl;
    cout << "  Remainder = " << 11%3 << endl;
    
Listing 5

An integer quotient

This code performs an integer division to get and display an integer quotient.  In this case, the remainder or fractional part is simply discarded.

The remainder

Then the code in Listing 5 performs a modulus operation to get and display the remainder produced by the same integer division.  In this case, the quotient is discarded.

The output produced by the code in Listing 5 is shown in Figure 3.

The modulus operator
 For 11/3:
  Quotient = 3
  Remainder = 2
  
Figure 3

Using a cast operator to change type

We learned in an earlier lesson that when the insertion operator is used along with cout to display a variable of type char:

The code in Listing 6 uses a cast operator to force the numeric value of a variable of type char to be displayed.

    cout << "\nThe cast operator" << endl;
    char var = 65;
    cout << "  Display as type char: "<< var 
                                         << endl;
    cout << "  Display as type short: " 
                           << (short)var << endl;
                           
Listing 6

A temporary change of type

The code in Listing 6 uses a cast operator to temporarily change the type of data in a variable of type char to type short.

As a result, the insertion operator will treat it as type short and display the numeric value instead of the character represented by the numeric value.

The output produced by the code in Listing 6 is shown in Figure 4.

The cast operator
  Display as type char: A
  Display as type short: 65
  
Figure 4

A value of 65

As shown in Listing 6, a value of 65 is assigned to the variable of type char named var.

As shown by the second line of output in Figure 4, when this variable is displayed as type char, the value of 65 is automatically converted and displayed as an upper-case A.

(See the table at http://www.lookuptables.com/.)

When the cast operator is used to force the insertion operator to view the variable as type short, the actual numeric value stored in that variable is displayed.

A temporary change only

The use of a cast operator to change the type of the contents of a variable is temporary and lasts only for the duration of the evaluation of the expression in which the cast is performed.

There is no permanent change to the type of data stored in the variable.

In fact, it is not possible to permanently change the type of a variable.

Once a variable is declared to be of a given type, its type can never be changed thereafter.

Complete Program Listing

A complete listing of the program is shown in Listing 7.

/*File:  Expressions01.cpp
This C++ program illustrates expressions and
operators.  In particular, it illustrates the use
of:

The Scope Resolution operator
The Indirection operator
The new operator
The Assignment operator
The Pointer-to-Member operator
Multiplicative operators
Additive operators
Parenthesis to control precedence
The modulus operator to get a remainder
The cast operator to temporarily change the type
  of a value.
  
The program also illustrates the impact of 
operand type on the result of an arithmetic
operation.

The program displays the following output on the
screen:

Precedence:
  6*3+5 = 23
  (6*3)+5 = 23
  6*(3+5) = 48

Types of arithmetic
  Float:   10.0/3.0 = 3.33333
  Mixed:   10.0/3 = 3.33333
  Integer: 10/3 = 3

The modulus operator
 For 11/3:
  Quotient = 3
  Remainder = 2

The cast operator
  Display as type char: A
  Display as type short: 65
Press any key to continue

************************************************/

#include <iostream>
using namespace std;

class Expressions01{ 
  public:
  static void classMain(){
    //Instantiate an object in dynamic memory
    // and save its reference in a pointer 
    // variable.  Note the use of the Indirection
    // operator, the new operator, and the
    // Assignment operator.
    Expressions01* ptrToObject = 
                             new Expressions01();

    //Invoke an instance function on the object.
    // Note the use of the Pointer-to-Member, or
    // Member access operator.
    ptrToObject -> doSomething();
  }//End classMain function
  //-------------------------------------------//

  //An instance function of the Expressions01
  // class
  void doSomething(){
    //Illustrate arithmetic operators and the use
    // of parentheses to control precedence.
    cout << "Precedence:\n";
    cout << "  6*3+5 = " << 6*3+5 << endl;
    cout << "  (6*3)+5 = " << (6*3)+5 << endl;
    cout << "  6*(3+5) = " << 6*(3+5) << endl;

    cout << "\nTypes of arithmetic" << endl;
    cout << "  Float:   10.0/3.0 = " 
                             << 10.0/3.0 << endl;
    cout << "  Mixed:   10.0/3 = " << 10.0/3 
                                         << endl;
    cout << "  Integer: 10/3 = " << 10/3 << endl;

    //Illustrate the use of the modulus operator
    // to get a remainder.
    cout << "\nThe modulus operator" << endl;
    cout << " For 11/3:\n";
    cout << "  Quotient = " << 11/3 << endl;
    cout << "  Remainder = " << 11%3 << endl; 

    //Illustrate the use of the cast operator to
    // temporarily change the type of a value.
    cout << "\nThe cast operator" << endl;
    char var = 65;
    cout << "  Display as type char: "<< var 
                                         << endl;
    cout << "  Display as type short: " 
                           << (short)var << endl;
 
  }//end doSomething function
};//End Expressions01 class
//---------------------------------------------//

int main(){
  //Note the use of the Scope Resolution
  // operator.
  Expressions01::classMain();
  return 0;
}//end main

Listing 7

 


Copyright 2005, Richard G. Baldwin.  Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas.  He is the author of Baldwin's Programming Tutorials, which have gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP).  His first job after he earned his Bachelor's degree was doing DSP in the Seismic Research Department of Texas Instruments.  (TI is still a world leader in DSP.)  In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

Baldwin@DickBaldwin.com

-end-