PART 2

Features of C++

Compiler options and error checking

Constants and variables

Data types and operations

Expressions and assignment

Control structures and looping

Type casting

Default parameters

Error Checking in Borland C++ 4.0 for Windows

1. Select options from main menu

2. Select project from options menu

3. Double click on messages (if preceded by a +)

3.a. This allows viewing the 8 message categories

4. Click on each message category in turn

4.a. This allows viewing of 3 to 13 check boxes

5. Click on each unchecked item to check it

6. Click on OK after completion of 8 message categories

OR

1. Select options from main menu

2. Select project from options menu

3. Click on messages

4. Click on ALL diamond to enable all messages (does not change selected messages in each category - messages not checked in each category will be disabled when the SELECTED diamond is clicked)

PROGRAM ERROR CHECKING

Borland C++ uses compiler switches or options to control the extent of error checking.

The sequence on the opposing page will make the Borland C++ compiler as error sensitive as possible.

Not all programming errors, of course, can be found during compile time. Be sure to watch for compiler, linking, and execution errors.

Thus, you should do separate compilation, linking, and running (Alt-F9, followed by F9, or Alt-F9 followed by Ctrl-F9).

To enable checking for stack overflow:
1. Select options from main menu
2. Select project from options menu
3. Click on compiler until compiler options expanded
4. Click on debugging until debugging options expanded
4. Click on TEST STACK OVERFLOW box until box is checked.

Be sure to watch for messages at the end of execution. If you have "left something behind" that is discovered at the end of execution, this is a very serious error and must be fixed.

Be particularly wary of any program that gives a “null pointer assignment” error message at the end of execution or warns of possible “memory leakage.”

Borland C++ 4.0 for Windows Error Options

The Borland C and C++ compilers have 51 to 56 independent error checking options that can be enabled or disabled. Borland C++ for Windows has 56 options divided into 8 categories.

Portability

Non-portable pointer conversion

Non-portable pointer comparison

Constant out of range in comparison

Constant is long

Conversion may lose significant digits

Mixing pointers to different ‘char’ types

ANSI violations

Void functions may not return a value

Both return and return with a value used

Suspicious pointer conversion

Undefined structure structure

Redefinition of macro is not identical

Hexadecimal value contains more than three digits

Bit fields must be signed or unsigned int

Identifier is declared as both external and static

Declare type prior to use in prototype

Division by zero

Initializing identifier with identifier

Initialization is only partially bracketed

Non-ANSI keyword used: word

Obsolete C++

Base initialization without a class name is now obsolete

Style of function definition is now obsolete

Overloaded prefix operator used as a postfix operator

Inefficient C++ Coding

Functions containing identifier are not expanded inline

Temporary used to initialize identifier

Temporary used for parameter in call to identifier

Borland C++ 4.0 for Windows Error Options (Continued)

Potential C++ errors

Constant member identifier is not initialized

Assigning type to enumeration

Function1 hides virtual function function2

Non-const function function called for const object

Base class base1 is also a base class of base2

Array size for ‘delete’ ignored

Use qualified name to access nested type type

Handler for xxx is hidden by previous handler for yyy

Conversion to type will fail for members of virtual base base

Maximum precision used for member pointer type type

Use ‘> >‘ for nested templates instead of ‘>‘

Non-volatile function function called for volatile object

Potential Errors

Possibly incorrect assignment

Possible use of identifier before definition

No declaration for function function

Call to function with no prototype

Function should return a value

Ambiguous operators need parentheses

Condition is always true/false

Inefficient Coding

Identifier is assigned a value that is never used

Parameter identifier is never used

Identifier is declared but never used

Structure passed by value

Unreachable code

Code has no effect

General

Unknown assembler instruction

Ill-formed pragma

Array variable variable is near

Superfluous & with function

Identifier is obsolete

Cannot create precompiled header: header

maxline.cpp

/* MAXLINE.CPP: Find & print the longest line from input.

Functions in separate files, parameters passed */

/* iostream.h should be in all files containing I/O */

#include <iostream.h>

/* all functions invoked should be declared external

and their type should be specified */

extern int getline(char [], int);

extern void copy(char [], char[]);

main() // Computes and prints the longest line

{

const int maxline=1000; // maximum input line size

int len,// current line length

max = 0;// maximum length seen so far

char line[maxline], // current input line

save[maxline]; // longest line saved here

while ( (len = getline(line, maxline)) > 0 )

if (len > max) // beat previous length

{

max = len; // record this length

copy(save, line); // and save line

}

if (max > 0) // there was a line

{

cout < "\nlength of longest line: " < (max-1);

cout < "\nthe longest line is:\n\n";

cout < save < endl;

}

return 0;

}

SEPARATE SOURCE FILES

Sometimes source code is so long that it must be divided into files.

Sometimes source code exists in project source code libraries for common use.

When defining classes and objects, each group of class definitions will generally reside in a separate file.

Variables and functions used across files must be declared in such a way that needed information is available when each file goes through the compiler. The extern specifier declares that variables and functions are to be found in other files. Actually, since functions are external by default, the extern specifier could have been omitted in front of the declarations (prototypes) for the functions getline and copy.

Each file can be compiled separately, or several files can be compiled together.

Finally, the parts are linked together to form the final executable version of the program.

For example, main, getline, and copy are divided into three files, with function main() in file maxline.cpp, function getline(s, lim) in file getline.cpp, and function copy(s1,s2) in file copy.cpp.

Note that the function main() in file maxline.cpp requires two extern statements to declare the functions called by the function main(), but not defined in the file maxline.cpp.

getline.cpp

/* GETLINE.CPP this routine fetches a line

- the file needs a define for input */

#include <iostream.h>

/* the file needs no external statements */

int getline(char s[], int lim)

/* Get input line into array s. Check is

performed to avoid overflowing the array. The

function getline returns the length of the input

line, including a newline character, if present.

The array s is terminated with an ascii null */

{

char c; // input character

int i = 0; // intra-line counter

while( i<lim-1 & cin.get(c) & c != '\n' )

s[i++] = c;

if (c == '\n') // did we fall out with a \n?

s[i++] = c; // if so, keep it

s[i] = '\0'; // always terminate strings!

return(i);

}

copy.cpp

// COPY.CPP: separately compiled function to copy a string

// needs no includes, defines, or externals

// copy 'from' into 'to'; assume 'to' is big enough

void copy(char to[], char from[])

{

int i = 0; // string position counter

while( (to[i] = from[i]) != '\0' ) // move & check

++i;

}

Compiling Separate Files

VMS

cxx getline

cxx copy

cxx maxline

link maxline, getline, copy

run maxline

Turbo C++

tcc -c getline

tcc -c copy

tcc maxline getline.obj copy.obj

maxline

Borland C++

bcc -c getline

bcc -c copy

bcc maxline getline.obj copy.obj

maxline

SEPARATE COMPILATION

Many times there are common functions that do not change. It is inefficient to recompile a function each time it is used in a program.

The idea is to not only divide the source code into separate files, but also to compile these files separately, storing the compiled version of the program rather than the source code.

The -c option on the tcc or bcc command tells the compiler to suppress the loading phase of the compilation (thus not looking for a function main(), nor expecting all parts of the program to be present.) It also forces the creation of the object files getline.obj and copy.obj, respectively.

Separate compilation reduces compile time if there are many programs that need the functions stored in getline.cpp and copy.cpp, or if they are lengthy functions not subject to frequent change.

In Borland C++ 4.0 for Windows you should first exit windows to run these commands from the DOS prompt. The resulting .exe file runs from the DOS prompt. If you want the program to run under Windows, add the -W compiler switch.

In Borland C++ 4.0 for Windows if you wish to the DOS compile from a DOS window you must first create a PIF file for the DOS window that specifies -1 (infinite) for extended memory (XMS) limit (KB Limit).SEPARATE COMPILATION

In VMS, the three compile lines may be replaced by the single line:

cxx maxline, getline, copy

In this case, three separate object files are created.

In addition, source files in VMS may be treated as if they were contained in a single file by using the single command line:

cxx maxline + getline + copy

In the above case, only the object file maxline.obj would be generated. (The first name is used.)

maxline2.cpp

/* MAXLINE2.CPP: Find & print the longest line from input.

Uses global variables, no parameters passed */

#include <iostream.h>

const int maxline = 1000; // maximum input line size

int max = 0; // maximum length seen so far

char line[maxline]; // current input line

char save[maxline]; // longest line saved here

int getline(void);

void copy(void);

/* Computes and prints longest line; specialized version*/

main()

{

int len; // current line length

max = 0;

while ( (len = getline()) > 0 )

if (len > max) // beat previous length

{

max = len; // record this length

copy(); // and save line

}

if (max > 0)// there was a line

{

cout < "\nlength of longest line: " < (max-1);

cout < "\nthe longest line is:\n\n";

cout < save < endl;

}

return 0;

}

maxline2.cpp EXPLANATION

The three functions comprising this program file accomplish the same goal as in maxline1.cpp, but are organized in a very different way.

In maxline1.cpp, all data was local to each function. Whenever one function needed information from another it had to be passed back and forth via parameters and return values. This is not always practical.

In maxline2.cpp, the integer max, and the character arrays line and save are defined to be external (or global) variables. This means they are available to all functions that want them without using parameters or return values. An external definition is made by merely placing the definition outside of any function.

Since the philosophy of data sharing between functions has been altered, the declarations of the functions, as well as the functions themselves, must be altered. No data needs to be passed to getline, so we must declare that getline takes no parameters. This is done with the statement

int getline(void);

which also declares that getline will (still) return an integer.

Likewise, the function copy does not need any parameters, and, since it doesn't need to return any values either, it is declared as

void copy(void);

For a function to use an external variable defined in the same file, it need do nothing but use the variable name in the correct way. For a function to use an external variable defined in another file, it must declare its use at the beginning. If another function that wished to use the variable max were written with its source code in a different file, it would need to have the following statement in the beginning:

extern int max;

maxline2.cpp (continued)

/* Get input line into array line. The function getline

returns the length of the input line, including a newline

character, if present. The array line is terminated with

an ascii null; specialized version */

int getline(void)

{

char c; // input character

int i = 0; // intra-line counter

while( i<maxline-1 & cin.get(c) & c != '\n' )

line[i++] = c;

if (c == '\n') // did we fall out with a \n?

line[i++] = c; // if so, keep it

line[i] = '\0'; // always terminate strings!

return(i);

}

/* copy: copy 'line' into 'save';

assume 'save' is big enough; specialized version */

void copy(void)

{

int i = 0; // string position counter

while( (save[i] = line[i]) != '\0' ) // move & check

++i;

}

maxline2.cpp EXPLANATION (Continued)

Note that this program becomes "easier" to write without parameters. It will probably also achieve minor performance gains in execution speed.

The functions, however, are much less general. They will only work with properly named external variables. The external names also get involved in the linking process. So while execution may go a bit faster, compiling and linking will take longer.

In general, external variables should be avoided in favor of passing parameters at almost all costs. The most notable exception to this rule is for keeping track of machine status information across a variety of routines. In particular, error status is the most common status information that might require the use of global variables.

UNIX AND DOS REDIRECTION AND PIPES

Normally, a C++ program written for a UNIX or DOS system is written to read its data from "standard input" and write its data to "standard output." Usually, standard input and standard output default to the user terminal.

If it is desired to take input from a file rather than the terminal, input redirection can be used. This is done by using the sign followed by the filename. For example, suppose that the C++ program maxline.cpp has been compiled to generate the executable file maxline.exe. To run the program, taking input from the file named mydata.dat, the following command is used:

maxline < mydata.dat

Likewise, if it is desired to send the output to a file rather than to a terminal, output redirection can be used. This is done by using the sign followed by the filename. Thus to run the maxline program sending the output to the file named myoutput.dat, the following command is used:

maxline > myoutput.dat

Both input and output can be redirected in a single command as follows:

maxline < mydata.dat > myoutput.dat

Sometimes it is desirable to make the output of one program the input to another following program. This is done by using the pipe construction. A pipe is constructed by placing a | character between the two processes. For example, the UNIX and DOS command more causes output to be sent to the terminal in screenfuls. To obtain the results of a C++ program at the terminal in screenfuls, use the following command:

maxline | more

VMS REDIRECTION

In VMS temporary input redirection is achieved by using a VMS command to temporarily change the default location that VMS uses for program input. Thus to run the compiled C++ program named maxline.exe that takes input from the file named mydata.dat, the following two commands need to be executed in sequence (with no other commands in between):

$ define /user_mode sys$input mydata.dat

$ run maxline

Likewise, temporary output redirection in achieved in VMS by a similar define statement. To run the compiled C++ program named maxline.exe that sends the output to a file named myoutput.dat, the following two commands need to be executed in sequence:

$ define /user_mode sys$output myoutput.dat

$ run maxline

If both input and output redirection are desired, then two define statements are required prior to the run statement. In addition, the define for sys$input must come after the define for sys$output as follows:

$ define /user_mode sys$output myoutput.dat

$ define /user_mode sys$input mydata.dat

$ run maxline

declar.cpp

/* DECLAR.CPP: The sqrt and log are math functions (in the

C or C++ library) that return the square root and

natural logarithm, respectively, of their arguments.

Both functions take doubles as their arguments and

return doubles. */

/* Under Unix, the fact that the math functions in the

math library are being used must be conveyed to the

linker. If prog.cpp is a C++ program that uses these

math functions, then the program is compiled as:

% cpp prog.cpp -o prog -lm

(-lm tells the linker to use the math library) */

#include <iostream.h>

/* The following declaration(s) for sqrt and log are

necessary - remove them or get them wrong and see what

happens. The point of this program is that all

functions MUST be declared before they are used. */

#include <math.h> // always gets it "right"

// extern double sqrt(), log(); // old C style won't work

// extern "C" double sqrt(double), log double); //Borland

// extern double sqrt(double), log(double); //VAX

// risky trying to "hand craft" library function prototype

main()

{

double c;

for ( c = 1.0; c <= 10.0; ++c )

cout < c < " " < sqrt(c) <

" " < log(c) < endl;

for ( c = 1.0; c <= 10.0; ++c)

cout < c < " " < log(c) <

" " < sqrt(c) < endl;

return 0;

}

declar.cpp EXPLANATION

This program invokes functions not included in any of the programmer's source code files. The functions are mathematical functions included in the C math library.

To use these functions two things are needed. First, the proper declarations must be given in the source file. Second, the proper object code for the functions used must be obtained.

It is very risky to try to specify the function declarations explicitly. The proper way to obtain a correct function prototype by using the statement: