Public |
Document
Document(int) ~Document InsertLine(int) DeleteLine(int) ChangeLine(int) Display(int, int) Save Retrieve |
Construct empty document
Construct empty document of specified size Free up text storage Add a line at specified position Delete a line at specified position Change line at specified position Display lines in specified range Store document to disk file Read document from disk file |
Private |
maxLines
numberLines ShiftLines(int, int) Grow text |
int
int Move lines of text from specified position up or down Double size of text array OCString* |
Streams, Revisited
ios / | \ istream ostream fstreambase | \ / \ | | \ / \ | ifstream iostream ofstream
istream.h
//extraction operators
istream& operator>> (int& i);
istream& operator>> (double& d);
istream& operator>> (char& c);
istream& operator>> (char* s);
istream& get(char& c);
istream& get(char* s, int n, int ch='n');
Stream cin is a predefined, open stream that is automatically associated with the standard input device.
Insertion operators and cout are defined similarily in ostream.h
File I/O uses ifstream and ofstream:
char fileName[30];
cout << "\nOpen which file?";
cin fileName;
ifstream fInput(fileName);
int i;
char c;
fInput >> i >> c;
Format-state flags
eof() - returns true if end-of-file condition detected on stream input
fail() - returns true if any attempt to do input or output fails
bad() - severe failure
good() - eof & fail & bad all false
ex. istream ist;
ist >> aValue;
while (!ist.fail())
{ //process aValue
...
}
while (!ist.fail()) can also be abbreviated by while (ist >> aValue)
Strings revisited
string.h functions:
Copy functions
char* strcpy(dest, src) |
char* strncpy(dest, src, nbrChar) |
Concatenation functions
char* strcat(dest, src) |
char* strncat(dest, src, nbrChar) |
Comparison functions
char* strcmp(src1, src2) |
char* strncmp(src1, src2, nbrChar) |
Search functions
char* strchr(src, ch) //returns pointer to first instance of ch in src |
char* strrchr(src, ch) //returns pointer to last instance of ch in src |
char* strstr(src1, src2) //returns pointer to first instance of src2 in src1 |
Length function
size_t strlen(src) |
ex. p = strcat(u, strncpy(t, "bonehead", 4);
lexicographical order:
1. First n(>=0) characters of s and t are equal, but s[n+1]<t[n+1]
2. First n(>=0) characters of s and t match, but s has exactly n characters and t has more
// OCSTRING.H // This file contains the declaration of the Object Concept version of class OCString. #ifndef _OCSTRING_H #define _OCSTRING_H #include <iostream.h> // for istream, ostream class OCString { public: // We define three different String constructors, and one destructor OCString(); // creates empty string OCString(char* array); // constructor using a standard C++ string OCString(const OCString& Other_String); // constructor using an OC String ~OCString(); // destructor for our Strings int GetLength(); // returns current length // We overload operators for assignment, subscripting, equality, extraction and insertion OCString& operator=(const OCString& str); char& operator[](int i); friend int operator==(const OCString& str1, const OCString& str2); friend istream& operator>>(istream& is, OCString& str); friend ostream& operator<<(ostream& os, OCString& str); private: char* s; // pointer to the first character of the string int length; // current length of the string }; #endif
9.3 Documenting Programs
1. An identifier should almost always be an English word that describes the purpose of the variable. (Except possibly for loop control variables)
2. Nouns should be used for class objects, types and quantities.
3. Verbs should be used to describe functions.
4. Names should be precise and unambiguous.
5. Be consistent with capitalization.
1. Include comments at the beginning of every file, at every declaration, at the beginning of every function, at every compound control structure, at any tricky or unusual code or anywhere theat requires explanation.
2. Comments should be in English and not be redundant.
3. Comments should relate parts of the program to one another.
4. Style of comments should be consistent.
// DOCUMENT.H // This file declares class Document, which serves as the basis for our PIP for chapter 9, // a lineoriented word processor. #ifndef _DOCUMENT_H #define _DOCUMENT_H #include "OCSTRING.H" // for class OCString class Document { public: Document(); // create default document of 10 lines Document(int i); // create document of specified size ~Document(); // destructor frees document storage void InsertLine(int); // insert new line at specified position void DeleteLine(int); // delete line from specified position void ChangeLine(int); // change the line at specified position void Display(int, int); // display range of lines on screen void Save(); // save text to a file void Retrieve(); // retrieve text from a file private: int maxLines; // current maximum for number of lines int numberLines; // current number of lines of text void ShiftLines(int, int); // shift lines up or down by one position void Grow(); // expand text array to fit more lines OCString* text; // points to the start of the text, // so we can make it grow dynamically }; #endif
syntax of a language = collection of grammar rules of a language
name ::= identifier | operator_function_name | conversion_function_name | qualified_name
qualified_name ::= class_name :: identifer | class_name :: operator_function_name | class_name :: conversion_function_name | class_name :: class_name | class_name :: ~class_name
conditional_expression ::= logical_OR_expression | logical_OR_expression ? expression : conditional_expression
assignment_expression ::= conditional_expression | unary_expression assignment_operator assignment_expression
assignment_operator ::= = | *= | /= | += | -= | %= | <<= | >>= | &= | ^= | |=
|
compiler (translator) |
|
object code |
syntax error
- C++ code violates one of the syntax rules (grammar)
RULES FOR REPAIRING SYNTAX ERRORS
1. Look at the line of code where the error is indicated.
2. If the source of the error is not evident, look earlier in the file of references to each of the identifiers that occur in the indicated line.
3. Start from the indicated line and work backwards towards the beginning of the file. Make sure that identifier names are spelled correctly and used consistently.
// DOCUMENT.CPP // The definition of class Document, for use in our word processor of PIP 9. // (With SYNTAX ERRORS) #include <iostream.h> // for cin, cout #include <fstream.h> // for ifstream, ofstream #include "DOCUMENT.H" // for class Document #include "OCSTRING.H" // for class OCString #include "UTILITY.H" // for Swap Document::Document() // constructor creates a default document of 10 lines, and allocates storage for document { maxLines=10; numberLines=1; text = new OCString[maxLines+1]; }; Document :: Document(int i) // constructor sets maximum and current number of lines, // and allocates storage for document { maxLines = i; numberLines = 1; text = new OCString[maxLines+1]; }; Document :: ~Document() // This destructor function for class Document deallocates, first the OCStrings that // comprise the text of the document, and then the document's pointer to its text. { delete [] text; }; void Document :: InsertLine(int lineNum) // This function inserts a new line of text at the position specified by parameter lineNum. { // Use class OCString and its overloaded I/O operators to read in a new line. OCString newLine; cout << "Type new line, followed by <Enter>:\n; ************unterminated string****************** cin >> newLine; ************statement missing ;****************** if(numberLines = maxLines) // if we have to expand text array Grow(); // do it ************possibly incorrect assignment****************** if (lineNum < 1) // if line number is too small lineNum = 1; // assume we'll insert at start if (lineNum > numLines) // if line number is too big text[numberLines+1] = newLine; // insert at the end ***********undefined symbol numLines****************** else { // normal insertion involves . . . ShiftLines(1,lineNum); // moving lines to make space, and text[lineNum] = newLine; // copying the line into our array } numberLines++; // in any case, we have one more line } void Document :: DeleteALine(int lineNum) ***********Document::DeleteALine is not a member of class Document****************** // This function removes a line of text from a document by shifting lines up. { if((lineNum<1) || (lineNum > numberLines)) // if illegal line specified cout << "\n*** No such line.\n"; // don't assume anything! else { cout << "\nDeleting line " << lineNum << ". . .\n"; ShiftLines(1,lineNum); // shift lines in array up numberLines; // one fewer line now } } void Document :: ChangeLine(int lineNum) // This function uses OCString assignment to replace an existing line with a new // one provided by the user. { if((lineNum<1) || (lineNum > numberLines)) // Can't replace a line cout << "\n*** No such line.\n"; // that doesn't exist else { cout << "Current line " << lineNum << ":" ; // Show the old line cout << '\n\t' << text[lineNum] << '\n'; cout << "Enter new line: \n\t"; cin >> text[lineNum]; // Read the new one } } void Document :: Display(int start, int finish) // Display a range of lines from the document on the screen. The hardest part is making // sure the line numbers make sense. { if (start > finish) Swap (start, finish); if (start < 1) start = 1; if (( finish > numberLines) || (finish < 1)) finish = numberLines; // use loop and OCString's overloaded insertion operator // to display each line of text in the range for (int lineNum=start; lineNum<=finish; lineNum++) { cout << "\n" << lineNum << ":\t"; cout << text[lineNum]; }; cout << "\n\n"; } void Document : Save() ***********declaration syntax error****************** // This function writes a document to a disk file. // The user provides a file name, and the function // opens that file and connects it to this program. { char fileName[30]; cout << "\n\nSave document in what file? Type full file name"; cout << "\nfollowed by <Enter>: "; cin >> fileName; ofstream f(fileName); // Now send the document one line at a time to the open file // Notice that we start with line #1, to be consistent with the user's counting cout << "\nWriting file: " << fileName << '\n'; for(int thisLine=1; thisLine <= numberLines; thisLine++) f << text[thisLine] << '\n'; // Close the file for safety's sake f.close(); } void Document :: Retrieve() // This function reads a document from a disk file. The user provides a file name, and the // function opens that file and connects it to this program. { char fileName[30]; cout << "\n\nOpen which document? Type full file name"; cout << "\nfollowed by <Enter>: "; cin >> fileName; ifstream f(fileName); // Since a file to be input must exist before reading it, we check to make sure it // does, and reprompt if we can't open the file name specified while (!f) { cout << "\nSpecified file cannot be opened. Try again..."; cout << "\n\nOpen which document? Type full file name"; cout << "\nfollowed by <Enter>: "; cin >> fileName; ifstream f(fileName); // Read the file in, one OCString at a time, starting with line #1 of the document // (leaving text[0] uninitialized that's OK because we don't access it!) cout << "\nReading file: " << fileName << '\n'; numberLines = 1; while(f >> text[numberLines]) { if (numberLines == maxLines) Grow(); numberLines++; } // the last read failed, so decrement the number of lines numberLines; f.close(); } void Document :: ShiftLines(int direction, int start) // This function moves lines of text one position up or down in our document, depending // upon the value of parameter direction (+1 means move lines down, making a space; 1 // means move lines up, deleting a line). Parameter start indicates the line number // from which the moving is to begin. { int i; if (direction > 0) // We want to make space, so copy lines "down" starting from the last line for(i = numberLines + 1; i >= start + 1; i) text[i]=text[i1]; else if (direction < 0) // We want to remove a line, so move lines "up" starting from the specified line for(i = start; i <= numberLines 1; i++) text[i]=text[i+1]; } void Document :: Grow() // Doubles the size of the dynamic array that holds the document's text. Called whenever // we run out of space when trying to insert a new line. { int newSize = 2 * maxLines; // double the size of current text OCString* newText = new OCString[newSize+1]; // create a new array of that size for (int i = 1; i <= maxLines; i++) // copy all lines into new array newText[i] = text[i]; delete[] text; text = newText; // make our document point to new text maxLines = newSize; // set new maximum size } ************compound statement missing }******************
Linking - integrating program libraries into a cohesive running program
1) forget to include a library file (identifiers not declared)
2) misspelled include file name
3) must have corresponding .CPP file for each .H file (identifiers undefined)
4) multiple declarations of include files (use #ifndef)
5) incorrect access control (functions that should be public are declared private)
RULES FOR AVOIDING LINKER ERRORS
1. Comment all include directives to indicate why it is being included.
2. Check file names in include directives to make sure that they match intended files.
3. Use #ifndef for all programmer-defined header files.
4. Define inline functions, global constants, and machine-dependent code in header files.
5. Comment all class declarations to describe access control.
Run-time errors = fatal errors & logic errors
Use built-in debugger
// PIP9.CPP // A program (and a support function) that combines our User, OCString, and Document // classes to make a simple, lineoriented word processor. #include <iostream.h> // for cin, cout #include <ctype.h> // for toupper #include "DOCUMENT.H" // for class Document (includes class OCString) #include "USER2.H" // for class User (revised for this program) void ProcessDocumentMenu(char c, int p1, int p2, Document d) // This function serves the purpose of associating commands and parameters received // from our menu with operations performed on Document objects. { // Choose an operation to perform switch(c) // based on the value of char c. . . { case 'I': d.InsertLine(p1); // insert a line a position p1 break; case 'C': d.ChangeLine(p1); // change the line at position p1 break; case 'D': d.DeleteLine(p1); // delete the line at position p1 break; case 'P': d.Display(p1, p2); // display the range of lines p1p2 break; case 'Q': return; // simply return to quit }; } void main() { Document d; // creates a new, empty document char ans; // Either leave the document blank, or read one in from disk cout << "\n\nType N to start a new document, or O to open an existing"; cout << "\ndocument. Then hit <Enter>: "; cin >> ans; ans = toupper(ans); if (ans == 'O') d.Retrieve(); // Create our menu, and the necessary variables to read commands User u; char command; int param1, param2; // The menu loop continues to get and process commands until // a quit command is entered do { u.ShowMenu(); u.GetMenu(command, param1, param2); ProcessDocumentMenu(command, param1, param2, d); } while(command != 'Q'); // Give the user a chance to save the current document before terminating cout << "\n\nType S to save current document, or X to exit without"; cout << "\nsaving. Then hit <Enter>: "; cin >> ans; ans = toupper(ans); if (ans == 'S') d.Save(); }
GENERAL DEBUGGING RULES
1. Become familiar and comfortable with the debugging tools.
2. When analyzing runtime errors, "play computer".
3. Start at point of error or incorrect behaviour and trace backwards.
4. In tracing backwards, examine every function and data item. Pay careful attention to values of array subscripts, formal and actual parameters and pointers.
5. Be systematic and thorough.
6. Avoid "fix and pray" approach to debugging.