ISTE Home
About ISTE
Advocacy
Educator Resources
Membership
Affiliates
All-Inclusives
Awards and Recognition
ISTE 100
Join or Renew
Member Campaigns
Member Central
Member Networking
My Profile
Podcasts
Special Interest Groups
SIG Newsletter
Join a SIG
SIG1to1 (1 to 1 Computing)
SIGAdmin (Administrators)
SIGCT (Computing Teachers)
Join SIGCT
SIGCT Officers
Journal for Computing Teachers (JCT)
JCSE Online - Journal of Computer Science Education
Past Issues
2005-2006
2004-2005
2003-2004
2002-2003
2001-2002
April 2002
February 2002
November 2001
October 2001
Submission Guidelines
SIGDE (Digital Equity)
SIGHC (Handheld Computing)
SIGILT (Innovative Learning Technologies)
SIGIVC (Interactive Video Conferencing)
SIGMS (Media Specialists)
SETSIG (Special Education Technology)
SIGTC (Technology Coordinators)
SIGTE (Teacher Educators)
SIGTel (Telelearning)
SIG Council
Volunteer
NECC
NETS
Career Center
News & Events
Professional Development
Publications
Research
Store

Printer Friendly

A Robot Model of Function Behavior in C/C++

John C. Molluzzo
Pace University

Two of the most difficult topics for students in C and C++ courses are functions and pointers. Though many books do a good job discussing pointers, few address the problems beginning students have when first encountering the function concept. Students usually have some difficulty understanding:

  • how a function is executed by a calling program;
  • how to use a function that returns void and a function that returns a value;
  • how arguments are passed by value;
  • how return values are passed back to the calling function;
  • how parameters, local variables, static local variables, and global variables are treated by functions;
  • how arguments are passed by pointers; and
  • how (in C++) arguments are passed by reference.

This article discusses function behavior through a model that uses a robot and its specially constructed environment. Being a model, it does not perfectly reflect every aspect of function behavior. However, it does model most of the basic and important aspects of functions and argument passing. I have used the model very successfully in teaching functions in both C and C++ courses to undergraduate and graduate students as well as professional programmers in a workshop environment.

Throughout the article, I shall distinguish between the terms argument and parameter. A function argument (sometimes called an actual parameter) is an actual value passed to a function in the function call. A parameter (sometimes called a formal parameter) is a variable declared in the function's definition header that the function uses to store the corresponding argument value supplied by the calling function in the function call.

The Basis of the Model—The Function Robot

Figure 1 shows the basis of this model. The computer microprocessor is modeled by a robot, CPU, pronounced "CeePoo," which carries out program instructions. A function is modeled by a room, which houses variables and instructions. The robot can move from room to room. CPU can also carry things as it travels from one room to the next. (More about what kinds of things the robot can carry later.) CPU, when in a function room, carries out the function's instructions. A function room contains a door through which the robot can pass. When in a function room, CPU cannot see into any other room. If a variable is declared inside the function—say int n—the robot retrieves a storage box from main memory and places a label with the variable's name on the outside of the box (i.e., the robot allocates storage for the variable). Such a box represents a local automatic variable. If the function requires a parameter—say int i—the parameter is treated as an ordinary variable. Thus, parameters are also modeled as boxes inside the function room. The only difference between a parameter and an ordinary variable is that CPU gives a value to a parameter upon entering the function room. Therefore, I depict a parameter at the entrance to the door. The value the robot gives to the parameter is determined by how the function is called.

Figure 1.

All functions are modeled in this way, including the function main(). Thus, virtually every C/C++ program involves using at least two functions: main() and one or more library or user-defined functions.

A First Example—Passing Arguments by Value

To show how the basic model works, let's consider a simple C++ program that uses one user-defined function: Add(). Here is the program code:

// Program1.cpp 

#include <iostream.h>

int Add(int, int);

int main()

{

   int n1, n2, sum;

   cout << "Enter a number: ";

   cin >> n1;

   cout << "Enter another number: ";

   cin >> n2;

   sum = Add(n1, n2);

   cout << "The sum is " << sum;

   return 0;

}

int Add(int i1, int i2)

{

   int sum;

   sum = i1 + i2;

   return sum;

}

Figure 2 shows the two function rooms and the other components of the Robot Model—MainStorage, the cin input conveyor belt, and the cout output conveyor belt.

Figure 2.

MainStorage, which is accessible to CPU from any function room, contains storage boxes. Each box is capable of storing a single value. The boxes are of different types—integer, float, double, character, and so on. When a function declares a variable, the robot takes a storage box of the appropriate type from MainStorage, brings it into the function room, and labels it with the name of the variable. If the variable is initialized in its declaration, the robot immediately empties the box of any garbage value it might contain from a previous use and places the initial value into the box.

The cout conveyor belt is available to CPU from any function room. If the robot executes a cout statement, it places the data indicated by the statement onto the cout conveyor belt. The data is then sent to the monitor for display. Similarly, if the robot executes a cin statement, it waits for data to come down the cin conveyor belt. It retrieves this data and places a copy of it into the variable indicated in the cin statement.

To show these elements in action, I discuss the behavior of Program1.cpp. Before executing the instructions in main(), CPU sees the function prototypes. These tell the robot which functions will be used in the program, the types of their arguments, and how their arguments should be passed. In Program1.cpp, the prototype tells the robot that function Add() has two integer arguments that are passed by value. To begin the program, CPU enters the main() room and creates three variables—n1, n2, and sum—by taking three integer boxes from MainStorage and labeling them with the variable names. It then places the string "Enter a number" onto the cout conveyor for display on the monitor. This prompts the user to enter a number. Let's assume that the user enters 14. To execute the cin statement, the robot waits for a number to arrive on the cin conveyor so it can be placed into the variable box n1. When the number 14 arrives, CPU empties any value that might be in the n1 variable box and places 14 into that box. In the same manner, the robot prompts for and obtains a number (let's assume 45) to place into the n2 variable box.

The next statement CPU executes is the assignment that places a value into the variable sum. The value it must place into sum is the value of the function call Add(n1, n2). To call the function, the robot first copies the value of the first function argument onto a slip of paper and copies the value of the second function argument onto a second slip of paper. Then, CPU takes the two slips of paper and leaves the room main() to execute the function Add(). Because CPU leaves the room main() before the function ends (the return statement), all the variables in the room are left as they are.

CPU now enters the room Add() and begins executing the instructions of that function. The first thing the robot must do is give values to the function’s parameters. As CPU enters the room, it retrieves an integer storage box from MainStorage, labels it i1, and places the value that it wrote on the first slip of paper (14) into the box. In the same way, CPU creates the second parameter, i2, and places the second value (45) into the box.

This method of transferring arguments to a function is called passing arguments by value. The values of the arguments are used, not the original variables themselves (n1 and n2, in this case). Therefore, any changes to the parameters i1 and i2 do not affect the values of n1 and n2 back in main(). Even if numeric constants are passed as an arguments, say Add(4, 7), CPU makes copies of the argument values (4 and 7) and brings the copies to the room Add().

Next, the robot creates the variable sum by taking an integer box from MainStorage and labeling it sum. Because this box labeled sum is in a different room from the box labeled sum in the room main(), CPU cannot mix up them up. Whatever it does to the sum box in the Add() room has no effect on the sum box in room main().

The next statement the robot executes is the assignment. It adds the values that are in the parameters i1 and i2 and places the total (59) into the variable sum. Then CPU executes the return statement. To execute this statement, the robot writes the value of the expression that follows the word return onto a slip of paper to take when it leaves the room. It then must clean up after itself, so it removes the labels from all the variables and parameters in the room, and returns the boxes to MainStorage. Thus, the parameters and any variables declared inside the function no longer exist. Finally, CPU leaves the room and returns to the room it left, main(), to resume where it left off.

When CPU returns to main() it uses the value on the slip of paper it is carrying, 59, as the value of the function call in the assignment. Thus, the robot places 59 into the variable sum. Finally, to execute the last cout statement, the robot places the string "The sum is " followed by the value of the variable sum onto the cout conveyor. When CPU executes the return statement in main(), it removes all labels from the variables declared in main(), returns the boxes to MainStorage, writes 0 on a slip of paper, and returns to execute a statement in an operating system program.

Passing Arguments by Pointer

Pointers are probably the most difficult concept that beginning C/C++ programmers encounter. Following is a way of looking at pointers and their use in function calls that fits into the robot model.

Pointers

A pointer is a special type of storage box. Think of a pointer as a remote control box. The robot can attach one end of a remote control cable to a pointer box and the other end to another box. (The robot has an unlimited supply of cables.) The robot can use the controls on the pointer box to manipulate the box that the other end of the cable is attached to. A pointer's cable is specific to a particular data type. Thus, an integer pointer's cable can only be attached to an integer box; a character pointer's cable can only be attached to a character box, and so on. (The only way an integer pointer can be plugged into a box of a different type is to use a special adapter called a type cast.) To illustrate, the following declarations produce the situation shown in Figure 3.

int i = 5;

int j = 7;

int* i_ptr = &i;

int* j_ptr;

Figure 3.

When CPU executes these statements, it first creates two ordinary integer variables labeled i and j, as described previously. The data type in the third declaration, int*, tells the robot that it must retrieve an integer pointer box from MainStorage. The robot does so and labels the box i_ptr. The pointer initialization means that the robot attaches i_ptr's remote control cable to the box labeled i. Finally, the fourth declaration tells the robot to retrieve an integer pointer box from storage and label it j_ptr. Note that this pointer is not initialized at this time. Therefore, it is not attached to any box.

Suppose that now the robot is instructed to carry out the following statement.

*i_ptr = 9;

This tells the robot to use the remote controls of the pointer i_ptr to place the integer 9 into the box that the pointer is connected to. Thus, the value 9 is placed into the box labeled i (Figure 4).

Figure 4.

The following statement instructs the robot to attach j_ptr's cable to the same box that i_ptr's cable is attached to (Figure 5).

j_ptr = i_ptr;

Figure 5.

Pointers and Functions

To show how pointers are passed to functions, I discuss Program2.cpp,which uses a standard swap function to interchange the values of two integer variables.

// Program2.cpp

#include <iostream.h>

void Swap(int*, int*);

int main()

{

   int i = 3;

   int j = 5;

   cout << "Before Swap: i = " << i << 
" and j = " << j << endl;

   Swap(&i, &j);

   cout << "After Swap: i = " << i << " 

and j = " << j << endl;

   return 0;

}

void Swap(int* a_ptr, int* b_ptr)

{

   int temp;

   temp = *a_ptr;

   *a_ptr = *b_ptr;

   *b_ptr = temp;

}

When main() calls Swap(), CPU attaches an integer remote control cable to each of the arguments it passes, namely i and j, and then carries the other ends of the cables to the Swap() function room.

Once inside the room, the robot takes the first cable (which is attached to i) and attaches it to the first parameter, the pointer a_ptr. Then it takes the second cable (which is attached to j) and attaches it to its second parameter, the pointer b_ptr. Thus, a_ptr is a remote control for the variable i and b_ptr is a remote control for the variable j (Figure 6).

Figure 6.

When the robot executes the assignment

temp = *a_ptr;

it uses the remote controls of the pointer a_ptr to make a copy of the contents, 3, of the box that a_ptr is attached to, i back in main(), and places this copy into its variable temp (Figure 7).

Figure 7.

When the robot executes the second assignment

*a_ptr = *b_ptr;

it uses the remote control cable attached to b_ptr to make a copy of the contents, 5, of the box to which b_ptr is attached, j in main(), and places that copy into the box to which a_ptr is attached, i in main(), using the remote cable attached to a_ptr. Thus, the value of i in main() is changed by the actions of the robot while executing in the function room Swap() (Figure 8).

Figure 8.

Finally, the robot executes

*b_ptr = temp;

CPU, using the remote cable attached to b_ptr, places a copy of its variable temp into the box to which b_ptr is attached, j in main(). This changes the value of j in main() (Figure 9).

Figure 9.

When the function ends, the robot detaches the cables attached to a_ptr and b_ptr and returns all the variable boxes that belong to Swap() to MainStorage. It then carries the ends of the cables back to main(). When the robot returns to main(), that function reactivates. CPU disconnects the remote cables that it had attached to i and j. Then the robot executes the next instruction of main().

The net result of using Swap(), then, is to interchange the values of the two variables in main().

Functions That Return a Pointer

The following program, Program3.cpp, discusses how the model works for a function that returns a pointer. The program replaces the first blank it finds in a string by a dollar sign. For simplicity, let's assume that the string contains at least one blank.

// Program3.cpp

//

// For simplicity, the program assumes 

// that the string contains                            

// at least one blank.

#include <iostream.h>

char* FindBlank(char*);

int main()

{

   char* words = "This is Program3.c";

   char* c_ptr;

   c_ptr = FindBlank(words);

   *c_ptr = '$';

   cout << words;

}

char* FindBlank(char* c_ptr)

{

   while (*c_ptr != ' ')

   ++c_ptr;

   return c_ptr;

}

A string is stored as a character array. To execute the first declaration and initialization in main(), CPU must first create the initialization string and then create and initialize the character pointer words. To compose the string constant used in the initialization of the character pointer words, the robot counts the number of characters in the string (18). It then retrieves that number plus one (19) of character storage boxes from MainStorage and glues them together in sequence. This collection of boxes is the character array. It then places the characters in the string into the boxes in the array one-by-one and places the null character in the last box. The declaration and initialization of the character pointer words occurs as follows. CPU retrieves a character pointer box from MainStorage, labels it words, and connects a remote control cable from words to the first character of the array that contains the character string.

Therefore, when the robot calls FindBlank(words), it passes the address of the first element of the array words. In terms of the model, the robot attaches a second remote cable to the box that words is attached to (the first character in the string) and takes the other end to FindBlank(). Once in the function room FindBlank(), the robot attaches the cable to c_ptr (Figure 10).

Figure 10.

The while loop in FindBlank() finds the first blank in the string. The statement ++c_ptr; moves the cable from the box to which it is attached to the next box. When the loop ends, the cable is attached to the first box in the string that contains a blank (Figure 11). To execute the return statement, the robot detaches the cable from c_ptr, returns the variable c_ptr to MainStorage, and leaves the room FindBlank() still carrying the end of the remote control cable. Remember that the other end of the cable, which is in the room main(), is attached to the first blank in the string.

Figure 11.

When the robot resumes executing in main(), it attaches the end of the cable it is carrying to the pointer c_ptr that is in room main(). Therefore, main()'s c_ptr is now attached to the first blank in the string (Figure 12). The next statement in main() then places a $ at the position containing the blank. Finally, CPU places a copy of the string onto the cout conveyor as follows. It places a copy of the first character that words is attached to on the cout conveyor and then places each succeeding character on the conveyor until it reaches the null character.

Figure 12.

Passing Arguments by Reference

References are often easier to work with than pointers and in some cases must be used to achieve a program's objectives. In this section, I first discuss how references can be viewed in terms of the basic robot model, then I show how to use the model to explain the use of references in function calls.

Reference Variables

In C++, a reference is an alias for an existing variable. Thus, the following declarations and assignment create a variable and a reference to that variable.

int i = 7;

int& r = i; // r is a reference to i

The reference r is simply another name for the variable i. In this model, let's think of the reference r as another label that the robot pastes onto the box labeled i. Assume the label is circular to distinguish it from the variable label (Figure 13). Any statement using r references the box labeled i because the labels r and i are on the same box.

Figure 13.

References and Functions

To consider how passing arguments by reference works within this model, consider the following program, which uses a function to swap integer values by using call by reference.

//Program4.cpp

#include <iostream.h>

void RefSwap(int&, int&);

int main()

{

   int i = 3,

   j = 5;

   cout << "Before RefSwap: i = " << i << 
" j = " << j << endl;

   RefSwap(i, j);

   cout << "After RefSwap: i = " << i << 
" j = " << j;

   return 0;

}

void RefSwap(int& a, int& b)

{

   int temp;

   temp = a;

   a = b;

   b = temp;

}

The prototype for RefSwap() tells CPU that the two arguments are to be passed by reference. This means to CPU that it must paste labels onto existing storage boxes when it gets to the RefSwap() room. The only way to do this is to carry the storage boxes themselves to the function room. Therefore, when the robot calls RefSwap(i, j) it carries the boxes i and j themselves to the room RefSwap(). The parameters in the function definition of RefSwap() are declared as references. Hence, they are labels, not variables (Figure 14).

Figure 14.

When the robot enters room RefSwap(), it pastes the label a (which is the name of its first parameter) on the first box it was carrying. Likewise, the robot pastes the second parameter label, b, on the second box it was carrying (Figure 15).

Figure 15.

The first assignment the robot executes in RefSwap() places the value that is in the box labeled a into the variable temp. Therefore, it actually places the value of the variable i into temp. Likewise in the other statements, when the robot uses the boxes labeled a and b, it is really using the boxes labeled i and j (Figure 16).

Figure 16.

When the robot stops executing, it removes the labels it placed on the boxes (a and b) and takes the boxes back to main(). The values in the boxes were interchanged in room RefSwap() (Figure 17). Therefore, when CPU displays the values of i and j for the second time in main(), they are the reverse of the values it displayed previously.

Figure 17.

Global and Static Variables

We can extend the basic robot model to include global variables (declared outside functions) and local static variables (local variables declared with the keyword static). A global variable is declared outside any function and, therefore, must exist outside all function rooms. Assume that MainStorage contains an area called StaticStorage. When a global variable is declared in a program, CPU places the variable in StaticStorage in such a way that only functions defined after the declaration have access to the variable. When in a function room, CPU can look out the function room’s window. The window has a shutter that opens only partway (Figure 18). Thus, the robot can only see into StaticStorage in one direction.

Figure 18.

Because static variables are in StaticStorage, their existence is independent of the activation/deactivation of any function room. Therefore, they retain their values independently of any function in the program.

A local static variable, that is one declared inside a function with the keyword static, exists in the StaticStorage area but is visible only to the function in which it is declared (Figure 19). Because the local static variable does not exist inside the function room, it retains its value from one function execution to the next. Because it is not in the room, CPU cannot return it to MainStorage when it leaves the room.

Figure 19.

We leave as an exercise for the reader to explain how the function Func1() in Program5.cpp works in terms of the model. Note that when the robot sees a reference to a variable in an instruction, it first looks in the room in which it is executing for a variable of that name. If it finds such a variable, the robot uses it to carry out the instruction. If there is no variable of the given name in the room, the robot looks into StaticStorage for the variable.

Note that the scope resolution operator causes the robot to act differently. The reference to ::g3 in Func1() causes CPU to look into StaticStorage for the variable g3 rather than in the Func1() room.

//Program5.cpp

#include <iostream.h>

void Func1();

int g1 = 6;

int main()

{

   cout << "Global g1 = " << g1 << endl 
<< endl;

   Func1();

   Func1();

   return 0;

}

   int g2 = 1;

   int g3 = 7;

   void Func1()

{

   int g3 = 8;

   static k = 2;

   cout << endl << endl;

   cout << "Function Func1() Executing" << endl 
<< endl;

   ::g3++;

   cout << "Global g1 = " << g1 << endl;

   cout << "Global g2 = " << g2 << endl;

   cout << "Global g3 = " << ::g3 << endl;

   cout << "Local g3 = " << g3 << endl;

   cout << "Local k = " << k << endl;

   ++g3;

   ++k;

   cout << endl << "After incrementing, local 
variables: " << endl;

   cout << "Local g3 = " << g3 << " 
Local k = " << k;

}

Acknowledgements

I would like to thank Professor Joe Bergin of Pace University for several useful comments that lead to improving the basic robot model. I would also like to thank Dean Susan Merritt, also of Pace University, for her continued support of this project.


Contributor

Dr. Molluzzo is chair of the Information Systems Department at Pace University, New York. He has authored articles in mathematics and various aspects of computing. He is also author of several books, including C++ for Business Programming (Prentice Hall, 1999). His main interests include computer architecture, programming languages, operating systems, and distance education. His main interests outside academe include the American Civil War, baseball, and bowling.

Contact

John C. Molluzzo
Information Systems Department
Pace University
Pace Plaza
New York, NY 10038
jmolluzzo@pace.edu

Copyright © 2002, ISTE (International Society for Technology in Education). All rights reserved.

Customer Service: iste@iste.org   1.800.336.5191   1.541.302.3777 (Int'l)   1.541.302.3778 (fax)
Visit the ISTE Career Center for educational technology jobs, resources, and listings.