The set functions' idea:
First argument is a reference, allocates space to hold copy of testing, sets str member of beany to point to the new block, copies testing to new block, and sets ct member of beany.
Problem:
1) Line that contains:
for (int i = 0; i < temp.length(); i++)
Error:expression must have a class
type
2) Line that contains:
temp[i] = cstr[i];
Error: expression must have
pointer-to-object type
3) overload of function show() for stringy type can't find matching function signature due to presence of const
Very new to these concepts, could someone explain the reason for the errors?
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <cstring>
#include <cctype>
struct stringy {
char * str; //points to a string
int ct; //length of string(not counting '\0')
};
void set(stringy & obj, char cstr);
void show(const stringy & obj, int times=1);
void show(const char * cstr, int times = 1);
int _tmain(int argc, _TCHAR* argv[])
{
string beany;
char testing[] = "Reality isn't what it used to be.";
set(beany, testing);
show(beany);
show(beany, 2);
testing[0] = 'D';
testing[1] = 'u';
show(testing);
show(testing, 3);
show("Done");
return 0;
}
void set(stringy & obj, char cstr)
{
char * temp = new char[cstr];
obj.str = temp;
for (int i = 0; i < temp.length(); i++)
temp[i] = cstr[i];
}
void show(const stringy & obj, int times)
{
for (int i = 0; i < times; i++)
cout << obj.str;
}
void show(const char * cstr, int times)
{
for (int i = 0; i < times; i++)
cout << cstr;
}
I hope you won't take this personally... but this code has so many errors on so many logical levels that in my opinion it's simply FUBAR.
Please do yourself a favor and start by reading a C++ book. A list of good ones can be found here and you can also find decent resources for free on the internet.
C++ is not a language that you (or anyone else indeed) can hope to learn by just typing it some characters and looking at what happens... that is simply just a suicidal approach to C++.
EDIT:
After doing some googling seems indeed that you are following a book. From a few excerpts I found on the net seems a book that is teaching programming using C++. I don't think this is a good idea because C++ is too complex and apparently illogical to be the first language for a programmer, also it's very very easy to get programs that compile fine and that will just drive you crazy when you run them. There are some gurus however that think this is a viable approach.
Your book is indeed listed, not because is good, but just because the title is close to one of a good book. Probably just a marketing trick to sell it.
EDIT2:
I felt a bit sorry for being so rude when your only fault is choosing a bad book to learn C++. To try compensate here is my attempt to tell all problems I think are present in your C++ code:
1. Learn standard C++
#include "stdafx.h"
If you are learning C++ then you should try to put aside everything that microsoft tells you about the language. Standard C++ has never been important for microsoft; probably because portable code is more a threat to microsoft than good for them.
Once you know C++ (but only then) it's ok to write microsoft-specific code if that is your platform. But it's important that you know what is ms-only and what is C++. There are cases in which the difference is just plain stupid and not worth considering (e.g. for scoping or handling of allocation failures) but sometimes you actually MUST use their variation of the language to work with windows.
MS development tools are great (or at least they were... I was simply in love with VC6 for example) but they will always try to trick you into writing unportable code. This is done both in IDEs and in the windows API examples. Don't fall into those traps: write portable code unless you have a real need for platform-specific code and be always be conscious about it.
2. Don't pollute the global namespace
using namespace std;
This is a bad idea. Even if it's a bit annoying it's much better if you get used to write std:: before standard functions. The reasons are because of the complex rules of name lookup and overload resolution that are present in the language and because of all the names that you are getting into your namespace without being conscious about them.
Saving typing time is not really that important in C++ (it's important in PERL if you are writing a throw-away script... but not for general programs). Much more important to help who is reading your code (and this includes yourself) and using std:: does that.
3. Use a proper main declaration
This is again about not falling in stupid MS traps. The correct declaration for main is
int main(int argc, const char *argv[])
You should never use anything else when learning about C++. If the MS tool you are using doesn't allow you to write a correct declaration (that wouldn't be a surprise) then just drop it on the floor now and learn C++ using a tool that shows some respect for the standard instead. Once you know C++ you can begin use non-portable stuff if you really need but knowing that's non-portable stuff.
Mingw is a good free C++ compiler for windows and there are free good IDEs if you like them. Over the years I got to like more using a good editor like emacs (vim is also ok, I used it for many years) and a command line compiler, but mainly because I work in a variety of languages on several different operating systems and no single IDE can cover all that. I want to put low level knowledge (how to copy a piece of text, how to search for a string, how to ask to completion, how to open another file) at a finger level and not having to think consciously in which IDE I am just to find the proper command. You cannot really play Chopin if you've to think every time to where G# is on the keyboard.
May be I'm just old, however... ;-)
4. Pick a reasonable naming convention
struct stringy {
char * str; //points to a string
int ct; //length of string(not counting '\0')
};
In your code your are naming a class stringy. It's better if you get used to what is the most common naming convention in C++ for classes, that is having it named Stringy instead.
The standard C++ library is not following this convention but those classes will always be prefixed by std:: anyway.
My advice is also to NOT use the idea of system hungarian notation of calling variables depending on the C++ type (like iIndex, sFileName) that is sometimes present in MS documentation. That idea doesn't scale up and simply means you will use bad names for all your variables.
5. Problems with set function
void set(stringy & obj, char cstr)
{
char * temp = new char[cstr];
obj.str = temp;
for (int i = 0; i < temp.length(); i++)
temp[i] = cstr[i];
}
In this function there are several errors:
You want to pass a char * not a char. A char holds the room for a single character and instead you want to initialize your stringy instance with a sequence of characters. In C++ you can use a char pointer for that because there is a specific support for char sequences in memory that are closed with the special ascii char NUL (note the single "L", the ASCII NUL character in C++ is spelled '\0' and is not to be confused with the NULL pointer). C++ preferred way for handling sequences of characters is actually the std::string standard class, but NUL-terminated sequences of characters are also fully supported for backward-compatibility with C.
A pointer is however just the address of a charater... that character will be followed by other characters until you find the closing '\0' but a pointer has no length member (actually has no members at all, it's a primitive type like int or double).
To know the lenght of a sequence of characters that has been passed using a pointer there is the standard function strlen (that returns the number of characters in the sequence excluding the terminating '\0'). So your code should probably be something like:
void set(stringy & obj, char *cstr)
{
char * temp = new char[1 + strlen(cstr)];
obj.str = temp;
strcpy(obj.str, cstr);
}
I've been using also the standard function strcpy that does the copy of a char sequence including the end '\0' marker. A possibile implementation of strcpy (here just to show the idea of '\0'-terminated strings) is the following:
char *mystrcpy(char *dest, const char *src)
{
int i = 0;
while (src[i] != '\0')
{
dest[i] = src[i];
i++;
}
dest[i] = '\0';
return dest;
}
6. Memory allocation
The stringy class is badly designed (in C++ there isn't any big difference between struct and class: just what is the default for visibility). To be specific construction and destruction are not handled where they should be (inside the stringy class), and for a class designed this way also assignment and copy construction must be handled or forbidden.
As a consequence your program is simply forgetting deallocation leaking memory (normally not a serious issue for main, but it's important to understand the problem).
Hopefully this problem is just because the book didn't arrive yet to explain those concepts.
Anyway I find it strange a book that talks about new[] but not about delete[] (may be there is a reason that your book is not listed as a good book).
A properly implemented stringy should IMO look something like:
struct stringy
{
int size; // Number of characters EXCLUDING ending '\0'
char *ptr; // Pointer to first character
stringy(const char *s = "")
: size(strlen(s)), ptr(new char[1 + size])
{
strcpy(ptr, s);
}
~stringy()
{
delete[] ptr;
}
stringy(const stringy& other)
: size(other.size), ptr(new char[1 + size])
{
strcpy(ptr, other.ptr);
}
stringy& operator=(const stringy& other)
{
char *newptr = new char[1 + other.size];
strcpy(newptr, other.ptr);
delete[] ptr;
ptr = newptr;
size = other.size;
return *this;
}
};
temp is a const char*. That type does not provide any kind of length facilities- it is not an object and does not have a length() member method. Use a std::string- that is what it is for.
Related
I want to make a function that removes all the characters of ch in a c-string.
But I keep getting an access violation error.
Unhandled exception at 0x000f17ba in testassignments.exe: 0xC0000005: Access violation writing location 0x000f787e.
void removeAll(char* &s, const char ch)
{
int len=strlen(s);
int i,j;
for(i = 0; i < len; i++)
{
if(s[i] == ch)
{
for(j = i; j < len; j++)
{
s[j] = s[j + 1];
}
len--;
i--;
}
}
return;
}
I expected the c-string to not contain the character "ch", but instead, I get an access violation error.
In the debug I got the error on the line:
s[j] = s[j + 1];
I tried to modify the function but I keep getting this error.
Edit--
Sample inputs:
s="abmas$sachus#settes";
ch='e' Output->abmas$sachus#settes, becomes abmas$sachus#stts
ch='t' Output-> abmas$sachus#stts, becomes abmas$sachus#ss.
Instead of producing those outputs, I get the access violation error.
Edit 2:
If its any help, I am using Microsoft Visual C++ 2010 Express.
Apart from the inefficiency of your function shifting the entire remainder of the string whenever encountering a single character to remove, there's actually not much wrong with it.
In the comments, people have assumed that you are reading off the end of the string with s[j+1], but that is untrue. They are forgetting that s[len] is completely valid because that is the string's null-terminator character.
So I'm using my crystal ball now, and I believe that the error is because you're actually running this on a string literal.
// This is NOT okay!
char* str = "abmas$sachus#settes";
removeAll(str, 'e');
This code above is (sort of) not legal. The string literal "abmas$sachus#settes" should not be stored as a non-const char*. But for backward compatibility with C where this is allowed (provided you don't attempt to modify the string) this is generally issued as a compiler warning instead of an error.
However, you are really not allowed to modify the string. And your program is crashing the moment you try.
If you were to use the correct approach with a char array (which you can modify), then you have a different problem:
// This will result in a compiler error
char str[] = "abmas$sachus#settes";
removeAll(str, 'e');
Results in
error: invalid initialization of non-const reference of type ‘char*&’ from an rvalue of type ‘char*’
So why is that? Well, your function takes a char*& type that forces the caller to use pointers. It's making a contract that states "I can modify your pointer if I want to", even if it never does.
There are two ways you can fix that error:
The TERRIBLE PLEASE DON'T DO THIS way:
// This compiles and works but it's not cool!
char str[] = "abmas$sachus#settes";
char *pstr = str;
removeAll(pstr, 'e');
The reason I say this is bad is because it sets a dangerous precedent. If the function actually did modify the pointer in a future "optimization", then you might break some code without realizing it.
Imagine that you want to output the string with characters removed later, but the first character was removed and you function decided to modify the pointer to start at the second character instead. Now if you output str, you'll get a different result from using pstr.
And this example is only assuming that you're storing the string in an array. Imagine if you actually allocated a pointer like this:
char *str = new char[strlen("abmas$sachus#settes") + 1];
strcpy(str, "abmas$sachus#settes");
removeAll(str, 'e');
Then if removeAll changes the pointer, you're going to have a BAD time when you later clean up this memory with:
delete[] str; //<-- BOOM!!!
The I ACKNOWLEDGE MY FUNCTION DEFINITION IS BROKEN way:
Real simply, your function definition should take a pointer, not a pointer reference:
void removeAll(char* s, const char ch)
This means you can call it on any modifiable block of memory, including an array. And you can be comforted by the fact that the caller's pointer will never be modified.
Now, the following will work:
// This is now 100% legit!
char str[] = "abmas$sachus#settes";
removeAll(str, 'e');
Now that my free crystal-ball reading is complete, and your problem has gone away, let's address the elephant in the room:
Your code is needlessly inefficient!
You do not need to do the first pass over the string (with strlen) to calculate its length
The inner loop effectively gives your algorithm a worst-case time complexity of O(N^2).
The little tricks modifying len and, worse than that, the loop variable i make your code more complex to read.
What if you could avoid all of these undesirable things!? Well, you can!
Think about what you're doing when removing characters. Essentially, the moment you have removed one character, then you need to start shuffling future characters to the left. But you do not need to shuffle one at a time. If, after some more characters you encounter a second character to remove, then you simply shunt future characters further to the left.
What I'm trying to say is that each character only needs to move once at most.
There is already an answer demonstrating this using pointers, but it comes with no explanation and you are also a beginner, so let's use indices because you understand those.
The first thing to do is get rid of strlen. Remember, your string is null-terminated. All strlen does is search through characters until it finds the null byte (otherwise known as 0 or '\0')...
[Note that real implementations of strlen are super smart (i.e. much more efficient than searching single characters at a time)... but of course, no call to strlen is faster]
All you need is your loop to look for the NULL terminator, like this:
for(i = 0; s[i] != '\0'; i++)
Okay, and now to ditch the inner loop, you just need to know where to stick each new character. How about just keeping a variable new_size in which you are going to count up how long the final string is.
void removeAll(char* s, char ch)
{
int new_size = 0;
for(int i = 0; s[i] != '\0'; i++)
{
if(s[i] != ch)
{
s[new_size] = s[i];
new_size++;
}
}
// You must also null-terminate the string
s[new_size] = '\0';
}
If you look at this for a while, you may notice that it might do pointless "copies". That is, if i == new_size there is no point in copying characters. So, you can add that test if you want. I will say that it's likely to make little performance difference, and potentially reduce performance because of additional branching.
But I'll leave that as an exercise. And if you want to dream about really fast code and just how crazy it gets, then go and look at the source code for strlen in glibc. Prepare to have your mind blown.
You can make the logic simpler and more efficient by writing the function like this:
void removeAll(char * s, const char charToRemove)
{
const char * readPtr = s;
char * writePtr = s;
while (*readPtr) {
if (*readPtr != charToRemove) {
*writePtr++ = *readPtr;
}
readPtr++;
}
*writePtr = '\0';
}
I' m trying to understad the work with a pointers. So I've wrote a test program where name is split into labels by removing the separating dots. Each label is represented as a length/data pair as follows:
google.ru represents as "x\06googlex\02ru"
I get signal SIGABRT when i returned from my test function
I guess it's caused with my bad work with pointer.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void test(unsigned char* dns, unsigned char* host);
int main(int argc, const char * argv[])
{
unsigned char host[]="google.ru";
unsigned char* dnsTest=(unsigned char*)malloc(20);
if(dnsTest==NULL)
{
exit(1);
}
test(dnsTest, host);
printf("%s", dnsTest);
free(dnsTest);
return 0;
}
void test(unsigned char* dns, unsigned char* host)
{
strcat((char*)host, ".");
int lock=0;
for(int i=0; i<strlen((char *)host);i++)
{
if(host[i]=='.')
{
*dns=i-lock;
dns++;
for(;lock<i; lock++)
{
*dns=host[lock];
dns++;
}
lock++;
}
}
*dns='\0';
}
Since you tagged c++ as well, you can use new \ delete instead of malloc \ free. New will call constructor (when you will learn classes it will be useful), and new return to you exact type, so no need to cast (and casting is almost always a bad idea)
Then assertion after memory allocation with new will be redundant:
if(dnsTest==NULL)
since c++ new will throw an exception by default.
If you go ahead, you can use std::string - its much more simple than c null terminated strings (but not for the task of understanding pointers).
Every other comments (about redundant strlen usage and absence of '\0' symbol) is correct too, but I want to give you two advices, how to grasp pointers.
First - read K&R - it's the Bible.
Second - if you use Microsoft Visual Studio, you can compile your code in Debug mode, and use Memory View tab. Visual Studio compiler place some magic number inside memory (link) at debug mode. They can help you with understanding where you addressing unallocated memory or how exactly your memory layout looks like.
This question already has answers here:
Easiest way to convert int to string in C++
(30 answers)
Closed 7 years ago.
I was wondering if there was an alternative to itoa() for converting an integer to a string because when I run it in visual Studio I get warnings, and when I try to build my program under Linux, I get a compilation error.
In C++11 you can use std::to_string:
#include <string>
std::string s = std::to_string(5);
If you're working with prior to C++11, you could use C++ streams:
#include <sstream>
int i = 5;
std::string s;
std::stringstream out;
out << i;
s = out.str();
Taken from http://notfaq.wordpress.com/2006/08/30/c-convert-int-to-string/
boost::lexical_cast works pretty well.
#include <boost/lexical_cast.hpp>
int main(int argc, char** argv) {
std::string foo = boost::lexical_cast<std::string>(argc);
}
Archeology
itoa was a non-standard helper function designed to complement the atoi standard function, and probably hiding a sprintf (Most its features can be implemented in terms of sprintf): http://www.cplusplus.com/reference/clibrary/cstdlib/itoa.html
The C Way
Use sprintf. Or snprintf. Or whatever tool you find.
Despite the fact some functions are not in the standard, as rightly mentioned by "onebyone" in one of his comments, most compiler will offer you an alternative (e.g. Visual C++ has its own _snprintf you can typedef to snprintf if you need it).
The C++ way.
Use the C++ streams (in the current case std::stringstream (or even the deprecated std::strstream, as proposed by Herb Sutter in one of his books, because it's somewhat faster).
Conclusion
You're in C++, which means that you can choose the way you want it:
The faster way (i.e. the C way), but you should be sure the code is a bottleneck in your application (premature optimizations are evil, etc.) and that your code is safely encapsulated to avoid risking buffer overruns.
The safer way (i.e., the C++ way), if you know this part of the code is not critical, so better be sure this part of the code won't break at random moments because someone mistook a size or a pointer (which happens in real life, like... yesterday, on my computer, because someone thought it "cool" to use the faster way without really needing it).
Try sprintf():
char str[12];
int num = 3;
sprintf(str, "%d", num); // str now contains "3"
sprintf() is like printf() but outputs to a string.
Also, as Parappa mentioned in the comments, you might want to use snprintf() to stop a buffer overflow from occuring (where the number you're converting doesn't fit the size of your string.) It works like this:
snprintf(str, sizeof(str), "%d", num);
Behind the scenes, lexical_cast does this:
std::stringstream str;
str << myint;
std::string result;
str >> result;
If you don't want to "drag in" boost for this, then using the above is a good solution.
We can define our own iota function in c++ as:
string itoa(int a)
{
string ss=""; //create empty string
while(a)
{
int x=a%10;
a/=10;
char i='0';
i=i+x;
ss=i+ss; //append new character at the front of the string!
}
return ss;
}
Don't forget to #include <string>.
С++11 finally resolves this providing std::to_string.
Also boost::lexical_cast is handy tool for older compilers.
I use these templates
template <typename T> string toStr(T tmp)
{
ostringstream out;
out << tmp;
return out.str();
}
template <typename T> T strTo(string tmp)
{
T output;
istringstream in(tmp);
in >> output;
return output;
}
Try Boost.Format or FastFormat, both high-quality C++ libraries:
int i = 10;
std::string result;
WIth Boost.Format
result = str(boost::format("%1%", i));
or FastFormat
fastformat::fmt(result, "{0}", i);
fastformat::write(result, i);
Obviously they both do a lot more than a simple conversion of a single integer
You can actually convert anything to a string with one cleverly written template function. This code example uses a loop to create subdirectories in a Win-32 system. The string concatenation operator, operator+, is used to concatenate a root with a suffix to generate directory names. The suffix is created by converting the loop control variable, i, to a C++ string, using the template function, and concatenating that with another string.
//Mark Renslow, Globe University, Minnesota School of Business, Utah Career College
//C++ instructor and Network Dean of Information Technology
#include <cstdlib>
#include <iostream>
#include <string>
#include <sstream> // string stream
#include <direct.h>
using namespace std;
string intToString(int x)
{
/**************************************/
/* This function is similar to itoa() */
/* "integer to alpha", a non-standard */
/* C language function. It takes an */
/* integer as input and as output, */
/* returns a C++ string. */
/* itoa() returned a C-string (null- */
/* terminated) */
/* This function is not needed because*/
/* the following template function */
/* does it all */
/**************************************/
string r;
stringstream s;
s << x;
r = s.str();
return r;
}
template <class T>
string toString( T argument)
{
/**************************************/
/* This template shows the power of */
/* C++ templates. This function will */
/* convert anything to a string! */
/* Precondition: */
/* operator<< is defined for type T */
/**************************************/
string r;
stringstream s;
s << argument;
r = s.str();
return r;
}
int main( )
{
string s;
cout << "What directory would you like me to make?";
cin >> s;
try
{
mkdir(s.c_str());
}
catch (exception& e)
{
cerr << e.what( ) << endl;
}
chdir(s.c_str());
//Using a loop and string concatenation to make several sub-directories
for(int i = 0; i < 10; i++)
{
s = "Dir_";
s = s + toString(i);
mkdir(s.c_str());
}
system("PAUSE");
return EXIT_SUCCESS;
}
Allocate a string of sufficient length, then use snprintf.
int number = 123;
stringstream = s;
s << number;
cout << ss.str() << endl;
I wrote this thread-safe function some time ago, and am very happy with the results and feel the algorithm is lightweight and lean, with performance that is about 3X the standard MSVC _itoa() function.
Here's the link. Optimal Base-10 only itoa() function? Performance is at least 10X that of sprintf(). The benchmark is also the function's QA test, as follows.
start = clock();
for (int i = LONG_MIN; i < LONG_MAX; i++) {
if (i != atoi(_i32toa(buff, (int32_t)i))) {
printf("\nError for %i", i);
}
if (!i) printf("\nAt zero");
}
printf("\nElapsed time was %f milliseconds", (double)clock() - (double)(start));
There are some silly suggestions made about using the caller's storage that would leave the result floating somewhere in a buffer in the caller's address space. Ignore them. The code I listed works perfectly, as the benchmark/QA code demonstrates.
I believe this code is lean enough to use in an embedded environment. YMMV, of course.
The best answer, IMO, is the function provided here:
http://www.jb.man.ac.uk/~slowe/cpp/itoa.html
It mimics the non-ANSI function provided by many libs.
char* itoa(int value, char* result, int base);
It's also lightning fast and optimizes well under -O3, and the reason you're not using c++ string_format() ... or sprintf is that they are too slow, right?
If you are interested in fast as well as safe integer to string conversion method and not limited to the standard library, I can recommend the format_int method from the {fmt} library:
fmt::format_int(42).str(); // convert to std::string
fmt::format_int(42).c_str(); // convert and get as a C string
// (mind the lifetime, same as std::string::c_str())
According to the integer to string conversion benchmarks from Boost Karma, this method several times faster than glibc's sprintf or std::stringstream. It is even faster than Boost Karma's own int_generator as was confirm by an independent benchmark.
Disclaimer: I'm the author of this library.
Note that all of the stringstream methods may involve locking around the use of the locale object for formatting. This may be something to be wary of if you're using this conversion from multiple threads...
See here for more. Convert a number to a string with specified length in C++
On Windows CE derived platforms, there are no iostreams by default. The way to go there is preferaby with the _itoa<> family, usually _itow<> (since most string stuff are Unicode there anyway).
Most of the above suggestions technically aren't C++, they're C solutions.
Look into the use of std::stringstream.
Ps: This is more of a conceptual question.
I know this makes things more complicated for no good reason, but here is what I'm wondering. If I'm not mistaken, a const char* "like this" in c++ is pointing to l and will be automatically zero terminated on compile time. I believe it is creating a temporary variable const char* to hold it, unless it is keeping track of the offset using a byte variable (I didn't check the disassembly). My question is, how would you if even possible, add characters to this string without having to call functions or instantiating strings?
Example (This is wrong, just so you can visualize what I meant):
"Like thi" + 's';
The closest thing I came up with was to store it to a const char* with enough spaces and change the other characters.
Example:
char str[9];
strcpy(str, "Like thi")
str[8] = 's';
Clarification:
Down vote: This question does not show any research effort; it is unclear or not useful
Ok, so the question has been highly down voted. There wasn't much reasoning on which of these my question was lacking on, so I'll try to improve all of those qualities.
My question was more so I could have a better understanding of what goes on when you simply create a string "like this" without storing the address of that string in a const char* I also wanted to know if it was possible to concatenate/change the content of that string without using functions like strcat() and without using the overloaded operator + from the class string. I'm aware this is not exactly useful for dealing with strings in C++, but I was curious whether or not there was a way besides the standard ways for doing so.
string example = "Like thi" + "s"; //I'm aware of the string class and its member functions
const char* example2 = "Like this"; //I'm also aware of C-type Strings (CString as well)
It is also possible that not having English as my native language made things even worst, I apologize for the confusion.
Instead of using a plain char string, you should use the string library provided by the C++ library:
#include <string>
#include <iostream>
using namespace std;
int main()
{
string str = "Like thi";
cout << str << endl;
str = str + "s";
cout << str << endl;
return 0;
}
Normally, it's not possible to simply concatenate plain char * strings in C or C++, because they are merely pointers to arrays of characters. There's almost no reason you should be using a bare character array in C++ if you intend on doing any string manipulations within your own code.
Even if you need access to the C representation (e.g. for an external library) you can use string::c_str().
First, there is nothing null terminated, but the zero terminated. All char* strings in C end with '\0'.
When you in code do something like this:
char *name="Daniel";
compiler will generate a string that has a contents:
Daniel\0
and will initialize name pointer to point at it at a certain time during program execution depending on the variable context (member, static, ...).
Appending ANYTHING to the name won't work as you expect, since memory pointed to by name isn't changeable, and you'll probably get either access violation error or will overwrite something else.
Having
const char* copyOfTheName = name;
won't create a copy of the string in question, it will only have copyOfTheName point to the original string, so having
copyOfTheName[6]='A';
will be exactly as
name[6]='A';
and will only cause problems to you.
Use std::strcat instead. And please, do some investigating how the basic string operations work in C.
An answer to one of my questions included the following line of code:
label = std::safe_string(name); // label is a std::string
The intent seems to be a wrapper around a string literal (so presumably no allocation takes place). I've never heard of safe_string and neither, apparently, has google (nor could I find it in the 98 standard).
Does anyone know what this is about?
After searching google code search (I should have thought of this first...) I found this:
//tools-cgi.cpp
string safe_string (const char * s)
{
return (s != NULL) ? s : "";
}
Which converts NULLs to zero length strings. Although this is not standard it's probably some sort of extension in a specific STL implementation which was referred to in the answer.
There is no standard safe_string. The safe_string you're seeing in that answerer's response is from what looks like a private STL extensions utility library.
Google for "stlext/stringext.h" and you'll see the same library referenced in a post on another forum.
There is no such thing as std::safe_string
It is not part of C++ standard (but perhaps it should be?)
I have been using the same kind of helper function to avoid a std::string throw an exception with a NULL char * string. But it was more something like:
// defined somewhere else as ""
extern const char * const g_strEmptyString ;
inline const char * safe_string(const char * p)
{
return (p) ? (p) : (g_strEmptyString) ;
}
No overhead, and no crash of a std::string when I feed it a char * string that could be NULL but that, in that particular case, should behave as an empty string.