You want to build a program but where to start?
OK, I'll tell you. This should be done in the following steps:
1. Specifications
2. Design
3. Implementation
4. Test & Debug
5. Documentation
We go through this article by an example program. Imagine we are ordered to make a program for a school. They need a program to store student's name and average of marks. Then they should be able to find a student's average by knowing his/her name and vice versa. The program should also be able to show all the averages on the screen, alphabetically sorted.
OK. Now we know what they want, so we can enter step one, Specifications:
> Program should start with a menu with the following options: 1) Show list 2) Enter new name 3) Change a mark 4) Delete an entry 5) Search by name 6) Search by mark 7)Exit
> The program should be able to do all the tasks in menu
> The program should keep the records (names and marks) on hard disk in order to keep them safe on power off and retrieve them when program starts.
Now step two, Design:
It is the most important part of the development because a good design will make implementation easy and efficient while a bad one will make you cry (and program users may insult you!). How should we start? There are classic ways to design a program. For trivial programs like this, we use top down functional decomposition technique. We write pseudo codes to demonstrate the design. As we see in specifications, 6 functions are necessary. In addition there should be a function to read user choice and call appreciate function. We also need to save the records somewhere and read them again when the program starts. So we should have a main() like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
int main()
{
LoadDataFromFile();
while(userChoice != 7){
userChoice = GetUserChoice();
switch (userChoice) {
case 1: ShowList(); break;
case 2: AddEntry(); break;
case 3: ChangeMark(); break;
case 4: Delete(); break;
case 5: ShowMark(); break;
case 6: ShowName(); break;
}
}
SaveDataToFile();
return 0;
}
|
main() gets user choice, calls the appreciate function and will loop until it gets the choice 7, which means exit. In this case main() returns and program terminates. main() also loads the data from a file and saves them on exit (just before return).
This is the function which reads data from a file. For the first time the program runs there is no file to be opened. So this function creates an empty file to store data.
1 2 3 4 5 6 7 8 9 10
|
LoadDataFromFile()
{
if(fileExists){
OpenFile();
ReadFileToMemory();
}
else
CreateNewFile();
}
|
We need to sorts the list then prints each item in the list until reaches the end of list. We sort list every time an item is added, so we will always have a sorted list in memory.
1 2 3 4
|
ShowList()
{
for(int i = 0; i < listCount; ++i ) cout << i << "\t" << listItem<i>;
}
|
To add an entry, program asks for name and mark of the student. There is an integer named listCount that keeps the number of records in the list.
1 2 3 4 5 6 7 8
|
AddEntry()
{
name = GetStudentName();
mark = GetStudentMark();
listCount++;
AddToList(name, mark);
SortList();
}
|
Each entry (name and mark pair) in the list has an index number. Suppose the user wants to change the mark of or delete an entry. She/He should first select the Show List option or using search options to find the desired entry and see its index. Then he/she can use Delete or Change Mark options which will ask for the index of desired entry. Every time an item is added, the list will be sorted. So indices may change.
1 2 3 4 5 6
|
ChangeMark()
{
idx = GetStudentIdx();
mark = GetStudentMark();
SetNewMark(idx, mark);
}
|
We will discuss SetNewMark() later.
Functions below seem straightforward:
1 2 3 4 5 6
|
Delete()
{
idx = GetStudentIdx();
DeleteFromTheList(idx);
listCount--;
}
|
1 2 3 4 5
|
ShowName()
{
mark = GetStudentMark();
for(int i = 0; i < listCount; ++i ) if(listItem<i>.mark == mark) cout << i << "\t" << listItem.name;
}
|
1 2 3 4 5
|
ShowMark()
{
name = GetStudentName();
for(int i = 0; i < listCount; ++i ) if(listItem<i>.name == name) cout << i << "\t" << listItem.mark;
}
|
Sort function uses bubble sort algorithm to sort the list. Study its code in implementation step.
You can see some new functions have been revealed in pseudo code. Some of them are straightforward like GetStudentMark() and some have to get studied like AddToList(). To get into more detail of those functions, we should now think about how to keep the records in the memory.
It is a branch of IT that discusses the ways which should be used to store particular kinds of data. But as I don't want to enter that area, I choose a simple method. We will have a class that defines a pair of name and mark.
1 2 3 4 5 6
|
class StudentEntry
{
public:
string name;
int mark;
}
|
One entry is defined. To have a list we use an array of pointers to that class which keeps a pointer to each entry.
|
StudentEntry *entryList[max_student];
|
AddToList() is something like this:
1 2 3 4 5
|
AddToList(name, mark)
{
entryList[entryCount] = new StudentEntry(name, mark);
}
|
You can read about "new" keyword in this web site, if you are not familiar with it.
And DeleteFromTheList() is like this:
1 2 3 4 5 6
|
if(entryCount != idx)
for(int i = idx; i < entryCount; i++) {
entryList<i>->name = entryList[i+1]->name;
entryList<i>->mark = entryList[i+1]->mark;
}
delete entryList[entryCount];
|
To delete an entry we just replace it by its successor and repeat this action till the end of list. We also must delete the last entry that is duplicated when the list is shifted up. If not we will have a memory leak.
You can see some things like (listItem
.name == name) in the design pseudo code. I wrote them before deciding how exactly entries are stored into memory. We can rewrite it as (entryList->name == name) now that we know we are using an array of pointers to class.
We have finished the design step. Now we exactly know how program works. We have actually written some parts of it.
Step three, Implementation:
Its time to write the code in the C++ language. As you noticed our pseudo code is nearly in C++ syntax but it needs to be polished to be a functional C++ program. I feel good to explain a little about the process of translating a cpp source code into an executable. First we write a code in cpp syntax and save it on hard disk. This cpp file is readable by humen of course. Next we give this file to a special executable, named "compiler". Compiler is a program that translates human readable data into machine readable data and saves it on hard disk as an object file (these are files with .obj extension). These files are not yet ready to be executed by the system. The reason is that they call many routines that are written in other files. For example the cout << operator is defined in a .lib or .dll file. There is another program named "linker" that copies the code from .lib or other .obj files and puts them in the target file (That is the .obj file with main() entry point). After this operation, the file is ready to be executed and will have the .exe extension.
So to make a program you first need to write its source code files somewhere, for example in Windows notepad, and save them, then give them to compiler. The compiler output is .obj of our .cpp files which will be given to linker in addition of needed .lib files to produce the final executive file.
It may seem complex and will be a real pain if you really try this actually. Because of this, there are programs named IDE (Integrated Development Environment) that make the work simple. They have usually an easy to use interface, they highlight cpp keywords, format document using spacing and indentation to make the code easy to read, and more important they do this compile and linking without bothering you. They do their job that smooth that you will not know a separate compiler and linker program exist and work independent of IDE program. IDEs usually also have some useful debug tools which helps us find bugs in program. Nevertheless you have to know how to use your IDE and we suppose you do. If you don't, please read its help and documentation. Now I make a new empty cpp file to write my code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
|
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
/////Declarations////////////////////////////////////////////////
const int MAX_STUDENT = 500;
const char FILE_PATH[] = "C:\\entry_file.txt";
typedef int INDEX;
typedef double MARK;
typedef string NAME;
int entryCount = -1; //-1 means the list is empty
fstream entryFile;
class StudentEntry
{
public:
StudentEntry(NAME name, MARK mark): name(name), mark(mark){}
StrudentEntry& operator = (StudentEntry &entry)
{
name = entry.name;
mark = entry.mark;
return *this;
}
NAME name;
MARK mark;
}*entryList[MAX_STUDENT];
/////Function prototypes////////////////////////////////////////
INDEX GetStudentIdx(); //Gets number of index from user
MARK GetStudentMark(); //Gets number of maerk from user
NAME GetStudentName(); //Gets string of name from user
void DeleteFromTheList(INDEX idx); //Deletes an item with index of idx
void Delete(); //Called by DeleteFromTheList(INDEX)
void ChangeMark(); //Changes the mark field of a record
void SetNewMark(INDEX idx, MARK mark); //Called by ChangeMark()
void AddEntry(); //Adds new item to list
void AddToList(NAME name, MARK mark); //Called by AddEntry()
void SortList(); //Does a buble sort on list
void ShowMark(); //Shows all marks with the same name
void ShowName(); //Shows all names with the same mark
void ShowList(); //Shows all the items in the list
int GetUserChoice(); //Gets numbet of option from user
void LoadDataFromFile(); //Loads data from a file
void SaveDataToFile(); //Saves data to a file
/////////////////////////////////////////////////////////////
INDEX GetStudentIdx()
{
cout << "Enter index: ";
INDEX idx;
cin >> idx;
return idx;
}
MARK GetStudentMark()
{
cout << "Enter mark: ";
MARK mark;
cin >> mark;
return mark;
}
NAME GetStudentName()
{
cout << "Enter name: ";
NAME name;
cin >> name;
return name;
}
void DeleteFromTheList(INDEX idx)
{
if(entryCount != idx)
for(int i = idx; i < entryCount; i++) {
entryList<i>->name = entryList[i+1]->name;
entryList<i>->mark = entryList[i+1]->mark;
}
delete entryList[entryCount];
}
void Delete()
{
if(entryCount != -1){
DeleteFromTheList(GetStudentIdx());
entryCount--;
}
}
void SetNewMark(INDEX idx, MARK mark)
{
entryList[idx]->mark = mark;
}
void ChangeMark()
{
SetNewMark(GetStudentIdx(), GetStudentMark());
}
void AddToList(NAME name, MARK mark)
{
entryList[entryCount] = new StudentEntry(name, mark);
}
void SortList()
{
for(int i = 0 ; i < entryCount;i++){
for(int j = 0 ; j < entryCount;j++)
{
if(entryList[j]->name.compare(entryList[j+1]->name ) == 1)
{
StudentEntry temp = *entryList[j+1];
*entryList[j+1] = entryList[j];
*entryList[j] = temp;
}
}
}
}
void AddEntry()
{
entryCount++;
NAME name = GetStudentName();
AddToList(name , GetStudentMark());
SortList();
}
void ShowMark()
{
NAME name = GetStudentName();
for(int i = 0; i <= entryCount; ++i ) if(entryList<i>->name == name) cout << i << "\t" << entryList<i>->mark << endl;
}
void ShowName()
{
MARK mark = GetStudentMark();
for(int i = 0; i <= entryCount; ++i ) if(entryList<i>->mark == mark) cout << i << "\t" << entryList<i>->name <<endl;
}
void ShowList()
{
for(int i = 0; i <= entryCount; ++i ) cout << i << "\t" << entryList<i>->name << "\t" << entryList<i>->mark << endl;
}
int GetUserChoice()
{
int choice;
cout << "Enter the option's number and press enter: ";
cin >> choice;
return choice;
}
void LoadDataFromFile()
{
entryFile.open(FILE_PATH,ios_base::in);
if(entryFile.is_open()){
cout << "File opened." << endl;
char temp[100];
for(entryCount = 0; entryFile >> temp; entryCount++)
{
entryList[entryCount] = new StudentEntry(temp, 0);
entryFile >> entryList[entryCount]->mark;
}
entryCount--;
entryFile.close();
entryFile.clear();
}
else{
entryFile.clear();
cout << "File not found in " << FILE_PATH << endl;
}
}
void SaveDataToFile()
{
entryFile.open(FILE_PATH,ios_base::out);
if(entryFile.is_open()){
if(!entryFile.good())
{
cout << "Error writing file." << endl;
}
else
for(int i =0 ;i<=entryCount;i++)
{
entryFile << entryList<i>->name<<endl;
entryFile << entryList<i>->mark<< endl;
}
entryFile.close();
}
}
int main()
{
LoadDataFromFile();
int userChoice;
do{
cout <<"1: Show List\n2: Add Entry\n3: Change Mark\n4: Delete\n5: Search Name\n6: Search Mark\n7: Save and Exit\n";
cout << "Current number of records: " << entryCount + 1<< endl;
userChoice = GetUserChoice();
switch (userChoice) {
case 1: ShowList(); break;
case 2: AddEntry(); break;
case 3: ChangeMark(); break;
case 4: Delete(); break;
case 5: ShowMark(); break;
case 6: ShowName(); break;
}
}while(userChoice != 7);
SaveDataToFile();
return 0;
}
|
This step is done by now. You should read this code carefully and compare it to pseudo code. It is not a perfect implementation as it has many shortcomings:
- You cannot enter a pair of name and sir name, only one of them
- If you enter any thing other than a number when it asks for mark or index, program crashes
- There is no error handling in program
- When it asks for an option, user is able to enter things like: "asd" or "23423".
- You may find many other similar things
This is all because I tried to keep the code simple.
Step 4, Test and Debug:
The above code actually has passed this step because I couldn't place a buggy code in the site. For testing, I ran it many times and tried different input data. I had some problems with reading from a file, which was simply because I had forgotten to allocate memory for items that were read from the file (using new).
I gave the program to my sister in order to test it. She said your program does not accept marks with floating point like 12.5. Because of good implementation I just had to change
To
The other problem I saw in my code was that marks were not linked to names. It was a bug in my SortList() function as it only sorted names and not the corresponding marks.
At last it couldn't save the data when the file was not opened in LoadDataFromFile(). It was because I didn't use clear() function which resets the stream flags after the file could not be opened. It was a beginner fault.
The code was tested and debugged on MSVC++ 2005 SP1.
Step 5, Documentation:
Documentation satisfies two peoples need; Developers and Users. Users need to know how to use the program, known issues, and how to troubleshoot. Developers need to know how the program works, how the design is, what the plug-in interface is (for programs that support), etc in order to develop the program in the future or for maintenance purposes. Using remarks to explain the ambiguous or key parts of the program is a very good practice. But additional design and implementation description should be written somewhere for further use.
Note: The code in this tutorial at the implementation phase is not a well written C++ code and by many is considered even wrong.
Feel free to contact me.