variables pass out of scope when their declaring functions end.
4.5.2
Pass-by-value vs. pass-by-reference
By default, the variables declared in the argument list of a function definition are local
variables to that function. When a function is called, its arguments are copied into the
argument variables. The original variables, in the calling program, are not affected by any
changes made by the function to its argument variables. This style of argument passing is
pass-by-value.
Alternatively, the programmer may wish for changes made by the function to one or more
of its arguments to be reflected in the corresponding variables of the calling program. To
accomplish this, when the variable is passed into the function through one of its arguments,
the copy process is skipped and the function has access to the actual variable as it exists
in the calling program. This style of argument passing is pass-by-reference. The syntax
to inform the compiler what style of argument passing is desired is to simply precede the
argument name with a ’&’ character.
Pass-by-reference is particularly useful when the programmer wishes to have a function
return more than one piece of information to the calling program. For example, suppose in
our Mean() function we wished, not only to have the mean returned to the calling program,
but also to have the function give us the sum of the two arguments.
A simple return
statement is unable to return more than one value. To get around this, consider the function
in Listing 4.8.
Compare this to the function in Listing 4.7. The return type is now void and there are two pass-by-reference arguments. Observe the use of the ’&’ character in the second two
arguments to indicate that these arguments are pass-by-reference. Listing 4.9 shows how to use this function to get both the sum and the mean of the first two arguments.
The main program declares 4 float-type variables. The x and y variables hold the numbers
to be summed and averaged. Notice that we also need variables, s and m, to hold the results of
the MeanSum() function. As the instructions of the main program are carried out from top to
bottom, before the call to MeanSum(), the variables s and m are empty (uninitialized). After
the call to MeanSum(), they contain the sum and mean respectively. Only after MeanSum()
has been allowed to do its work, can we display the contents of s and m. If we mistakenly try
to display the contents of s and m before the call to MeanSum(), the results are unpredictable–
we may just see a zero, or we may see some random number.
4.5. FUNCTIONS
25
✞
☎
// computes the sum and the mean of its
// first two arguments , the sum is placed
// in the third argument , the mean is
// placed in the fourth argument
void M e a n S u m ( f l o a t a , f l o a t b , f l o a t & sum ,
f l o a t & mean ) {
sum = a + b ;
mean = ( a + b )/2;
r e t u r n ;
}
✝
✆
Listing 4.8: A function that accepts two pass-by-value float-type arguments and two pass-
by-reference arguments, computes the sum and mean, and puts the results into the pass-by-
reference arguments.
✞
☎
task main () {
f l o a t x , y , s , m ;
x = 3 . 4 ; y = 2 . 8 ;
M e a n S u m ( x , y , s , m );
n x t D i s p l a y S t r i n g (0 , " Sum = %5.2 f " , s );
n x t D i s p l a y S t r i n g (1 , " Mean = %5.2 f " , m );
w a i t 1 0 M s e c ( 2 0 0 ) ;
}
✝
✆
Listing 4.9: A main program that uses the MeanSum() function and displays the results.
26
CHAPTER 4. SENSORS AND FUNCTIONS
More on RobotC function syntax can be found here2.
2http://carrot.whitman.edu/Robots/PDF/Functions.pdf
4.6. EXERCISES
27
4.6
Exercises
1. Which of the following variable names are valid?
n, 2n, tax2, SpeciesType, sales tax, dog#, ?89
If invalid, why?
2. Suppose a programmer wrote a program that, when executed, displayed a message
on the screen indicating whether the touch sensor was depressed or not. What is the
indeterminate in the program?
3. Suppose we have an integer-type variable, count. Give two different RobotC expres-
sions that decrement count by 2.
4. Do some experiments (run little test programs), to determine what happens when a
character-type variable is decremented. How about incremented? Give your observa-
tions and speculate about what might be going on.
5. Write a program that reads a value from the sonar sensor and displays the value
graphically as a horizontal line across the center of the screen that starts at (0,31)
and ends at (x,31) where x is the value of the sonar sensor. The idea is that the
length of the line indicates the magnitude of the sonar reading.
6. Write a program that reads a value from the light sensor and displays the value graph-
ically as a filled circle with center (50,32) and radius x, where x is the value of the
light sensor. The idea is that the size of the circle indicates the magnitude of the light
reading.
7. Write a program that starts, waits 1 second, reads the light sensor, displays the value
for 1 second, and exits.
8. Write a program that starts, waits 1 second, reads the sonar sensor, displays the value
for 1 second, and exits.
9. Write a program that implements a function called
displayLightSensor()
that accepts one argument called wait. The function will read the light sensor and
display its value for wait seconds before exiting. Use the function to write a program
that reads the light sensor and displays its value three separate times, pausing 1.5
second between reads.
10. Write a program that displays an uninitialized variable. What happens when you run
the program?
11. Modify the DisplaySmiley() function in Listing 4.6 so that it shows a frown instead.
Use it to animate a bouncing frowny face.
28
CHAPTER 4. SENSORS AND FUNCTIONS
12. Write a function that displays an equilateral triangle with center (x, y), side length a,
and orientation θ. You may assume that the side length is in pixels and that orientation
is in degrees.
Chapter 5
Decisions
In Section 4.1, we discussed the notion of indeterminacy–values in programs that are not known to the programmer when they write the program. When dealing with indeterminate information, we must have a method of making decisions. In real life, decisions are
complicated, based on incomplete information and thousands of variables. In computer sci-
ence, decisions are more straightforward and ultimately result in one of two possible choices.
Because of this clear dichotomy, programming languages base decision making on Boolean
algebra–the study of true and false statements. This explains why one of the basic datatypes
summarized in Table 4.1 is Boolean.
5.1
Boolean Algebra
In ordinary algebra, we study variables that take on any real value. We study the behavior of
these variables as they interact using the ordinary operations of arithmetic, namely addition,
subtraction, multiplication and division. In Boolean algebra, the variables can have only two
values, true or false. Further, the operations are no longer those of arithmetic, but rather
those of symbolic logic and are called conjunction, disjunction and negation.
In RobotC, we can declare a pair of Boolean variables as
bool p,q;
and we can assign values to them as
p=false; q=true;
In much the same way that we can combine integer- and float-type variables using the ordi-
nary arithmetic operations, we can combine boolean-type variables with Boolean operations.
The Boolean operations are defined as follows.
5.1.1
Conjunction
Also known as the “and operator”, conjunction in RobotC is represented by ’&&’. Two
Boolean values are combined syntactically as
p && q;
29
30
CHAPTER 5. DECISIONS
&&
true
false
true
true
false
false
false
false
Table 5.1: Conjunction, the “and operator”.
||
true
false
true
true
true
false
true
false
Table 5.2: Disjunction, the “or operator”.
and the result is a new Boolean value. The result depends on the values of p and q and
follows the rules outlined in Table 5.1.
5.1.2
Disjunction
Also known as the “or operator”, disjunction in RobotC is represented by ’||’. Two
Boolean values are combined syntactically as
p || q;
and the result is a new Boolean value. The result depends on the values of p and q and
follows the rules outlined in Table 5.2.
5.1.3
Negation
Also known as the “not operator”, negation in RobotC is represented by ’~’. Unlike the
conjunction and disjunction operators, the negation operator only acts on a single boolean
value as
~p;
and the result is a new Boolean value that is simply the opposite of the value of p. If p
is false, then ~p is true. If p is true, then ~p is false. Additional information about
Boolean algebra in RobotC is available here1.
5.1.4
Boolean Expressions
It is surprising how complicated Boolean algebra can get given the simple and limited nature
of its variables and operations. A Boolean expression is any combination of Boolean
variables and operations that can be evaluated to a Boolean value if all the values of the
1http://carrot.whitman.edu/Robots/PDF/Boolean%20Algebra.pdf
5.2. COMPARISON OPERATORS
31
Syntax
Description
>=
greater than or equal, evaluates to true if the left-hand
side is greater than or equal to the right-hand side, false
otherwise.
>
greater than, evaluates to true if the left-hand side is
greater than the right-hand side, false otherwise.
==
equal to, evaluates to true if the left-hand side is equal
to the right-hand side, false otherwise.
<=
less than or equal, evaluates to true if the left-hand side
is less than or equal to the right-hand side, false other-
wise.
<
less than, evaluates to true if the left-hand side is less
than the right-hand side, false otherwise.
!=
not equal to, evaluates to true if the left-hand side is not
equal to the right-hand side, false otherwise.
Table 5.3: The comparison operators.
variables are known. For convenience, Boolean expressions may also include parentheses to
control the order of evaluation. Negation takes precedence over conjunction and disjunction.
In the case of ties, expressions are evaluated from left to right. Consider the snippet of
instruction in Listing 5.1.
✞
☎
bool p , q , r , s ;
p = true ; q = f a l s e ; r = true ;
s =~( p || q ) && ( q || r ) && ( r && p );
✝
✆
Listing 5.1: A compound Boolean expression. At the end of the block, s has the value false.
5.2
Comparison Operators
Now that we have an understanding of Boolean algebra, it is important to note that in
programming we rarely construct expressions comprised solely of Boolean variables like that
of Listing 5.1. Instead, we usually construct Boolean expressions that arise by comparing variables of the other types. In RobotC there are 6 operators designed to compare values
and return Boolean values. They are: greater than or equal, greater than, equal, less than,
less than or equal, and not equal. Each has its own syntax summarized in Table 5.3
Be wary of the == operator! A common programming error is to use the assignment
operator, =, to compare values. This error is exacerbated by the fact that, because the
mistaken syntax actually makes sense to the compiler (a fact that we will discuss later), it
will not cause a compiler error.
32
CHAPTER 5. DECISIONS
Listing 5.2 shows how to use comparison operators. It shows the common task of testing whether a variable lies inside a certain range. The expressions in parentheses evaluate to
either true or false depending on the values of the variables x, y, and z.
✞
☎
f l o a t x =5.2 , y =0.0 , z = 1 0 . 0 ;
bool s ;
s = ( x >= y ) && ( x <= z );
✝
✆
Listing 5.2: An example of using comparison operators. The value of s at the end of the
snippet is true. This shows how a programmer would test if y ≤ x ≤ z.
It is interesting to note that the comparison operators also work on string and character
values using alphabetical order. When comparing two strings/characters, whichever comes
first in the dictionary is the smaller of the two. String/character comparisons are case-
sensitive with the rule that capital letters are less than their corresponding lower-case letters.
5.3
Conditional Statements
Now that we have the ability to create Boolean expressions, we introduce conditional state-
ments. A conditional statement allows a block of instruction to be executed depending
on the value of a Boolean expression.
5.3.1
If-statements
An if-statement is a block of instruction that is executed only if its predicate is true. The
predicate is the Boolean expression that controls whether or not the block of an if-statement
is executed. If the predicate is true, then the block will be executed, if it is false then the
block will be skipped and program execution will resume after the closing brace of the block.
The syntax, given in Listing 5.3 is simple and quite readable.
✞
☎
if ( [ p r e d i c a t e ] ) {
// c o n d i t i o n a l block
}
✝
✆
Listing 5.3: The syntax of an if-statement. The predicate, a Boolean expression, determines
whether the succeeding block of instruction is executed.
5.3.2
If-else statements
A straightforward extension of the if-statement is the if-else-statement. In an if-else-statement
the value of the predicate determines which of two blocks of instructions is executed. The
syntax is summarized in Listing 5.4.
5.3. CONDITIONAL STATEMENTS
33
✞
☎
if ( [ p r e d i c a t e ] ) {
// c o n d i t i o n a l block executed if
// the pr edic ate is true
}
else {
// c o n d i t i o n a l block executed if
// the pr edic ate is false
}
✝
✆
Listing 5.4: The syntax of an if-else-statement. If the predicate is true, the first block is
executed, otherwise the second block is executed.
More on the if-else statement can be found here2.
In Listing 5.5, we test the value of the sonar sensor and display different messages depending on the distance measured by the sensor at run time.
✞
☎
# p r a g m a c o n f i g ( Sensor , S1 , Sonar , s e n s o r S O N A R )
task main () {
int d i s t a n c e = 0;
d i s t a n c e = S e n s o r V a l u e [ S o n a r ];
n x t D i s p l a y S t r i n g (3 , " S o n a r : % d " , d i s t a n c e );
if ( d i s t a n c e > 50) {
n x t D i s p l a y S t r i n g (4 , " Come closer , " );
n x t D i s p l a y S t r i n g (5 , " I can ’ t see you ! " );
}
else {
n x t D i s p l a y S t r i n g (4 , " Back off man ! , " );
}
w a i t 1 0 M s e c ( 3 0 0 ) ;
}
✝
✆
Listing 5.5: An example of an if-else-statement. If the distance measured by the sonar is
greater than 50cm, then the first message is displayed. If it is less than or equal to 50cm,
then the second message is displayed. The instruction at the top “declares” the sonar sensor
and was inserted by RobotC.
The current value of the sensor is an integer and is always available in SensorValue[Sonar]
(this is actually an array element, we will discuss arrays a little later). For convenience and
readability, we copy the current value of the sonar sensor into the integer-type variable,
distance. For the sake of the example, we arbitrarily decide that if the sonar reading is
more than 50cm, then the target is too far away and if it is less than or equal to 50cm, then
it is too close. We use the if-else-statement to display different messages depending on this
2http://carrot.whitman.edu/Robots/PDF/Decision%20Making.pdf
34
CHAPTER 5. DECISIONS
condition. The predicate in this case is (distance>50). The value of the predicate depends
on the value of the indeterminate, distance.
5.4
Mathematical Expressions
Numeric variables and literals can be combined using the infix style of mathematical ex-
pressions. Infix is the method of expression in which the mathematical operation is placed
between the values upon which it acts (as opposed to prefix or postfix). This is the style
common in most TI calculators.
5.4.1
Basic arithmetic
RobotC recognizes the usual mathematical symbols: + (addition), - (subtraction), * (mul-
tiplication), and / (division). In addition, RobotC recognizes the use of parentheses for
grouping in mathematical expressions. RobotC also recognizes a number of more advanced
mathematical functions like sine, cosine, logarithms and the exponential function. Some
of those additional functions are summarized in the RobotC On-line Support on the left side-bar under the NXT Functions → Math section.
5.4.2
Integer arithmetic
The basic arithmetic operations are straightforward and intuitive in most cases. However,
when working with integer datatypes there is an exception. The / operator (division) au-
tomatically detects when it is operating on a pair of integers and, in that case, switches to
whole number division. Whole number division returns an integer value that represents
the number of times the denominator goes into the numerator, dropping any remainder.
For example, the expression 3/2 in RobotC evaluates to 1 not 1.5. The expression -1/2
evaluates to 0. The expression 33/10 evaluates to 3.
The / (division) operator only performs whole number division if both the numerator
and denominator are integer type variables or literals. In all other cases, ordinary division
is used. To force ordinary division of two integers either include a decimal point if it is a
literal value, e.g. 3/2.0 instead of just 3/2, or convert the integer variable to a float, e.g.
((float)n)/2 instead of n/2.
If we want the remainder after whole number division, there is separate operator for inte-
gers, % (modulus) that returns an integer value that represents the remainder after dividing
the left-hand side by the right-hand side. For example, 3%2 evaluates to 1, 33%10 evaluates
to 3.
Together these operators provide powerful methods of manipulating integer values.
5.4.3
Exponentiation
A curious omission from this collection of mathematical functions is the exponentiation
function for computing quantities like 23 or 100.33. However, we have the tools necessary
to build our own.
The C programming language uses the function, pow(), to perform
5.4. MATHEMATICAL EXPRESSIONS
35
exponentiation. For example, 23 = pow(2,3), and 100.33 = pow(10,0.33). If we have need
of exponentiation, we simply take advantage of the properties of logarithms base e and the
exponential function, ex. Recall that
log (xa) = a log x.
e
e
Also, recall that log (ex) = x. Combining these two properties, we have
e
xa = ea loge(x).
In RobotC, ex = exp(x), and log (x) =
e
log(x). Therefore, the function in Listing 5.6 will
give us the standard C exponentiation function.
✞
☎
f l o a t pow ( f l o a t x , f l o a t a ) {
r e t u r n exp ( a * log ( x ));
}
✝
✆
Listing 5.6: The standard C language exponentiation function built of available RobotC
functions.
5.4.4
Randomness
Another important function is the random number generator, random(). Randomness is
important in computer science for the purpose of running realistic simulations, for security,
and for introducing unpredictability in game play.
Each time the random() function is called, it returns a positive integer between 0 and
its single argument. For example, random(10) will return a number between 0 and 10
inclusively each time it is called. If we only wanted a random number between 1 and 10,
we would use the expression random(9) + 1. The expression random(100)-50 will return
an integer between -50 and 50 inclusively. The maximum range of the random() function
is 32767.
To generate random float type values between 0 and 1 inclusively, we can use the expres-
sion random(32767)/(float)32767. Here we use the maximum possible range so that we
get as many possibilities between 0 and 1 as we can.
Since computers are completely deterministic, getting randomness can be difficult. In
many programming environments (not RobotC) careful analysis of the random() function
will show that it generates the same sequence of random numbers every time you restart your
program. To change the sequence, programmers must seed the random number generator
with some externally obtained (and hopefully) random number. The seed of a random
number generator is the number that the generator starts with when applying its randomness
formula for computing the next random number. To set the seed, we call the srand()
function with an integer argument, just once, at the beginning of the program. Afterwards,
the random() function will generate a sequence of random numbers based on the seed.
Fortunately, robots have lots of external sources for seeds. The programmer could read
the sound sensor and use that value as the seed before proceeding. The sequence of random
36
CHAPTER 5. DECISIONS
numbers would then depend upon the sound level at the time the program was started.
In a noisy room, this would be a good source of randomness. However, in a quiet room,
the reading may be the same each time, which gives the same random sequence each time
the program runs. To get around this, there are lots of possibilities. The programmer
could read numbers from several sensors and mix the values together in a formula. A very
reliable random seed is value of the system clock when the program is executed. With this
method, each time the program runs, a different seed, based on the system clock, will be
used and, in turn, a different sequence of random numbers will be generated. The reserved
variable, nSysTime, contains an ever-changing integer that represents the number of elapsed
milliseconds since the brick was powered up. Mo