Showing posts with label code. Show all posts
Showing posts with label code. Show all posts

Tuesday, December 7, 2010

Useful link,article and source code directories

Millions of peoples are trying to get traffic to their websites and spending lots of money in this. Submit article to article directory is a good and popular way of getting SEO and traffic to website.There are lots of paid article directories available in web but a very few free. This software give you chance to submit your article to world's best free article directory article.ognilab.com totally free of cost.

Submit Your article to world's best free article directory

This softwre can help you to find your most needed C,C++ source code from the C,C++ source code directory cprogram.org.You can also submit your source code in web to spread and test your knowledge on programming.Submit C,C++ source code to this directory to make it rich with source code and welfare of other programmers.


Millions of peoples are trying to get traffic to their websites and spending lots of money in this. Submit website link to Web directory is a good and popular way of getting SEO and traffic to website.There are lots of paid web directories available in web but a very few free. This software give you chance to submit your website link to world's best free web directory dir.ognilab.com totally free of cost.

Tuesday, September 21, 2010

Expression Statements

a few special points are
mentioned here. Remember, an expression statement is simply a valid expression
followed by a semicolon, as in
func(); /* a function call */
a = b+c; /* an assignment statement */
b+f(); /* a valid, but strange statement */
; /* an empty statement */
The first expression statement executes a function call. The second is an assignment.
The third expression, though strange, is still evaluated by the C++ compiler because
the function f() may perform some necessary task. The final example shows that a
statement can be empty (sometimes called a null statement).



Block Statements

Block statements are simply groups of related statements that are treated as a unit. The
statements that make up a block are logically bound together. Block statements are also
called compound statements. A block is begun with a { and terminated by its matching }.
Programmers use block statements most commonly to create a multistatement target
for some other statement, such as if. However, you may place a block statement
anywhere you would put any other statement. For example, this is perfectly valid
(although unusual) C/C++ code:
#include <stdio.h>
int main(void)
{
int i;
{ /* a block statement */
i = 120;
printf("%d", i);
}
return 0;
}

Jump Statements in C C++

C/C++ has four statements that perform an unconditional branch: return, goto, break,
and continue. Of these, you may use return and goto anywhere in your program. You
may use the break and continue statements in conjunction with any of the loop
statements. As discussed earlier in this chapter, you can also use break with switch.

The return Statement

The return statement is used to return from a function. It is categorized as a jump
statement because it causes execution to return (jump back) to the point at which the
call to the function was made. A return may or may not have a value associated with it.
If return has a value associated with it, that value becomes the return value of the
function. In C, a non-void function does not technically have to return a value. If no
return value is specified, a garbage value is returned. However, in C++, a non-void
function must return a value. That is, in C++, if a function is specified as returning a
value, any return statement within it must have a value associated with it. (Even in C,
if a function is declared as returning a value, it is good practice to actually return one.)
The general form of the return statement is
return expression;
The expression is present only if the function is declared as returning a value. In this
case, the value of expression will become the return value of the function.
You can use as many return statements as you like within a function. However, the
function will stop executing as soon as it encounters the first return. The } that ends a
function also causes the function to return. It is the same as a return without any
specified value. If this occurs within a non-void function, then the return value of the
function is undefined.
A function declared as void may not contain a return statement that specifies a
value. Since a void function has no return value, it makes sense that no return
statement within a void function can return a value.

The goto Statement

Since C/C++ has a rich set of control structures and allows additional control using
break and continue, there is little need for goto. Most programmers' chief concern
about the goto is its tendency to render programs unreadable. Nevertheless, although
the goto statement fell out of favor some years ago, it occasionally has its uses. There
are no programming situations that require goto. Rather, it is a convenience, which, if
used wisely, can be a benefit in a narrow set of programming situations, such as
jumping out of a set of deeply nested loops. The goto is not used outside of this section.
The goto statement requires a label for operation. (A label is a valid identifier
followed by a colon.) Furthermore, the label must be in the same function as the goto
that uses it—you cannot jump between functions. The general form of the goto
statement is
goto label;
..
.
label:
where label is any valid label either before or after goto. For example, you could create
a loop from 1 to 100 using the goto and a label, as shown here:
x = 1;
loop1:
x++;
if(x<100) goto loop1;

The break Statement

The break statement has two uses. You can use it to terminate a case in the switch
statement (covered in the section on switch earlier in this chapter). You can also use it
to force immediate termination of a loop, bypassing the normal loop conditional test.
When the break statement is encountered inside a loop, the loop is immediately
terminated and program control resumes at the next statement following the loop. For
example,
#include <stdio.h>
int main(void)
{
int t;
for(t=0; t<100; t++) {
printf("%d ", t);
if(t==10) break;
}
return 0;
}
prints the numbers 0 through 10 on the screen. Then the loop terminates because break
causes immediate exit from the loop, overriding the conditional test t<100.
Programmers often use the break statement in loops in which a special condition
can cause immediate termination. For example, here a keypress can stop the execution
of the look_up() function:
void look_up(char *name)
{
do {
/* look up names ... */
if(kbhit()) break;
} while(!found);
/* process match */
}
The kbhit() function returns 0 if you do not press a key. Otherwise, it returns a
nonzero value. Because of the wide differences between computing environments,
neither Standard C nor Standard C++ defines kbhit(), but you will almost certainly
have it (or one with a slightly different name) supplied with your compiler.
A break causes an exit from only the innermost loop. For example,
for(t=0; t<100; ++t) {
count = 1;
for(;;) {
printf("%d ", count);
count++;
if(count==10) break;
}
}
prints the numbers 1 through 10 on the screen 100 times. Each time execution
encounters break, control is passed back to the outer for loop.
A break used in a switch statement will affect only that switch. It does not affect
any loop the switch happens to be in.

The exit( ) Function

Although exit() is not a program control statement, a short digression that discusses it
is in order at this time. Just as you can break out of a loop, you can break out of a
program by using the standard library function exit() . This function causes immediate
termination of the entire program, forcing a return to the operating system. In effect,
the exit() function acts as if it were breaking out of the entire program.
The general form of the exit() function is
void exit(int return_code);
The value of return_code is returned to the calling process, which is usually the
operating system. Zero is generally used as a return code to indicate normal program
termination. Other arguments are used to indicate some sort of error. You can also use
the macros EXIT_SUCCESS and EXIT_FAILURE for the return_code. The exit()
function requires the header stdlib.h. A C++ program may also use the new-style
header <cstdlib>.
Programmers frequently use exit() when a mandatory condition for program
execution is not satisfied. For example, imagine a virtual reality computer game that
requires a special graphics adapter. The main() function of this game might look
like this:
#include <stdlib.h>
int main(void)
{
if(!virtual_graphics()) exit(1);
play();
/* ... */
}
/* .... */
where virtual_graphics() is a user-defined function that returns true if the
virtual-reality graphics adapter is present. If the adapter is not in the system,
virtual_graphics() returns false and the program terminates.
As another example, this version of menu() uses exit() to quit the program and
return to the operating system:
void menu(void)
{
char ch;
printf("1. Check Spelling\n");
printf("2. Correct Spelling Errors\n");
printf("3. Display Spelling Errors\n");
printf("4. Quit\n");
printf(" Enter your choice: ");
do {
ch = getchar(); /* read the selection from
the keyboard */
switch(ch) {
case '1':
check_spelling();
break;
case '2':
correct_errors();
break;
case '3':
display_errors();
break;
case '4':
exit(0); /* return to OS */
}
} while(ch!='1' && ch!='2' && ch!='3');
}

The continue Statement

The continue statement works somewhat like the break statement. Instead of forcing
termination, however, continue forces the next iteration of the loop to take place,
skipping any code in between. For the for loop, continue causes the conditional test
and increment portions of the loop to execute. For the while and do-while loops,
program control passes to the conditional tests. For example, the following program
counts the number of spaces contained in the string entered by the user:
/* Count spaces */
#include <stdio.h>
int main(void)
{
char s[80], *str;
int space;
printf("Enter a string: ");
gets(s);
str = s;
for(space=0; *str; str++) {
if(*str != ' ') continue;
space++;
}
printf("%d spaces\n", space);
return 0;
}
Each character is tested to see if it is a space. If it is not, the continue statement forces
the for to iterate again. If the character is a space, space is incremented.
The following example shows how you can use continue to expedite the exit from a
loop by forcing the conditional test to be performed sooner:
void code(void)
{
char done, ch;
done = 0;
while(!done) {
ch = getchar();
if(ch=='$') {
done = 1;
continue;
}
putchar(ch+1); /* shift the alphabet one
position higher */
}
}
This function codes a message by shifting all characters you type one letter higher. For
example, an A becomes a B. The function will terminate when you type a $. After a $
has been input, no further output will occur because the conditional test, brought into
effect by continue, will find done to be true and will cause the loop to exit.

The Conditional Expression

Sometimes newcomers to C/C++ are confused by the fact that you can use any valid
expression to control the if or the ? operator. That is, you are not restricted to
expressions involving the relational and logical operators (as is the case in languages
like BASIC or Pascal). The expression must simply evaluate to either a true or false
(zero or nonzero) value. For example, the following program reads two integers from
the keyboard and displays the quotient. It uses an if statement, controlled by the
second number, to avoid a divide-by-zero error.
/* Divide the first number by the second. */
#include <stdio.h>
int main(void)
{
int a, b;
printf("Enter two numbers: ");
scanf("%d%d", &a, &b);
if(b) printf("%d\n", a/b);
else printf("Cannot divide by zero.\n");
return 0;
}
This approach works because if b is 0, the condition controlling the if is false and the
else executes. Otherwise, the condition is true (nonzero) and the division takes place.
One other point: Writing the if statement as shown here
if(b != 0) printf("%d\n", a/b);
is redundant, potentially inefficient, and is considered bad style. Since the value of b
alone is sufficient to control the if, there is no need to test it against 0.

Shorthand Assignments

There is a variation on the assignment statement, sometimes referred to as a shorthand
assignment, that simplifies the coding of a certain type of assignment operation. For
example,
x = x+10;
can be written as
x += 10;
The operator += tells the compiler to assign to x the value of x plus 10.
This shorthand works for all the binary operators (those that require two
operands). In general, statements like:
var = var operator expression
can be rewritten as
var operator = expression
For another example,
x = x-100;
is the same as
x -= 100;
Shorthand notation is widely used in professionally written C/C++ programs; you
should become familiar with it.

Spacing and Parentheses

You can add tabs and spaces to expressions to make them easier to read. For example,
the following two expressions are the same:
x=10/y~(127/x);
x = 10 / y ~(127/x);
Redundant or additional parentheses do not cause errors or slow down the execution
of an expression. You should use parentheses to clarify the exact order of evaluation,
both for yourself and for others. For example, which of the following two expressions
is easier to read?
x = y/3-34*temp+127;
x = (y/3) - (34*temp) + 127;

Type Casts in C C++

You can force an expression to be of a specific type by using a cast. The general form of
a cast is
(type) expression
where type is a valid data type. For example, to make sure that the expression x/2
evaluates to type float, write
(float) x/2
Casts are technically operators. As an operator, a cast is unary and has the same
precedence as any other unary operator.
Although casts are not usually used a great deal in programming, they can be very
useful when needed. For example, suppose you wish to use an integer for loop control,
yet to perform computation on it requires a fractional part, as in the following
program:
#include <stdio.h>
int main(void) /* print i and i/2 with fractions */
{
int i;
for(i=1; i<=100; ++i)
printf("%d / 2 is: %f\n", i, (float) i /2);
return 0;
}
Without the cast (float), only an integer division would have been performed. The cast
ensures that the fractional part of the answer is displayed.

Precedence Summary

Table 2-8 lists the precedence of all operators defined by C. Note that all operators,
except the unary operators and ?, associate from left to right. The unary operators
(*, &, −) and ? associate from right to left.

Highest              ( ) [ ] −> .
                      ! ~ ++ – – (type) * & sizeof
                           * / %
                            + −
                          << >>
                           < <= > >=
                          == !=
                              &
                          ^
                            |
                         &&
                          ||
                               ?:
                    = += −=*= /= etc.
Lowest ,

Table 2-8. The Precedence of C Operators


The Compile-Time Operator sizeof

sizeof is a unary compile-time operator that returns the length, in bytes, of the variable
or parenthesized type-specifier that it precedes. For example, assuming that integers
are 4 bytes and doubles are 8 bytes,
double f;
printf("%d ", sizeof f);
printf("%d", sizeof(int));
will display 8 4.
Remember, to compute the size of a type, you must enclose the type name in
parentheses. This is not necessary for variable names, although there is no harm done
if you do so.

C/C++ defines (using typedef) a special type called size_t, which corresponds
loosely to an unsigned integer. Technically, the value returned by sizeof is of type
size_t. For all practical purposes, however, you can think of it (and use it) as if it were
an unsigned integer value.
sizeof primarily helps to generate portable code that depends upon the size of the
built-in data types. For example, imagine a database program that needs to store six
integer values per record. If you want to port the database program to a variety of
computers, you must not assume the size of an integer, but must determine its actual
length using sizeof. This being the case, you could use the following routine to write a
record to a disk file:
/* Write 6 integers to a disk file. */
void put_rec(int rec[6], FILE *fp)
{
int len;
len = fwrite(rec, sizeof(int)*6, 1, fp);
if(len != 1) printf("Write Error");
}
Coded as shown, put_rec() compiles and runs correctly in any environment, including
those that use 16- and 32-bit integers.
One final point: sizeof is evaluated at compile time, and the value it produces is
treated as a constant within your program.

The & and * Pointer Operators

A pointer is the memory address of some object. A pointer variable is a variable that is
specifically declared to hold a pointer to an object of its specified type. Knowing a
variable's address can be of great help in certain types of routines. However, pointers
have three main functions in C/C++. They can provide a fast means of referencing
array elements. They allow functions to modify their calling parameters. Lastly,
they support linked lists and other dynamic data structures. Chapter 5 is devoted
exclusively to pointers. However, this chapter briefly covers the two operators that
are used to manipulate pointers.
The first pointer operator is &, a unary operator that returns the memory address of
its operand. (Remember, a unary operator only requires one operand.) For example,
m = &count;
places into m the memory address of the variable count. This address is the computer's
internal location of the variable. It has nothing to do with the value of count. You can
think of & as meaning "the address of." Therefore, the preceding assignment statement
means "m receives the address of count."
To better understand this assignment, assume that the variable count is at memory
location 2000. Also assume that count has a value of 100. Then, after the previous
assignment, m will have the value 2000.
The second pointer operator is *, which is the complement of &. The * is a unary
operator that returns the value of the variable located at the address that follows it. For
example, if m contains the memory address of the variable count,
q = *m;
places the value of count into q. Now q has the value 100 because 100 is stored at
location 2000, the memory address that was stored in m. Think of * as meaning
"at address." In this case, you could read the statement as "q receives the value at
address m."
Unfortunately, the multiplication symbol and the "at address" symbol are the
same, and the symbol for the bitwise AND and the "address of" symbol are the same.
These operators have no relationship to each other. Both & and * have a higher
precedence than all other arithmetic operators except the unary minus, with which
they share equal precedence.
Variables that will hold memory addresses (i.e., pointers), must be declared by
putting * in front of the variable name. This indicates to the compiler that it will hold a
pointer. For example, to declare ch as a pointer to a character, write
char *ch;
Here, ch is not a character but a pointer to a character—there is a big difference. The
type of data that a pointer points to, in this case char, is called the base type of the
pointer. However, the pointer variable itself is a variable that holds the address to an
object of the base type. Thus, a character pointer (or any pointer) is of sufficient size
to hold an address as defined by the architecture of the computer that it is running on.
However, remember that a pointer should only point to data that is of that pointer's
base type.
You can mix both pointer and nonpointer variables in the same declaration
statement. For example,
int x, *y, count;
declares x and count as integer types and y as a pointer to an integer type.
The following program uses * and & operators to put the value 10 into a variable
called target. As expected, this program displays the value 10 on the screen.
#include <stdio.h>
int main(void)
{
int target, source;
int *m;
source = 10;
m = &source;
target = *m;
printf("%d", target);
return 0;
}

Bitwise Operators

Unlike many other languages, C/C++ supports a full complement of bitwise
operators. Since C was designed to take the place of assembly language for most
programming tasks, it needed to be able to support many operations that can be done
in assembler, including operations on bits. Bitwise operation refers to testing, setting, or
shifting the actual bits in a byte or word, which correspond to the char and int data
types and variants. You cannot use bitwise operations on float, double, long double,
void, bool, or other, more complex types. Table 2-6 lists the operators that apply to
bitwise operations. These operations are applied to the individual bits of the
operands.

Operator          Action
&                      AND
|                        OR
^                Exclusive OR (XOR)
~                 One's complement (NOT)
>>                  Shift right
<<                    Shift left

Table 2-6. Bitwise Operators

The bitwise AND, OR, and NOT (one's complement) are governed by the same
truth table as their logical equivalents, except that they work bit by bit. The exclusive
OR has the truth table shown here:
p   q    p^q
0   0     0
1   0     1
1   1     0
0   1     1
As the table indicates, the outcome of an XOR is true only if exactly one of the
operands is true; otherwise, it is false.
Bitwise operations most often find application in device drivers—such as modem
programs, disk file routines, and printer routines —because the bitwise operations
can be used to mask off certain bits, such as parity. (The parity bit confirms that the
rest of the bits in the byte are unchanged. It is usually the high-order bit in each byte.)
Think of the bitwise AND as a way to clear a bit. That is, any bit that is 0 in either
operand causes the corresponding bit in the outcome to be set to 0. For example, the
following function reads a character from the modem port and resets the parity bit to 0:
char get_char_from_modem(void)
{
char ch;
ch = read_modem(); /* get a character from the
modem port */
return(ch & 127);
}
Parity is often indicated by the eighth bit, which is set to 0 by ANDing it with a
byte that has bits 1 through 7 set to 1 and bit 8 set to 0. The expression ch & 127 means
to AND together the bits in ch with the bits that make up the number 127. The net
result is that the eighth bit of ch is set to 0. In the following example, assume that ch
had received the character "A" and had the parity bit set:
The bitwise OR, as the reverse of AND, can be used to set a bit. Any bit that is set
to 1 in either operand causes the corresponding bit in the outcome to be set to 1. For
example, the following is 128 | 3:
Ill 2-2
An exclusive OR, usually abbreviated XOR, will set a bit on if and only if the bits
being compared are different. For example, 127 ^120 is
Remember, relational and logical operators always produce a result that is either
true or false, whereas the similar bitwise operations may produce any arbitrary value
in accordance with the specific operation. In other words, bitwise operations may
produce values other than 0 or 1, while logical operators will always evaluate to 0 or 1.
The bit-shift operators, >> and <<, move all bits in a variable to the right or left as
specified. The general form of the shift-right statement is
 
1 0 0 0 0 0 0 0 128 in binary
0 0 0 0 0 0 1 1 3 in binary
¦___________ bitwise OR
1 0 0 0 0 0 1 1 result
0 1 1 1 1 1 1 1 127 in binary
0 1 1 1 1 0 0 0 120 in binary
^___________ bitwise XOR
0 0 0 0 0 1 1 1 result
Parity bit
1 1 0 0 0 0 0 1 ch containing an "A" with parity set
0 1 1 1 1 1 1 1 127 in binary
&___________ bitwise AND
0 1 0 0 0 0 0 1 "A"without parity
The bitwise OR, as the reverse of AND, can be used to set a bit. Any bit that is set
to 1 in either operand causes the corresponding bit in the outcome to be set to 1. For
example, the following is 128 | 3:
Ill 2-2
An exclusive OR, usually abbreviated XOR, will set a bit on if and only if the bits
being compared are different. For example, 127 ^120 is
Remember, relational and logical operators always produce a result that is either
true or false, whereas the similar bitwise operations may produce any arbitrary value
in accordance with the specific operation. In other words, bitwise operations may
produce values other than 0 or 1, while logical operators will always evaluate to 0 or 1.
The bit-shift operators, >> and <<, move all bits in a variable to the right or left as
specified. The general form of the shift-right statement isvariable >> number of bit positions
The general form of the shift-left statement is
variable << number of bit positions
As bits are shifted off one end, 0's are brought in the other end. (In the case of a
signed, negative integer, a right shift will cause a 1 to be brought in so that the sign bit
is preserved.) Remember, a shift is not a rotate. That is, the bits shifted off one end do
not come back around to the other. The bits shifted off are lost.
Bit-shift operations can be very useful when you are decoding input from an
external device, like a D/A converter, and reading status information. The bitwise shift
operators can also quickly multiply and divide integers. A shift right effectively divides
a number by 2 and a shift left multiplies it by 2, as shown in Table 2-7. The following
program illustrates the shift operators:
/* A bit shift example. */
#include <stdio.h>
int main(void)
{
unsigned int i;
int j;
i = 1;
/* left shifts */
for(j=0; j<4; j++) {
i = i << 1; /* left shift i by 1, which
is same as a multiply by 2 */
printf("Left shift %d: %d\n", j, i);
}
/* right shifts */
for(j=0; j<4; j++) {
i = i >> 1; /* right shift i by 1, which
is same as a division by 2 */
printf("Right shift %d: %d\n", j, i);
}
return 0;
}

unsigned char x;                     x as each statement executes                 value of x
x = 7;                                                   0 0 0 0 0 1 1 1                           7
x = x<<1;                                            0 0 0 0 1 1 1 0                           14
x = x<<3;                                            0 1 1 1 0 0 0 0                          112
x = x<<2;                                           1 1 0 0 0 0 0 0                           192
x = x>>1;                                            0 1 1 0 0 0 0 0                            96
x = x>>2;                                             0 0 0 1 1 0 0 0                           24

*Each left shift multiplies by 2. Notice that information has been lost after x<<2 because
a bit was shifted off the end.
**Each right shift divides by 2. Notice that subsequent divisions do not bring back any
lost bits.
Table 2-7. Multiplication and Division with Shift Operators
The one's complement operator, ~, reverses the state of each bit in its operand. That
is, all 1's are set to 0, and all 0's are set to 1.
The bitwise operators are often used in cipher routines. If you want to make a disk
file appear unreadable, perform some bitwise manipulations on it. One of the simplest
methods is to complement each byte by using the one's complement to reverse each bit
in the byte, as is shown here:
Notice that a sequence of two complements in a row always produces the original
number. Thus, the first complement represents the coded version of that byte. The
second complement decodes the byte to its original value.
You could use the encode() function shown here to encode a character.
/* A simple cipher function. */
char encode(char ch)
{return(~ch); /* complement it */
}
Of course, a file encoded using encode() would be very easy to crack!

Arithmetic Operators

Table 2-4 lists C/C++'s arithmetic operators. The operators +, −, *, and / work as they
do in most other computer languages. You can apply them to almost any built-in data
type. When you apply / to an integer or character, any remainder will be truncated.
For example, 5/2 will equal 2 in integer division.
The modulus operator % also works in C/C++ as it does in other languages,
yielding the remainder of an integer division. However, you cannot use it on
floating-point types. The following code fragment illustrates %:
int x, y;
x = 5;
y = 2;
printf("%d ", x/y); /* will display 2 */
printf("%d ", x%y); /* will display 1, the remainder of
the integer division */
x = 1;
y = 2;
printf("%d %d", x/y, x%y); /* will display 0 1 */
The last line prints a 0 and a 1 because 1/2 in integer division is 0 with a remainder of 1.
The unary minus multiplies its operand by –1. That is, any number preceded by a
minus sign switches its sign.

Increment and Decrement
C/C++ includes two useful operators not generally found in other computer
languages. These are the increment and decrement operators, ++ and −−. The operator
++ adds 1 to its operand, and −− subtracts one. In other words:
x = x+1;
is the same as
++x;
and
x = x-1;
is the same as
x--;
Both the increment and decrement operators may either precede (prefix) or follow
(postfix) the operand. For example,
x = x+1;
can be written
++x;
or
x++;
There is, however, a difference between the prefix and postfix forms when you use
these operators in an expression. When an increment or decrement operator precedes
its operand, the increment or decrement operation is performed before obtaining the
value of the operand for use in the expression. If the operator follows its operand,
 
Operator                             Action
−                             Subtraction, also unary minus
+                                          Addition
*                                       Multiplication
/                                           Division
%                                        Modulus
– –                                     Decrement
++                                      Increment

Table 2-4. Arithmetic Operators

the value of the operand is obtained before incrementing or decrementing it. For
instance,
x = 10;
y = ++x;
sets y to 11. However, if you write the code as
x = 10;
y = x++;
y is set to 10. Either way, x is set to 11; the difference is in when it happens.
Most C/C++ compilers produce very fast, efficient object code for increment and
decrement operations—code that is better than that generated by using the equivalent
assignment statement. For this reason, you should use the increment and decrement
operators when you can.
Here is the precedence of the arithmetic operators:
highest ++ – –
– (unary minus)
* / %
lowest + –
Operators on the same level of precedence are evaluated by the compiler from left to
right. Of course, you can use parentheses to alter the order of evaluation. C/C++ treats
parentheses in the same way as virtually all other computer languages. Parentheses
force an operation, or set of operations, to have a higher level of precedence.

Relational and Logical Operators
In the term relational operator, relational refers to the relationships that values can
have with one another. In the term logical operator, logical refers to the ways these
relationships can be connected. Because the relational and logical operators often
work together, they are discussed together here.
The idea of true and false underlies the concepts of relational and logical operators.
In C, true is any value other than zero. False is zero. Expressions that use relational or
logical operators return 0 for false and 1 for true.
C++ fully supports the zero/non-zero concept of true and false. However, it also
defines the bool data type and the Boolean constants true and false. In C++, a 0 value
is automatically converted into false, and a non-zero value is automatically converted
into true. The reverse also applies: true converts to 1 and false converts to 0. In C++,

the outcome of a relational or logical operation is true or false. But since this
automatically converts into 1 or 0, the distinction between C and C++ on this issue is
mostly academic.
Table 2-5 shows the relational and logical operators. The truth table for the logical
operators is shown here using 1's and 0's.
p             q               p && q                 p || q               !p
0             0                    0                          0                 1
0             1                    0                          1                1
1             1                    1                          1                0
1             0                    0                          1                0
Both the relational and logical operators are lower in precedence than the
arithmetic operators. That is, an expression like 10 > 1+12 is evaluated as if it were
written 10 > (1+12). Of course, the result is false.
You can combine several operations together into one expression, as shown here:
10>5 && !(10<9) || 3<=4

Relational Operators
Operator                     Action
>                               Greater than
>=                        Greater than or equal
<                               Less than
<=                       Less than or equal
= =                               Equal
!=                                Not equal

Logical Operators
Operator                       Action
&&                                AND
||                                      OR
!                                     NOT

Table 2-5. Relational and Logical Operators

In this case, the result is true.
Although neither C nor C++ contain an exclusive OR (XOR) logical operator, you
can easily create a function that performs this task using the other logical operators.
The outcome of an XOR operation is true if and only if one operand (but not both) is
true. The following program contains the function xor() , which returns the outcome of
an exclusive OR operation performed on its two arguments:
#include <stdio.h>
int xor(int a, int b);
int main(void)
{
printf("%d", xor(1, 0));
printf("%d", xor(1, 1));
printf("%d", xor(0, 1));
printf("%d", xor(0, 0));
return 0;
}
/* Perform a logical XOR operation using the
two arguments. */
int xor(int a, int b)
{
return (a || b) && !(a && b);
}
The following table shows the relative precedence of the relational and logical
operators:
Highest
!
> >= < <=
== !=
&&
Lowest
  ||

As with arithmetic expressions, you can use parentheses to alter the natural order of
evaluation in a relational and/or logical expression. For example, 

!0&& 0 || 0
is false. However, when you add parentheses to the same expression, as shown here,
the result is true:
!(0 && 0) || 0
Remember, all relational and logical expressions produce either a true or false
result. Therefore, the following program fragment is not only correct, but will print
the number 1.
int x;
x = 100;
printf("%d", x>10);

The Assignment Operator

You can use the assignment operator within any valid expression. This is not the
case with most computer languages (including Pascal, BASIC, and FORTRAN), which
treat the assignment operator as a special case statement. The general form of the
assignment operator is
variable_name = expression;
where an expression may be as simple as a single constant or as complex as you
require. C/C++ uses a single equal sign to indicate assignment (unlike Pascal or
Modula-2, which use the := construct). The target, or left part, of the assignment
must be a variable or a pointer, not a function or a constant.
Frequently in literature on C/C++ and in compiler error messages you will see
these two terms: lvalue and rvalue. Simply put, an lvalue is any object that can occur
on the left side of an assignment statement. For all practical purposes, "lvalue" means
"variable." The term rvalue refers to expressions on the right side of an assignment and
simply means the value of an expression.

Type Conversion in Assignments

When variables of one type are mixed with variables of another type, a type conversion
will occur. In an assignment statement, the type conversion rule is easy: The value of
the right side (expression side) of the assignment is converted to the type of the left
side (target variable), as illustrated here:
int x;
char ch;
float f;
void func(void)
{
ch = x; /* line 1 */
x = f; /* line 2 */
f = ch; /* line 3 */
f = x; /* line 4 */
}
In line 1, the left high-order bits of the integer variable x are lopped off, leaving ch with
the lower 8 bits. If x were between 255 and 0, ch and x would have identical values.
Otherwise, the value of ch would reflect only the lower-order bits of x. In line 2, x will
receive the nonfractional part of f. In line 3, f will convert the 8-bit integer value stored
in ch to the same value in the floating-point format. This also happens in line 4, except
that f will convert an integer value into floating-point format.
When converting from integers to characters and long integers to integers, the
appropriate amount of high-order bits will be removed. In many 16-bit environments,
this means that 8 bits will be lost when going from an integer to a character and 16 bits
will be lost when going from a long integer to an integer. For 32-bit environments, 24
bits will be lost when converting from an integer to a character and 16 bits will be lost
when converting from an integer to a short integer.
Table 2-3 summarizes the assignment type conversions. Remember that the
conversion of an int to a float, or a float to a double, and so on, does not add any precision or accuracy. These kinds of conversions only change the form in which the
value is represented. In addition, some compilers always treat a char variable as
positive, no matter what value it has, when converting it to an int or float. Other
compilers treat char variable values greater than 127 as negative numbers when
converting. Generally speaking, you should use char variables for characters, and use
ints, short ints, or signed chars when needed to avoid possible portability problems.
To use Table 2-3 to make a conversion not shown, simply convert one type at a time
until you finish. For example, to convert from double to int, first convert from double
to float and then from float to int.

Multiple Assignments
C/C++ allows you to assign many variables the same value by using multiple
assignments in a single statement. For example, this program fragment assigns x, y,
and z the value 0:
x = y = z = 0;

Target                             Type Expression                          Type Possible Info Loss
signed char                        char                                   If value > 127, target is negative
char                                 short int                                              High-order 8 bits
char                                  int (16 bits)                                      High-order 8 bits
char                                  int (32 bits)                                        High-order 24 bits
char                                long int                                            High-order 24 bits
short int                             int (16 bits)                                                  None
short int                          int (32 bits)                                      High-order 16 bits
int (16 bits)                     long int                                            High-order 16 bits
int (32 bits)                     long int                                                    None
int                                     float                                     Fractional part and possibly more
float                                double                             Precision, result rounded
double                            long                                  double Precision, result rounded

Table 2-3. The Outcome of Common Type Conversions

String and Backslash Character Constants

String Constants

C/C++ supports one other type of constant: the string. A string is a set of characters
enclosed in double quotes. For example, "this is a test" is a string. You have seen
examples of strings in some of the printf() statements in the sample programs.
Although C allows you to define string constants, it does not formally have a string
data type. (C++ does define a string class, however.)
You must not confuse strings with characters. A single character constant is
enclosed in single quotes, as in 'a'. However, "a" is a string containing only one letter.

Backslash Character Constants

Enclosing character constants in single quotes works for most printing characters. A
few, however, such as the carriage return, are impossible to enter into a string from the
keyboard. For this reason, C/C++ include the special backslash character constants
shown in Table 2-2 so that you may easily enter these special characters as constants.
These are also referred to as escape sequences. You should use the backslash codes
instead of their ASCII equivalents to help ensure portability.
For example, the following program outputs a new line and a tab and then prints
the string This is a test.
#include <stdio.h>
int main(void)
{
printf("\n\tThis is a test.");
return 0;
}

Code               Meaning
\b                    Backspace
\f                     Form feed
\n                     New line
\r                  Carriage return
\t                  Horizontal tab
\"                  Double quote
\'                  Single quote
\0                      Null
\\                   Backslash
\v                  Vertical tab
\a                      Alert
\?                Question mark
\N             Octal constant (where N is an octal constant)
\xN           Hexadecimal constant (where N is a hexadecimalconstant)

Table 2-2. Backslash Codes

Hexadecimal and Octal Constants

It is sometimes easier to use a number system based on 8 or 16 rather than 10 (our
standard decimal system). The number system based on 8 is called octal and uses the digits 0 through 7. In octal, the number 10 is the same as 8 in decimal. The base 16
number system is called hexadecimal and uses the digits 0 through 9 plus the letters
A through F, which stand for 10, 11, 12, 13, 14, and 15, respectively. For example, the
hexadecimal number 10 is 16 in decimal. Because these two number systems are
used frequently, C/C++ allows you to specify integer constants in hexadecimal or octal
instead of decimal. A hexadecimal constant must consist of a 0x followed by the
constant in hexadecimal form. An octal constant begins with a 0. Here are some
examples:
int hex = 0x80; /* 128 in decimal */
int oct = 012; /* 10 in decimal */

Constants in C and C++

Constants refer to fixed values that the program may not alter. Constants can be of any
of the basic data types. The way each constant is represented depends upon its type.
Constants are also called literals.
Character constants are enclosed between single quotes. For example 'a' and '%' are
both character constants. Both C and C++ define wide characters (used mostly in character constant, precede the character with an L. For example,
wchar_t wc;
wc = L'A';
Here, wc is assigned the wide-character constant equivalent of A. The type of wide
characters is wchar_t. In C, this type is defined in a header file and is not a built-in
type. In C++, wchar_t is built in.
Integer constants are specified as numbers without fractional components. For
example, 10 and –100 are integer constants. Floating-point constants require the
decimal point followed by the number's fractional component. For example, 11.123
is a floating-point constant. C/C++ also allows you to use scientific notation for
floating-point numbers.
There are two floating-point types: float and double. There are also several
variations of the basic types that you can generate using the type modifiers. By default,
the compiler fits a numeric constant into the smallest compatible data type that will
hold it. Therefore, assuming 16-bit integers, 10 is int by default, but 103,000 is a long.
Even though the value 10 could fit into a character type, the compiler will not cross
type boundaries. The only exception to the smallest type rule are floating-point
constants, which are assumed to be doubles.
For most programs you will write, the compiler defaults are adequate. However,
you can specify precisely the type of numeric constant you want by using a suffix. For
floating-point types, if you follow the number with an F, the number is treated as a
float. If you follow it with an L, the number becomes a long double. For integer types,
the U suffix stands for unsigned and the L for long. Here are some examples:

Data type                          Constant examples
int                                     1 123 21000 −234
long int                              35000L −34L
unsigned int                     10000U 987U 40000U
float                                   123.23F 4.34e−3F
double                             123.23 1.0 −0.9876324
long double                          1001.2L

Variable Initializations in C and C++

You can give variables a value as you declare them by placing an equal sign and a
value after the variable name. The general form of initialization is
type variable_name = value;
Some examples are
char ch = 'a';
int first = 0;
float balance = 123.23;
Global and static local variables are initialized only at the start of the program. Local
variables (excluding static local variables) are initialized each time the block in which
they are declared is entered. Local variables that are not initialized have unknown
values before the first assignment is made to them. Uninitialized global and static local
variables are automatically set to zero.

Storage Class Specifiers in C

There are four storage class specifiers supported by C:
extern
static
register
auto
These specifiers tell the compiler how to store the subsequent variable. The general
form of a declaration that uses one is shown here.
storage_specifier type var_name;
Notice that the storage specifier precedes the rest of the variable declaration.

extern

Because C/C++ allows separate modules of a large program to be separately compiled
and linked together, there must be some way of telling all the files about the global
variables required by the program. Although C technically allows you to define a
global variable more than once, it is not good practice (and may cause problems when
linking). More importantly, in C++, you may define a global variable only once. How,
then, do you inform all the files in your program about the global variables used by
the program?
The solution to the problem is found in the distinction between the declaration
and the definition of a variable. A declaration declares the name and type of a variable.

File One                   File Two
int x, y;                   extern int x, y;
char ch;                  extern char ch;
int main(void)           void func22(void)
{                               {
/* ... */                     x = y / 10;
}                              }
void func1(void)       void func23(void)
{                                {
x = 123;                        y = 10;
}                               }

Figure 2-1. Using global variables in separately compiled modules
A definition causes storage to be allocated for the variable. In most cases, variable
declarations are also definitions. However, by preceding a variable name with the
extern specifier, you can declare a variable without defining it. Thus, in a multifile
program, you can declare all of your global variables in one file and use extern
declarations in the other, as in Figure 2-1.
In File Two, the global variable list was copied from File One and the extern
specifier was added to the declarations. The extern specifier tells the compiler that the
variable types and names that follow it have been defined elsewhere. In other words,
extern lets the compiler know what the types and names are for these global variables
without actually creating storage for them again. When the linker links the two
modules, all references to the external variables are resolved.
The extern keyword has this general form:
extern var-list;
There is another, optional use of extern that you may occasionally see. When you
use a global variable inside a function, you can declare it as extern, as shown here:
int first, last; /* global definition of first
and last */
main(void)
{
extern int first; /* optional use of the
extern declaration */
.
.
.
}

static Variables
static variables are permanent variables within their own function or file. Unlike global
variables, they are not known outside their function or file, but they maintain their
values between calls. This feature makes them useful when you write generalized
functions and function libraries that other programmers may use. static has different
effects upon local variables and global variables.
static Local Variables
When you apply the static modifier to a local variable, the compiler creates permanent
storage for it, much as it creates storage for a global variable. The key difference
between a static local variable and a global variable is that the static local variable
remains known only to the block in which it is declared. In simple terms, a static
local variable is a local variable that retains its value between function calls.
static local variables are very important to the creation of stand-alone functions
because several types of routines must preserve a value between calls. If static variables
were not allowed, globals would have to be used, opening the door to possible side
effects. An example of a function that benefits from a static local variable is a numberseries
generator that produces a new value based on the previous one. You could use
a global variable to hold this value. However, each time the function is used in a
program, you would have to declare that global variable and make sure that it did not
conflict with any other global variables already in place. The better solution is to declare
the variable that holds the generated number to be static, as in this program fragment:
int series(void)
{
static int series_num;
series_num = series_num+23;
return series_num;
}
In this example, the variable series_num stays in existence between function calls,
instead of coming and going the way a normal local variable would. This means that
each call to series() can produce a new member in the series based on the preceding
number without declaring that variable globally.
You can give a static local variable an initialization value. This value is assigned
only once, at program start-up—not each time the block of code is entered, as with
normal local variables. For example, this version of series() initializes series_num
to 100:
int series(void)
{
static int series_num = 100;
series_num = series_num+23;
return series_num;
}
As the function now stands, the series will always begin with the value 123. While this
is acceptable for some applications, most series generators need to let the user specify
the starting point. One way to give series_num a user-specified value is to make it a
global variable and then let the user set its value. However, not defining series_num
as global was the point of making it static. This leads to the second use of static.
static Global Variables
Applying the specifier static to a global variable instructs the compiler to create a
global variable that is known only to the file in which you declared it. This means
that even though the variable is global, routines in other files may have no knowledge
of it or alter its contents directly, keeping it free from side effects. For the few situations
where a local static cannot do the job, you can create a small file that contains only the
functions that need the global static variable, separately compile that file, and use it
without fear of side effects.
To illustrate a global static, the series generator example from the previous section
is recoded so that a seed value initializes the series through a call to a second function
called series_start() . The entire file containing series() , series_start() , and series_num
is shown here:
/* This must all be in one file - preferably by itself. */
static int series_num;
void series_start(int seed);
int series(void);
int series(void)
{
series_num = series_num+23;
return series_num;
}
/* initialize series_num */
void series_start(int seed)
{
series_num = seed;
}
Calling series_start() with some known integer value initializes the series generator.
After that, calls to series() generate the next element in the series.
To review: The names of local static variables are known only to the block of code
in which they are declared; the names of global static variables are known only to the
file in which they reside. If you place the series() and series_start() functions in a
library, you can use the functions but cannot reference the variable series_num, which
is hidden from the rest of the code in your program. In fact, you can even declare and
use another variable called series_num in your program (in another file, of course). In
essence, the static modifier permits variables that are known only to the functions that
need them, without unwanted side effects.
static variables enable you to hide portions of your program from other portions.
This can be a tremendous advantage when you are trying to manage a very large and
complex program.
In C++, the preceding use of static is still supported, but deprecated. This means
that it is not recommended for new code. Instead, you should use a namespace,
which is described in Part Two.

register Variables
The register storage specifier originally applied only to variables of type int, char, or
pointer types. However, in Standard C, register's definition has been broadened so that
it applies to any type of variable.
Originally, the register specifier requested that the compiler keep the value of a
variable in a register of the CPU rather than in memory, where normal variables are stored. This meant that operations on a register variable could occur much faster than
on a normal variable because the register variable was actually held in the CPU and
did not require a memory access to determine or modify its value.
Today, the definition of register has been greatly expanded and it now may be
applied to any type of variable. Standard C simply states "that access to the object be
as fast as possible." (Standard C++ states that register is a "hint to the implementation
that the object so declared will be heavily used.") In practice, characters and integers
are still stored in registers in the CPU. Larger objects like arrays obviously cannot be
stored in a register, but they may still receive preferential treatment by the compiler.
Depending upon the implementation of the C/C++ compiler and its operating
environment, register variables may be handled in any way deemed fit by the
compiler's implementor. In fact, it is technically permissible for a compiler to ignore
the register specifier altogether and treat variables modified by it as if they weren't,
but this is seldom done in practice.
You can only apply the register specifier to local variables and to the formal
parameters in a function. Global register variables are not allowed. Here is an example
that uses register variables. This function computes the result of Me for integers:
int int_pwr(register int m, register int e)
{
register int temp;
temp = 1;
for(; e; e--) temp = temp * m;
return temp;
}
In this example, e, m, and temp are declared as register variables because they
are all used within the loop. The fact that register variables are optimized for speed
makes them ideal for control of or use in loops. Generally, register variables are used
where they will do the most good, which are often places where many references will
be made to the same variable. This is important because you can declare any number
of variables as being of type register, but not all will receive the same access speed
optimization.
The number of register variables optimized for speed allowed within any one code
block is determined by both the environment and the specific implementation of
C/C++. You don't have to worry about declaring too many register variables because
the compiler automatically transforms register variables into nonregister variables
when the limit is reached. (This ensures portability of code across a broad line of
processors.)
Usually at least two register variables of type char or int can actually be held in the
registers of the CPU. Because environments vary widely, consult your compiler's user
manual to determine if you can apply any other types of optimization options.
In C, you cannot find the address of a register variable using the & operator
(discussed later in this chapter). This makes sense because a register variable might be
stored in a register of the CPU, which is not usually addressable. But this restriction
does not apply to C++. However, taking the address of a register variable in C++ may
prevent it from being fully optimized.
Although the description of register has been broadened beyond its traditional
meaning, in practice it still generally has a significant effect only with integer and
character types. Thus, you should probably not count on substantial speed
improvements for other variable types.

volatile datatype in C and C++

The modifier volatile tells the compiler that a variable's value may be changed in ways
not explicitly specified by the program. For example, a global variable's address may
be passed to the operating system's clock routine and used to hold the real time of thesystem. In this situation, the contents of the variable are altered without any explicit
assignment statements in the program. This is important because most C/C++
compilers automatically optimize certain expressions by assuming that a variable's
content is unchanging if it does not occur on the left side of an assignment statement;
thus, it might not be reexamined each time it is referenced. Also, some compilers
change the order of evaluation of an expression during the compilation process. The
volatile modifier prevents these changes.
You can use const and volatile together. For example, if 0x30 is assumed to be the
value of a port that is changed by external conditions only, the following declaration
would prevent any possibility of accidental side effects:
const volatile char *port = (const volatile char *) 0x30;

Access Modifiers and constants in C and C++

Access Modifiers
There are two modifiers that control how variables may be accessed or modified. These
qualifiers are const and volatile. They must precede the type modifiers and the type
names that they qualify. These modifiers are also referred to as cv-qualifiers.

const
Variables of type const may not be changed by your program. (A const variable can be
given an initial value, however.) The compiler is free to place variables of this type into
read-only memory (ROM). For example,
const int a=10;
creates an integer variable called a with an initial value of 10 that your program may
not modify. However, you can use the variable a in other types of expressions. A const
variable will receive its value either from an explicit initialization or by some
hardware-dependent means.
The const qualifier can be used to protect the objects pointed to by the arguments
to a function from being modified by that function. That is, when a pointer is passed
to a function, that function can modify the actual variable pointed to by the pointer.
However, if the pointer is specified as const in the parameter declaration, the function
code won't be able to modify what it points to. For example, the sp_to_dash() function
in the following program prints a dash for each space in its string argument. That is,
the string "this is a test" will be printed as "this-is-a-test". The use of const in the
parameter declaration ensures that the code inside the function cannot modify the
object pointed to by the parameter.
#include <stdio.h>
void sp_to_dash(const char *str);
int main(void)
{
sp_to_dash("this is a test");
return 0;
}
void sp_to_dash(const char *str)
{
while(*str) {
if(*str== ' ') printf("%c", '-');
else printf("%c", *str);
str++;
}
}
If you had written sp_to_dash() in such a way that the string would be modified, it
would not compile. For example, if you had coded sp_to_dash() as follows, you would
receive a compile-time error:
/* This is wrong. */
void sp_to_dash(const char *str)
{
while(*str) {
if(*str==' ' ) *str = '-'; /* can't do this; str is const */
printf("%c", *str);
str++;
}
}
Many functions in the standard library use const in their parameter declarations.
For example, the strlen() function has this prototype:
size_t strlen(const char *str);
Specifying str as const ensures that strlen() will not modify the string pointed to by str.
In general, when a standard library function has no need to modify an object pointed to
by a calling argument, it is declared as const.
You can also use const to verify that your program does not modify a variable.
Remember, a variable of type const can be modified by something outside your
program. For example, a hardware device may set its value. However, by declaring
a variable as const, you can prove that any changes to that variable occur because of
external events.