|
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| siavoshkc (21) | |||||||||||||||||||||||||
|
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:
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.
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.
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.
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.
We will discuss SetNewMark() later. Functions below seem straightforward:
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.
One entry is defined. To have a list we use an array of pointers to that class which keeps a pointer to each entry.
AddToList() is something like this:
You can read about "new" keyword in this web site, if you are not familiar with it. And DeleteFromTheList() is like this:
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[i].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[i]->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. | |||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||
| siavoshkc (21) | |||
|
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.
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 things similar This is all because I tried to keep the code simple. | |||
|
|
|||
| siavoshkc (21) | |||||
|
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. Feel free to contact me. | |||||
|
|
|||||
| pdusen (4) | |
|
Thanks, your modification works. However, would you mind explaining to me what some of it does? I am unclear on what (!(cin >> input)) means, what cin.clear() or cin.get() does, and why your while statement has no commands within it (it immediately terminates with a semicolon). Thank you very much! | |
|
|
|
| OnlineCop (7) | |||||||
|
pdusen: When cin (or std::cin) inputs the user's text into the variable (in this case, "input" is the variable name), it may occasionally have an error. Here is an example:
If a user were to input anything that wasn't a number (like a letter [a..z, A..Z], a symbol [$*%], etc.), the code would have problems. The "cin" returns a 0 (zero) if there is a problem, such as invalid user input. In siavoshkc's post, the "if (!(...))" is the same as saying "if ((...) == 0)". That way, if the user DID do something that you didn't expect, the whole program isn't affected. The "clear()" function is related to the cin() error. If cin() DOES have some sort of error, then cin.clear() would make it so future uses of cin() can function correctly:
If, in the first prompt for user input, the user typed in a non-number, the cin() would report an error (although no one was "listening" for that error). When it gets to the second portion where it prompts for a string of text, the cin() notices that it still has an error that wasn't resolved, so it doesn't actually collect any more information: it just basically skips the second cin() portion. Now, if you were to test the first cin() and see that it had a bad value, you could clear that cin() error code by using "clear()". It's as simple as using "cin.clear()". It doesn't necessarily re-prompt the user for input, but at least at the next instance of cin(), it will wait for input instead of skipping past due to the "unresolved error". Example:
You'll notice that when outputting at the end, the "userInputNumber" reports a garbage value, but at least the string displays correctly (at least, it displays the letter(s) you entered for the number prompt). Finally, cin.get() is explained here: http://www.cplusplus.com/reference/iostream/istream/get.html (actually, all these are explained on this site, but I thought some example code might be helpful). Hope this helps! | |||||||
|
Last edited on
|
|||||||
| yang (33) | |
| this is really helpful for us beginners, hope more posts on this topic. | |
|
|
|
| krystnika (4) | |||
That's a really great and helpful topic for us-the beginners and I understood almost everything but one thing...I read one book for C++ and there the class defining was explained a little bit different and I couldn't get this part here so can you explain more specifically that part:
I have no idea what the first and second line after "public" are doing and shouldn't we use constructors and destructors and shouldn't the two variables be in "Private" section? | |||
|
|
|||
| Faldrax (324) | |||
|
The class definition is probably not the best example for beginners. A revised (and hopefuly more obvious) version would be
As commented, the fist public declaration is the constructor. Using the same name for the type and variable (but different case) is fine for the compiler, but more confusing to read. The confusion was heightened by having the same name for the parameter and class member. Again, by using member initialisers for the compiler can distinguish between 'name' (the class member) and 'name' (the constructor parameter), but it's harder for someone reading the code - or perhaps more accurately it's easier for someone to make a mistake when reading the code! The second line is an overloaded '=' opperator, to allow you to use '=' to assign one StudentEntry to another. Operator overloading is reasonably common but somethign that probably deservs a comment (documentation for developers!) when presented for beginners. I have also modified it to make the members private - which is generaly regarded as good practice BUT it does mean we have to add get and set methods to access and modify the members - this would mean changing the rest of the code to use these. The one thing this does show is that there are often multiple ways to do things in C++, and often the 'best' way will depend on circumstances - which is confusing for beginners! The use of public vs private members is a good example of this. Making them public made the class simpler and use easier in the example, so could be said to be 'best'. But it is generally accepted that making them private with public methods to access and modify is 'best' - it allows the class to hide it's internal representation of the data (and thus allows the internal represetation to change without chanign teh use of the class) and provides a layer to incorporate validation of changes, for example. | |||
|
Last edited on
|
|||