This page is of historical value only. It was written to address the Borland Turbo C++ of the 20th century, so much of it isn't relevant, or even accurate, for modern compilers, so please do not rely on it. This page is no longer being maintained. |
Steve Litt is the author of Troubleshooting Techniques of the Successful Technologist, Rapid Learning: Secret Weapon of the Successful Technologist, and Samba Unleashed. |
Some versons of the gcc C++ compiler that you find in some Linux distros cannot compile C++ code with the standard command. If no C++ compiles on your system, try the following command: g++ -lstdc++ myprogram.cppThe -lstdc++ argument solves the problem. |
const char *add2strings(const char *sz1, const char *sz2);
Such a declaration guarantee's that no matter what wierd things go on within the function, it can't harm the application programmer's two strings sz1 and sz2. If any memory corruption occurs, it will be to variables within the function's scope. This, of course, greatly reduces side effect bugs. Of course, if the program has global variables, all bets are off...
Furthermore, the declaration of the return pointer as const means that the application programmer can't "reach inside" the function to corrupt its scope. For instance, if the return value is a static array of 40 characters, if the return wasn't static the application programmer could do this:
char *pchName = add2strings("Philbinoff", "James");
strcat(pchName, " is the name of the first author of the three
books");
cout << "I just corrupted an internal variable of add2strings.
";
cout << "Will I see this message?\n";
cout << "Will it crash later in the program? Who knows!\n";
Fortunately, because add2strings() returns a const pointer, you'll get a compiler error on this:
char *pchName = add2strings("Philbinoff", "James");
Even if you declared pchName as a const char *, the moment you modified its contents with strcat() you'd get a compile error. The const keyword helps the programmer keep any errors localized, thus greatly reducing the likelihood of side-effect errors.
There are many implementations of string classes. Stroustrup describes a simple one in chapter/section 7.11 of his book, The C++ Programming Language, Second Edition (ISBN0-201-53992-6). Your organization may make its own. Whatever you use, it should have provisions to output to and input from streams, concatenate, search/replace, etc, WITHOUT the application programmmer having to resort to pointer arithmetic. Such an implementation might use the plus sign for concatenation.
//***** Create nametag string ****** ostrstream ost; ost << "My name is " << ychFname; ost.put(0); //null terminate the string makenametag(ost.str());
//***** Also create a nametag with the last name after first ***** ost.seekp(ost.tellp()-1); //get rid of the null termination ost << " " << ychLname; ost.put(0); //null terminate the string makenametag(ost.str());
char *pchPerson = "Magdelena Alexandra de la Romero"; char ychName[20]; strcpy(ychName, pchPerson); //CRUNCH! cout << ychName << '\n'; //what this will output is anybody's guess.Now handle it intelligently with strncpy instead
char *pchPerson = "Magdelena Alexandra de la Romero"; char ychName[20]; strncpy(ychName, pchPerson, sizeof(ychName)-1); ychName[sizeof(ychName)-1] = '\0'; cout << ychName << '\n'; //Magdelena AlexandraHere's another way that won't corrupt memory:
char *pchPerson = "Magdelena Alexandra de la Romero"; char pchName = new char[strlen(pchPerson) + 1]; strcpy(pchName, pchPerson); cout << pchName << '\n'; //Magdelena Alexandra de la Romero
//***** Of course, sooner or later pchName must be deleted ***** if(pchName) { delete(pchName) pchName = 0; }
//***** This might cause a big problem ***** class bufferhandler { void zero(){*buf='\0';}; void put(const char *pch){strncpy(buf, pch, sizeof(buf)-1);}; const char *get(){return(buf);}; private: char buf[2000]; };
void myprocess(void) { bufferhandler bh1; //2000+ bytes gone from the stack bufferhandler bh2; //Another 2000+ gone. Will there be enough? bh1.put("Steve was here"); bh2.put("Sylvia was here"); /* . . . */ }One way around this (though I think it's ugly) is to use pointers:
void myprocess(void) { bufferhandler *pbh1 = new bufferhandler; //4 bytes gone for the pointer bufferhandler *pbh2 = new bufferhandler; //Another 4 gone. Stack is cool. pbh1->put("Steve was here"); pbh2->put("Fred was here"); /* . . . */
//***** be sure to delete the pointers ***** if(pbh1) { delete(pbh1); pbh1=0; } if(pbh2) { delete(pbh2); pbh2=0; } }
The last time I did this (1994), it created a bug that occurred once every few days :-(. It took myself and two other people a week (off and on) to narrow it to returning a local string. Now I'm EXTREMELY careful not to make this goof.
//***** BONEHEAD MISTAKE ***** char *addstrings(const char *sz1, const char *sz2) { char ychDst[100]; //life would be easier if I had made this static
strncpy(ychDst, sz1, sizeof(ychDst) - 1); strncpy(ychDst + n1, sz2, sizeof(ychDst) - strlen(sz1) - 1); ychDst[sizeof(ychDst) - 1] = '\0'; return(ychDst]; //BONEHEAD }
#include <iostream.h>
#include <stdio.h>
/* . . . */
char ychString[100];
sprintf(ychString, "%s, %s %c", ychLname, ychFname, *ychMname);
cout << ychString << '\n';
Try This:
#include <iostream.h>
#include <strstream.h>
/* . . . */
ostrstream ost;
ost << ychLname << ", " << ychFname <<
" " << *ychMname;
ost.put(0); //null terminate the string cout
cout << ost.str() << '\n';
See also: [ Code Corner | Troubleshooters.Com | Email Steve Litt | Copyright Notice ]