• Articles
  • You want to build a program but where to
Published by
Jan 14, 2008 (last update: Aug 4, 2011)

You want to build a program but where to start?

Score: 3.6/5 (39 votes)
*****
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
 
typedef int MARK;


To

 
typedef double MARK; 


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.