For example, the statement enum day a,b,c; declares the variables a, b,and c to be of type day,and is consistent with thedeclaration of variables using standard C data types such as char
Trang 113.1 The AND Operator
Program 13-2 uses this masking property to convert lowercase letters in ~
word into their its uppercase form, assuming the letters are stored using the
ASCII code The algorithm for converting letters is based on the fact that the
binary codes for lowercase and uppercase letters in ASCIIare the same except for
bit 6, which is 1 for lowercase letters and 0 for uppercase letters For example, the
binary code for the letter a is 01100001 (hex 61), while the binary code for the
letter A is 01000001 (hex 41) Similarly, the binary code for the letter z is
01111 010 (hex 7A), while the binary code for the letter Z is 01011 010 (hex SA),
(See Appendix F for the hexadecimal values of the uppercase and lowercase let~
ters.) Thus, a lowercase letter can be converted into its uppercase form by forcing
the sixth bit to zero This is accomplished in Program 13-2by masking the letter's
code with the binary value 11011111, which has the hexadecimal value OF
}Ol, Program 13-2
#include <stdio.h>
main( )
{
char word[81]; /* enough storage for a complete line */
void upper(char *); /* function prototype */
*word++ &= OXDF;
A sample run using Program 13-2follows:
Enter a string of both upper and lowercase letters:
Trang 2Notice that the lowercase letters are converted to uppercase form, whileuppercase letters are unaltered This is because bit 6 of all uppercase letters iszero to begin with, so that forcing this bit to zero using the mask has no effect.Only when bit 6 is a one, as it is for lowercase letters, is the input characteraltered.
13.2 The Inclusive OR Operator
The inclusive OR operator, I, performs a bit-by-bit comparison of its twooperands in a fashion similar to the bit-by-bit AND The result of the OR compar-ison, however, is determined by the following rule:
The result of the comparison is 1 if either bit being compared is a 1, wise the result is a O
other-Figure 13-2 illustrates an OR operation As shown in the figure, when either
of the two bits being compared is a 1, the result is a 1, otherwise the result is a O
As with all bit operations, the result of each comparison is, of course, dent of any other comparison
indepen-Program 13-3 illustrates an OR operation, using the octal values of theoperands illustrated in Figure 13-2
Jql, Program 13-3
#include <stdio.h>
main( )
{
int op1 = 0325, op2 = 0263;
printf("%o ORed with %0 is %0",op1, op2, op1 I op2);
Program 13-3 produces the following output:
325 ORed with 263 is 367The result of ORing the octal numbers 325 and 263 is the octal number 367.The binary equivalent of 367 is 1 1 1 1 0 1 1 1, which is the result of the ORoperation illustrated in Figure 13-2
Inclusive OR operations are extremely useful in forcing selected bits to take
on a 1 value or for passing through other bit values unchanged This is a directresult of the fact that ORing any bit (l or0)with a 1 forces the resulting bit to be a
1, while ORing any bit (l or 0) with a a leaves the original bit unchanged For
Trang 313.2 The Inclusive OR Operator
1 0 1 1 0 0 1 1
1 1 0 1 0 101
111 1 0 1 1 1
FIGURE 13-2 A Sample OR Operation
example, assume that the variable opl has the arbitrary bit pattern x x x x x
x x x, where each x can be either 1 or 0, independent of any other x in the
num-ber The result of ORing this binary number with the binary number 1 1 1 1 0
As can be seen from this example, the ones in op2 force the resulting bits to 1,
while the zeros in op2 filter, or pass, the respective bits in opl through with no
change in their values Thus, using an OR operation a masking operation similar;
to an AND operation can be produced, except the masked bits are set to ones
rather than cleared to zeros Another way of looking at this is to say that ORing
with a zero has the same effect as ANDing with a one
Program 13-4 uses this masking property to convert uppercase letters in a
Trang 4word into their respective lowercase form, assuming the letters are stored usingthe ASCII code The algorithm for converting letters is similar to that used inProgram 13-2 It converts uppercase letters into their lowercase form by forcingthe sixth bit in each letter to a one This is accomplished in Program 13-4 bymasking the letter's code with the binary value 00100000, which has the hex-adecimal value 20.
A sample run using Program 13-4 follows:
Enter a string of both upper and lowercase letters: abcdefgHIJKLMNOPqrstuvwxyz
The string of letters just entered is:
abcdefgHIJKLMNOPqrstuvwxyz This string in lowercase letters is:
abcdefghijklrnnopqrstuvwxyzNotice that the uppercase letters are converted to lowercase form, while low-ercase letters are unaltered This is because bit 6 of all lowercase letters is one tobegin with, so that forcing this bit to one using the mask has no effect Onlywhen bit 6 is a zero, as it is for uppercase letters, is the input character altered
13.3 The Exclusive OR Operator
The exclusive OR operator, A, performs a bit-by-bit comparison of its twooperands The result of the comparison is determined by the following rule:The result of the comparison is 1 if one and only one of the bits being com-pared is a I, otherwise the result is O
Figure 13-3 illustrates an exclusive OR operation As shown in the figure,when both bits being compared are the same value (both 1 or both 0), the result is
a zero Only when both bits have different values (one bit a 1 and the other a 0) isthe result a 1 Again, each pair or bit comparison is independent of any other bitcomparison
An exclusive OR operation can be used to create the opposite value, or plement, of any individual bit in a variable This is a direct result of the fact thatexclusive ORing any bit (1 or 0) with a 1 forces the resulting bit to be of the oppo-site value of its original state, while exclusive ORing any bit (1 or 0) with a a
com-leaves the original bit unchanged For example, assume that the variable op1has
FIGURE 13-3 A Sample Exclusive OR Operation
1 0 1 1 0 0 1 1
~ 1 1 0 1 0 1 0 1
o 1 1 0 0 110
Trang 513.3 The Exclusive OR Operator
the arbitrary bit pattern x x x x x x x x, where each x can be either 1 or 0,
independent of any other x in the number Using the notation that x is the com~
plement (opposite) value of x, the result of exclusive ORing this binary numbe~
523
oplop2Result
x x x x x x x x
o 1 0 1 010 1-
x x x x x x x x
As can be seen from this example, the ones in op2 force the resulting bits to
be the complement of their original bit values, while the zeros in op2 filter, or
pass, the respective bits in opl through with no change in their values
Many encryption methods use the exclusive OR operation to code data For
example, the string Hello there world! initially used in Program 1-1 can be
encrypted by exclusive ORing each character in the string with a mask value of
52 The choice of the mask value, which is referred to as the encryption key, is
arbitrary Any key value can be used
Program 13-5uses an encryption key of 52 to code a user-entered message
void encrypt (char *);
/* enough storage for a complete ltne *//* function prototype*/
Trang 6-The sentence just entered is:
Good morning The encrypted version of this sentence is:
s[[P Y[FZ]ZS
Note that the encrypted version appears to have fewer characters This is due
to the non-printable codes contained within the encrypted version Decoding anencrypted message requires exclusive GRing the coded message using the origi-nal encryption key, which is left as a homework exercise
13.4 The Complement Operator
The complement operator, -, is a unary operator that changes each 1 bit in itsoperand to a and each a bit to 1 For example, if the variable op1 contains thebinary number 11001010, -op1.replaces this binary number with the number
0011 0101 The complement operator is used to force any bit in an operand tozero, independent of the actual number of bits used to store the number Forexample, the statement
op1 op1 & -07;
or its shorter form,
op1 &= -07;
both set the last three bits of op1 to zero, regardless of how op1 is stored withinthe computer Either of these two statements can, of course, be replaced byANDing the last three bits of op1 with zeros, if the number of bits used to storeop1 is known In a computer that uses 16 bits to store integers, the appropriateAND operation is:
op1 = op1 & 0177770;
For a computer that uses 32 bits to store integers, the above AND sets the most or higher order 16 bits to zero also, which is an unintended result The cor-rect statement for 32 bits is:
left-op1 = op1 & 037777777770;
Using the complement operator in this situation frees the programmer fromhaving to determine the storage size of the operand and, more importantly,makes the program portable between machines using different integer storagesizes
Trang 713.5 Different Size Data Items
13.5 Different-Size Data Items
When the bit operators &, I, and" are used with operands of different sizes, the
shorter operand is always increased in bit size to match the size of the larger
operand Figure 13-4 illustrates the extension of a 16-bit unsigned integer into a
As the figure shows, the additional bits are added to the left of the original
number and filled with zeros This is the equivalent of adding leading zeros to
the number, which has no effect on the number's value
When extending signed numbers, the original leftmost bit is reproduced in
the additional bits that are added to the number As illustrated in Figure 13-5, if
FIGURE 13-4 Extending 16-Bit Unsigned Data to 32 Bits
16 bits
A.
r - -,
A sign bit of 0 OXXXXXXXXXXXXXXX either 1 or 0
16 zeros The original 16 bits
Trang 8the original leftmost bit is 0, corresponding to a positive number, 0 is placed ineach of the additional bit positions If the leftmost bit is 1, which corresponds to anegative number, 1 is placed in the additional bit positions In either case, theresulting binary number has the same sign and magnitude as the original number.
13.6 The Shift Operators
The left shift operator, «, causes the bits in an operand to be shifted to the left
by a given amount For example, the statement
op1 = op1 « 4;
causes the bits in op1 to be shifted four bits to the left, filling any vacated bitswith a zero Figure 13-6 illustrates the effect of shifting the binary number
1111100010101011 to the left by four bit positions
For unsigned integers, each left shift corresponds to multiplication by 2 This isalso true for signed numbers using two's complement representation, as long asthe leftmost bit does not switch values Since a change in the leftmost bit of a two'scomplement number represents a change in both the sign and magnitude repre-sented by the bit, such a shift does not represent a simple multiplication by 2.The right shift operator, », causes the bits in an operand to be shifted to theright by a given amount For example, the statement
For unsigned numbers, the leftmost bit is not used as a sign bit For this type
of number, the vacated leftmost bits are always filled with zeros This is the casethat is illustrated in Figure 13-7a
For signed numbers, what is filled in the vacated bits depends on the
comput-er Most computers reproduce the original sign bit of the numbcomput-er Figure 13-7b
FIGURE 13-{j An Example of a Left Shift
Each bit is shifted to the leftbythe designated number of places
VVacated bit positionsare filledwithzeros
Trang 913.6 The Shift Operators
•• Each bit is shifted to the right by
the designated number of places
••
527
Vacated bit positions
are filled with zeros
FIGURE 13-7a An Unsigned Arithmetic Right Shift
The sign bit is a 1
+
••
v
Vacated bit positions
are filled with 1s
Each bit is shifted to the right by the designated number of places
••
FIGURE 13-7b The Right Shift of a Negative Binary Number
The sign bit is a zero
+
••
V
Vacated bit positions
are filled with Os
Each bit is shifted to the right by the designated number of places
••
FIGURE 13-7c The Right Shift of a Positive Binary Number
Trang 10illustrates the right shift of a negative binary number by four bit positions, wherethe sign bit is reproduced in the vacated bits Figure 13-7c illustrates the equiva-lent right shift of a positive signed binary number.
The type of fill illustrated in Figures 13-7b and c, where the sign bit is duced in vacated bit positions, is called an arithmetic right shift In an arithmeticright shift, each single shift to the right corresponds to a division by 2
repro-Instead of reproducing the sign bit in right-shifted signed numbers, somecomputers automatically fill the vacated bits with zeros This type of shift iscalled a logical shift For positive signed numbers, where the leftmost bit is zero,both arithmetic and logical right shifts produce the same result The results ofthese two shifts are different only when negative numbers are involved
Exercises for Chapter 13
1 Determine the results of the following operations:
a. 11001010 b. 11001010 c 11001010
& 10100101 I 10100101 A 10100101
2 Write the octal representations of the binary numbers given in Exercise 1.
3 Determine the octal results of the following operations, assuming unsigned numbers:
a the octal number 0157 shifted left by one bit position
b the octal number 0701 shifted left by two bit positions
c the octal number 0673 shifted right by two bit positions
d the octal number 067 shifted right by three bit positions
4 Repeat Exercise 3 assuming that the numbers are treated as signed values.
5a Assume that the arbitrary bit pattern xxxxxxxx, where each x can represent either 1
or 0, is stored in the integer variable flag Determine the octal value of a mask that can
be ANDed with the bit pattern to reproduce the third and fourth bits of flag and set all other bits to zero The rightmost bit in flag is considered bit zero.
b Determine the octal value of a mask that can be inclusively ORed with the bit pattern
in flag to reproduce the third and fourth bits of flag and set all other bits to one Again, consider the rightmost bit in flag to be bit zero.
c Determine the octal value of a mask that can be used to complement the values of the
third and fourth bits of flag and leave all other bits unchanged Determine the bit operation that should be used with the mask value to produce the desired result.
6a Write the two's complement form of the decimal number -1, using eight bits (Hint:
Refer to Section 1.7 for a review of two's complement numbers.)
b. Repeat Exercise 6a using 16 bits to represent the decimal number -1 and compare your answer to your previous answer Could the 16-bit version have been obtained by sign-extending the 8-bit version?
7 As was noted in the text, Program 13-2 has no effect on uppercase letters Using the ASCII codes listed in Appendix F, determine what other characters would be unaffected
by Program 13-2.
8 Modify Program 13-2 so that a complete sentence can be read in and converted to
lowercase values (Hint: When a space is masked by Program 13-2, the resulting character
is \0, which terminates the output.)
9 Modify Program 13-4 to allow a complete sentence to be input and converted to uppercase letters Make sure that your program does not alter any other characters or symbols entered.
Trang 1113.7 Chapter Summary
10 Modify Program 13-5 to permit the encryption key to be a user-entered input value.
'11 Modify Program 13-5 to have its output written to a file named coded.dat.
12 Write a C program that reads the encrypted file produced by the program written for
Exercise 10, decodes the file, and prints the decoded values.
13 Write a C program that displays the first eight bits of each character value input into a
variable named ch (Hint:Assuming each character is stored using eight bits, start by
using the hexadecimal mask 80, which corresponds to the binary number 10000000 If
the result of the masking operation is a zero, display a zero; else display a one Then shift
the mask one place to the right to examine the next bit, and so on until all bits in the
variable ch have been processed.)
14 Write a C program that reverses the bits in an integer variable named okay and stores
the reversed bits in the variable named rev_okay For example, if the bit pattern
11100101, corresponding to the octal number 0345, is assigned to okay, the bit pattern
10100111, corresponding to the octal number 0247, should be produced and stored in
rev_okay.
1 Individual bits of character and integer variables and constants can be
manipulated using C's bit operators These are the AND, inclusive OR,
exclusive OR, one's complement, left shift, and right shift operators
2 The AND and inclusive OR operators are useful in creating masks These
masks can be used to pass or eliminate individual bits from the selected
operand The exclusive OR operator is useful in complementing an operand's
bits
'3 When the AND and OR operators are used with operands of different sizes,
the shorter operand is always increased in bit size to match the size of the
larger operand
4 The shift operators produce different results depending on whether the
operand is a signed or an unsigned value
529
Trang 12Command Line ArgumentsThe goto StatementChapter Summary
Chapter Fourteen
Trang 1314.1 Expressions Revisited
Previous chapters presented C's basic capabilities and structure The variations
on these capabilities, which are almost endless, are a source of delight to many
programmers who continuously find new possibilities of expression using
varia-tions of the basic language building blocks This chapter presents some of these
additional capabilities
14.1 Expressions Revisited
One of the most common pitfalls in C results from misunderstanding the full
implications of an expression Recall that an expression is any combination of
operands and operators that yields a result This definition is extremely broad
and more encompassing than is initially apparent For example, all of the
follow-ing are valid C expressions:
a + 5
a = b
a == b
a = b = c = 6flag = a == bAssuming that the variables are suitably declared, each of the above expres-
sions yields a result Program 14-1 uses the printf ( )function to display the
value of the first three expressions for specific initial values of the variables a
printf("\nThe value of the first expression is %d", a + 5);
printf("\nThe value of the second expression is %d", a == b); printf("\nThe value of the third expression is %d", a = b );
The display produced by Program 14-1 is:
The value of the first expression is 12
The value of the second expression is 0
The value of the third expression is 10
As the output of Program 14-1 illustrates, each expression, by itself, has a
value associated with it The value of the first expression is the sum of the
vari-531
Trang 14able a plus 5, which is 12 The value of the second expression is zero, since a isnot equal to b, and a false condition is represented in C with a value of zero Ifthe values in a and b had been the same, the conditional expression a = = bwould be true and would have a value of 1 The value of the third expression is
10, which is also assigned to the variable a
In this section we will review the rules for evaluating expressions with ple operators and "mixed" operands of different data types We will also intro-duce a new expression type and C operator
multi-Expressions containing multiple operators are always evaluated by the
priori-ty, or precedence, of each operator Table E-l in Appendix E lists the relative ority of each C operator and its associativity
pri-Even when the order of evaluation is known, expressions with multiple ators can still produce unusual and undesired results, remaining a potential trapfor the unwary For example, consider the statement
oper-flag = a == bi
Consulting Table E-l we see that the == operator has a higher precedencethan the = operator Therefore, a is first compared to b If a is equal to b, theresult of the expression a == b is 1, otherwise it is O.The value of this expres-sion is then assigned to flag. Thus, the variable flag will have either a value of
1 or a value of 0 after the statement is executed A problem arises if the sion is inadvertently typed as flag = a = b Here, the value of b is firstassigned to a,which is then assigned to flag. Because of the mistake of typing
expres-an equal operator instead of the comparison operator, flag is assigned the value
of b, rather than the 1 or 0 that was intended
The real problem with the statement flag = a == bi is that it has beenused in place of the more obvious and complete statement
if (a b) flag 1i
else flag ai
Although the same error can be made in substituting an equal operator forthe comparison operator in this statement, the error can be detected more easilythan in the more obscure expression flag = a == b
Because of the generality of C expressions and the fact that most sequences ofoperands connected by operators can be evaluated to produce a result (including
an unintended one), it is extremely important to be careful in creating' sions To avoid undesired results and to make program checking, testing, anddebugging easier, keep expressions as simple and as uncomplicated as possible.Generally expressions using arithmetic operators (+, -, *, /, %,etc.) should not bemixed with expressions using relational and logical operators (==, <, >, &&, I I,etc.), which, in turn, should not be mixed with expressions using bit operators(&, I,etc.)
expres-Finally, although Table E-l appears to be all-inclusive, it is not In particular,the order of evaluations for operands is not specified, as it is not specified inmost computer languages For example, in the expression a + b it is not knownwhich operand is accessed first Generally this is not a problem because the order
of operand access doesn't affect the result of the expression However, in sions such as:
Trang 15expres-14.1 Expressions Revisited
(val[i]) + (i++)
the order of access is important Here the subscript may be either the old or the
new value of i, depending on which operand is accessed first
Similarly, the order of evaluation of function arguments is not specified in C
Thus, the function call
printf("%d %d", i, i++);
may result in the same number being printed twice if the second argument is
evaluated before the first argument
Expressions that depend on the order of operand access should always be
avoided, because they can produce different results on different computers Such
expressions can always be replaced with temporary variables that explicitly
define the desired evaluation order For example, the statements
n = ++i;
printf("%d %d", i, n);
clearly indicate the values that are passed to the print f ( ) function
Conditional Expressions
In addition to expressions formed with the arithmetic, relational, logical, and bit
operators, C provides a conditional expression A conditional expression uses the
conditional operator, ? : It provides an alternate way of expressing a simple
The general form of a conditional expression is:
expressionl ? expression2 : expression3
If the value of expressionl is nonzero (true), expression2 is evaluated,
otherwise expression3 is evaluated The value for the complete conditional
expression is the value of either expression2 or expression3, depending on
which expression was evaluated As always, the value of the expression may be
Conditional expressions are most useful in replacing simple if - e 1s e
state-ments For example, the if-else statement
if ( hours> 40)rate 045;
Trang 16operator, ?:, has a higher precedence than the assignment operator Within theconditional expression, the expression hours > 40 is evaluated first If thisexpression has a nonzero value, which is equivalent to a logical true value, thevalue of the complete conditional expression is set to .045; otherwise the condi-tional expression has a value of 02 Finally, the value of the conditional expres-sion, either .045 or.02,is assigned to the variable rate.
The conditional operator, ?:, is unique in C in that it is a ternary operator.This means that the operator connects three operands The first operand isalways evaluated first It is usually a conditional expression that uses the logicaloperators The next two operands are any other valid expressions, which can besingle constants, variables, or more general expressions The complete condition-
al expression consists of all three operands connected by the conditional operatorsymbols, ?and :
Conditional expressions are only useful in replacing if - e 1s e statementswhen the expressions in the equivalent if-else statements are not long or com-plicated For example, the statement
max_val = a > b ? a : b;
is a one-line statement that assigns the maximum value of the variables a and b
to max_val A longer, equivalent form of this statement is:
if (a > b)max_val a;
elsemax_val b;
Because of the length of the expressions involved, a conditional expressionwould not be useful in replacing the following if - e 1s e statement:
if (amoun t > 2 0000 )taxes 025(amount - 20000) + 400;
elsetaxes 02 * amount;
Exercises 14.1
1 Evaluate the following expressions Assume that all variables are integers and that a has a value of 2, b has a yalue of 3, c has a value of 4, and d has a value of 5 before each expression is evaluated.
Trang 1714.2 User Specified Data types
2 Whichof the expressionsin Exercise1 should not be included in a program?Why?
3 Rewritethe statement a = b = c = amount * rate; as a seriesof three individual
assignmentstatements
4 Rewritethe followingstatementsas if-else statements:
a. flag = a >= b;
b. flag = a == b I I c == d;
5 Rewritethe statementsin Exercise4 using conditionalexpressions
6 Rewriteeach of the followingif-else statementsusing a conditionalexpression:
14.2 User-Specified Data Types
In this section we present two user-specified data types The first permits a user
to create new data types Since the creation of a data type requires the
program-mer to specifically list or enuprogram-merate the values appropriate to the data type, these
data types are referred to as enumerated data types The second capability allows
the programmer to create new names for existing data types
Enumerated Data Types
An enumerated data type is a user-created data type in which the values
appro-priate to the data type are specified in a user-defined list Such data types are
identified by the reserved word enum followed by an optional, user-selected
name for the data type and a listing of acceptable values for the data type
Consider the following user-specified data types:
enum flag {true, false};
enum time {am, pm};
enum day {man, tue, wed, thr, fri, sat, sun};
enum color {red, green, yellow};
535
Trang 18The first user-specified data type is the type flag.Any variable subsequentlydeclared to be of this type can take on only a value of true or false The secondstatement creates a data type named time.Any variable subsequently declared
to be of type time can take on only a value ofam orpm.Similarly, the third andfourth statements create the data types day and color,respectively, and list thevalid values for variables of these two types For example, the statement
enum day a,b,c;
declares the variables a, b,and c to be of type day,and is consistent with thedeclaration of variables using standard C data types such as char, int, float,
ordouble.Once variables have been declared as enumerated types, they may beassigned values or compared to variables or values appropriate to their type.This again is consistent with standard variable operations For example, for thevariables a, b, and cdeclared above, the following statements are valid:
a = red;
b = a;
if (c == yellow) printf("\nThe color is yellow");
Internally, the acceptable values for each enumerated data type are orderedand assigned sequential integer values beginning with O For example, for thevalues of the user-defined type color, the correspondences created by the Ccompiler are that red is equivalent to 0,green is equivalent to I, and yellow isequivalent to 2 The equivalent numbers are required when inputting valuesusing scanf ( )or printing values using printf ( ).Program 14-2 illustrates auser-defined data type
Jql, Program 14-2
#include <stdio.h>
main( )
{
enum color {red,green,yellow};
enum color crayon = red; /* crayon is declared to be of type */
/* color and initialized to red */ printf ("\nThe color is %d", crayon);
printf("\nEnter in a value: ");
scanf("%d", &crayon);
if (crayon == red)
printf("The crayon is red.");
else if (crayon == green)
printf("The crayon is green.");
else if (crayon == yellow)
printf ("The crayon is"'yellow ") ;
else
printf("The color is not defined.");
Trang 1914.2 User Specified Data types
A sample run of Program 14-2produced the following output:
The color is 0Enter a value: 2The crayon is yellow
As illustrated in Program 14-2, expressions containing variables declared as
user-defined data types must be consistent with the values specifically listed for
the type Although a switch statement would be more appropriate in Program
14-2, the expressions in the if-else statement better highlight the use of
enu-merated values Program 14-2 also shows that the initialization of a
user-speci-fied data type variable is identical to the initialization of standard data type
vari-ables For input and output purposes, however, the equivlent integer value
assigned by the C compiler to each enumerated value must be used in place of
the actual data type value This is also seen in the program
In order to assign equivalent integers to each user-specified value, the C
compiler retains the order of the values as they are listed in the enumeration
A side effect of this ordering is that expressions can be constructed using
rela-tional and logical operators For example, for the data type color created in
Program 14-2, expressions such as crayon < yellow and red < green are
both valid
The numerical value assigned by the compiler to enumerated values can be
altered by direct assignment when a data type is created For example, the
defini-tion
enum color (red,green = 7, yellow);
causes the compiler to associate the value red with the integer () and the value
green with the integer 7 Altering the integer associated with the value green
causes all subsequent integer assignments to be altered too; thus, the value
yel-low is associated with the integer 8 If any other values were listed after yelyel-low,
they would be associated with the integers 9, 10, II, and so on, unless another
alteration was made
Naming a user-defined data type is similar to naming a template for
struc-tures Just as a template name can be omitted when defining a structure by
declaring the structure directly, the same can be done with user-defined data
types For example, the declaration enum {red, green, yellow} crayon;
defines crayon to be an enumerated variable with the valid values of red,
green, and yellow
Scope rules applicable to the standard C data types also apply to
enumer-ated data types For example, placing the statement enum color {red,
green', yellow}; before the main ( ) function in Program 14-2 would make
the data type named color global and available for any other function in the
file
Finally, since there is a one-to-one correspondence between integers and
user-defined data types, the cast operator can either coerce integers into a
user-speci-fied data value or coerce a user-speciuser-speci-fied value into its equivalent integer
Assuming that val is an integer variable with a value of I, and color has been
declared as in Program 14-2,the expression (enum color) val has a value of
green and the expression (int) yellow has a value of2. The compiler will
not warn you, however, if a cast to a nonexistent value is attempted
537
Trang 20Thetypedef Statement
In addition to creating new data types, C allows both standard and user-defineddata types to be renamed using typedef statements The statement
typedef float REAL;
makes the name REALa synonym for float The name REALcan now be used inplace of the term float anywhere in the program after the synonym has beendeclared For example, the definition
typedef float REAL;
actually specifies that REALis a placeholder that will be replaced with anothervariable name A subsequent declaration such as
REAL val;
has the effect of substituting the variable named val for the placeholder namedREALin the terms following the word typedef Substituting val for REALinthe typedef statement and retaining all terms after the reserved word typedefresults in the equivalent declaration float val;
Once the mechanics of the replacement are understood, more useful lences can be constructed Consider the statement
equiva-typedef int ARRAY[lOO];
Here, the name ARRAYis actually a placeholder for any subsequently definedvariables Thus, a statement such as ARRAY first, second; is equivalent tothe two definitions
int first[lOO];
int second[lOO];
Trang 2114.3 Defining Macros
Each of these definitions is obtained by replacing the name ARRAY with the
variable names first and second in the terms following the reserved word
typedef
As another example, consider the following statement:
typedef struct
char name[20Jiint id_numi
EMP_RECi
Here EMP _REC is a convenient placeholder for any subsequent variable For
example, the declaration EMP _REC employee [75Ji is equivalent to the
decla-ration
structchar name[20Jiint id_numiemployee [75Ji
This last declaration is obtained by directly substituting the term
emplo:0-ee [75Jin place of the word EMP_REC in the terms following the word typed~f
in the original typedef statement
14.3 Defining Macros
In its simplest form, the #define preprocessor is used to equate constants and
operators to symbolic names For example, the statement
#define SALESTAX 05equates the symbolic name SALESTAX to the number 05.When SALESTAX is
used in any subsequent statement or expression the equivalent value of 05 is
substituted for the symbolic name The substitutions are made by the C
prepro-cessor just prior to program compilation
C places no restrictions on the equivalences that can be established with the
#define statement The symbolic name following the #define designation can
be equated to any text and can even include arguments For example, all of the
following are valid equivalences:
3.1416
*
"The answer is if"
The use of these equivalence statements is illustrated in Program 14-3
Trang 22float circum, radius = 6.3;
circum EQUALS2.0 TIMES PI TIMES radius;
printf(FORMAT,circum);
Before Program 14-3 is compiled, the preprocessor directly substitutes theequivalent operator, constant, variable, or text in place of each subsequent occur-rence of the symbolic name
In addition to using #define preprocessor statements for simple lences, as in Program 14-3, these statements can also be used to equate symbolicnames to either partial or complete expressions When the equivalent text con-sists of more than a single value, operator, or variable, the symbolic name isreferred to as amacro, and the substitution of the text in place of the symbolicname is called amacro expansion or macro substitution. The word macro refers tothe direct, in-line expansion of one word into many words For example, theequivalence established by the statement
equiva-#define CONVERTenables us to write the statement
2.0 * 3.1416
circum = CONVERT* radius;
When this statement is encountered by the preprocessor, the symbolic nameCONVERTis replaced by the equivalent text 2.0 * 3.1416 The compiler alwaysreceives the expanded version after the text has been inserted in place of the sym-bolic name by the preprocessor This direct substitution of the text for CONVERToccurs in every place that CONVERTis encountered after it has been defined Thisallows a previously defined symbolic name to be used in subsequent symbolicdefinitions For example, the definition for CONVERTcould have been establishedusing the following set of #define statements:
#define PI
#define CONVERT
3.14162.0 * PISince PI is made equivalent to the constant 3.1416 in the first #definestatement, it can be used legitimately in any following #de fine statements
Trang 23of making SQUARE (x) a macro rather than a function.
Take care when defining macros with arguments For example, in the tion ofSQUARE (x) , there must be no space between the symbolic name SQUAREand the left parenthesis used to enclose the argument There can, however, bespaces within the parentheses if more than one argument is used
defini-Additionally, since the expansion of a macro involves direct text substitution,unintended results may occur if you do not use macros carefully For example,the assignment statement
val = SQUARE(numl + numl);
does not assign the value of (numl + num2)2to val Rather, the expansion ofSQUARE (numl + num2) results in the equivalent statement
val = numl + num2 * numl + num2;
This statement results from the direct text substitution of the term numl +
num2 for the argument x in the expression x * x that is produced by the pre- ,
Trang 24is expanded to produce the desired assignment:
val = (numl + num2) * (numl + num2);
Macros are extremely useful when the calculations or expressions they tain are relatively simple and can be kept to one or at most two lines Largermacro definitions tend to become cumbersome and confusing; they are betterwritten as functions If necessary, a macro definition can be continued on a newline by typing a backslash character, \, before the RETURN or ENTER key ispressed The backslash acts as an escape character that causes the preprocessor totreat the RETURN literally and not include it in any subsequent text substitu-tions
con-The advantage of using a macro instead of a function is an increase in tion speed Since the macro is directly expanded and included in every expres-sion or statement using it, there is no execution time loss due to the call andreturn procedures required by a function The disadvantage is the increase inrequired program memory space when a macro is used repeatedly Each time amacro is used the complete macro text is reproduced and stored as an integralpart of the program Thus, if the same macro is used in ten places, the final codeincludes ten copies of the expanded text version of the macro A function, how-ever, is stored in memory only once No matter how many times the function iscalled, the same code is used The memory space required for one copy of a func-tion used extensively throughout a program can be considerably less than thememory required for storing multiple copies of the same code defined as amacro
execu-Exercises 14.3
1 a Define a macro named NEGATE (x) that produces the negative of its argument.
b Include theNEGATE (x) macro defined in Exercise 1a in a complete C program and run the program to confirm proper operation of the macro for various cases.
2 a Define a macro named ABS_ VAL (x) that produces the absolute value of its
radius, where 1t equals 3.1416.
b. Include the CIRCUM (x) macro defined in Exercise 3a in a complete C program and run the program to confirm proper operation of the macro for various cases.
4 a Define a macro named MIN (x, y) that determines the minimum value of its two arguments.
b. Include the MIN (x, y) macro defined in Exercise 4a in a complete C program and run the program to confirm proper operation of the macro for various cases.
5 a Define a macro named MAX (x, y) that determines the maximum value of its two arguments.
b Include theMAX (x, y) macro defined in Exercise Sa in a complete C program and run the program to confirm proper operation of the macro for various cases.
Trang 2514.4 CommandLineArguments 543
Arguments can be passed to any function in a program, including the main ( )
function In this section we describe the procedures for passing arguments to
main ( ) when a program is initially invoked and having main ( ) correctly
receive and store the arguments passed to it Both the sending and receiving
sides of the transaction must be considered Fortunately, the interface for
trans-mitting arguments to a main ( ) function has been standardized in C, so both
sending and receiving arguments can be done almost mechanically
All the programs that have been run ,so far have been invoked by typing the
name of the executable version of the program after the operating system prompt
is displayed The command line for these programs consists of a single word,
which is the name of the program For computers that use the UNIX@Operating
System the prompt is usually the $ symbol and the executable name of the
gram is a out For these systems, the simple command line $a out begins
pro-gram execution of the last compiled source propro-gram currently residing in a out
If you are using a C compiler on an IBM PC, the equivalent operating system
prompt is either A> or C>, and the name of the executable program is typically
the same name as the source program with an exe extension rather than a c
extension Assuming that you are using an IBM PC with the A> operating system
prompt, the complete command line for running an executable program named
showad exe is A> showa~ As illustrated in Figure 14-1, this command line
causes the showad program to begin execution with its main ( ) function, but no
arguments are passed to main ( )
Now assume that we want to pass the three separate string arguments three
blind mice directly into showad's main function Sending arguments into a
main ( ) function is extremely easy It is accomplished by including the
ments on the command line used to begin program execution Because the
argu-ments are typed on the command line they are, naturally, called command line
arguments To pass the arguments three blind mice directly into the main ( )
function of the showad program, we only need to add the desired words after
the program name on the command line:
A> showad thFee blind mlce
FIGURE 14-1 Invoking the showad Program
Executableversion
of showadmain(){
A>showad -1" Invokesthe program -.t
startingat main ( ),but
no argumentsare passed
Trang 26FIGURE 14-2 TheCommandLineStoredin Memory
Upon encountering the command line showad three blind mice, theoperating system stores it as a sequence of four strings Figure 14-2 illustrates thestorage of this command line, assuming that each character uses one byte of stor-age As shown in the figure, each string terminates with the standard C null char-acter \ O
Sending command line arguments to main ( ) is always this simple Thearguments are typed on the command line and the operating system nicely storesthem as a sequence of separate strings We must now handle the receiving side ofthe transaction and let main ( ) know that arguments are being passed to it.Arguments passed to main ( ), like all function arguments, must be declared
as part of the function's definition To standardize argument passing to a main ( )function, only two items are allowed: a number and an array The number is aninteger variable, which must be named argc (short for argument counter), andthe array is a one-dimensional list, which must be named argv (short for argu-ment values) Figure 14-3 illustrates these two arguments
The integer passed to main ( ) is the total number of items on the commandline In our example, the value of argc passed to main ( ) is four, whichincludes the name of the program plus the three command line arguments Theone-dimensional list passed to main ( ) is a list of pointers containing the start-ing storage address of each string typed on the command line, as illustrated inFigure 14-4
We can now write the complete function definition for main ( ) to receivearguments Since an integer and an array are passed to main ( ) and C requiresthat these two items be named argc and argv, respectively, the first line inmain ( )'s definition must be main (int argc, char *argv [ ])
Because argc is an integer, its declaration is int argc; Because argv isthe name of an array whose elements are addresses that point to where the actualcommand line arguments are stored, its proper declaration is char *argv [ ];.This is nothing more than the declaration of an array of pointers It is read "argv
is an array whose elements are pointers to characters." Putting all this together,the full function header line for a main ( ) function that will receive commandline arguments is:!
main(int argc, char *argv[]) /* complete main() header line */
No matter how many arguments are typed on the command line, main ( )only needs the two standard pieces of information provided by argc and argv:the number of items on the command line and the list of starting addresses indi-cating where each argument is actually stored
1 In traditional (non-ANSI) C, this header is written as:
Trang 2714.4 Command Line Arguments 545
argc I Integer
Table
addresses
FIGURE 14-3 An Integer and an Array Are Passed to main ( )
Program 14-4 verifiesour descriptionby printingthe data actuallypassed tb
main ( ).The variableargv [i] used in Program 14-4 containsan address.Thb
notation *argv [i ] refers to lithe character pointed to" by the address in
FIGURE 14-4 Addresses Are Stored in the argv Array
The argv array
Trang 28546 Chapter Fourteen Additional Capabilities
Assuming that the executable version of Program 14-4 is namedshowad exe, a sample output for the command line showad three blindmice is:
The number of items on the command line is 4The address stored in argv [0] is FFE4
The character pointed to is sThe address stored in argv [0] is FFEBThe character pointed to is t
The address stored in argv[O] is FFFlThe character pointed to is b
The address stored in argv[O] is FFF7The character pointed to is m
The addresses displayed by Program 14-4 clearly depend on the machineused to run the program Figure 14-5 illustrates the storage of the command line
as displayed by the sample output.2 As anticipated, the addresses in the argvarray "point" to the starting characters of each string typed on the command line.Once command line arguments are passed to a C program, they can be usedlike any other C strings Program 14-5causes its command line arguments to bedisplayed from within main ( )
Assuming that the name of the executable version of Program 14-5is a out,the output of this program for the command line a out three blind miceis:
The following arguments were passed to main( ): three blind mice
FIGURE 14-5 The Command Line Stored in Memory
Trang 2914.4 Command Line Arguments
Notice that when the addresses in argv [ ] are passed to the printf ( )
function in Program 14-5, the strings pointed to by these addresses are
dis-played When these same addresses were passed to the printf ( )function in
Program 14-4, the actual values of the addresses were printed The difference in
displays is caused by the printf ( )function When a %s control sequence is
used in printf ( ),as it is in Program 14-5,it alerts the function that a string
will be accessed.printf ( )then expects the address of the first character in the
string; this is exactly what each element inargv [ ]supplies
One final comment about command line arguments: Any argument typed on
a command line is considered to be a string If you want numerical data passed
tomain ( ),it is up to you to convert the passed string into its numerical coun1
terpart This is seldom an issue, however, since most command line arguments
are used as flags to pass appropriate processing control signals to an invoked
program
Exercises 14.4
1 a Write a C program that accepts the name of a data file as a command line argument.
Have your program open the data file and display its contents, line by line, on the CRT
screen.
b Would the program written for Exercise 1a work correctly for a program file?
2 a Modify the program written for Exercise 1a so that each line displayed is preceded
by a line number.
b Modify the program written for Exercise 2a so that the command line argument -p
will cause the program to list the contents of the file on the printer attached to your
system.
3 Write a C program that accepts a command line argument as the name of a data file.
Given the name, your program should display the number of characters in the file.(Hint: I
Use the fseek ( ) and ftell ( ) library functions discussed in Section 8.2.) :
4 Write a C program that accepts two integer values as command line arguments The
program should multiply the two values entered and display the result. (Hint: The
command line must be accepted as string data and converted to numerical values before
multiplication.)
Trang 3014.5 The goto Statement
The goto statement provides an unconditional transfer of control to some otherstatement in a program The general form of a goto statement is:
goto label;
where label is any unique name chosen according to the rules for creating al;>lenames The label name must appear, followed by a colon, in front of anyother statement in the function that contains the goto statement For example,the following section of code transfers control to the label named err if division
vari-by zero is attempted:
if (denom == 0.0)goto err;
elseresult num / denom;
err: printf("Error - Attempted Division by Zero";
The astute reader will realize that in this case goto provides a cumbersomesolution to the problem It would require a second goto above the printf ( )statement to stop this statement from always being executed Generally it ismuch easier either to call an error routine for unusual conditions or to use abreak statement if this is necessary
Theoretically, a goto statement is never required because C's normal tures provide sufficient flexibility to handle all possible flow control require-ments Also, gotos tend to complicate programs For example, consider the fol-lowing code:
struc-if (a == 100)goto first;
Trang 3114.6 Chapter Summary
Both sections of code produce the same result; however, the second version:
clearly is easier to read It is worthwhile to convince yourself that the two sec-'
tions of code do, in fact, producelthe same result by running the code on your'
computer This will let you experience the sense of frustration when working
with goto-invaded code
In C/ the goto statement should be used in a limited manner, if at all The
presence of goto statements can rapidly make a program extremely difficult to:
1 An expression is any combination of operands and operators that yields a
value
2 A conditional expression provides an alternate way of expressing a simple
if - e 1s e statement The general form of a conditional expression is:
expressionl ? expression2 : expression3
The equivalent if-else statement for this is:
if (expressionl)expression2;
elseexpression3;
3 An enumerated data type is a user-defined scalar data type The user must
select a name and list the acceptable values for the data type For example, the
enumeration
enum color {red, green, yellow}
creates a color data type Any variable may be subsequently declared with
this data type and may store one of the acceptable values listed
4 A typedef statement creates synonyms for both standard and enumerated
data types For example, the statement
typedef int WHOLE_NUM;
makesWHOLE_NUM a synonym for into
5 Using the #def ine command, complete expressions can be equated to
symbolic names These expressions can include arguments I
6 Arguments passed to main ( ) are termed command line arguments C provide~
a standard argument-passing procedure in which main ( ) can accept any ,
number of arguments passed to it Each argument passed to main ( ) is
549
Trang 32considered a string and is stored using a pointer array named argv The totalnumber of items on the command line is stored in an integer variable namedargc.
7 C also provides a goto statement In theory this statement need never beused In practice it produces confusing and unstructured code It should beused only in a very limited and controlled manner, if at all
Trang 33Appendixes
551