Anda di halaman 1dari 55

CHAPTER 2

Operators, Expressions, and the If Statement


A Gentle Introduction
Reference: Brooks, Chapter 2
Continuing from our last session, we now create a new project
This time, we shall include it in the same workspace as our existing project

Copyright (c)1998 by Robert C. Carden IV, Ph.D.


11/10/2015

Types, Operators, and Expressions


Do a File|New and fill in the dialog as we did before
This time, however, I checked the Add to current workspace button
The default would be to make it a subfolder of hello

2-2

Types, Operators, and Expressions


Now our workspace has two projects in it. One is the project from the previous
chapter, hello. The other is our new project, circle.
Notice the hello.c file is still open

2-3

Types, Operators, and Expressions


Select the File|New menu option and fill in the dialog
Notice that you can choose any name you wish for the file, but it must end with a
.c
Visual Studio determines which compiler to invoke according to the file's suffix
A .c file is a C source file. Visual Studio will invoke the C compiler on it.
A .cpp file is a C++ source file. Visual Studio will invoke the C++ compiler on
it.

2-4

Types, Operators, and Expressions


As a result of this, you should see something like what we show below.
An empty window for main.c will appear superimposed on top of the existing
windows
Also, the circle project now has a + to the left of it which we can click

2-5

Types, Operators, and Expressions


Here we have a program to compute the area of a circle
It asks the user to give the radius, performs the computation, the prints out a
result

2-6

Types, Operators, and Expressions


Here again is the program

[Instructor: discuss the components of this program to introduce next section]

/*
* File : main.c
* Author: Robert C. Carden IV
*/
#include <stdio.h>
int main (void)
{
const double pi = 3.14159;
double radius, area;
printf ("Enter the radius of the circle: ");
scanf ("%lf", &radius);
/* area = PI times R^2 */
area = pi * radius * radius;
printf ("Using PI=%g to compute the area...\n", pi);
printf ("The area of a circle of radius %f is %-10.4f\n",
radius, area);
return 0;
}

Here is an example run of this program:

2-7

Types, Operators, and Expressions


Dissection of the Circle Program - Comments
/*
* File : main.c
* Author: Robert C. Carden IV
*/
Comments start with a /* character sequence and end the a */
Comments are remarks and are ignored by the compiler
Programmers include comments to clarify their program, document their work,
and in general, make their programs more understandable to other people and
themselves
Good programmers write comments as they write the code
Comments may span multiple lines (as in the example above) or may be
restricted to one line:
/* area = PI times R^2 */
Comments may also be embedded within a statement:
printf ( /* format */ "Hello world\n");
Many compilers support C++ style comments
In C++ a comment starts with a // and extends to the end of a line
// This is a typical C++ comment
printf ("Hello world\n); // say hello to the world
// printf ("Goodbye cruel world\n");

2-8

Types, Operators, and Expressions


Dissection of the Circle Program - Preprocessor Statements
#include <stdio.h>
Lines starting with a # character are preprocessor statements
Preprocessor statements begin with the # character and extend to the end of that
logical line
Compiling a C program to object code occurs in two phases
In the first phase, a C preprocessor reads in the source code, expands and
replaces all preprocessor directives, and then produces a file ready for
compilation
In the second phase, the output from the preprocessor is compiled by a C
compiler and translated into object code
The preprocessor directive in our original program is a #include statement
The preprocessor will locate the file stdio.h in the standard include folder
In Visual Studio, this folder is probably
C:\Program Files\DevStudio\Vc\include
This single line is replaced by the contents of this file and those contents are
subsequently processed
We can add a second preprocessor director to our program, as well:
#define PI 3.141592654
and can use it in place of the magic number we had before:
const double pi = PI;
This second preprocessor directive is a #define statement
It defines a symbolic constant called PI
All subsequent occurrences of this identifier are replaced by the replacement
text that appears to the right of that identifier
In this example, the replacement text is: 3.141592654

2-9

Types, Operators, and Expressions


Dissection of the Circle Program - main
int main (void)
The first line marks the beginning of the function main
This function is defined to return an int, as in integer
This first line is called a function header (by some) and specifically, a function
definition
The parenthesis may contain declarations of data which we are passing into
main
In this example, we choose to specify nothing
Consider this definition:
void main (void)

In this example, we specify that main returns a void


A void is nothing, devoid of all meaning
Specifying that a function returns void specifies that it returns nothing
By the same token, we specify that main expects a void passed into it
Expecting void means expecting nothing
However, it is considered poor style to define main() to return nothing
because it is non-portable

Notice that there is no semicolon following the function definition


The opening brace
{
marks the beginning of the function body that contains the declarations and
statements implementing the function

2-10

Types, Operators, and Expressions


Dissection of the Circle Program - Declarations
const double pi = PI; /* or 3.141592654 */
double radius, area;
The two lines above are declarations of three variables
The first line declares the existence of a variable called pi which is of type
double, which is also constant (cannot be changed) and whose initial (and
only) value is defined by the macro PI, which expands to 3.141592654
The second line declares two variables
Both variables, radius and area, are to be of type double
Unlike the first line, these variables may be modified and may contain different
values over the life of this function
Also, because we did not specify an initial value, they are left uninitialized
All variables must be declared before they may be used
Each declaration must end with a semicolon
The first declaration declares one identifier
The second declaration declares two identifiers, with the two separated by
commas

2-11

Types, Operators, and Expressions


Dissection of the Circle Program - printf() function
printf ("Enter the radius of the circle: ");
The printf() function is part of the C standard library that comes with the C
compiler
The function printf is used for printing output to the terminal
In <stdio.h>, this function is declared
int printf (const char *format, ...);
This specifies that printf returns an integer (a value we usually ignore) and
expects a format string, followed by zero or more additional arguments
In this example, the format string is
"Enter the radius of the circle: "
Note for future reference that we did not include a \n in the string
The \n is the code for the newline character and tells the computer to start a
new line
In this example, we prefer not to start a new line
In this example, there are no replacement directives such as %d
Because of this, no additional arguments are to be passed to printf()
Only the format string is passed on

2-12

Types, Operators, and Expressions


Dissection of the Circle Program - Comments
scanf ("%lf", &radius);
The scanf() function is part of the C standard library that comes with the C
compiler
The scanf function is used for scanning input from the terminal
In <stdio.h>, this function is declared
int scanf (const char *format, ...);
This specifies that scanf returns an integer and expects a format string, followed
by zero or more additional arguments
In this particular example, the format string contains the replacement directive
%lf which instructs scanf to read in a long float value, i.e. read in a double
value, and store this value in the variable radius
Since scanf needs to return something to us, we must pass a reference to the
variable it needs to store the result in, not just a copy
Thus, we pass in the address of that variable by preceding the variable with an
ampersand (&)
When you learn about and understand pointers, this will make a lot more sense
For now, you must trust me and stick the ampersand (&) in front of all nonarray/string variables that you pass into scanf
Failure to do so will not result in a compiler error but instead a run-time error

2-13

Types, Operators, and Expressions


Dissection of the Circle Program - Statements
/* area = PI times R^2 */
area = pi * radius * radius;
On the previous two pages, you should note that the calls to printf() and scanf()
ended with a semicolon
Here also, the computation of area is performed by a single statement which is
terminated with a semicolon
Semicolons are statement terminators
In general, all statements must end with a semicolon
The only exception is a compound statement that we will encounter later on
The second line is an arithmetic statement
It computes the area of a circle by multiplying the contents of the variable pi
with the contents of the variable radius
It then takes that result and multiplies it with the contents of the variable radius
The final result is stored into the variable area
The resulting assembler on an Intel box might look something like this:
fld QWORD
fmul QWORD
fmul QWORD
fstp QWORD

PTR
PTR
PTR
PTR

_pi$[ebp]
_radius$[ebp]
_radius$[ebp]
_area$[ebp]

On the Unisys A-Series computer, the object code might look something like:
VALC
VALC
VALC
MULT
MULT
NAMC
STOD

3,2
3,3
3,3
3,4

2-14

Types, Operators, and Expressions


Dissection of the Circle Program - printf (again)
printf ("Using PI=%g to compute the area...\n",
pi);
printf ("The area of a circle of "
"radius %f is %-10.4f\n",
radius, area);
Here we have two printf statements giving us the result of our program
It first tells us what value of pi it is using
It then tells us the radius which we specified and the resulting area
In the first printf, the string literal contains a substitution string %g
To match with that, we passed in an additional argument pi
Also, the string literal contains a \n character which tells the computer to start a
new line (which is what we want)
The second printf contains two adjacent string literals
One of the first things the compiler will do is concatenate the two string literals
into one long string literal
This printf and the one shown in the example achieve exactly the same results
In this printf, the resulting format string contains two substitution strings, %f
followed by %-10.4f (and also contains the newline character)
As a result, we must pass in two variables in the proper order
The first substitution string specifies that we are printing out a floating point
value (in this case either float or double will work)
The second substitution string specified that we are printing out a floating point
value but to also use a field width of 10, include 4 decimal places, and left-justify
Left-justify means put the extra blanks on the right
Right-justify means put the extra blanks on the left

2-15

Types, Operators, and Expressions


Dissection of the Circle Program - Wrapping it up
return 0;
}

Since main() is declared to return an integer, it is wise to do so


Returning 0 tells the operating system that main finished successfully
In most cases, the operating system does not care
However, it is good style to declare main to return an int and always return 0
as the result

The closing brace } marks the end of the function main


In general, for every opening brace in C, you must have a corresponding closing
brace later on

2-16

Types, Operators, and Expressions


Identifiers
Reference: Brooks, Chapter 2
letter:
underscore:
digit:
identifier:

[a-zA-Z]
_
[0-9]
(letter | underscore)(letter | underscore | digit)*

That is, an identifier is a string of characters starting with either a letter or


underscore and followed by zero or more letters, underscores, or digits.

examples
identifier
3id
__yes
o_no_o_no
00_go
star*it
1_i_am
one_i_aren't
me_to-2
xYshouldI
int

legal?
no
yes
yes
no
no
no
no
no
yes
yes

reasons for illegality; special notes


cannot start with a digit
cannot start with a digit
* symbol cannot be part of identifier
cannot start with a digit
' symbol cannot be part of identifier
- symbol cannot be part of identifier
keywords are also identifiers

2-17

Types, Operators, and Expressions


Notes on identifiers

C keywords (such is int or while) are identifiers but may not be used as variable
or function names.
C is case sensitive
the identifiers xyz, xYz, and XyZ are all different
Internally, identifiers (variable and function names) are significant to at least the
first 31 characters
Internal identifiers are those that are declared and referenced within a single
compilation unit, i.e. a file. These include:
local variables
static global variables
local functions within a single file
Externally, it may be less (e.g., 14 or 6)
External identifiers are those which are visible to other files
Identifiers are considered to be equivalent if their significant characters are the
same, i.e. if the compiler guarantees at least 31 significant characters, then if at
least one corresponding character in the first 31 are different, the two identifiers
are considered to be different.

2-18

Types, Operators, and Expressions


Basic data types and sizes
Reference: Brooks, Chapter 3 (3.1)
name

semantic meaning

char

size
on
PC
1

A single byte, holds one


character in local character set
short int Integer [short or long]
2
int
2 or 4
int: typically natural size on
long int
4
host machine
float
single-precision floating point
4
double
double-precision floating point
[ANSI: natural size on host
8
machine]
long double super double precision [ANSI]
?
long long GNU C/C++ extension: double
[GNU only]
precision integers

size
under
Unix
1

size on
A-Series
C
1

2 or 4
4
4
4

6
6
6
6

16
8

12
-

The int data type is specified to be the natural integer type for the target
machine. Modifiers short and long request short and long representations of
int.
All we know is that
sizeof short sizeof int sizeof(long)
sizeof(float) sizeof(double) sizeof(long double)
sizeof(int) sizeof(signed int) sizeof(unsigned int)

The double data type is specified under ANSI to be the natural floating point
type for the target machine.
The long long data type is part of GNU C. GNU (Gnu's not Unix) is a
research laboratory at MIT headed by Richard Stallman dedicated to writing a
public domain version of the Unix operating system.

2-19

Types, Operators, and Expressions


Notes on data types

fundamental types are char, int, float, and double


long and short are modifiers
short is an abbreviation for short int
long is an abbreviation for long int
integral types may also be declared to be unsigned or signed
an unsigned integer is one that may never become negative, i.e. conceptually its
sign bit may be used to represent additional positive integers.
short form
unsigned char
char
short
unsigned short
int
unsigned
long
unsigned long
long float

usual meaning
unsigned char
signed char
signed short int
unsigned short int
signed int
unsigned int
signed long int
unsigned long int
double (archaic)

2-20

Types, Operators, and Expressions


Data Types - Integers

Integers are whole numbers


They may have positive or negative values
Negative numbers must be preceded by a - sign
The size and range of integers depends on the machine architecture
C provides three different types of integer types: short, int, and long
On Intel platforms, we can assume that shorts are 16 bits and that longs are 32
bits
An int, under Windows 16 is generally 16 bits whereas under Windows 95 and
Windows NT it is 32 bits
The size of these values is indeed machine and compiler dependent
The standard include file limits.h contains macros which describe these
limits
On my Windows NT system using Visual Studio 5.0, I find:
#define
#define
#define
#define
#define
#define
#define
#define
#define

SHRT_MIN
SHRT_MAX
USHRT_MAX
INT_MIN
INT_MAX
UINT_MAX
LONG_MIN
LONG_MAX
ULONG_MAX

(-32768)
/*
32767
/*
0xffff
/*
(-2147483647 - 1) /*
2147483647
/*
0xffffffff
/*
(-2147483647L - 1)/*
2147483647L
/*
0xffffffffUL
/*

minimum
maximum
maximum
minimum
maximum
maximum
minimum
maximum
maximum

(signed)
(signed)
unsigned
(signed)
(signed)
unsigned
(signed)
(signed)
unsigned

short value
short value
short value
int value
int value
int value
long value
long value
long value

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

From this I can tell that shorts are 16 bits, and that ints and longs are both 32 bits

2-21

Types, Operators, and Expressions


Data Types - Unsigned Integers

The type of int by default is signed


That is, it can represent both positive and negative values
Unsigned integers are integers that can have only positive values
The modifier unsigned is applied to any integer type to specify that it may
represent only positive values
Consequently, the unsigned integer can represent twice as many positive numbers
are its signed counterpart, but cannot represent any negative numbers
An unsigned short, for instance, may represent the numbers 0 through 65,535
compared to short which may represent the numbers -32,768 through 32767
#define
#define
#define
#define
#define
#define
#define
#define
#define

SHRT_MIN
SHRT_MAX
USHRT_MAX
INT_MIN
INT_MAX
UINT_MAX
LONG_MIN
LONG_MAX
ULONG_MAX

(-32768)
/*
32767
/*
0xffff
/*
(-2147483647 - 1) /*
2147483647
/*
0xffffffff
/*
(-2147483647L - 1)/*
2147483647L
/*
0xffffffffUL
/*

minimum
maximum
maximum
minimum
maximum
maximum
minimum
maximum
maximum

2-22

(signed)
(signed)
unsigned
(signed)
(signed)
unsigned
(signed)
(signed)
unsigned

short value
short value
short value
int value
int value
int value
long value
long value
long value

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

Types, Operators, and Expressions


Integer constants

An integer is a string of digits with an optional suffix. The suffixes l or L may


be used to specify that the constant is long, while the suffixes u or U may be
used to specify that the constant is unsigned.
A 0 prefix indicates that the integer is octal (base 8).
A 0x or 0X prefix indicates that the integer is hexadecimal, i.e. base 16.
The type of integer constant is the first of the corresponding list in which its
value can be represented (ANSI draft, section 3.1.3.2)

unsuffixed decimal:
unsuffixed octal or hexadecimal:

int, long, unsigned long


int, long, unsigned long

suffixed by letter u or U:
suffixed by letter l or L:

unsigned int,
unsigned long
long, unsigned long

suffixed by both u or U and l or L:

unsigned long

example
integer
25

semantics
integer

default data type


int

25L

long integer

long

25U

unsigned integer

unsigned int

25LU

unsigned long integer

unsigned long

025

octal integer 25

int

0xff

hexadecimal integer 'ff'

int

0x23AF

hexadecimal integer '23af'

int

025LU

unsigned long integer


octal 25
unsigned integer
hexadecimal 25

unsigned long int

0x25U

2-23

unsigned int

Types, Operators, and Expressions


-25

constant integer expression

0xFFFFFFFF integer large enough to hold this


32 bit quantity

2-24

int
int
unsigned long int

Types, Operators, and Expressions


Integer constants - LIMITS.H
#define
#define
#define
#define
#define
#define
#define
#define
#define

SHRT_MIN
SHRT_MAX
USHRT_MAX
INT_MIN
INT_MAX
UINT_MAX
LONG_MIN
LONG_MAX
ULONG_MAX

(-32768)
/*
32767
/*
0xffff
/*
(-2147483647 - 1) /*
2147483647
/*
0xffffffff
/*
(-2147483647L - 1)/*
2147483647L
/*
0xffffffffUL
/*

minimum
maximum
maximum
minimum
maximum
maximum
minimum
maximum
maximum

(signed)
(signed)
unsigned
(signed)
(signed)
unsigned
(signed)
(signed)
unsigned

short value
short value
short value
int value
int value
int value
long value
long value
long value

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

The above extract is from the standard include file LIMITS.H


SHRT_MAX is defined to be the constant integer 32767
This constant is an unsuffixed decimal integer
Therefore, according to the rules outlined on the previous page, it is an int since
this is the first type on the list {int, long, unsigned long} which is large enough
to represent this number

SHRT_MIN is defined to be a constant integer expression


The constant integer in the constant integer expression is 32768
This constant is an unsuffixed decimal integer
Therefore, according to the rules outlined on the previous page, it is an int since
this is the first type on the list {int, long, unsigned long} which is large enough
to represent this number
Negating that constant integer produces another constant integer of type int
Since the expression involves only constants, the resulting expression is
effectively a constant
Putting parenthesis around the expression does not change the constant-ness of
this expression
USHRT_MAX is defined to be the constant integer 0xFFFF
This constant is an unsuffixed hexadecimal integer
Therefore, according to the rules outlined on the previous page, it is an int since
this is the first type on the list {int, long, unsigned long} which is large enough
to represent this number
The other constants involve more advanced concepts which we will get to later
Particularly, this includes type conversions

2-25

Types, Operators, and Expressions


Floating point constants

Any number with a decimal point or exponent is a floating point constant


The default type is double!
To write a floating point constant of type float, one must use a float suffix, i.e.
either f or F
To write a floating point constant of type long double, one must use a long
suffix, i.e. either l or L
number
25.0

type
double

semantics
25, double precision

2.5e1

double

2.5 * power(10,1)

25e0

double

25 * power(10,0)

25.0F

float

25, single precision floating point

25.0L

long double

25, super double precision

The following are legal floating point constants


1.23

.23

0.23

1.

1.0

1.2e10

1.23e-10 25e0

A space cannot occur in the middle of a floating point constant


For example, 65.43 e-21 is not a floating point but instead four lexical
tokens
65.43

21

2-26

Types, Operators, and Expressions


Range and Precision of Floating Point Types
The precise number of digits and values of variables of type float and double
depend on the particular implementation
The header file float.h contains many constants which define the characteristics
of the floating point numbers on this implementation
Let us consider in detail the float data type
#define
#define
#define
#define
#define
#define
#define
#define
#define

FLT_DIG
6 /* # of decimal digits of precision */
FLT_MANT_DIG 24
/* # of bits in mantissa */
FLT_MAX 3.402823466e+38F /* max value */
FLT_MAX_10_EXP
38
/* max decimal exponent */
FLT_MAX_EXP
128
/* max binary exponent */
FLT_MIN 1.175494351e-38F /* min positive value */
FLT_MIN_10_EXP
(-37)
/* min decimal exponent */
FLT_MIN_EXP
(-125)
/* min binary exponent */
FLT_RADIX
2
/* exponent radix */

The first thing to understand is that floating point numbers are stored in binary
scientific notation
That is it looks something like
e e e p

b1b2 bn bn 1bn 2 bn m 2 1 2

where each subscripted letter is a binary digit


This is generally normalized to look something like
e e e p m

b1b2 bnbn 1bn 2 bn m 2 1 2

In the normalized form, we have two integers: a 24 bit integer consisting of the
b's and an 8 bit integer consisting of the f's
The 24 bit integer is called the mantissa
The 8 bit integer (32-8) is called the exponent or characteristic
The RADIX (which on this system is defined to be 2) is the exponent to which
we raise the exponent

2-27

Types, Operators, and Expressions


Comparing float and double (float.h)
Consider float (32 bits) and its limitations:
#define
#define
#define
#define
#define
#define
#define
#define
#define

FLT_DIG
6 /* # of decimal digits of precision */
FLT_MANT_DIG 24
/* # of bits in mantissa */
FLT_MAX 3.402823466e+38F /* max value */
FLT_MAX_10_EXP
38
/* max decimal exponent */
FLT_MAX_EXP
128
/* max binary exponent */
FLT_MIN 1.175494351e-38F /* min positive value */
FLT_MIN_10_EXP
(-37)
/* min decimal exponent */
FLT_MIN_EXP
(-125)
/* min binary exponent */
FLT_RADIX
2
/* exponent radix */

Compare this to double (64 bits):


#define
#define
#define
#define
#define
#define
#define
#define
#define

DBL_DIG
15 /* # of decimal digits of precision */
DBL_MANT_DIG
53 /* # of bits in mantissa */
DBL_MAX
1.7976931348623158e+308 /* max value */
DBL_MAX_10_EXP 308
/* max decimal exponent */
DBL_MAX_EXP
1024
/* max binary exponent */
DBL_MIN 2.2250738585072014e-308 /* min positive value */
DBL_MIN_10_EXP (-307)
/* min decimal exponent */
DBL_MIN_EXP
(-1021)
/* min binary exponent */
_DBL_RADIX
2
/* exponent radix */

I would have added a section on long double but the current Microsoft compiler
does not support it
In my experience long double is either not supported or poorly supported and
should be avoided

2-28

Types, Operators, and Expressions


Character constants

Enclosed in single quotes, e.g. 'a', 'e', 'E'


Special escape sequences preceded by backslash character, e.g. '\n'
escape seq
\a

alert (bell)

\b

backspace

\f

formfeed

\n

newline

\r

carriage return

\t

horizontal tab

\v

vertical tab

\\

backslash

\?

question mark (Why? '?' works too...)

\'

single quote

\"

double quote (important for string constants)

\0

the zero (null) character

\ooo
\xhh

semantics of escape sequence

octal escape characters, where ooo is 1 to 3 octal digits.


Example: '\025' or '\25'
hex escape characters, where hh is one or two hex
digits. Example: '\x3f'

Single quote character: '\''


Note that ''' is not legal
Double quote character: '"' or '\"'

The following list gives examples of how any machine's character set can be
represented as either an octal constant, a hex constant, or integer ascii value
2-29

Types, Operators, and Expressions

These can then be embedded within character strings


'\6'
'\60'

'\x6'
'\x30'

6
48

ASCII ack
ASCII '0'

'\137'

'\x5f'

95

ASCII '_'

2-30

Types, Operators, and Expressions


String constants (literals)

A string constant begins with a double quote character ("), then contains 0 or
more characters or character escape sequences, and then ending with a double
quote character.

legal examples
"hello world\n"

illegal examples
"hello world
"

"quote \" character"

"quote " character"

"a single 'quote' in a string"


"a multi\nline\nstring\n"
"\ta string starting one tab"
"A string with \\n printed\n"

Strings are null terminated, that is enough space is set aside for all characters
within the string plus one more
The end of the string contains a zero, i.e. '\0'
The null character '\0' has ordinal value of 0
All other characters are nonzero
Adjacent string literals are concatenated

examples
string literal
"Hello"

size
5+1=6

representation
l o \0

"\"Quote\""

7+1=8

"

"

\0

"un"

7+1=8

\0

"Hello\\n\n"

8+1=9

\n

""

0+1=1

\0

"happy"

2-31

\0

Types, Operators, and Expressions


"a\xfah\0129"

5+1=6

\xfa

\12

\0

"a\xfah\129"

5+1=6

\xfa

\12

\0

"a\xad\129"

4+1=5

\xad

\12

"a\xad3\1372"

6+1=7

\xad

2-32

\0

\137

\0

Types, Operators, and Expressions


ANSI trigraphs

Be aware of these though you should never have to use them


Reference: ANSI draft, section 2.2.1.1 (p. 11-12)
"All occurrences in a source file of the following sequences of three
characters (called trigraph sequences) are replaced with the corresponding
single character."
??=
??(
??/
??)
??'
??<
??!
??>
??-

#
[
\
]
^
{
|
}
~

"No other trigraph sequences exist. Each ? that does not begin one of the
trigraphs listed above is not changed."
example
with trigraphs
??=include <stdio.h>
int main()
??<
printf("Eh???/n");
return(0);
??>

after trigraph step


#include <stdio.h>
int main()
{
printf("Eh?\n");
return(0);
}

??=
??<
??/
??>

#
{
\
}

2-33

Types, Operators, and Expressions

[Instructor: Review identifiers, keywords, variable names, and constants in this program]

/*
* File : main.c
* Author: Robert C. Carden IV
*/
#include <stdio.h>
int main()
{
const double pi = 3.14159;
double radius, area;
printf("Enter the radius of the circle: ");
scanf("%lf", &radius);
/* area = PI times R^2 */
area = pi * radius * radius;
printf("Using PI=%g to compute the area...\n", pi);
printf("The area of a circle of "
"radius %f is %-10.4f\n",
radius, area);
}

return(0);

2-34

Types, Operators, and Expressions


Declarations

Variables must be declared before use


Variables may be initialized (as part of their definition)
The const qualifier specifies that a variable is read-only within that scope

syntax:

<declaration>
<decl>

examples
int x;
const int x;
const int y = 5;
int z = 10;
int x, y, z = 20;

::
::

<qualifiers> <type> <decls>


<declaration> <opt-initializer>

interpretation
x is an integer
x is a read-only integer
y is a read-only integer with initial value of 5
z is an integer with initial value of 10
x and y are integers
z is an integer with an initial value of 20

The declaration const int x; is meaningful in the context of a function


parameter declaration:
void foo(const int size)
{
...
}

2-35

Types, Operators, and Expressions

Arithmetic operators
Reference: Brooks, Chapter 3 (3.2 - 3.4)
int
double

i, j;
x, y, z;

operator
+

semantics
addition

subtraction

*
/

multiplication
integer division

real division

integer modulus

examples
i + j
+ x
i - j
- x
i * j
both arguments are integers
i / j
at least one arg is floating point
i / x
x / j
x / y
i % j
both arguments must be integers

Important note on / operator


How / behaves depends on the type of its arguments
If both arguments are integers, the resulting integer division truncates
fractional part. It does not round.
Unary + is a no-op
Unary - negates its argument

2-36

Types, Operators, and Expressions


Example using arithmetic operators
/*
* File : main.c
* Author: Robert C. Carden IV
*/
#include <stdio.h>
void main(void)
{
int
a=10, b=25;
float x=10, y=25;
printf("Arithmetic Operators\n");
printf("a=%d, b=%d\tx=%-4.2f, y=%-4.2f\n", a, b, x, y);
printf("\ta + b = %6d\t\tx + y = %6.2f\n", a+b, x+y);
printf("\ta - b = %6d\t\tx - y = %6.2f\n", a-b, x-y);
printf("\ta * b = %6d\t\tx * y = %6.2f\n\n", a*b, x*y);
printf("\ta / b = %6d\t\tx / y = %6.2f\n", a/b, x/y);
printf("\tb / a = %6d\t\ty / x = %6.2f\n\n", b/a, y/x);
printf("\tx / y = %6.2f\t\ty / x = %6.2f\n", x/y, y/x);
printf("\ta / b = %6d\t\tb / a = %6d\n\n", a/b, b/a);
printf("\ta %% b = %6d\t\tb %% a = %6d\n", a%b, b%a);
}

2-37

Types, Operators, and Expressions


IF-ELSE STATEMENT
Reference: Brooks, Chapter 4 (4.1 - 4.2)
There are two forms for the if-else statement in C
if ( expression )
statement-1

if ( expression )
statement-1
else
statement-2

Semantics
1. The expression is evaluated
2. If true (non-zero), statement-1 is executed.
3. If false (zero), then if there is an else part, then statement-2 is executed
Basic Axiom
FALSE IS ZERO
TRUE IS NOT FALSE

FALSE
TRUE

ZERO
NULL
'\0'
NOT FALSE
NOT 0
NOT NULL
NOT '\0'

2-38

Types, Operators, and Expressions


IF statement usage
The if statement is a control statement that selects alternative statements for
execution based on the result of a test
The simplest form of the if statement is as follows:
if ( condition )
statement ;
More typically, we build a compound statement to be executed
if ( condition )
{
statement1;
statement2;
...
statementN;
}

if

conditi
on
true
statement1
statement2
...
statementN

fals
e

2-39

Types, Operators, and Expressions


Statement and blocks

An expression followed by a semicolon ';' becomes a statement


The semicolon is a statement terminator, not a separator (as in Pascal or Algol)

example
if (x > 5)
x = 5;
else
x++;

/* semicolon is required */
/* but not allowed in Pascal */

Braces { and } are used to group declarations and statements together into a
compound statement (no declarations), or block, so that they are syntactically
equivalent to a single statement.

Null statement

A sole semicolon is a null statement.


Null statements are noops

example
;
;
3;
Here we have two null statements followed by a expression ; form statement
The latter is a statement because 3 is the simplest type of expression

2-40

Types, Operators, and Expressions

Relational and logical operators


Relational operators
>
greater than
>=
greater than or equal to
<
less than
<=
less than or equal to
Equality operators
==
is equal to
!=
not equal to
Logical operators
&&
logical and
||
logical or
Unary logical negation
!
logical negation

if (count < max_items)


{
sum
= sum + count;
count = count + 1;
}
if (sum == MAX_SUM)
printf("You are a winner!!!\n");
if ( !(sum >= max_items) )
printf("sum < max_items...\n");
if ( !sum )
printf("sum is also equal to zero\n");

2-41

Types, Operators, and Expressions


Behavior of operators
Unary +
Unary Binary +
Binary Binary *
Binary /
Binary %
< <= >
&& ||
!

>=

Noop (leaves sign alone)


Changes sign of operand
Addition
Subtraction
Multiplication
Integer or real division
Modulus operator
(integers only)
Relational and logic operators
Return 1 if true, 0 if false

Integers and floating point values may be mixed in an expression


The rule of thumb is that in an expression, if the operands are of different types,
the operand of the lower type is promoted to the higher type.
Let x and n be integers
Then x == (x/n)*n + (x%n)
expression
3 + 5
5 / 3
5 / 2.0
5 < 3
5 > 3
5 % 3
3 % 5
8 % 5
-3 % 5
-3 / 5
-5 / 2
5 / 2

value
8
1
2.5
0
1
2
3
3
-3
0
-2
2

2-42

type
int
int
double
int
int
int
int
int
int
int
int
int

Types, Operators, and Expressions


Expressions in C control structures
Relational operators and expressions
relational_expression

::=
|
|
|

valid examples

invalid examples

a < 3

a =< b
/* out of order */
a < = b
/* space not allowed */
a >> b
/* shift expression */
/*syntactically correct, but
confusing*/

a > b
-1.3 >= (2.0*x + 3.3)
a < b < c

expression < expression


expression > expression
expression <= expression
expression >= expression

In the first invalid example, the = and < signs are out of order
In the second invalid example, the space between < and = causes these to be
treated as two separate tokens, i.e. LESS and ASSIGN, instead of
LESS_EQUAL
In the third invalid example, using >> yields an expression which will compile,
but it is not a relational expression as this section is trying to illustrate
Values of e1-e2
positive
zero
negative

e1 < e2
0
0
1

e1 > e2
1
0
0

2-43

e1 <= e2
0
1
1

e1 >= e2
1
1
0

Types, Operators, and Expressions


Equality operators and expressions
equality_expression
valid examples

invalid examples

c == 'A'

a = b
/*assignment statement*/
a =
= b - 1
/*space not allowed*/
(x + y) =! 44
/* equivalent to (x + y) = (!44) */

k != -2
x + y == 3 * z - 7

Values of
expr1 - expr2
zero
nonzero

::= expression == expression


| expression != expression

expr1 == expr2

expr1 != expr2

1
0

0
1

Observe that the expression a != b is equivalent to !(a == b)


Also note that a == b is a test for equality, while a = b is an assignment
expression.
Writing
if (a = b) ...
instead of
if (a == b) ...
is a common programming error.

2-44

Types, Operators, and Expressions


Logical Operators
Logical operators allow us to combine two or more relational expressions to
build compound test conditions
a

a && b

a || b

! a

! b

nonzero

nonzero

nonzero

nonzero

if ((age >= 18) && (age < 65))


{
printf("You are a non-retirement age adult.\n");
}
if ( ((salary < 10000) || (salary > 1000000)) &&
! independently_wealthy )
{
printf("Please place your thumb on the glass\n");
}

2-45

Types, Operators, and Expressions


Back to the if-else statement
valid examples
if (y != 0.0)
x = x / y;
if ( c == ' ' )
{
blank_cnt = blank_cnt + 1;
printf("blank\n");
}
if (c>='a' && c<='z')
lc_cnt = lc_cnt + 1;
else
{
other_cnt = other_cnt + 1;
printf("%c not lc\n", c);
}

invalid/misleading examples
if b == a
/* parentheses missing */
area = a * a;
if ( i < j )
min = i;
printf("i is smaller than j\n");
/*second statement not part of if*/
if ( i !=
{
i = i +
j = j +
};
else
i = i -

j )
1;
2;
/*syntax error*/
j;

In the first invalid example, the parentheses were missing.


Unlike Pascal, the parentheses separate the expression from the rest of the if-else
statement.
In the second invalid example, the indentation implies that the printf statement is
supposed to be part of the if statement. It is not because the if statement expects
a single statement. To get the desired result, the user must use a compound
statement, i.e. surround the code with braces.
In the third invalid example, the semicolon following the compound statement
belonging to the if is a null statement. Consequently, the else keyword is
completely out of place.

2-46

Types, Operators, and Expressions


If-else (continued)
Consider the following code fragment:
if (n > 0)
if (a > b)
z = a;
else
z = b;
How is this parsed?
Rule:
The else is associated with the closest
previous else-less if
Thus, this is equivalent to writing:
if (n > 0)
{
if (a > b)
z = a;
else
z = b;
}
To get the other form, we must write:
if (n > 0)
{
if (a > b)
z = a;
}
else
z = b;

To be safe, use { } around all statements in an if-else.


This prevents any ambiguity from popping up.

2-47

Types, Operators, and Expressions


Else-if

You can string together if statements using the following approach:


if (expression-1)
statement-1
else if (expression-2)
statement-2
...
else if (expression-k)
statement-k
else
statement-n
This is simply a sequence of if-else statements.
This would be equivalent to writing:
if (expression-1) {
statement-1
} else {
if (expression-2) {
statement-2
} else {
...
} else {
if (expression-k) {
statement-k
} else {
statement-n
}
}
...
}
}
The first form is useful for documenting multiway decisions.

2-48

Types, Operators, and Expressions


Consider precedence
Reference: Brooks, Chapter 3 (3.2)
What does x + y * z represent?
(a) (x + y) * z
(b) x + (y * z)

*
+
x

*
y

The answer is (b) because multiplicative operators have higher precedence than
additive operators and thus bind onto their arguments quicker than the lower
precedence operators.
That is, operators of higher precedence are grouped together first.

What does x - y - z represent?


(a) (x - y) - z
(b) x - (y - z)

The answer is (a) because operators of equal precedence (in this case the
subtraction operator) follow associativity rules.
Additive operators associate from left to right.

2-49

Types, Operators, and Expressions


Precedence of operators

The following table lists the operators we have seen thus far.
The operators of highest precedence are at the top of the table.
Operators of lower precedence are listed below those of higher precedence
Operators in the same row are of equal precedence
Operator
()
+ (unary) - (unary)
* / %
+ < <= > >=
== !=
&&
||

Associativity
left to right
right to left
left to right
left to right
left to right
left to right
left to right
left to right

(Reference: p. 53 of K&R)

2-50

Types, Operators, and Expressions


Exercise
Fully parenthesize the following expressions.
x + y + z
x * y / z + t - v
x <= y == z >= t
x && y || z && t
x + y - z + t - v
-x + -y * z
x <= y <= z
x <= y && y || t >= x
x == y <= z || y >= t != x
x * y % z * t
x && y || z || t && v && w
x > y < z >= t != v <= w
x * y != a / b <= c - -a * -b
a - -b + +c - d - -f + g
a && b > c || d < e < f != g

2-51

Types, Operators, and Expressions


Answer to exercise
((x + y) + z)
((((x * y) / z) + t) - v)
((x <= y) == (z >= t))
((x && y) || (z && t))
((((x + y) - z) + t) - v)
((-x) + ((-y) * z))
((x <= y) <= z)
(((x <= y) && y) || (t >= x))
((x == (y <= z)) || ((y >= t) != x))
(((x * y) % z) * t)
(((x && y) || z) || ((t && v) && w))
((((x > y) < z) >= t) != (v <= w))
((x * y) != ((a / b) <= (c - ((-a) * (-b)))))
(((((a - (-b)) + (+c)) - d) - (-f)) + g)
((a && (b > c)) || (((d < e) < f) != g))

2-52

Types, Operators, and Expressions


Potential pitfall
Consider the following code fragment:
if (10 <= x <= 20)
{
printf("x(%d) is between 10 and 20\n", x);
}
else
{
printf("x(%d) < 10 or > 20\n", x);
}

This will compile and run, but it will not give the desired result.
The first part of the if-else will always execute because the expression is always
true.
The reason is that the expression 10 <= x <= 20 is really equivalent to the
expression (10 <= x) <= 20 and the first subexpression evaluates to either
0 or 1.
In strongly typed languages such as Pascal, the first subexpression would yield a
BOOLEAN type which in turn could not be compared to an integer.

2-53

Types, Operators, and Expressions


Example

A year is a leap year if it is divisible by 4, but not by 100, except that years
divisible by 400 are leap years.

void leap_year(int year)


{
if (year % 4 == 0 && year % 100 != 0
|| year % 400 == 0)
printf("%d is a leap year\n", year);
else
printf("%d is not a leap year\n", year);
}
year % 4 == 0 When the remainder is 0, that implies that year is
divisible by 4.
Note that && has higher precedence than ||.
Another way to write it without logical && or ||:
void leap_year(int year)
{
int leap_flag;
if (year % 400 == 0)
leap_flag = 1;
else if (year % 100 == 0)
leap_flag = 0;
else if (year % 4 == 0)
leap_flag = 1;
else
leap_flag = 0; /*not divisible by 4*/

if (leap_flag)
printf("%d is a leap year\n", year);
else
printf("%d is not a leap year\n", year);

2-54

Types, Operators, and Expressions


OPERATORS -- ORDER OF EVALUATION

In general, the order in which operators are evaluated is undefined


For example, in the expression (x + y) + (z - t) we should assume that each
subexpression (x + y) and (z - t) is evaluated in parallel
Logical && and logical || define order of evaluation to be left to right, short
circuit
That is, "expressions connected by && or || are evaluated left to right, and
evaluation stops as soon as the truth or falsehood of the result is known." (p.41,
K&R)
This is often called short circuit evaluation

Example
#include <stdio.h>
int
{
int
{
int
{

foo()
printf("foo\n"); return(1); }
bar()
printf("bar\n"); return(0); }
fubar()
printf("fubar\n"); return( foo() || bar(); ) }

main()
{
if ( foo() && bar() && fubar() )
return( foo() );
else
return( fubar() && foo() );
}
What gets printed? (exercise)

2-55

Anda mungkin juga menyukai