Showing posts with label in C. Show all posts
Showing posts with label in C. Show all posts

Monday, October 4, 2010

Bit-Fields in C, C++

Unlike some other computer languages, C/C++ has a built-in feature called a bit-field
that allows you to access a single bit. Bit-fields can be useful for a number of reasons,
such as:
If storage is limited, you can store several Boolean (true/false) variables in
one byte.
Certain devices transmit status information encoded into one or more bits
within a byte.
Certain encryption routines need to access the bits within a byte.
Although these tasks can be performed using the bitwise operators, a bit-field can
add more structure (and possibly efficiency) to your code.
To access individual bits, C/C++ uses a method based on the structure. In fact,
a bit-field is really just a special type of structure member that defines how long,
in bits, the field is to be. The general form of a bit-field definition is
struct struct-type-name {
type name1 : length;
type name2 : length;
..
.
type nameN : length;
} variable_list;
Here, type is the type of the bit-field and length is the number of bits in the field.
A bit-field must be declared as an integral or enumeration type. Bit-fields of length
1 should be declared as unsigned, because a single bit cannot have a sign.
Bit-fields are frequently used when analyzing input from a hardware device.
For example, the status port of a serial communications adapter might return a
status byte organized like this:

Bit    Meaning When Set

0        Change in clear-to-send line
1         Change in data-set-ready
2         Trailing edge detected
3        Change in receive line
4       Clear-to-send
5        Data-set-ready
6      Telephone ringing
7       Received signal

You can represent the information in a status byte using the following bit-field:

struct status_type {
unsigned delta_cts: 1;
unsigned delta_dsr: 1;
unsigned tr_edge: 1;
unsigned delta_rec: 1;
unsigned cts: 1;
unsigned dsr: 1;
unsigned ring: 1;
unsigned rec_line: 1;
} status;

You might use a routine similar to that shown here to enable a program to determine
when it can send or receive data.
status = get_port_status();
if(status.cts) printf("clear to send");
if(status.dsr) printf("data ready");
To assign a value to a bit-field, simply use the form you would use for any other type
of structure element. For example, this code fragment clears the ring field:
status.ring = 0;
As you can see from this example, each bit-field is accessed with the dot operator.
However, if the structure is referenced through a pointer, you must use the −> operator.
You do not have to name each bit-field. This makes it easy to reach the bit you
want, bypassing unused ones. For example, if you only care about the cts and dsr
bits, you could declare the status_type structure like this:
struct status_type {
unsigned : 4;
unsigned cts: 1;
unsigned dsr: 1;
} status;
Also, notice that the bits after dsr do not need to be specified if they are not used.
It is valid to mix normal structure members with bit-fields. For example,
struct emp {
struct addr address;
float pay;
unsigned lay_off: 1; /* lay off or active */
unsigned hourly: 1; /* hourly pay or wage */
unsigned deductions: 3; /* IRS deductions */
};
defines an employee record that uses only 1 byte to hold three pieces of information:
the employee's status, whether the employee is salaried, and the number of deductions.
Without the bit-field, this information would have taken 3 bytes.
Bit-fields have certain restrictions. You cannot take the address of a bit-field. Bitfields
cannot be arrayed. They cannot be declared as static. You cannot know, from
machine to machine, whether the fields will run from right to left or from left to right;
this implies that any code using bit-fields may have some machine dependencies.
Other restrictions may be imposed by various specific implementations, so check the
user manual for your compiler.

Arrays and Structures Within Structures

A member of a structure may be either a simple or compound type. A simple
member is one that is of any of the built-in data types, such as integer or character.
You have already seen one type of compound element: the character arrays used in
addr. Other compound data types include one-dimensional and multidimensional
arrays of the other data types and structures.
A member of a structure that is an array is treated as you might expect from
the earlier examples. For example, consider this structure:
struct x {
int a[10][10]; /* 10 x 10 array of ints */
float b;
} y;
To reference integer 3,7 in a of structure y, write
y.a[3][7]
When a structure is a member of another structure, it is called a nested structure.
For example, the structure address is nested inside emp in this example:
struct emp {
struct addr address; /* nested structure */
float wage;
} worker;
Here, structure emp has been defined as having two members. The first is a structure
of type addr, which contains an employee's address. The other is wage, which holds
the employee's wage. The following code fragment assigns 93456 to the zip element
of address.

worker.address.zip = 93456;
As you can see, the members of each structure are referenced from outermost to
innermost. Standard C specifies that structures may be nested to at least 15 levels.
Standard C++ suggests that at least 256 levels of nesting be allowed.

Friday, October 1, 2010

Using Structure Pointers in C,C++

There are two primary uses for structure pointers: to pass a structure to a function
using call by reference, and to create linked lists and other dynamic data structures that
rely on dynamic allocation. This chapter covers the first use.
There is one major drawback to passing all but the simplest structures to functions:
the overhead needed to push the structure onto the stack when the function call is
executed. (Recall that arguments are passed to functions on the stack.) For simple
structures with few members, this overhead is not too great. If the structure contains
many members, however, or if some of its members are arrays, run-time performance
may degrade to unacceptable levels. The solution to this problem is to pass only a
pointer to the function.
When a pointer to a structure is passed to a function, only the address of the
structure is pushed on the stack. This makes for very fast function calls. A second
advantage, in some cases, is when a function needs to reference the actual structure
used as the argument, instead of a copy. By passing a pointer, the function can
modify the contents of the structure used in the call.
To find the address of a structure variable, place the & operator before the
structure's name. For example, given the following fragment:
struct bal {
float balance;
char name[80];
} person;
struct bal *p; /* declare a structure pointer */
then
p = &person;

places the address of the structure person into the pointer p.
To access the members of a structure using a pointer to that structure, you must
use the −> operator. For example, this references the balance field:
p->balance
The −> is usually called the arrow operator, and consists of the minus sign followed
by a greater-than sign. The arrow is used in place of the dot operator when you are
accessing a structure member through a pointer to the structure.
To see how a structure pointer can be used, examine this simple program, which
prints the hours, minutes, and seconds on your screen using a software timer.
/* Display a software timer. */
#include <stdio.h>
#define DELAY 128000
struct my_time {
int hours;
int minutes;
int seconds;
} ;
void display(struct my_time *t);
void update(struct my_time *t);
void delay(void);
int main(void)
{
struct my_time systime;
systime.hours = 0;
systime.minutes = 0;
systime.seconds = 0;
for(;;) {
update(&systime);
display(&systime);
}
return 0;
}

void update(struct my_time *t)
{
t->seconds++;
if(t->seconds==60) {
t->seconds = 0;
t->minutes++;
}
if(t->minutes==60) {
t->minutes = 0;
t->hours++;
}
if(t->hours==24) t->hours = 0;
delay();
}
void display(struct my_time *t)
{
printf("%02d:", t->hours);
printf("%02d:", t->minutes);
printf("%02d\n", t->seconds);
}
void delay(void)
{
long int t;
/* change this as needed */
for(t=1; t<DELAY; ++t) ;
}
The timing of this program is adjusted by changing the definition of DELAY.
As you can see, a global structure called my_time is defined but no variable is
declared. Inside main() , the structure systime is declared and initialized to 00:00:00.
This means that systime is known directly only to the main() function.
The functions update() (which changes the time) and display() (which prints
the time) are passed the address of systime. In both functions, their arguments are
declared as a pointer to a my_time structure.
Inside update() and display() , each member of systime is accessed via a pointer.
Because update() receives a pointer to the systime structure, it can update its value.

For example, to set the hours back to 0 when 24:00:00 is reached, update() contains
this line of code:
if(t->hours==24) t->hours = 0;
This tells the compiler to take the address of t (which points to systime in main() )
and to reset hours to zero.
Remember, use the dot operator to access structure elements when operating on
the structure itself. When you have a pointer to a structure, use the arrow operator.

Structure Pointers in C, C++

C/C++ allows pointers to structures just as it allows pointers to any other type
of variable. However, there are some special aspects to structure pointers that
you should know.


Declaring a Structure Pointer
 
Like other pointers, structure pointers are declared by placing * in front of a structure
variable's name. For example, assuming the previously defined structure addr, the
following declares addr_pointer as a pointer to data of that type:
struct addr *addr_pointer;
Remember, in C++ it is not necessary to precede this declaration with the keyword
struct.

Passing Entire Structures to Functions in C,C++

When a structure is used as an argument to a function, the entire structure is passed
using the standard call-by-value method. Of course, this means that any changes 

made to the contents of the structure inside the function to which it is passed do not
affect the structure used as an argument.
When using a structure as a parameter, remember that the type of the argument
must match the type of the parameter. For example, in the following program both the
argument arg and the parameter parm are declared as the same type of structure.
#include <stdio.h>
/* Define a structure type. */
struct struct_type {
int a, b;
char ch;
} ;
void f1(struct struct_type parm);
int main(void)
{
struct struct_type arg;
arg.a = 1000;
f1(arg);
return 0;
}
void f1(struct struct_type parm)
{
printf("%d", parm.a);
}
As this program illustrates, if you will be declaring parameters that are structures,
you must make the declaration of the structure type global so that all parts of your
program can use it. For example, had struct_type been declared inside main() (for
example), then it would not have been visible to f1().
As just stated, when passing structures, the type of the argument must match
the type of the parameter. It is not sufficient for them to simply be physically similar;
their type names must match. For example, the following version of the preceding
program is incorrect and will not compile because the type name of the argument
used to call f1() differs from the type name of its parameter.

/* This program is incorrect and will not compile. */
#include <stdio.h>
/* Define a structure type. */
struct struct_type {
int a, b;
char ch;
} ;
/* Define a structure similar to struct_type,
but with a different name. */
struct struct_type2 {
int a, b;
char ch;
} ;
void f1(struct struct_type2 parm);
int main(void)
{
struct struct_type arg;
arg.a = 1000;
f1(arg); /* type mismatch */
return 0;
}
void f1(struct struct_type2 parm)
{
printf("%d", parm.a);

Thursday, September 30, 2010

Structure Assignments in C,C++

The information contained in one structure may be assigned to another structure of the
same type using a single assignment statement. That is, you do not need to assign the
value of each member separately. The following program illustrates structure
assignments:
#include <stdio.h>
int main(void)
 {
struct {
int a;
int b;
} x, y;
x.a = 10;
y = x; /* assign one structure to another */
printf("%d", y.a);
return 0;
}
After the assignment, y.a will contain the value 10.

Wednesday, September 29, 2010

Implementation Issues Of Functions in C,C++

There are a few important things to remember about functions that affect their
efficiency and usability. These issues are the subject of this section.

Parameters and General-Purpose Functions
A general-purpose function is one that will be used in a variety of situations, perhaps
by many different programmers. Typically, you should not base general-purpose
functions on global data. All of the information a function needs should be passed
to it by its parameters. When this is not possible, you should use static variables.
Besides making your functions general purpose, parameters keep your code
readable and less susceptible to bugs resulting from side effects.

Efficiency
Functions are the building blocks of C/C++ and are crucial to all but the simplest
programs. However, in certain specialized applications, you may need to eliminate
a function and replace it with inline code. Inline code performs the same actions as a
function, but without the overhead associated with a function call. For this reason,
inline code is often used instead of function calls when execution time is critical.
Inline code is faster than a function call for two reasons. First, a CALL instruction
takes time to execute. Second, if there are arguments to pass, these have to be placed
on the stack, which also takes time. For most applications, this very slight increase in
execution time is of no significance. But if it is, remember that each function call uses
time that would be saved if the function's code were placed in line. For example, the
following are two versions of a program that prints the square of the numbers from 1
to 10. The inline version runs faster than the other because the function call adds time.
in line function call
#include <stdio.h> #include <stdio.h>
int sqr(int a);
int main(void) int main(void)
{ {
int x; int x;
for(x=1; x<11; ++x) for(x=1; x<11; ++x)
printf("%d", x*x); printf("%d", sqr(x));
return 0; return 0;
} }
int sqr(int a)
{
return a*a;
}
 
Note : In C++, the concept of inline functions is expanded and formalized. In fact, inline
functions are an important component of the C++ language.

Declaring Variable-Length Parameter Lists Of function in C, C++

You can specify a function that has a variable number of parameters. The most
common example is printf() . To tell the compiler that an unknown number of
arguments may be passed to a function, you must end the declaration of its
parameters using three periods. For example, this prototype specifies that func()
will have at least two integer parameters and an unknown number (including 0)
of parameters after that.
int func(int a, int b, ...);
This form of declaration is also used by a function's definition.
Any function that uses a variable number of parameters must have at least one
actual parameter. For example, this is incorrect:
int func(...); /* illegal */

Function Prototypes in C, C++

In C++ all functions must be declared before they are used. This is normally
accomplished using a function prototype. Function prototypes were not part of the
original C language. They were, however, added when C was standardized. While
prototypes are not technically required by Standard C, their use is strongly encouraged.
Prototypes have always been required by C++. In this book, all examples include full
function prototypes. Prototypes enable both C and C++ to provide stronger type
checking, somewhat like that provided by languages such as Pascal. When you use
prototypes, the compiler can find and report any illegal type conversions between the
type of arguments used to call a function and the type definition of its parameters. The
compiler will also catch differences between the number of arguments used to call a
function and the number of parameters in the function.
The general form of a function prototype is
type func_name(type parm_name1, type parm_name2,. . .,
type parm_nameN);
The use of parameter names is optional. However, they enable the compiler to identify
any type mismatches by name when an error occurs, so it is a good idea to include
them.
The following program illustrates the value of function prototypes. It produces an
error message because it contains an attempt to call sqr_it() with an integer argument
instead of the integer pointer required. (It is illegal to convert an integer into a pointer.)
/* This program uses a function prototype to
enforce strong type checking. */
void sqr_it(int *i); /* prototype */
int main(void)
{

int x;
x = 10;
sqr_it(x); /* type mismatch */
return 0;
}
void sqr_it(int *i)
{
*i = *i * *i;
}
A function's definition can also serve as its prototype if the definition occurs prior
to the function's first use in the program. For example, this is a valid program.
#include <stdio.h>
/* This definition will also serve
as a prototype within this program. */
void f(int a, int b)
{
printf("%d ", a % b);
}
int main(void)
{
f(10,3);
return 0;
}
In this example, since f() is defined prior to its use in main(), no separate
prototype is required. While it is possible for a function's definition to serve as its
prototype in small programs, it is seldom possible in large onesespecially when
several files are used. The programs in this book include a separate prototype for
each function because that is the way C/C++ code is normally written in practice.
The only function that does not require a prototype is main(), since it is the first
function called when your program begins.
Because of the need for compatibility with the original version of C, there is a
small but important difference between how C and C++ handle the prototyping of a

function that has no parameters. In C++, an empty parameter list is simply indicated
in the prototype by the absence of any parameters. For example,
int f(); /* C++ prototype for a function with no parameters */
However, in C this prototype means something different. For historical reasons,
an empty parameter list simply says that no parameter information is given. As far as the
compiler is concerned, the function could have several parameters or no parameters. In
C, when a function has no parameters, its prototype uses void inside the parameter list.
For example, here is f() 's prototype as it would appear in a C program.
float f(void);
This tells the compiler that the function has no parameters, and any call to that function
that has parameters is an error. In C++, the use of void inside an empty parameter list
is still allowed, but is redundant.
In C++, f( ) and f(void) are equivalent.
Function prototypes help you trap bugs before they occur. In addition, they help
verify that your program is working correctly by not allowing functions to be called
with mismatched arguments.
One last point: Since early versions of C did not support the full prototype syntax,
prototypes are technically optional in C. This is necessary to support pre-prototype
C code. If you are porting older C code to C++, you may need to add full function
prototypes before it will compile. Remember: Although prototypes are optional in C,
they are required by C++. This means that every function in a C++ program must be
fully prototyped.

Returning Values in C, C+

All functions, except those of type void, return a value. This value is specified by the
return statement. In C, if a non-void function does not explicitly return a value via a
return statement, then a garbage value is returned. In C++, a non-void function must
contain a return statement that returns 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. However, if execution reaches the end of a non-void function, then a garbage value
is returned. Although this condition is not a syntax error, it is still a fundamental error
and should be avoided.
As long as a function is not declared as void, you may use it as an operand in an
expression. Therefore, each of the following expressions is valid:
x = power(y);
if(max(x,y) > 100) printf("greater");
for(ch=getchar(); isdigit(ch); ) ... ;
As a general rule, a function cannot be the target of an assignment. A statement
such as swap(x,y) = 100; /* incorrect statement */
is wrong. The C/C++ compiler will flag it as an error and will not compile a program
that contains it. (As is discussed in Part Two, C++ allows some interesting exceptions
to this general rule, enabling some types of functions to occur on the left side of an
assignment.)
When you write programs, your functions generally will be of three types. The
first type is simply computational. These functions are specifically designed to
perform operations on their arguments and return a value based on that operation.
A computational function is a "pure" function. Examples are the standard library
functions sqrt() and sin() , which compute the square root and sine of their arguments.
The second type of function manipulates information and returns a value that
simply indicates the success or failure of that manipulation. An example is the library
function fclose() , which is used to close a file. If the close operation is successful, the
function returns 0; if the operation is unsuccessful, it returns EOF.
The last type of function has no explicit return value. In essence, the function is
strictly procedural and produces no value. An example is exit() , which terminates a
program. All functions that do not return values should be declared as returning type
void. By declaring a function as void, you keep it from being used in an expression,
thus preventing accidental misuse.
Sometimes, functions that really don't produce an interesting result return
something anyway. For example, printf() returns the number of characters written.
Yet it would be unusual to find a program that actually checked this. In other words,
although all functions, except those of type void, return values, you don't have to use
the return value for anything. A common question concerning function return values
is, "Don't I have to assign this value to some variable since a value is being returned?"
The answer is no. If there is no assignment specified, the return value is simply
discarded. Consider the following program, which uses the function mul() :
#include <stdio.h>
int mul(int a, int b);
int main(void)
{
int x, y, z;
x = 10; y = 20;
z = mul(x, y); /* 1 */
printf("%d", mul(x,y)); /* 2 */
mul(x, y); /* 3 */

return 0;
}
int mul(int a, int b)
{
return a*b;
}
In line 1, the return value of mul() is assigned to z. In line 2, the return value is not
actually assigned, but it is used by the printf() function. Finally, in line 3, the return
value is lost because it is neither assigned to another variable nor used as part of an
expression.

Monday, September 27, 2010

Function Prototypes in C,C++

In C++ all functions must be declared before they are used. This is normally
accomplished using a function prototype. Function prototypes were not part of the
original C language. They were, however, added when C was standardized. While
prototypes are not technically required by Standard C, their use is strongly encouraged.
Prototypes have always been required by C++. In this book, all examples include full
function prototypes. Prototypes enable both C and C++ to provide stronger type
checking, somewhat like that provided by languages such as Pascal. When you use
prototypes, the compiler can find and report any illegal type conversions between the
type of arguments used to call a function and the type definition of its parameters. The
compiler will also catch differences between the number of arguments used to call a
function and the number of parameters in the function.
The general form of a function prototype is
type func_name(type parm_name1, type parm_name2,. . .,
type parm_nameN);
The use of parameter names is optional. However, they enable the compiler to identify
any type mismatches by name when an error occurs, so it is a good idea to include
them.
The following program illustrates the value of function prototypes. It produces an
error message because it contains an attempt to call sqr_it() with an integer argument
instead of the integer pointer required. (It is illegal to convert an integer into a pointer.)
/* This program uses a function prototype to
enforce strong type checking. */
void sqr_it(int *i); /* prototype */
int main(void)
{
int x;
x = 10;
sqr_it(x); /* type mismatch */
return 0;
}
void sqr_it(int *i)
{
*i = *i * *i;
}
A function's definition can also serve as its prototype if the definition occurs prior
to the function's first use in the program. For example, this is a valid program.
#include <stdio.h>
/* This definition will also serve
as a prototype within this program. */
void f(int a, int b)
{
printf("%d ", a % b);
}
int main(void)
{
f(10,3);
return 0;
}
In this example, since f() is defined prior to its use in main(), no separate
prototype is required. While it is possible for a function's definition to serve as its
prototype in small programs, it is seldom possible in large onesespecially when
several files are used. The programs in this book include a separate prototype for
each function because that is the way C/C++ code is normally written in practice.
The only function that does not require a prototype is main(), since it is the first
function called when your program begins.
Because of the need for compatibility with the original version of C, there is a
small but important difference between how C and C++ handle the prototyping of a

function that has no parameters. In C++, an empty parameter list is simply indicated
in the prototype by the absence of any parameters. For example,
int f(); /* C++ prototype for a function with no parameters */
However, in C this prototype means something different. For historical reasons,
an empty parameter list simply says that no parameter information is given. As far as the
compiler is concerned, the function could have several parameters or no parameters. In
C, when a function has no parameters, its prototype uses void inside the parameter list.
For example, here is f() 's prototype as it would appear in a C program.
float f(void);
This tells the compiler that the function has no parameters, and any call to that function
that has parameters is an error. In C++, the use of void inside an empty parameter list
is still allowed, but is redundant.
In C++, f( ) and f(void) are equivalent.
Function prototypes help you trap bugs before they occur. In addition, they help
verify that your program is working correctly by not allowing functions to be called
with mismatched arguments.
One last point: Since early versions of C did not support the full prototype syntax,
prototypes are technically optional in C. This is necessary to support pre-prototype
C code. If you are porting older C code to C++, you may need to add full function
prototypes before it will compile. Remember: Although prototypes are optional in C,
they are required by C++. This means that every function in a C++ program must be
fully prototyped.

Functions of Type void in C,C++

One of void's uses is to explicitly declare functions that do not return values. This
prevents their use in any expression and helps avert accidental misuse. For example,
the function print_vertical() prints its string argument vertically down the side of
the screen. Since it returns no value, it is declared as void.
void print_vertical(char *str)
{
while(*str)
printf("%c\n", *str++);
}
Here is an example that uses print_vertical() .
#include <stdio.h>
void print_vertical(char *str); /* prototype */

int main(int argc, char *argv[])
{
if(argc > 1) print_vertical(argv[1]);
return 0;
}
void print_vertical(char *str)
{
while(*str)
printf("%c\n", *str++);
}
One last point: Early versions of C did not define the void keyword. Thus, in
early C programs, functions that did not return values simply defaulted to type int.
Therefore, don't be surprised to see many examples of this in older code.

Returning Pointers in C,C++

Although functions that return pointers are handled just like any other type of
function, a few important concepts need to be discussed.
Pointers to variables are neither integers nor unsigned integers. They are the
memory addresses of a certain type of data. The reason for this distinction is because
pointer arithmetic is relative to the base type. For example, if an integer pointer is
incremented, it will contain a value that is 4 greater than its previous value (assuming
4-byte integers). In general, each time a pointer is incremented (or decremented), it
points to the next (or previous) item of its type. Since the length of different data types
may differ, the compiler must know what type of data the pointer is pointing to. For
this reason, a function that returns a pointer must declare explicitly what type of
pointer it is returning. For example, you should not use a return type of int * to return
a char * pointer!
To return a pointer, a function must be declared as having a pointer return type.
For example, this function returns a pointer to the first occurrence of the character c
in string s:
/* Return pointer of first occurrence of c in s. */
char *match(char c, char *s)
{
while(c!=*s && *s) s++;
return(s);
}
If no match is found, a pointer to the null terminator is returned. Here is a short
program that uses match() :


#include <stdio.h>
char *match(char c, char *s); /* prototype */
int main(void)
{
char s[80], *p, ch;
gets(s);
ch = getchar();
p = match(ch, s);
if(*p) /* there is a match */
printf("%s ", p);
else
printf("No match found.");
return 0;
}
This program reads a string and then a character. If the character is in the string, the
program prints the string from the point of match. Otherwise, it prints No match found.

Creating a Call by Reference in C,C++

Even though C/C++ uses call by value for passing parameters, you can create a
call by reference by passing a pointer to an argument, instead of the argument itself.
Since the address of the argument is passed to the function, code within the function
can change the value of the argument outside the function.
Pointers are passed to functions just like any other value. Of course, you need
to declare the parameters as pointer types. For example, the function swap() , which exchanges the values of the two integer variables pointed to by its arguments,
shows how.
void swap(int *x, int *y)
{
int temp;
temp = *x; /* save the value at address x */
*x = *y; /* put y into x */
*y = temp; /* put x into y */
}
swap() is able to exchange the values of the two variables pointed to by x and y
because their addresses (not their values) are passed. Thus, within the function,
the contents of the variables can be accessed using standard pointer operations, and
the contents of the variables used to call the function are swapped.
Remember that swap() (or any other function that uses pointer parameters) must
be called with the addresses of the arguments. The following program shows the correct
way to call swap() :
void swap(int *x, int *y);
int main(void)
{
int i, j;
i = 10;
j = 20;
swap(&i, &j); /* pass the addresses of i and j */
return 0;
}
In this example, the variable i is assigned the value 10 and j is assigned the value
20. Then swap() is called with the addresses of i and j. (The unary operator & is used
to produce the address of the variables.) Therefore, the addresses of i and j, not their
values, are passed into the function swap() .
C++ allows you to fully automate a call by reference through the use of reference
parameters. This feature is described in Part Two.

Function :The General Form of a Function in C,C++

Functions are the building blocks of C and C++ and the place where all program
activity occurs. This chapter examines their C-like features, including passing
arguments, returning values, prototypes, and recursion. Part Two discusses
the C++-specific features of functions, such as function overloading and reference
parameters.


The General Form of a Function

The general form of a function is
ret-type function-name(parameter list)
{
body of the function
}
The ret-type specifies the type of data that the function returns.Afunction may return
any type of data except an array. The parameter list is a comma-separated list of variable
names and their associated types that receive the values of the arguments when the
function is called.Afunction may bewithout parameters, in which case the parameter
list is empty. However, even if there are no parameters, the parentheses are still required.
In variable declarations, you can declare many variables to be of a common type
by using a comma-separated list of variable names. In contrast, all function parameters
must be declared individually, each including both the type and name. That is, the
parameter declaration list for a function takes this general form:
f(type varname1, type varname2, . . . , type varnameN)
For example, here are correct and incorrect function parameter declarations:
f(int i, int k, int j) /* correct */
f(int i, k, float j) /* incorrect */

Sunday, September 26, 2010

Arrays of Pointers in C,C++

Pointers may be arrayed like any other data type. The declaration for an int pointer
array of size 10 is
int *x[10];
To assign the address of an integer variable called var to the third element of the
pointer array, write
x[2] = &var;
To find the value of var, write
*x[2]
If you want to pass an array of pointers into a function, you can use the same
method that you use to pass other arrays—simply call the function with the array name
without any indexes. For example, a function that can receive array x looks
like this:
void display_array(int *q[])
{
int t;
for(t=0; t<10; t++)
printf("%d ", *q[t]);
}
Remember, q is not a pointer to integers, but rather a pointer to an array of pointers to
integers. Therefore you need to declare the parameter q as an array of integer pointers,
as just shown. You cannot declare q simply as an integer pointer because that is not
what it is.
Pointer arrays are often used to hold pointers to strings. You can create a function
that outputs an error message given its code number, as shown here:
void syntax_error(int num)
{
static char *err[] = {
"Cannot Open File\n",
"Read Error\n",
"Write Error\n",
"Media Failure\n"
};
printf("%s", err[num]);
}
The array err holds pointers to each string. As you can see, printf() inside
syntax_error() is called with a character pointer that points to one of the
various error messages indexed by the error number passed to the function.
For example, if num is passed a 2, the message Write Error is displayed.
As a point of interest, note that the command line argument argv is an
array of character pointers. (See Chapter 6.)

Pointer Comparisons in C,C++

You can compare two pointers in a relational expression. For instance, given two
pointers p and q, the following statement is perfectly valid:
if(p<q) printf("p points to lower memory than q\n");
Generally, pointer comparisons are used when two or more pointers point to
a common object, such as an array. As an example, a pair of stack routines are
developed that store and retrieve integer values. A stack is a list that uses first-in,
last-out accessing. It is often compared to a stack of plates on a table—the first
one set down is the last one to be used. Stacks are used frequently in compilers,
interpreters, spreadsheets, and other system-related software. To create a stack,
you need two functions: push() and pop() . The push() function places values on
the stack and pop() takes them off. These routines are shown here with a simple
main() function to drive them. The program puts the values you enter into the
stack. If you enter 0, a value is popped from the stack. To stop the program,
enter −1.
#include <stdio.h>
#include <stdlib.h>
#define SIZE 50
void push(int i);
int pop(void);
int *tos, *p1, stack[SIZE];
int main(void)
{
int value;
tos = stack; /* tos points to the top of stack */
p1 = stack; /* initialize p1 */
do {
printf("Enter value: ");
scanf("%d", &value);
if(value!=0) push(value);
else printf("value on top is %d\n", pop());
} while(value!=-1);

return 0;
}
void push(int i)
{
p1++;
if(p1==(tos+SIZE)) {
printf("Stack Overflow.\n");
exit(1);
}
*p1 = i;
}
int pop(void)
{
if(p1==tos) {
printf("Stack Underflow.\n");
exit(1);
}
p1--;
return *(p1+1);
}
You can see that memory for the stack is provided by the array stack. The pointer
p1 is set to point to the first element in stack. The p1 variable accesses the stack. The
variable tos holds the memory address of the top of the stack. It is used to prevent
stack overflows and underflows. Once the stack has been initialized, push() and
pop() may be used. Both the push() and pop() functions perform a relational test
on the pointer p1 to detect limit errors. In push() , p1 is tested against the end of
stack by adding SIZE (the size of the stack) to tos. This prevents an overflow. In
pop() , p1 is checked against tos to be sure that a stack underflow has not occurred.
In pop() , the parentheses are necessary in the return statement. Without them, the
statement would look like this:
return *p1 +1;
which would return the value at location p1 plus one, not the value of the location p1+1.

Pointer Arithmetic in C,C++

There are only two arithmetic operations that you may use on pointers: addition
and subtraction. To understand what occurs in pointer arithmetic, let p1 be an
integer pointer with a current value of 2000. Also, assume integers are 2 bytes long.
After the expression
p1++;
p1 contains 2002, not 2001. The reason for this is that each time p1 is incremented, it
will point to the next integer. The same is true of decrements. For example, assuming
that p1 has the value 2000, the expression
p1--;
causes p1 to have the value 1998.
Generalizing from the preceding example, the following rules govern pointer
arithmetic. Each time a pointer is incremented, it points to the memory location
of the next element of its base type. Each time it is decremented, it points to the
location of the previous element. When applied to character pointers, this will appear as "normal" arithmetic because characters are always 1 byte long. All other
pointers will increase or decrease by the length of the data type they point to. This
approach ensures that a pointer is always pointing to an appropriate element of its
base type. Figure 5-2 illustrates this concept.
You are not limited to the increment and decrement operators. For example, you
may add or subtract integers to or from pointers. The expression
p1 = p1 + 12;
makes p1 point to the twelfth element of p1's type beyond the one it currently points to.
Besides addition and subtraction of a pointer and an integer, only one other
arithmetic operation is allowed: You may subtract one pointer from another in
order to find the number of objects of their base type that separate the two. All
other arithmetic operations are prohibited. Specifically, you may not multiply or
divide pointers; you may not add two pointers; you may not aypply the bitwise
operators to them; and you may not add or subtract type float or double to or
from pointers.

What Are Pointers? Learning Pointers in C,C++

A pointer is a variable that holds a memory address. This address is the location of
another object (typically another variable) in memory. For example, if one variable
contains the address of another variable, the first variable is said to point to the second.

Pointer Variables
If a variable is going to hold a pointer, it must be declared as such. A pointer
declaration consists of a base type, an *, and the variable name. The general
form for declaring a pointer variable is
type *name;
where type is the base type of the pointer and may be any valid type. The name of
the pointer variable is specified by name.
The base type of the pointer defines what type of variables the pointer can point to.
Technically, any type of pointer can point anywhere in memory. However, all pointer
arithmetic is done relative to its base type, so it is important to declare the pointer
correctly. (Pointer arithmetic is discussed later in this chapter.)

The Pointer Operators
The pointer operators were discussed in Chapter 2. We will take a closer look at them
here, beginning with a review of their basic operation. There are two special pointer
operators: * and &. The & 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 returning "the address of." Therefore, the preceding assignment statement
means "m receives the address of count."
To understand the above assignment better, assume that the variable count uses
memory location 2000 to store its value. Also assume that count has a value of 100.
Then, after the preceding assignment, m will have the value 2000.
The second pointer operator, *, is the complement of &. It is a unary operator that
returns the value located at the address that follows. For example, if m contains the
memory address of the variable count,
q = *m;
places the value of count into q. Thus, q will have the value 100 because 100 is stored
at location 2000, which is the memory address that was stored in m. You can think of * as "at address." In this case, the preceding statement means "q receives the value at
address m."
Both & and * have a higher precedence than all other arithmetic operators except
the unary minus, with which they are equal.
You must make sure that your pointer variables always point to the correct type of
data. For example, when you declare a pointer to be of type int, the compiler assumes
that any address that it holds points to an integer variable—whether it actually does
or not. Because C allows you to assign any address to a pointer variable, the following
code fragment compiles with no error messages (or only warnings, depending upon
your compiler), but does not produce the desired result:
#include <stdio.h>
int main(void)
{
double x = 100.1, y;
int *p;
/* The next statement causes p (which is an
integer pointer) to point to a double. */
p = &x;
/* The next statement does not operate as
expected. */
y = *p;
printf("%f", y); /* won't output 100.1 */
return 0;
}
This will not assign the value of x to y. Because p is declared as an integer pointer, only
2 or 4 bytes of information will be transferred to y, not the 8 bytes that normally make
up a double.
In C++, it is illegal to convert one type of pointer into another without the use of an
explicit type cast. For this reason, the preceding program will not even compile if
you try to compile it as a C++ (rather than as a C) program. However, the type of
error described can still occur in C++ in a more roundabout manner.

A Tic-Tac-Toe Game Example in C,C++

The longer example that follows illustrates many of the ways that you can manipulate
arrays with C/C++. This section develops a simple tic-tac-toe program.
Two-dimensional arrays are commonly used to simulate board game matrices.
The computer plays a very simple game. When it is the computer's turn, it uses
get_computer_move() to scan the matrix, looking for an unoccupied cell. When it finds
one, it puts an O there. If it cannot find an empty location, it reports a draw game and
exits. The get_player_move() function asks you where you want to place an X. The
upper-left corner is location 1,1; the lower-right corner is 3,3.
The matrix array is initialized to contain spaces. Each move made by the player or
the computer changes a space into either an X or an O. This makes it easy to display the
matrix on the screen.
Each time a move has been made, the program calls the check() function. This
function returns a space if there is no winner yet, an X if you have won, or an O if the
computer has won. It scans the rows, the columns, and then the diagonals, looking for
one that contains either all X's or all O's.
The disp_matrix() function displays the current state of the game. Notice how
initializing the matrix with spaces simplified this function.
The routines in this example all access the matrix array differently. Study them to
make sure that you understand each array operation.
/* A simple Tic Tac Toe game. */
#include <stdio.h>
#include <stdlib.h>
char matrix[3][3]; /* the tic tac toe matrix */
char check(void);
void init_matrix(void);
void get_player_move(void);
void get_computer_move(void);
void disp_matrix(void);
int main(void)
{
char done;
printf("This is the game of Tic Tac Toe.\n");
printf("You will be playing against the computer.\n");
done = ' ';
init_matrix();
do{
disp_matrix();
get_player_move();
done = check(); /* see if winner */
if(done!= ' ') break; /* winner!*/
get_computer_move();
done = check(); /* see if winner */
} while(done== ' ');
if(done=='X') printf("You won!\n");
else printf("I won!!!!\n");
disp_matrix(); /* show final positions */
return 0;
}
/* Initialize the matrix. */
void init_matrix(void)
{
int i, j;
for(i=0; i<3; i++)
for(j=0; j<3; j++) matrix[i][j] = ' ';
}
/* Get a player's move. */
void get_player_move(void)
{
int x, y;
printf("Enter X,Y coordinates for your move: ");
scanf("%d%*c%d", &x, &y);
x--; y--;
if(matrix[x][y]!= ' '){
printf("Invalid move, try again.\n");
get_player_move();
}
else matrix[x][y] = 'X';
}
/* Get a move from the computer. */
void get_computer_move(void)
{
int i, j;
for(i=0; i<3; i++){
for(j=0; j<3; j++)
if(matrix[i][j]==' ') break;
if(matrix[i][j]==' ') break;
}
if(i*j==9) {
printf("draw\n");
exit(0);
}
else
matrix[i][j] = 'O';
}
/* Display the matrix on the screen. */
void disp_matrix(void)
{
int t;
for(t=0; t<3; t++) {
printf(" %c | %c | %c ",matrix[t][0],
matrix[t][1], matrix [t][2]);
if(t!=2) printf("\n---|---|---\n");
}
printf("\n");
}
/* See if there is a winner. */
char check(void)
{
int i;
for(i=0; i<3; i++) /* check rows */
if(matrix[i][0]==matrix[i][1] &&
matrix[i][0]==matrix[i][2]) return matrix[i][0];
for(i=0; i<3; i++) /* check columns */
if(matrix[0][i]==matrix[1][i] &&
/* test diagonals */
if(matrix[0][0]==matrix[1][1] &&
matrix[1][1]==matrix[2][2])
return matrix[0][0];
if(matrix[0][2]==matrix[1][1] &&
matrix[1][1]==matrix[2][0])
return matrix[0][2];
return ' ';
}