C++ Programming HOW-TO <!-- chapt change C++ Programming HOW-TO --> <author>Al Dev (Alavoor Vasudevan) <htmlurl url="mailto:alavoor@yahoo.com" name="alavoor@yahoo.com"> <date>v1.0, 19 March 2000 <abstract> This document discusses methods to avoid memory problems in C++ and also will help you to program properly in C++ language. The information in this document applies to all the operating sytems that is - Linux, MS DOS, Windows 95/NT, OS/2, IBM OSes, all flavors of Unix like Solaris, HPUX, AIX, SCO, Sinix, BSD, SCO, etc.. and to all other operating systems which support "C++" compiler (it means almost all the operating systems on this planet!). </abstract> <!-- Table of contents --> <toc> <!-- Begin the document --> <!-- ******************************************* ************ End of Section *************** ******************************************* <chapt>Introduction --> <sect>Introduction <p> C++ is the most popular language and will be used for a long time in the future inspite of emergence of Java. C++ runs <bf>extremely fast</bf> and is in fact <bf> 20 to 30 times FASTER than </bf> Java. Java runs very slow because it is interpreted language. The memory management in Java is automated and this document attempts to automate the memory management in C++. Also debugging C++ programs consumes a major portion of time while developing a software project. The information in this document will give you some better ideas and tips to reduce the debugging time. <!-- ******************************************* ************ End of Section *************** ******************************************* --> <sect1>Problems facing the current C++ compilers <p> Since C++ is super-set of C, it got all the bad features of "C" language. For example, in "C" memory leaks, memory overflows are very common due to usage of features like - <code> datatype char * and char[] functions like strcpy, strcat, strncpy, strncat etc.. </code> The usage of <bf>char *</bf> and <bf>strcpy</bf> causes <it>horrible</it> memory problems due to <it>"overflow"</it>, <it>"fence past errors"</it> or <it>"memory leaks"</it>. The memory problems are extremely hard to debug and are very time consuming to fix and trouble-shoot. Memory problems bring down the productivity of programmers. This document helps in increasing the productivity of programmers via different methods addressed to solve the memory defects in "C++". Memory related bugs are very tough to crack, and even experienced programmers take several days or weeks to debug memory related problems. Hence, the following techniques are proposed to overcome the faults of "C" language. It is proposed that C++ compilers should prevent the programmers from using the <bf>"char *"</bf>, <bf>"char[]"</bf> datatypes and functions like <bf>strcpy</bf>, <bf>strcat</bf>, <bf>strncpy</bf>, <bf>strncat</bf>. The datatypes like char *, char[] and functions like strcpy, strcat are <bf>evil</bf> and must be completetly <bf>BANNED</bf> from usage!! Instead of using char * and char[] all the C++ programmers MUST use the <bf><it>mychar class</it></bf> which is given in this document. The <bf><it>mychar class</it></bf> utilises the constructor and destructor to automate the memory management and also provides many functions like <it>ltrim</it>, <it>substring</it>, etc.. See also related <bf>'string class'</bf> in the compiler. The <bf>string class</bf> is part of the standard GNU C++ library and provides lot of string manipulation functions. Also, programmers must be encouraged to use 'new', 'delete' features instead of using 'malloc' or 'free'. The mychar class does everything that <bf>char *</bf> or <bf>char []</bf> does. It can completely replace <bf>char</bf> datatype. Plus added benefit is that programmers do not have to worry about the memory problems and memory allocation at all!! The GNU C++ compiler MUST drop off the support of <bf>char *, char[]</bf> datatypes and in order to compile older programs using <bf>char</bf> datatype, the compiler should provide a additional option called "-fchar-datatype" to g++ command. Over the next 2 years all the C++ programs will use mychar and string class and there will be no char * and char[]. The compiler should try to prevent bad programming practices! <!-- ******************************************* ************ End of Section *************** ******************************************* <chapt> Usage of mychar class --> <sect> Usage of mychar class <p> The <bf>mychar</bf> class is a complete replacement for char and char * datatype. You can use <bf>mychar</bf> class just like char and get much more functionalities. See illustration code as given below - <code> mychar aa; aa = " Washington DC is capital of USA "; // You can use aa.val like a 'char *' variable in programs !! for (unsigned long tmpii = 0; tmpii < aa.length(); tmpii++) { fprintf(stdout, "aa.val[%ld]=%c ", tmpii, aa.val[tmpii]); } // Using pointers on 'char *' val ... for (; *aa.val != 0; aa.val++) { fprintf(stdout, "aa.val=%c ", *aa.val); } </code> A complete example program "mychar.cpp" implementing the mychar class is given in <ref id ="Appendix A" name="Appendix A"> and mychar class is given in <ref id ="Appendix B" name="Appendix B">. <!-- ******************************************* ************ End of Section *************** ******************************************* --> <sect1> Operators <p> The <bf>mychar</bf> class provides these operators :- <itemize> <item> Equal to <bf>==</bf> <item> Not equal to <bf>!=</bf> <item> Assignment <bf>=</bf> <item> Add to itself and Assignment <bf>+=</bf> <item> String concatenation or addition <bf>+</bf> </itemize> For example to use operators - <code> mychar aa; aa = "put some value string"; aa += "add some more"; aa = "My name is" + " Alavoor Vasudevan "; if (aa == "some string") cout << "strings are equal" << endl; if (aa != "some string") cout << "strings are not equal" << endl; </code> <!-- ******************************************* ************ End of Section *************** ******************************************* --> <sect1> Functions <p> The <bf>mychar</bf> class provides these functions :- <itemize> <item> Current string length <bf>length()</bf> <item> Left trim the string. Remove leading white-spaces - newlines, tabs <bf>ltrim()</bf> <item> Right trim the string. Remove trailing white-spaces - newlines, tabs <bf>rtrim()</bf> <item> Remove trailing and leading white-spaces <bf>trim()</bf> <item> Remove trailing newlines <bf>chop()</bf> <item> Change string to upper case <bf>to_upper()</bf> <item> Change string to lower case <bf>to_lower()</bf> <item> Find position, matching substr beginning from start <bf>pos(char *substr, unsigned long start)</bf> <item> Explodes the string and returns the list in the list-head pointer explodeH <bf>explode(char *seperator)</bf> <item> Implodes the strings in the list-head pointer explodeH and returns the mychar variable <bf>implode(char *glue)</bf> <item> Joins the strings in the list-head pointer explodeH and returns the mychar variable <bf>join(char *glue)</bf> <item> Repeat the input string n times <bf>repeat(char *input, unsigned int multiplier)</bf> <item> Reverse the string characters <bf>reverse()</bf> <item> Replace all occurences of string 'needle' with 'str' in the haystack 'val' <bf>replace(char *needle, char *str)</bf> <item> Translate certain chars <bf>str_tr(char *from, char *to)</bf> <item> Center the text string <bf>center(int length, char padchar = ' ')</bf> <item> Formats the original string by placing 'number' of 'padchar' characters between each set of blank-delimited words. Leading and Trailing blanks are always removed. If 'number' is omitted or is 0, then all spaces are in the string are removed. The default number is 0 and default padchar ' ' <bf>space(int number = 0, char padchar = ' ')</bf> <item> The result is string comprised of all characters between and including 'start' and 'end' <bf>xrange(char start, char end)</bf> <item> Removes any characters contained in 'list'. The default character for 'list' is a blank ' ' <bf>compress(char *list)</bf> <item> Deletes a portion of string of 'length' characters from 'start' position. If start is greater than the string length than string is unchanged <bf>delstr(int start, int length)</bf> <item> The 'newstr' in inserted into val beginning at 'start'. The 'newstr' will be padded or truncated to 'length' characters. The default 'length' is string length of newstr <bf>insert(char *newstr, int start = 0, int length = 0, char padchar = ' ')</bf> <item> The result is string of 'length' chars madeup of leftmost chars in val. Quick way to left justify a string <bf>left(int length = 0, char padchar = ' ')</bf> <item> The result is string of 'length' chars madeup of rightmost chars in val. Quick way to right justify a string <bf>right(int length = 0, char padchar = ' ')</bf> <item> The 'newstr' in overlayed into val beginning at 'start'. The 'newstr' will be padded or truncated to 'length' characters. The default 'length' is string length of newstr <bf>overlay(char *newstr, int start = 0, int length = 0, char padchar = ' ')</bf> <item> Sub-string, extract a portion of string <bf>substr(int start, int length = 0)</bf> <item> matches first match of regx <bf>at(char *regx)</bf> <item> Returns string before regx <bf>before(char *regx)</bf> <item> Returns string after regx <bf>after(char *regx)</bf> <item> Returns true if string is NULL value <bf>bool isnull()</bf> <item> Resets the string to NULL <bf>clear()</bf> </itemize> <!-- ******************************************* ************ End of Section *************** ******************************************* --> <sect1> Miscellaneous Functions <p> Some miscellaneous mychar functions are given here, but <bf>DO NOT USE</bf> these, and instead use operators like '+', '+=', '==' etc.. <itemize> <item> Copy string <bf>str_cpy(char *bb)</bf> <item> Long integer converted to string <bf>str_cpy(unsigned long bb)</bf> <item> Integer converted to string <bf>str_cpy(int bb)</bf> <item> Float converted to string <bf>str_cpy(float bb)</bf> <item> str_cat(char *bb) <item> str_cat(int bb) <item> str_cat(unsigned long bb) <item> str_cat(float bb) <item> bool equalto(const mychar & rhs, bool type = false) <item> bool equalto(const char *rhs, bool type = false) </itemize> For example to convert integer to string do - <code> mychar aa; aa = 34; // The '=' operator will convert int to string cout << "The value of aa is : " << aa.val << endl; aa = 234.878; // The '=' operator will convert float to string cout << "The value of aa is : " << aa.val << endl; aa = 34 + 234.878; cout << "The value of aa is : " << aa.val << endl; // The output aa will be '268.878' // You must cast mychar to convert aa = (mychar) 34 + " Honourable President Ronald Reagan " + 234.878; cout << "The value of aa is : " << aa.val << endl; // The output aa will be '34 Honourable President Ronald Reagan 234.878' </code> <!-- ******************************************* ************ End of Section *************** ******************************************* <chapt> C++ Zap (Delete) command <label id="zap"> --> <sect> C++ Zap (Delete) command <label id="zap"> <p> The <bf>delete</bf> and <bf>new</bf> commands in C++ are much better than the malloc and free functions of "C". Consider using new and zap (delete command) instead of malloc and free as much as possible. To make <bf>delete</bf> command even more cleaner, make a Zap() command. Define a zap() command like this: <code> #define zap(x) if (x) { delete(x); x=0; } </code> Then, assuming all pointers start their lives as null pointers, I can safely delete what's been newed, and not delete things that haven't been newed, with a series of zap() commands like this: <code> zap(pchFirstname); zap(pchLastname); zap(pchJobDescription); </code> There is nothing magical about this, it just saves repetative code and makes it more readable. Do not stick a typecast in the zap() command -- if something errors out on the above zap() command it likely has another error somewhere. Also <ref id="my_malloc" name="my_malloc()"> , my_realloc() and my_free() should be used instead of malloc(), realloc() and free(), as they are much cleaner and have additional checks. For an example, see the file "mychar.h" which is using the <ref id="my_malloc" name="my_malloc()"> and my_free() functions. <!-- ******************************************* ************ End of Section *************** ******************************************* <chapt> Usage of my_malloc and my_free <label id="my_malloc"> --> <sect> Usage of my_malloc and my_free <label id="my_malloc"> <p> Try to avoid using malloc and realloc as much as possible and use <bf>new</bf> and <bf><ref id="zap" name="zap">(delete)</bf>. But sometimes you may need to use the "C" style memory allocations in "C++". Use the functions <bf>my_malloc()</bf> , <bf>my_realloc()</bf> and <bf>my_free()</bf>. These functions do proper allocations and initialisations and try to prevent memory problems. Also these functions (in DEBUG mode) can keep track of memory allocated and print total memory usage before and after the program is run. This tells you if there are any memory leaks. The my_malloc and my_realloc is defined as below. See <ref id ="Appendix C" name="Appendix C my_malloc.cpp">. and the header file <ref id ="Appendix D" name="Appendix D my_malloc.h">. <code> // size_t is type-defed unsigned long void *local_my_malloc(size_t size, char fname[], int lineno) { size_t tmpii = size + SAFE_MEM; void *aa = NULL; aa = (void *) malloc(tmpii); if (aa == NULL) raise_error_exit(MALLOC, VOID_TYPE, fname, lineno); memset(aa, 0, tmpii); call_check(aa, tmpii, fname, lineno); return aa; } // size_t is type-defed unsigned long char *local_my_realloc(char *aa, size_t size, char fname[], int lineno) { remove_ptr(aa, fname, lineno); size_t tmpii = sizeof (char) * size + SAFE_MEM; aa = (char *) realloc(aa, tmpii); if (aa == NULL) raise_error_exit(REALLOC, CHAR_TYPE, fname, lineno); // do not memset here!!! memset(aa, 0, tmpii); aa[tmpii-1] = 0; // set last location to 0 call_check(aa, tmpii, fname, lineno); return aa; } </code> An example on usage of my_malloc and my_free as below: <code> char *aa; int *bb; float *cc; aa = (char *) my_malloc(sizeof(char)* 214); bb = (int *) my_malloc(sizeof(int) * 10); cc = (float *) my_malloc(sizeof(int) * 20); aa = my_realloc(aa, sizeof(char) * 34); bb = my_realloc(bb, sizeof(int) * 14); cc = my_realloc(cc, sizeof(float) * 10); </code> Note that in my_realloc you do not need to cast the datatype as the variable itself is passed and correct my_realloc is called which returns the proper datatype pointer. The my_realloc has overloaded functions for char*, int* and float*. <!-- ******************************************* ************ End of Section *************** ******************************************* <chapt> Debug files --> <sect> Debug files <p> To debug any C++ or C programs include the file <ref id="Appendix E" name="debug.h"> and in your Makefile define DEBUG to turn on the traces from the debug.h functions. When you remove the '-DDEBUG' than the debug function calls are set to ((void)0) i.e. NULL, hence it has impact on final production release version of project. You can generously use the debug functions in your programs and it will not increase the size of production executable. See the file <ref id="Appendix F" name="debug.cpp"> for implementation of debug routines. And see the file <ref id="Appendix C" name="my_malloc.cpp"> for sample which uses debug.h and debug functions. <code> CC=g++ LIBS=-lstdc++ $(MYLIBS) OBJS=my_malloc.o mychar.o debug.o EXE=sample # For production uncomment this line #MYCFLAGS=-g3 -DDEBUG_MYCHAR -Wall # For debugging uncomment this line MYCFLAGS=-g3 -DDEBUG -DDEBUG_MYCHAR -Wall $(EXE): $(OBJS) @echo "Creating a executable " $(CC) -o $(EXE) $(OBJS) $(LIBS) </code> <!-- ******************************************* ************ End of Section *************** ******************************************* <chapt> C++ Online-Docs --> <sect> C++ Online-Docs <p> Visit the following C++ sites :- <itemize> <item>C++ Crash-proof site <url url="http://www.troubleshooters.com/codecorn/crashprf.htm"> <item>C++ Memory site<url url="http://www.troubleshooters.com/codecorn/memleak.htm"> </itemize> Internet has vast amounts of documentation on C++. Visit the search engines like Yahoo, Lycos, Infoseek, Excite. Type in the keywords <bf>'C++ tutorials'</bf> <bf>'C++ references'</bf> <bf>'C++ books'</bf> . You can narrow down the search criteria by clicking on <it>Advanced</it> search and select <it>search by exact phrase</it> <itemize> <item> HTML : <url url="http://www.yahoo.com"> <item> HTML : <url url="http://www.lycos.com"> <item> HTML : <url url="http://www.infoseek.com"> <item> HTML : <url url="http://www.excite.com"> <item> HTML : <url url="http://www.mamma.com"> </itemize> <sect1> C++ Tutorials <p> There are many on-line tutorials available on internet. Type 'C++ tutorials' in the search engine. <sect1> C++ Quick-Reference <p> Type 'C++ Reference' in the search engine. <sect1> C++ Usenet Newsgroups <p> <itemize> <item> C++ newsgroups : <url url="comp.lang.c++.announce"> <item> C++ newsgroups : <url url="comp.lang.c++.*"> </itemize> <!-- ******************************************* ************ End of Section *************** ******************************************* <chapt change> Memory Tools --> <sect> Memory Tools <p> Use the following memory debugging tools <itemize> <item> On linux contrib cdrom see mem_test*.rpm package <item> On linux cdrom see ElectricFence*.rpm package <item> Purify Tool from Rational Software Corp <url url="http://www.rational.com"> <item> Insure++ Tool from Parasoft Corp <url url="http://www.parasoft.com"> <item> Linux Tools at <url url="http://www.xnet.com/~blatura/linapp6.html#tools"> <item> Search the Internet engines like Yahoo, Lycos, Excite, Mamma.com for keyword "Linux memory debugging tools". </itemize> <!-- ******************************************* ************ End of Section *************** ******************************************* <chapt change> Related URLs --> <sect> Related URLs <p> Visit following locators which are related to C, C++ - <itemize> <item> <url url="http://metalab.unc.edu/LDP/HOWTO/Vim-HOWTO.html" name="Vim color text editor for C++, C"> <item> <url url="http://metalab.unc.edu/LDP/HOWTO/C-C++Beautifier-HOWTO.html" name="C++ Programming HOWTO"> <item> <url url="http://metalab.unc.edu/LDP/HOWTO/CVS-HOWTO.html" name="CVS HOWTO for C++ programs"> <item> Linux goodies main site <url url="http://www.aldev.8m.com"> <item> Linux goodies mirror site <url url="http://www.aldev.webjump.com"> </itemize> <!-- ******************************************* ************ End of Section *************** ******************************************* <chapt change> Other Formats of this Document --> <sect> Other Formats of this Document <p> This document is published in 10 different formats namely - DVI, Postscript, Latex, LyX, GNU-info, HTML, RTF(Rich Text Format), Plain-text, Unix man pages and SGML. <itemize> <item> You can get this HOWTO document as a single file tar ball in HTML, DVI, Postscript or SGML formats from - <url url="ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/other-formats/"> or <url url="ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/other-formats/"> <item>Plain text format is in: <url url="ftp://metalab.unc.edu/pub/Linux/docs/HOWTO"> or <url url="ftp://metalab.unc.edu/pub/Linux/docs/HOWTO"> <item>Translations to other languages like French, German, Spanish, Chinese, Japanese are in <url url="ftp://metalab.unc.edu/pub/Linux/docs/HOWTO"> or <url url="ftp://metalab.unc.edu/pub/Linux/docs/HOWTO"> Any help from you to translate to other languages is welcome. </itemize> The document is written using a tool called "SGML tool" which can be got from - <url url="http://www.xs4all.nl/~cg/sgmltools/"> Compiling the source you will get the following commands like <itemize> <item>sgml2html C++Programming-HOWTO.sgml (to generate html file) <item>sgml2rtf C++Programming-HOWTO.sgml (to generate RTF file) <item>sgml2latex C++Programming-HOWTO.sgml (to generate latex file) </itemize> This document is located at - <itemize> <item> <url url="http://metalab.unc.edu/LDP/HOWTO/C++Programming-HOWTO.html"> </itemize> Also you can find this document at the following mirrors sites - <itemize> <item> <url url="http://www.caldera.com/LDP/HOWTO/C++Programming-HOWTO.html"> <item> <url url="http://www.WGS.com/LDP/HOWTO/C++Programming-HOWTO.html"> <item> <url url="http://www.cc.gatech.edu/linux/LDP/HOWTO/C++Programming-HOWTO.html"> <item> <url url="http://www.redhat.com/linux-info/ldp/HOWTO/C++Programming-HOWTO.html"> <item> Other mirror sites near you (network-address-wise) can be found at <url url="http://metalab.unc.edu/LDP/hmirrors.html"> select a site and go to directory /LDP/HOWTO/C++Programming-HOWTO.html </itemize> In order to view the document in dvi format, use the xdvi program. The xdvi program is located in tetex-xdvi*.rpm package in Redhat Linux which can be located through ControlPanel | Applications | Publishing | TeX menu buttons. <tscreen><verb> To read dvi document give the command - xdvi -geometry 80x90 howto.dvi And resize the window with mouse. See man page on xdvi. To navigate use Arrow keys, Page Up, Page Down keys, also you can use 'f', 'd', 'u', 'c', 'l', 'r', 'p', 'n' letter keys to move up, down, center, next page, previous page etc. To turn off expert menu press 'x'. </verb></tscreen> You can read postscript file using the program 'gv' (ghostview) or 'ghostscript'. The ghostscript program is in ghostscript*.rpm package and gv program is in gv*.rpm package in Redhat Linux which can be located through ControlPanel | Applications | Graphics menu buttons. The gv program is much more user friendly than ghostscript. Ghostscript and gv are also available on other platforms like OS/2, Windows 95 and NT. <tscreen><verb> To read postscript document give the command - gv howto.ps To use ghostscript give - ghostscript howto.ps </verb></tscreen> You can read HTML format document using Netscape Navigator, Microsoft Internet explorer, Redhat Baron Web browser or any other web browsers. You can read the latex, LyX output using LyX a "X-Windows" front end to latex. <!-- ******************************************* ************ End of Section *************** ******************************************* <chapt> Copyright --> <sect> Copyright <p> Copyright policy is GNU/GPL as per LDP (Linux Documentation project). LDP is a GNU/GPL project. Additional restrictions are - you must retain the author's name, email address and this copyright notice on all the copies. If you make any changes or additions to this document then you should intimate all the authors of this document. <!-- ******************************************* ************ End of Section *************** ******************************************* <chapt> Appendix A mychar.cpp <label id="Appendix A"> --> <sect> Appendix A mychar.cpp <label id="Appendix A"> <p> In the web-browser, save this file as 'Text' type. <code> //***************************************************************** // Copyright policy is GNU/GPL but additional restriction is // that you include author's name and email on all copies // Author : Al Dev Email: alavoor@yahoo.com //***************************************************************** // To prevent memory problems - a char class to manage character variables // Always prefer to use mychar or string class instead of char[] or char * #ifdef DEBUG_MYCHAR #include <stdlib.h> // for putenv #include "mychar.h" ///////////////////////////////////////////////// // A example program to demo usage of mychar ///////////////////////////////////////////////// int main(int argc, char **argv) { char p_name[1024]; sprintf(p_name, "PROGRAM_NAME=%s", argv[0]); putenv(p_name); print_total_memsize(); // in the beginning mychar aa, bb; bb.str_cpy(" bbSTRing "); // Testing the + operator aa + " rhs "; fprintf(stdout, "\n0) aa.val is :%sEOF\n", aa.val); // Testing the = operator aa = " lhs " ; fprintf(stdout, "0) aa.val is :%sEOF\n", aa.val); // Testing the + operator //" lhs " + aa; //fprintf(stdout, "0) aa.val is :%sEOF\n", aa.val); aa.str_cpy(bb.val); aa.to_upper(); fprintf(stdout, "1) aa.val is :%sEOF\n", aa.val); aa.str_cpy(bb.val); aa.to_lower(); fprintf(stdout, "2) aa.val is :%sEOF\n", aa.val); aa.str_cpy(bb.val); aa.ltrim(); fprintf(stdout, "3) aa.val is :%sEOF\n", aa.val); aa.str_cpy(bb.val); aa.rtrim(); fprintf(stdout, "4) aa.val is :%sEOF\n", aa.val); aa.str_cpy(bb.val); aa.trim(); fprintf(stdout, "5) aa.val is :%sEOF\n", aa.val); aa.str_cpy(bb.val); aa = aa + " testing newlines \n\n\n\n"; aa.chop(); fprintf(stdout, "5-1) aa.val is :%sEOF\n", aa.val); aa.str_cpy(bb.val); aa = aa + " rhs "; fprintf(stdout, "6) aa.val is :%sEOF\n", aa.val); aa.str_cpy(bb.val); aa = " lhs " + aa; fprintf(stdout, "7) aa.val is :%sEOF\n", aa.val); aa.str_cpy(bb.val); aa = " lhs " + aa + " rhs " + " 9989 " + " 33 "; fprintf(stdout, "8) aa.val is :%sEOF\n", aa.val); aa.str_cpy(bb.val); aa = " lhs " + aa + " rhs " + " 9989 " + " 33 "; fprintf(stdout, "8) aa.val is :%sEOF\n", aa.val); aa.str_cpy(bb.val); aa = " lhs " + aa + " rhs " + " 9989 " + " 33 "; fprintf(stdout, "8) aa.val is :%sEOF\n", aa.val); aa.str_cpy(bb.val); aa = " lhs " + aa + " rhs " + " 9989 " + " 33 "; fprintf(stdout, "8) aa.val is :%sEOF\n", aa.val); aa.str_cpy(bb.val); aa = " lhs " + aa + " rhs " + " 9989 " + " 33 "; fprintf(stdout, "8) aa.val is :%sEOF\n", aa.val); aa.str_cpy(bb.val); aa = " lhs " + aa + " rhs " + " 9989 " + " 33 "; fprintf(stdout, "8) aa.val is :%sEOF\n", aa.val); aa.str_cpy(bb.val); aa = " lhs " + aa + " rhs " + " 9989 " + " 33 "; fprintf(stdout, "8) aa.val is :%sEOF\n", aa.val); aa.str_cpy(bb.val); aa = " lhs " + aa + " rhs " + " 9989 " + " 33 "; fprintf(stdout, "8) aa.val is :%sEOF\n", aa.val); aa.str_cpy(bb.val); aa = " lhs " + aa + " rhs " + " 9989 " + " 33 "; fprintf(stdout, "8) aa.val is :%sEOF\n", aa.val); aa.str_cpy(bb.val); aa = " lhs " + aa + " rhs " + " 9989 " + " 33 " + aa + bb; fprintf(stdout, "8) aa.val is :%sEOF\n", aa.val); aa.str_cpy(" AA value "); aa = bb + "alkja " + " 99djd " ; fprintf(stdout, "9) aa.val is :%sEOF\n", aa.val); aa.str_cpy(" AA value "); aa = (mychar) "alkja " + " 99djd " ; fprintf(stdout, "10) aa.val is :%sEOF\n", aa.val); aa.str_cpy(" AA value "); aa += (mychar) " al dev test kkk... " + " al2 slkj" + " al3333 "; fprintf(stdout, "11) aa.val is :%sEOF\n", aa.val); aa.str_cpy(" AA value "); aa = aa + " add aa " + aa + aa + aa + " 1111 " + " 2222 " + aa + aa + aa + " 3333 "; fprintf(stdout, "12) aa.val is :%sEOF\n", aa.val); aa.str_cpy("12345678"); aa.reverse(); fprintf(stdout, "13) aa.val is :%sEOF\n", aa.val); aa.str_cpy(" AA value "); aa = aa + " add aa " + aa + 1111 +" "+ 2222 + " " + 3.344 + aa; fprintf(stdout, "14) aa.val is :%sEOF\n", aa.val); // Test equal to operators aa.str_cpy(" AA value "); mychar cc(" AA value "); if (aa == cc) fprintf(stdout, "\naa=%s and cc=%s are equal!!\n", aa.val, cc.val); else fprintf(stdout, "\naa=%s and cc=%s are NOT equal!!\n", aa.val, cc.val); cc = "CC"; if (aa == cc) fprintf(stdout, "\naa=%s and cc=%s are equal!!\n", aa.val, cc.val); else fprintf(stdout, "\naa=%s and cc=%s are NOT equal!!\n", aa.val, cc.val); if (aa == " AA value ") fprintf(stdout, "\naa=%s and string are equal!!\n", aa.val); else fprintf(stdout, "\naa=%s and string are NOT equal!!\n", aa.val); if (aa == " AA valuexxx ") fprintf(stdout, "\naa=%s and string are equal!!\n", aa.val); else fprintf(stdout, "\naa=%s and string are NOT equal!!\n", aa.val); // You can use aa.val like a 'char *' variable in programs !! fprintf(stdout, "\n "); for (unsigned long tmpii = 0; tmpii < aa.length(); tmpii++) { fprintf(stdout, "aa.val[%ld]=%c ", tmpii, aa.val[tmpii]); } fprintf(stdout, "\n"); // Using pointers on 'char *' val ... fprintf(stdout, "\n "); for (; *aa.val != 0; aa.val++) { fprintf(stdout, "aa.val=%c ", *aa.val); } fprintf(stdout, "\n"); print_total_memsize(); // in the end exit(0); } #endif // DEBUG_MYCHAR </code> <!-- ******************************************* ************ End of Section *************** ******************************************* <chapt> Appendix B mychar.h<label id="Appendix B"> --> <sect> Appendix B mychar.h <label id="Appendix B"> <p> In the web-browser, save this file as 'Text' type. <code> //***************************************************************** // Copyright policy is GNU/GPL but additional restriction is // that you include author's name and email on all copies // Author : Al Dev Email: alavoor@yahoo.com //***************************************************************** // To prevent memory problems - a char class to manage character variables // Always prefer to use mychar or string class instead of char[] or char * #ifndef __MYCHAR_H_ #define __MYCHAR_H_ //#include <iostream> // do not use iostream as program becomes bulky.. //#include <stdlib.h> // for free() amd malloc() #include <string.h> // for strcpy() #include <ctype.h> // for isspace() #include <stdio.h> // for sprintf() #include <list.h> // for sprintf() #include "my_malloc.h" #include "debug.h" // debug_(name, value) debug2_(name, value, LOG_YES) #define INITIAL_SIZE 50 // a small class with a VERY MINIMUM of functions and variables... // This class to be kept small... class mychar { public: mychar(); mychar(char bb[]); // needed by operator+ mychar(int bb); // needed by operator+ mychar(unsigned long bb); // needed by operator+ mychar(float bb); // needed by operator+ mychar(double bb); // needed by operator+ mychar(const mychar & rhs); // Copy Constructor needed by operator+ ~mychar(); char *val; void str_cpy(char bb[]); void str_cpy(int bb); // itoa void str_cpy(unsigned long bb); void str_cpy(float bb); // itof void str_cat(char bb[]); void str_cat(int bb); void str_cat(unsigned long bb); void str_cat(float bb); unsigned long length() { return strlen(val); } void ltrim(); void rtrim(); void trim(); void chop(); void to_upper(); void to_lower(); long pos(char substr[], unsigned long start); void explode(char *seperator); void implode(char *glue); void join(char *glue); void repeat(char *input, unsigned int multiplier); void reverse(); void replace(char *needle, char *str); void str_tr(char *from, char *to); void center(int length, char padchar = ' '); void space(int number = 0, char padchar = ' '); void xrange(char start, char end); void compress(char *list); void delstr(int start, int length); void insert(char *newstr, int start = 0, int length = 0, char padchar = ' '); void left(int length = 0, char padchar = ' '); void right(int length = 0, char padchar = ' '); void overlay(char *newstr, int start = 0, int length = 0, char padchar = ' '); mychar substr(int start, int length = 0); mychar at(char *regx); // matches first match of regx mychar before(char *regx); // returns string before regx mychar after(char *regx); // returns string after regx bool equalto(const mychar & rhs, bool type = false); bool equalto(const char *rhs, bool type = false); bool isnull(); void clear(); // All Operators ... mychar operator+ (const mychar & rhs); friend mychar operator+ (const mychar & lhs, const mychar & rhs); mychar& operator+= (const mychar & rhs); // using reference will be faster mychar& operator= (const mychar & rhs); // using reference will be faster bool operator== (const mychar & rhs); // using reference will be faster bool operator== (const char *rhs); bool operator!= (const mychar & rhs); bool operator!= (const char *rhs); static list<mychar> explodeH; // list head private: //static mychar *global_mychar; // for use in add operator //inline void free_glob(mychar **aa); }; // Global variables .... //mychar *mychar::global_mychar = NULL; // global var list<mychar> mychar::explodeH; mychar::mychar() { debug_("In cstr()", "ok"); val = (char *) my_malloc(sizeof(char)* INITIAL_SIZE); } mychar::mychar(char *bb) { unsigned long tmpii = strlen(bb); val = (char *) my_malloc(sizeof(char)* tmpii); strncpy(val, bb, tmpii); val[tmpii] = '\0'; //debug_("In cstr(char *bb) bb", bb); //debug_("In cstr(char *bb) val", val); #ifdef DEBUG_MYCHAR //fprintf(stderr, "\nAddress of val=%x\n", & val); //fprintf(stderr, "\nAddress of this-pointer=%x\n", this); #endif // DEBUG_MYCHAR } mychar::mychar(int bb) { val = (char *) my_malloc(sizeof(int)); sprintf(val, "%d", bb); } mychar::mychar(unsigned long bb) { val = (char *) my_malloc(sizeof(unsigned long)); sprintf(val, "%lu", bb); } mychar::mychar(float bb) { val = (char *) my_malloc(sizeof(float)); sprintf(val, "%f", bb); } mychar::mychar(double bb) { val = (char *) my_malloc(sizeof(double)); sprintf(val, "%f", bb); } // Copy Constructor needed by operator + mychar::mychar(const mychar & rhs) { // Do a deep-copy instead of compiler's default shallow copy copy-cstr debug_("In copy-cstr()", "ok"); unsigned long tmpii = strlen(rhs.val); val = (char *) my_malloc(sizeof(char)* tmpii); strncpy(val, rhs.val, tmpii); val[tmpii] = '\0'; } mychar::~mychar() { //debug_("In dstr val", val); #ifdef DEBUG_MYCHAR //fprintf(stderr, "\nAddress of val=%x\n", & val); //fprintf(stderr, "\nAddress of this-pointer=%x\n", this); #endif // DEBUG_MYCHAR my_free(val); //delete [] val; val = NULL; } // MUST use pointer-to-pointer **aa, otherwise the argument // is NOT freed !! /* inline void mychar::free_glob(mychar **aa) { //fprintf(stderr, "\ncalled free_glob()\n"); if (*aa != NULL) // (*aa != NULL) { //fprintf(stderr, "\n*aa is not null \n"); delete *aa; *aa = NULL; } //else // fprintf(stderr, "\n*aa is null \n"); //if (*aa == NULL) // fprintf(stderr, "\n*aa set to null \n"); } */ // Explodes the string and returns the list in // the list-head pointer explodeH void mychar::explode(char *seperator) { char *aa = NULL, *bb = NULL; aa = (char *) my_malloc(length()); for (bb = strtok(aa, seperator); bb != NULL; bb = strtok(NULL, seperator) ) { mychar *tmp = new mychar(bb); mychar::explodeH.insert(mychar::explodeH.end(), *tmp); } my_free(aa); list<mychar>::iterator iter1; // see file include/g++/stl_list.h //fprintf(ferr, "\n%s Before checking.. !!\n", func_name); if (mychar::explodeH.empty() == true ) { //fprintf(ferr, "\n%s List is empty!!\n", func_name); } for (iter1 = mychar::explodeH.begin(); iter1 != mychar::explodeH.end(); iter1++) { if (iter1 == NULL) { fprintf(stderr, "\nIterator iter1 is NULL!!\n"); break; } //fprintf(stdout, "\nValue is : %s\n", (*iter1).val); } } // Implodes the strings in the list-head // pointer explodeH and returns the mychar class void mychar::implode(char *glue) { } // Joins the strings in the list-head // pointer explodeH and returns the mychar class void mychar::join(char *glue) { implode(glue); } // Repeat the input string n times void mychar::repeat(char *input, unsigned int multiplier) { // For example - // repeat("1", 4) returns "1111" if (!input) // input == NULL { val[0] = 0; return; } val = (char *) my_malloc(strlen(input) * multiplier); for (unsigned int tmpii = 0; tmpii < multiplier; tmpii++) { strcat(val, input); } } // Reverse the string void mychar::reverse() { // For example - // reverse() on "12345" returns "54321" char aa; unsigned long tot_len = length(); unsigned long midpoint = tot_len / 2; for (unsigned long tmpjj = 0; tmpjj < midpoint; tmpjj++) { aa = val[tmpjj]; // temporary storage var val[tmpjj] = val[tot_len - tmpjj - 1]; // swap the values val[tot_len - tmpjj - 1] = aa; // swap the values } } // Replace all occurences of string 'needle' with 'str' in the haystack 'val' void mychar::replace(char *needle, char *str) { // For example - // replace("AAA", "BB") on val = "some AAA and AAACC" // reurns val = "some BB and BBCC" } // Translate certain chars void mychar::str_tr(char *from, char *to) { // For e.g ("abcd", "ABC") translates all occurences of each // character in 'from' to corresponding character in 'to' } // Center the text void center(int length, char padchar = ' ') { // For example - // center(10, '*') on val="aa" returns "****aa****" // center(10) on val="aa" returns " aa " // The result is a string of 'length' characters with val centered in it. } // Formats the original string by placing <number> of <padchar> characters // between each set of blank-delimited words. Leading and Trailing blanks // are always removed. If <number> is omitted or is 0, then all spaces are // in the string are removed. The default number is 0 and // default padchar ' ' void space(int number, char padchar = ' ') { // For example - // space(3) on val = "I do not know" // will return "I do not know" // space(1, '_') on val = "A deep black space" // will return "A_deep_black_space" // space() on val = "I know this" // will return "Iknowthis" } // The result is string comprised of all characters between // and including <start> and <end> void xrange(char start, char end) { // For example - // xrange('a', 'j') returns val = "abcdefghij" // xrange(1, 8) returns val = "12345678" } // Removes any characters contained in <list>. The default character // for <list> is a blank ' ' void compress(char *list) { // For example - // compress("$,%") on val = "$1,934" returns "1934" // compress() on val = "call me alavoor vasudevan" returns "callmealavoorvasudevan" } // Deletes a portion of string of <length> characters from <start> position. // If start is greater than the string length than string is unchanged. void delstr(int start, int length) { // For example - // delstr(3,3) on val = 'pokemon' returns 'poon' } // The <newstr> in inserted into val beginning at <start>. The <newstr> will // be padded or truncated to <length> characters. The default <length> is // string length of newstr void insert(char *newstr, int start = 0, int length = 0, char padchar = ' ') { // For example - // insert("something new", 4, 20, '*') on val = "old thing" // returns "old something new*******thing" } // The result is string of <length> chars madeup of leftmost chars in val. // Quick way to left justify a string. void left(int length = 0, char padchar = ' ') { // For example - // left(10) on val = "Wig" returns "Wig " // left(4) on val = "Wighat" returns "Wigh" } // The result is string of <length> chars madeup of rightmost chars in val. // Quick way to right justify a string. void right(int length = 0, char padchar = ' ') { // For example - // right(10) on val = "never stop to saying" returns " to saying" // right(4) on val = "Wighat" returns "ghat" // right(6) on val = "4.50" returns " 4.50" } // The <newstr> in overlayed into val beginning at <start>. The <newstr> will // be padded or truncated to <length> characters. The default <length> is // string length of newstr void overlay(char *newstr, int start = 0, int length = 0, char padchar = ' ') { // For example - // overlay("12345678", 4, 10, '*') on val = "oldthing is very bad" // returns "old12345678**ery bad" } // sub string mychar mychar::substr(int start, int length = 0) { if (!length) // length == 0 return(mychar(& val[start-1]) ); else { mychar tmp = mychar(& val[start-1]); tmp.val[length-1] = 0; return(tmp); } } // If string is literrally equal to .. or not equal to // If type is false than it is == bool mychar::equalto(const mychar & rhs, bool type = false) { if (type == false) // test for == { if (strlen(rhs.val) == length()) { if (!strncmp(rhs.val, val, length())) // == 0 return true; else return false; } else return false; } else // test for != { if (strlen(rhs.val) != length()) { if (!strncmp(rhs.val, val, length())) // == 0 return true; else return false; } else return false; } } // If string is literrally equal to .. or not equal to // If type is false than it is == bool mychar::equalto(const char *rhs, bool type = false) { if (type == false) // test for == { if (strlen(rhs) == length()) { if (!strncmp(rhs, val, length())) // == 0 return true; else return false; } else return false; } else // test for != { if (strlen(rhs) != length()) { if (!strncmp(rhs, val, length())) // == 0 return true; else return false; } else return false; } } // find position, matching substr beginning from start.. long mychar::pos(char *substr, unsigned long start) { char * tok; long res = -1; if ( !isnull() && (start < strlen(val) ) ) { tok = strstr(val + start, substr); if (tok == NULL) res = -1; else res = (long) (tok - val); } return res; } bool mychar::isnull() { if (val[0] == '\0') return true; else { if (val == NULL) return true; else return false; } } void mychar::clear() { val = (char *) my_realloc(val, 10); val[0] = '\0'; } // Remove trailing new-lines void mychar::chop() { unsigned long tmpii = strlen(val) - 1 ; for (; tmpii >= 0; tmpii--) { if (val[tmpii] == '\n') val[tmpii] = 0; else break; } } void mychar::ltrim() { // May cause problems in my_realloc since // location of bb will be destroyed !! char *bb = val; if (bb == NULL) return; while (isspace(*bb)) bb++; debug_("bb", bb); if (bb != NULL && bb != val) { debug_("doing string copy", "done"); //str_cpy(bb); // causes problems in my_realloc and bb is getting destroyed!! strcpy(val, bb); // strcpy is ok since val space is > bb space } else debug_("Not doing string copy", "done"); } void mychar::rtrim() { for (long tmpii = strlen(val) - 1 ; tmpii >= 0; tmpii--) { if ( isspace(val[tmpii]) ) val[tmpii] = '\0'; else break; } } void mychar::trim() { rtrim(); ltrim(); } void mychar::to_lower() { for (long tmpii = strlen(val); tmpii >= 0; tmpii--) { val[tmpii] = tolower(val[tmpii]); } } void mychar::to_upper() { for (long tmpii = strlen(val); tmpii >= 0; tmpii--) { val[tmpii] = toupper(val[tmpii]); } } void mychar::str_cpy(char bb[]) { debug_("In str_cpy bb", bb); if (bb == NULL) { val[0] = '\0'; return; } unsigned long tmpii = strlen(bb); if (tmpii == 0) { val[0] = '\0'; return; } debug_("In str_cpy tmpii", tmpii); debug_("In str_cpy val", val); val = (char *) my_realloc(val, tmpii); //val = (char *) realloc(val, tmpii + 30); //val = new char [tmpii + SAFE_MEM_2]; debug_("In str_cpy bb", bb); strncpy(val, bb, tmpii); debug_("In str_cpy val", val); val[tmpii] = '\0'; debug_("In str_cpy val", val); } void mychar::str_cpy(int bb) { char tmpaa[100]; sprintf(tmpaa, "%d", bb); str_cpy(tmpaa); } void mychar::str_cpy(unsigned long bb) { char tmpaa[100]; sprintf(tmpaa, "%ld", bb); str_cpy(tmpaa); } void mychar::str_cpy(float bb) { char tmpaa[100]; sprintf(tmpaa, "%f", bb); str_cpy(tmpaa); } void mychar::str_cat(char bb[]) { unsigned long tmpjj = strlen(bb), tmpii = strlen(val); val = (char *) my_realloc(val, tmpii + tmpjj); //fprintf(stdout, "\nval in str_cat() is :%s\n", val); strncat(val, bb, tmpjj); } void mychar::str_cat(int bb) { char tmpaa[100]; sprintf(tmpaa, "%d", bb); unsigned long tmpjj = strlen(tmpaa), tmpii = strlen(val); val = (char *) my_realloc(val, tmpii + tmpjj); strncat(val, tmpaa, tmpjj); } void mychar::str_cat(unsigned long bb) { char tmpaa[100]; sprintf(tmpaa, "%ld", bb); unsigned long tmpjj = strlen(tmpaa), tmpii = strlen(val); val = (char *) my_realloc(val, tmpii + tmpjj); strncat(val, tmpaa, tmpjj); } void mychar::str_cat(float bb) { char tmpaa[100]; sprintf(tmpaa, "%f", bb); unsigned long tmpjj = strlen(tmpaa), tmpii = strlen(val); val = (char *) my_realloc(val, tmpii + tmpjj); strncat(val, tmpaa, tmpjj); } mychar operator+ (const mychar & lhs, const mychar & rhs) { /*******************************************************/ // Note : For adding two char strings, first cast mychar // as in - //aa = (mychar) "alkja " + " 99djd " ; /*******************************************************/ mychar tmp(lhs); tmp.str_cat(rhs.val); return(tmp); /* if (mychar::global_mychar == NULL) { mychar::global_mychar = new mychar; mychar::global_mychar->str_cpy(lhs.val); mychar::global_mychar->str_cat(rhs.val); //return *mychar::global_mychar; return mychar(mychar::global_mychar->val); } */ /* else if (mychar::global_mychar1 == NULL) { fprintf(stderr, "\n1)global"); mychar::global_mychar1 = new mychar; mychar::global_mychar1->str_cpy(lhs.val); mychar::global_mychar1->str_cat(rhs.val); return *mychar::global_mychar1; } */ /* else { fprintf(stderr, "\nError: cannot alloc global_mychar\n"); exit(-1); } */ /* mychar *aa = new mychar; aa->str_cpy(lhs.val); aa->str_cat(rhs.val); return *aa; */ } mychar mychar::operator+ (const mychar & rhs) { mychar tmp(*this); tmp.str_cat(rhs.val); //fprintf(stdout, "\nrhs val = %s", this->val); return (tmp); } // Using reference will be faster in = operator mychar& mychar:: operator= ( const mychar& rhs ) { if (& rhs == this) { //fprintf(stderr, "\nFatal Error: In operator=(), rhs is == to 'this pointer'!!\n"); return *this; } this->str_cpy(rhs.val); //fprintf(stdout, "\n\nrhs value is : %s\n\n", rhs.val); // Free global vars memory //free_glob(& mychar::global_mychar); //if (mychar::global_mychar == NULL) //fprintf(stderr, "\nglobal_mychar is freed!\n"); //return (mychar(*this)); return *this; } // Using reference will be faster in = operator mychar& mychar::operator+= (const mychar & rhs) { /*******************************************************/ // Note : For adding two char strings, first cast mychar // as in - //aa += (mychar) "cccc" + "dddd"; /*******************************************************/ if (& rhs == this) { //fprintf(stderr, "\nFatal Error: In operator+=(), rhs is equal to 'this pointer'!!\n"); return *this; } this->str_cat(rhs.val); return *this; //return (mychar(*this)); } bool mychar::operator== (const mychar & rhs) { return(equalto(rhs.val)); } bool mychar::operator== (const char *rhs) { return(equalto(rhs)); } bool mychar::operator!= (const mychar & rhs) { return(equalto(rhs.val, true)); } bool mychar::operator!= (const char *rhs) { return(equalto(rhs, true)); } #endif // __MYCHAR_H_ </code> <!-- ******************************************* ************ End of Section *************** ******************************************* <chapt> Appendix C my_malloc.cpp<label id="Appendix C"> --> <sect> Appendix C my_malloc.cpp <label id="Appendix C"> <p> In the web-browser, save this file as 'Text' type. <code> //***************************************************************** // Copyright policy is GNU/GPL but additional restriction is // that you include author's name and email on all copies // Author : Al Dev Email: alavoor@yahoo.com //***************************************************************** /* ** In your main() function put - char p_name[1024]; sprintf(p_name, "PROGRAM_NAME=%s", argv[0]); putenv(p_name); print_total_memsize(); // in the beginning ...... ...... print_total_memsize(); // in the end */ #include <stdio.h> #include <alloc.h> // for c++ -- malloc, alloc etc... #include <stdlib.h> // malloc, alloc.. #include <time.h> // strftime, localtime, ... #include <list.h> // strftime, localtime, ... see file include/g++/stl_list.h //#include <debug.h> // debug_("a", a); debug2_("a", a, true); #include "my_malloc.h" #define SAFE_MEM 10 #define DATE_MAX_SIZE 200 #define MALLOC 1 #define REALLOC 2 #define VOID_TYPE 1 #define CHAR_TYPE 2 #define SHORT_TYPE 3 #define INT_TYPE 4 #define LONG_TYPE 5 #define FLOAT_TYPE 6 #define DOUBLE_TYPE 7 #define LOG_FILE "memory_error.log" static void raise_error_exit(short mtype, short datatype, char fname[], int lineno); //#ifdef DEBUG_MEM #ifdef DEBUG class MemCheck { public: MemCheck(void *aptr, size_t amem_size, char fname[], int lineno); void *ptr; size_t mem_size; static list<MemCheck> mcH; // list head static unsigned long total_memsize; // total memory allocated }; // Global variables .... list<MemCheck> MemCheck::mcH; unsigned long MemCheck::total_memsize = 0; MemCheck::MemCheck(void *aptr, size_t amem_size, char fname[], int lineno) { char func_name[100]; FILE *ferr = NULL; sprintf(func_name, "MemCheck() - File: %s Line: %d", fname, lineno); ferr = fopen(LOG_FILE, "a"); if (ferr == NULL) { fprintf(stdout, "\nWarning: Cannot open file %s\n", LOG_FILE); fprintf(stderr, "\nWarning: Cannot open file %s\n", LOG_FILE); exit(-1); } // Search if the pointer already exists in the list... bool does_exist = false; list<MemCheck>::iterator iter1; // see file include/g++/stl_list.h //fprintf(ferr, "\n%s Before checking.. !!\n", func_name); if (MemCheck::mcH.empty() == true ) { //fprintf(ferr, "\n%s List is empty!!\n", func_name); } for (iter1 = MemCheck::mcH.begin(); iter1 != MemCheck::mcH.end(); iter1++) { if (iter1 == NULL) { fprintf(ferr, "\n%s Iterator iter1 is NULL!!\n", func_name); break; } if ( ((*iter1).ptr) == aptr) { does_exist = true; fprintf(ferr, "\n%s Already exists!!\n", func_name); fprintf(ferr, "\n%s Fatal Error exiting now ....!!\n", func_name); exit(-1); //------------------------------------------------------------------>>> // Now change the mem size to new values... // For total size - Remove old size and add new size //fprintf(ferr, "\n%s total_memsize = %lu\n", func_name, (*iter1).total_memsize); //fprintf(ferr, "\n%s mem_size = %u\n", func_name, (*iter1).mem_size); //fprintf(ferr, "\n%s amem_size = %u\n", func_name, amem_size); (*iter1).total_memsize = (*iter1).total_memsize + amem_size; if ((*iter1).total_memsize > 0 ) { if ((*iter1).total_memsize >= (*iter1).mem_size ) (*iter1).total_memsize = (*iter1).total_memsize - (*iter1).mem_size; else { fprintf(ferr, "\n\n%s total_memsize is less than mem_size!!", func_name); fprintf(ferr, "\n%s total_memsize = %lu", func_name, (*iter1).total_memsize); fprintf(ferr, "\n%s mem_size = %u", func_name, (*iter1).mem_size); fprintf(ferr, "\n%s amem_size = %u\n", func_name, amem_size); } } (*iter1).mem_size = amem_size; } } // The pointer aptr does not exist in the list, so append it now... if (does_exist == false) { //fprintf(ferr, "\n%s aptr Not found\n", func_name); ptr = aptr; mem_size = amem_size; MemCheck::total_memsize += amem_size; MemCheck::mcH.insert(MemCheck::mcH.end(), *this); } fclose(ferr); } static inline void call_check(void *aa, size_t tmpii, char fname[], int lineno) { MemCheck bb(aa, tmpii, fname, lineno); if (& bb); // a dummy statement to avoid compiler warning msg. } static inline void remove_ptr(void *aa, char fname[], int lineno) { char func_name[100]; if (aa == NULL) return; sprintf(func_name, "remove_ptr() - File: %s Line: %d", fname, lineno); FILE *ferr = NULL; ferr = fopen(LOG_FILE, "a"); if (ferr == NULL) { fprintf(stdout, "\nWarning: Cannot open file %s\n", LOG_FILE); fprintf(stderr, "\nWarning: Cannot open file %s\n", LOG_FILE); exit(-1); } bool does_exist = false; if (MemCheck::mcH.empty() == true) { //fprintf(ferr, "\n%s List is empty!!\n", func_name); //fclose(ferr); //return; } list<MemCheck>::iterator iter1; // see file include/g++/stl_list.h for (iter1 = MemCheck::mcH.begin(); iter1 != MemCheck::mcH.end(); iter1++) { if (iter1 == NULL) { fprintf(ferr, "\n%s Iterator iter1 is NULL!!\n", func_name); break; } if ( ((*iter1).ptr) == aa) { does_exist = true; // Now change the mem size to new values... // For total size - Remove old size //fprintf(ferr, "\n%s total_memsize = %lu\n", func_name, (*iter1).total_memsize); //fprintf(ferr, "\n%s mem_size = %u\n", func_name, (*iter1).mem_size); if ((*iter1).total_memsize > 0 ) { if ((*iter1).total_memsize >= (*iter1).mem_size ) (*iter1).total_memsize = (*iter1).total_memsize - (*iter1).mem_size; else { fprintf(ferr, "\n\n%s total_memsize is less than mem_size!!", func_name); fprintf(ferr, "\n%s total_memsize = %lu", func_name, (*iter1).total_memsize); fprintf(ferr, "\n%s mem_size = %u\n", func_name, (*iter1).mem_size); } } MemCheck::mcH.erase(iter1); break; // must break to avoid infinite looping } } if (does_exist == false) { /fprintf(ferr, "\n%s Fatal Error: - You did not allocate memory!! \n", func_name); //fprintf(ferr, "\n%s The value passed is %s\n", func_name, (char *) aa); } else //fprintf(ferr, "\n%s found\n", func_name); fclose(ferr); } static inline void call_free_check(void *aa, char *fname, int lineno) { char func_name[100]; sprintf(func_name, "call_free_check() - File: %s Line: %d", fname, lineno); FILE *ferr = NULL; ferr = fopen(LOG_FILE, "a"); if (ferr == NULL) { fprintf(stdout, "\nWarning: Cannot open file %s\n", LOG_FILE); fprintf(stderr, "\nWarning: Cannot open file %s\n", LOG_FILE); exit(-1); } bool does_exist = false; list<MemCheck>::iterator iter1; // see file include/g++/stl_list.h for (iter1 = MemCheck::mcH.begin(); iter1 != MemCheck::mcH.end(); iter1++) { if (iter1 == NULL) { fprintf(ferr, "\n%s Iterator iter1 is NULL!!\n", func_name); break; } if ( ((*iter1).ptr) == aa) { does_exist = true; //fprintf(ferr, "\n%s iter1.mem_size = %u\n", func_name, (*iter1).mem_size); //fprintf(ferr, "\n%s Total memory allocated = %lu\n", func_name, (*iter1).total_memsize); if ((*iter1).total_memsize > 0 ) { if ((*iter1).total_memsize >= (*iter1).mem_size ) (*iter1).total_memsize = (*iter1).total_memsize - (*iter1).mem_size; else { fprintf(ferr, "\n\n%s total_memsize is less than mem_size!!", func_name); fprintf(ferr, "\n%s total_memsize = %lu", func_name, (*iter1).total_memsize); fprintf(ferr, "\n%s mem_size = %u", func_name, (*iter1).mem_size); } } MemCheck::mcH.erase(iter1); break; // must break to avoid infinite looping } } if (does_exist == false) { fprintf(ferr, "\n%s Fatal Error: free() - You did not allocate memory!!\n", func_name); //fprintf(ferr, "\n%s The value passed is %s\n", func_name, (char *) aa); fclose(ferr); exit(-1); } else { //fprintf(ferr, "\n%s found\n", func_name); } fclose(ferr); } void local_print_total_memsize(char *fname, int lineno) { char func_name[100]; sprintf(func_name, "local_print_total_memsize() - %s Line: %d", fname, lineno); FILE *ferr = NULL; ferr = fopen(LOG_FILE, "a"); if (ferr == NULL) { fprintf(stdout, "\nWarning: Cannot open file %s\n", LOG_FILE); fprintf(stderr, "\nWarning: Cannot open file %s\n", LOG_FILE); exit(-1); } fprintf(ferr, "\n%s Total memory MemCheck::total_memsize = %lu\n", func_name, MemCheck::total_memsize); fclose(ferr); } #else //------------> DEBUG void local_print_total_memsize(char *fname, int lineno) { // This function is available whether debug or no-debug... } #endif // DEBUG void local_my_free(void *aa, char fname[], int lineno) { if (aa == NULL) return; call_free_check(aa, fname, lineno); free(aa); aa = NULL; } // size_t is type-defed unsigned long void *local_my_malloc(size_t size, char fname[], int lineno) { size_t tmpii = size + SAFE_MEM; void *aa = NULL; aa = (void *) malloc(tmpii); if (aa == NULL) raise_error_exit(MALLOC, VOID_TYPE, fname, lineno); memset(aa, 0, tmpii); call_check(aa, tmpii, fname, lineno); return aa; } // size_t is type-defed unsigned long char *local_my_realloc(char *aa, size_t size, char fname[], int lineno) { remove_ptr(aa, fname, lineno); size_t tmpii = sizeof (char) * size + SAFE_MEM; aa = (char *) realloc(aa, tmpii); if (aa == NULL) raise_error_exit(REALLOC, CHAR_TYPE, fname, lineno); // do not memset here!!! memset(aa, 0, tmpii); aa[tmpii-1] = 0; // set last location to 0 call_check(aa, tmpii, fname, lineno); return aa; } // size_t is type-defed unsigned long short *local_my_realloc(short *aa, size_t size, char fname[], int lineno) { remove_ptr(aa, fname, lineno); size_t tmpii = sizeof (short) * size + SAFE_MEM; aa = (short *) realloc(aa, tmpii); if (aa == NULL) raise_error_exit(REALLOC, CHAR_TYPE, fname, lineno); // do not memset here!!! memset(aa, 0, tmpii); aa[tmpii-1] = 0; // set last location to 0 call_check(aa, tmpii, fname, lineno); return aa; } // size_t is type-defed unsigned long int *local_my_realloc(int *aa, size_t size, char fname[], int lineno) { remove_ptr(aa, fname, lineno); size_t tmpii = sizeof (int) * size + SAFE_MEM; aa = (int *) realloc(aa, tmpii); if (aa == NULL) raise_error_exit(REALLOC, CHAR_TYPE, fname, lineno); // do not memset here!!! memset(aa, 0, tmpii); aa[tmpii-1] = 0; // set last location to 0 call_check(aa, tmpii, fname, lineno); return aa; } // size_t is type-defed unsigned long long *local_my_realloc(long *aa, size_t size, char fname[], int lineno) { remove_ptr(aa, fname, lineno); size_t tmpii = sizeof (long) * size + SAFE_MEM; aa = (long *) realloc(aa, tmpii); if (aa == NULL) raise_error_exit(REALLOC, CHAR_TYPE, fname, lineno); // do not memset here!!! memset(aa, 0, tmpii); aa[tmpii-1] = 0; // set last location to 0 call_check(aa, tmpii, fname, lineno); return aa; } // size_t is type-defed unsigned long float *local_my_realloc(float *aa, size_t size, char fname[], int lineno) { remove_ptr(aa, fname, lineno); size_t tmpii = sizeof (float) * size + SAFE_MEM; call_check(aa, tmpii, fname, lineno); aa = (float *) realloc(aa, tmpii); if (aa == NULL) raise_error_exit(REALLOC, CHAR_TYPE, fname, lineno); // do not memset here!!! memset(aa, 0, tmpii); aa[tmpii-1] = 0; // set last location to 0 call_check(aa, tmpii, fname, lineno); return aa; } // size_t is type-defed unsigned long double *local_my_realloc(double *aa, size_t size, char fname[], int lineno) { remove_ptr(aa, fname, lineno); size_t tmpii = sizeof (double) * size + SAFE_MEM; aa = (double *) realloc(aa, tmpii); if (aa == NULL) raise_error_exit(REALLOC, CHAR_TYPE, fname, lineno); // do not memset here!!! memset(aa, 0, tmpii); aa[tmpii-1] = 0; // set last location to 0 call_check(aa, tmpii, fname, lineno); return aa; } static void raise_error_exit(short mtype, short datatype, char fname[], int lineno) { if (mtype == MALLOC) { fprintf(stdout, "\nFatal Error: malloc() failed!!"); fprintf(stderr, "\nFatal Error: malloc() failed!!"); } else if (mtype == REALLOC) { fprintf(stdout, "\nFatal Error: realloc() failed!!"); fprintf(stderr, "\nFatal Error: realloc() failed!!"); } else { fprintf(stdout, "\nFatal Error: mtype not supplied!!"); fprintf(stderr, "\nFatal Error: mtype not supplied!!"); exit(-1); } // Get current date-time and print time stamp in error file... char date_str[DATE_MAX_SIZE + SAFE_MEM]; time_t tt; tt = time(NULL); struct tm *ct = NULL; ct = localtime(& tt); // time() in secs since Epoch 1 Jan 1970 if (ct == NULL) { fprintf(stdout, "\nWarning: Could not find the local time, localtime() failed\n"); fprintf(stderr, "\nWarning: Could not find the local time, localtime() failed\n"); } else strftime(date_str, DATE_MAX_SIZE , "%C", ct); FILE *ferr = NULL; char filename[100]; strcpy(filename, LOG_FILE); ferr = fopen(filename, "a"); if (ferr == NULL) { fprintf(stdout, "\nWarning: Cannot open file %s\n", filename); fprintf(stderr, "\nWarning: Cannot open file %s\n", filename); } else { // ************************************************** // ******* Do putenv in the main() function ********* // char p_name[1024]; // sprintf(p_name, "PROGRAM_NAME=%s", argv[0]); // putenv(p_name); // ************************************************** char program_name[200+SAFE_MEM]; if (getenv("PROGRAM_NAME") == NULL) { fprintf(ferr, "\n%sWarning: You did not putenv() PROGRAM_NAME env variable in main() function\n", date_str); program_name[0] = 0; } else strncpy(program_name, getenv("PROGRAM_NAME"), 200); if (mtype == MALLOC) fprintf(ferr, "\n%s: %s - Fatal Error - my_malloc() failed.", date_str, program_name); else if (mtype == REALLOC) { fprintf(ferr, "\n%s: %s - Fatal Error - my_realloc() failed.", date_str, program_name); char dtype[50]; switch(datatype) { case VOID_TYPE: strcpy(dtype, "char*"); break; case CHAR_TYPE: strcpy(dtype, "char*"); break; case SHORT_TYPE: strcpy(dtype, "char*"); break; case INT_TYPE: strcpy(dtype, "char*"); break; case LONG_TYPE: strcpy(dtype, "char*"); break; case FLOAT_TYPE: strcpy(dtype, "char*"); break; case DOUBLE_TYPE: strcpy(dtype, "char*"); break; default: strcpy(dtype, "none*"); break; } fprintf(ferr, "\n%s %s - Fatal Error: %s realloc() failed!!", date_str, program_name, dtype); } fprintf(ferr, "\n%s %s - Very severe error condition. Exiting application now....", date_str, program_name); fclose(ferr); } exit(-1); } </code> <!-- ******************************************* ************ End of Section *************** ******************************************* <chapt> Appendix D my_malloc.h<label id="Appendix D"> --> <sect> Appendix D my_malloc.h <label id="Appendix D"> <p> In the web-browser, save this file as 'Text' type. <code> //***************************************************************** // Copyright policy is GNU/GPL but additional restriction is // that you include author's name and email on all copies // Author : Al Dev Email: alavoor@yahoo.com //***************************************************************** /* ** In your main() function put - char p_name[1024]; sprintf(p_name, "PROGRAM_NAME=%s", argv[0]); putenv(p_name); print_total_memsize(); // in the beginning ...... ...... print_total_memsize(); // in the end */ void *local_my_malloc(size_t size, char fname[], int lineno); char *local_my_realloc(char *aa, size_t size, char fname[], int lineno); short *local_my_realloc(short *aa, size_t size, char fname[], int lineno); void local_my_free(void *aa, char fname[], int lineno); void local_print_total_memsize(char fname[], int lineno); #define my_free(NM) (void) (local_my_free(NM, __FILE__, __LINE__)) #define my_malloc(SZ) (local_my_malloc(SZ, __FILE__, __LINE__)) #define my_realloc(NM, SZ) (local_my_realloc(NM, SZ, __FILE__, __LINE__)) #define print_total_memsize() (void) (local_print_total_memsize(__FILE__, __LINE__)) #ifdef DEBUG //------------> DEBUG #else //------------> DEBUG #define call_check(AA, BB, CC, DD) ((void) 0) #define call_free_check(AA, BB, CC) ((void) 0) #define remove_ptr(AA, CC, DD) ((void) 0) #endif //------------> DEBUG </code> <!-- ******************************************* ************ End of Section *************** ******************************************* <chapt> Appendix E debug.h<label id="Appendix E"> --> <sect> Appendix E debug.h <label id="Appendix E"> <p> In the web-browser, save this file as 'Text' type. <code> //***************************************************************** // Copyright policy is GNU/GPL but additional restriction is // that you include author's name and email on all copies // Author : Al Dev Email: alavoor@yahoo.com //***************************************************************** /**************************************************************** Program for debugging C++/C programs *****************************************************************/ #define print_log(AA, BB, CC, DD, EE) ((void) 0) #ifdef DEBUG #include <iostream> #include <string> //#include <assert.h> // assert() macro which is also used for debugging #define LOG_YES true // print output to log file #define LOG_NO false // Do not print output to log file // Debugging code // Use debug2_ to output result to a log file #define debug_(NM, VL) (void) ( local_dbg(NM, VL, __FILE__, __LINE__) ) #define debug2_(NM, VL, LOG_FILE) (void) ( local_dbg(NM, VL, __FILE__, __LINE__, LOG_FILE) ) void local_dbg(char name[], char value[], char fname[], int lineno, bool logfile= false); void local_dbg(char name[], string value, char fname[], int lineno, bool logfile= false); void local_dbg(char name[], int value, char fname[], int lineno, bool logfile= false); void local_dbg(char name[], unsigned long value, char fname[], int lineno, bool logfile= false); void local_dbg(char name[], float value, char fname[], int lineno, bool logfile= false); #else //--------> else #define debug_(NM, VL) ((void) 0) #define debug2_(NM, VL, LOG_FILE) ((void) 0) #endif // DEBUG </code> <!-- ******************************************* ************ End of Section *************** ******************************************* <chapt> Appendix F debug.cpp <label id="Appendix F"> --> <sect> Appendix F debug.cpp <label id="Appendix F"> <p> In the web-browser, save this file as 'Text' type. <code> //***************************************************************** // Copyright policy is GNU/GPL but additional restriction is // that you include author's name and email on all copies // Author : Al Dev Email: alavoor@yahoo.com //***************************************************************** /**************************************************************** Program for debugging C++/C programs *****************************************************************/ #ifdef DEBUG // ONLY if DEBUG is defined than these functions below are needed #include "debug.h" //#include "log.h" // Variable value[] can be char, string, int, unsigned long, float, etc... void local_dbg(char name[], char value[], char fname[], int lineno, bool logfile) { if (value == NULL) return; if (logfile == true) print_log("\nDebug %s : Line: %d %s is = %s\n", fname, lineno, name, value); else cout << "\nDebug " << fname << ": Line: " << lineno << " " << name << " is = " << value << endl; } void local_dbg(char name[], string value, char fname[], int lineno, bool logfile) { if (logfile == true) print_log("\nDebug %s : Line: %d %s is = %s\n", fname, lineno, name, value.c_str()); else cout << "\nDebug " << fname << ": Line: " << lineno << " " << name << " is = " << value.c_str() << endl; } void local_dbg(char name[], int value, char fname[], int lineno, bool logfile) { if (logfile == true) print_log("\nDebug %s : Line: %d %s is = %d\n", fname, lineno, name, value); else cout << "\nDebug " << fname << ": Line: " << lineno << " " << name << " is = " << value << endl; } void local_dbg(char name[], unsigned int value, char fname[], int lineno, bool logfile) { if (logfile == true) print_log("\nDebug %s : Line: %d %s is = %u\n", fname, lineno, name, value); else cout << "\nDebug " << fname << ": Line: " << lineno << " " << name << " is = " << value << endl; } void local_dbg(char name[], long value, char fname[], int lineno, bool logfile) { if (logfile == true) print_log("\nDebug %s : Line: %d %s is = %d\n", fname, lineno, name, value); else cout << "\nDebug " << fname << ": Line: " << lineno << " " << name << " is = " << value << endl; } void local_dbg(char name[], unsigned long value, char fname[], int lineno, bool logfile) { if (logfile == true) print_log("\nDebug %s : Line: %d %s is = %u\n", fname, lineno, name, value); else cout << "\nDebug " << fname << ": Line: " << lineno << " " << name << " is = " << value << endl; } void local_dbg(char name[], short value, char fname[], int lineno, bool logfile) { if (logfile == true) print_log("\nDebug %s : Line: %d %s is = %d\n", fname, lineno, name, value); else cout << "\nDebug " << fname << ": Line: " << lineno << " " << name << " is = " << value << endl; } void local_dbg(char name[], unsigned short value, char fname[], int lineno, bool logfile) { if (logfile == true) print_log("\nDebug %s : Line: %d %s is = %u\n", fname, lineno, name, value); else cout << "\nDebug " << fname << ": Line: " << lineno << " " << name << " is = " << value << endl; } void local_dbg(char name[], float value, char fname[], int lineno, bool logfile) { if (logfile == true) print_log("\nDebug %s : Line: %d %s is = %f\n", fname, lineno, name, value); else cout << "\nDebug " << fname << ": Line: " << lineno << " " << name << " is = " << value << endl; } void local_dbg(char name[], double value, char fname[], int lineno, bool logfile) { if (logfile == true) print_log("\nDebug %s : Line: %d %s is = %f\n", fname, lineno, name, value); else cout << "\nDebug " << fname << ": Line: " << lineno << " " << name << " is = " << value << endl; } // You add many more here - value can be a class, ENUM, datetime, etc... #endif // DEBUG </code> <!-- ******************************************* ************ End of Section *************** ******************************************* --> </article>