In my project, I need the user to input a string, and the string that is typed is const char* by default (with using quotation marks). In my project, I also need to modify these strings, so I cannot really use const.
So I thought about transforming the const char* into a char* with the following function:
Not 100% sure this is the problem (since it crashes for me) but I believe the problem is that the New string does not have enough memory to store the whole string. I tried sort of allocating it memory by writing like this:
const char* szOldString = "Test";
char* szNewString[0x1024];
noconst(&szOldString, &szNewString, 5);
This also did not work considering my parameters and the constexpr.
I am wondering if anybody knows any cool hacks I can use to make this work. I have been working on this for some time so the solution might be an obvious one and I just cannot see it. If that's the case, my bad :D
The easier way is to use the function strncpy (which is more secure than just using strcpy).
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
//char oldString[]= "Hello World!";
const char* oldString = "Hello World!";
char newString[40];
/* copy to sized buffer (overflow safe): */
strncpy ( newString, oldString, sizeof(newString) );
cout << newString;
return 0;
}
Another way is to allocate with malloc space for where you wish to copy the string.
After, you can modify it as your please.
Related
This is from C++ Primer 5th edition. What do they mean by "the size of largeStr". largeStr is an instance of std::string so they have dynamic sizes?
Also I don't think the code compiles:
#include <string>
#include <cstring>
int main()
{
std::string s("test");
const char ca1[] = "apple";
std::strcpy(s, ca1);
}
Am I missing something?
strcpy and strcat only operate on C strings. The passage is confusing because it describes but does not explicitly show a manually-sized C string. In order for the second snippet to compile, largeStr must be a different variable from the one in the first snippet:
char largeStr[100];
// disastrous if we miscalculated the size of largeStr
strcpy(largeStr, ca1); // copies ca1 into largeStr
strcat(largeStr, " "); // adds a space at the end of largeStr
strcat(largeStr, ca2); // concatenates ca2 onto largeStr
As described in the second paragraph, largeStr here is an array. Arrays have fixed sizes decided at compile time, so we're forced to pick some arbitrary size like 100 that we expect to be large enough to hold the result. However, this approach is "fraught with potential for serious error" because strcpy and strcat don't enforce the size limit of 100.
Also I don't think the code compiles...
As above, change s to an array and it will compile.
#include <cstring>
int main()
{
char s[100] = "test";
const char ca1[] = "apple";
std::strcpy(s, ca1);
}
Notice that I didn't write char s[] = "test";. It's important to reserve extra space for "apple" since it's longer than "test".
You are missing the
char largeStr[100];
or similar the book doesn't mention.
What you should do is forget about strcpy and strcat and C-style strings real quick. Just remember how to make c++ std::string out of them and never look back.
I have a problem which i cannot fix on my own.
string filenameRaw;
filenameRaw= argv[1];
function(filenameRaw.c_str(),...);
function(const char* rawDataFile,const char* targetfieldFile,const char* resultFile,const char* filename)
...
this->IOPaths.rawData=rawDataFile;
...
works very fine so far. Now I try to put another string in the variable IOPaths.rawData...
function(const char* rawDataFile,const char* targetfieldFile,const char* resultFile,const char* filename)
...
string filenameRaw;
filenameRaw=reader.Get("paths", "rawData", "UNKNOWN")
...
const char* rawDataFile1=filenameRaw.c_str();
cout << "Compare: " << strcmp(rawDataFile,rawDataFile1) <<endl;
...
this->IOPaths.rawData=rawDataFile1;
this does not work any more. Later in my programm I get errors with the filename. The strcmp definitly gives a 0, so the strings must be equal. Does anyone has an idea what i am doing wrong?
The validity of the output of c_str() is limited to, at most, the lifetime of the object on which c_str() was called.1
I suspect that this->IOPaths.rawData is pointing to deallocated memory once filenameRaw is out of scope.
An adequate remedy would be to pass the std::string around rather than [const] char*. A good stl implementation would use copy on write semantics for the string class so perhaps you wouldn't be repeatedly copying string data.
1In certain instances (such as if the object is modified), it could be less.
I have char* which is of fixed (known) width but is not null terminated.
I want to pass it into LOG4CPLUS_ERROR("Bad string " << char_pointer); but as its not null terminated it will print it all.
Any suggestions of some light weight way of getting "(char[length])*char_pointer" without performing a copy?
No, you'll have to deep-copy and null-terminate it. That code expects a null-terminated string and it means a contiguous block of characters ending with a null terminator.
If your goal is to print such a string, you could:
Store the last byte.
Replace it with \0.
Print the string.
Print the stored byte.
Put the stored byte back into the last position of the string.
Wrap all this in a function.
Real iostreams
When you're writing to a real iostream, then you can just use ostream.write() which takes a char* and a size for how many bytes to write -- no null termination necessary. (In fact, any null characters in the string would be written to the ostream, and would not be used to determine the size.)
Logging libraries
In some logging libraries, the stream that you write to is not a real iostream. This is the case in Log4CPP.
However, in Log4CPlus which is what it appears matt is using, the object that you're writing to is a std::basic_ostringstream<tchar> (see loggingmacros.h and streams.h for the definition, since none of this is obvious from the documentation). There's just one problem: in the macro LOG4CPLUS_ERROR, the first << is already built into the macro, so he won't be able to call LOG4CPLUS_ERROR(.write(char_pointer,length)) or anything like that. Unfortunately, I don't see an easy way around this without deconstructing the LOG4CPLUS_ERROR error macro and getting into the internals of Log4CPlus
Solution
I'm not sure why you're trying to avoid copying the string at this point, since you can see that there's a lot of copying going on inside the logging library. Any attempt to avoid that extra string copy is probably unwarranted optimization.
I'm going to assume that it's an issue of code cleanliness, and maybe an issue of making sure the copy happens inside the LOG4CPLUS_ERROR macro, as opposed to outside it. In that case, just use:
LOG4CPLUS_ERROR("Bad string " << std::string(char_pointer, length));
We're getting hung up on the semantics of conversion between char* and char[]. Take a step back, what are you trying to do? If this is a simple case of on an error condition, streaming out the content of a structure to a stream, why not do it properly?
e.g.
struct foo
{
char a1[10];
char a2[10];
char a3[10];
char a4[10];
};
// free function to stream the above structure properly..
std::ostream operator<<(std::ostream& str, foo const& st)
{
str << "foo::a1[";
std::copy(st.a1, st.a1 + sizeof(st.a1), std::ostream_iterator<char>(str));
str << "]\n";
str << "foo::a2[";
std::copy(st.a2, st.a2 + sizeof(st.a2), std::ostream_iterator<char>(str));
str << "]\n";
:
return str;
}
Now you can simply stream out an instance of foo and don't have to worry about null terminated string etc.!
I keep a string reference class in my toolkit just for these type of situations. Here is a greatly abbreviated version of that class. I trimmed away anything that is not relevant to this particular problem:
#include <iostream>
class stringref {
public:
stringref(const char* ptr, unsigned len) : ptr(ptr), len(len) {}
unsigned length() { return len; }
const char* data() { return ptr; }
private:
const char* ptr;
unsigned len;
};
std::ostream& operator<< (std::ostream& os, stringref sr) {
const char* data = sr.data();
for (unsigned len = sr.length(); len--; )
os << *data++;
return os;
}
using namespace std;
int main (int argc, const char * argv[])
{
cout << "string: " << stringref("test", 4) << endl;
}
or, in your case:
LOG4CPLUS_ERROR("Bad string " << stringref(char_pointer, length));
should work.
The idea of a string reference class is to keep enough information about a string (a size and a pointer) to refer to any block of memory which represents a string. It relies on you to make sure that the underlying string data is valid throughout the lifetime of a stringref object. This way you can pass around and process string information with a minimum of overhead.
When you know it is of fixed length: Why not simply add one more charakter to the size of the array? Then you can easily fill this last char with \0 terminating character and all will be fine
No, you'll have to copy it. There is no proper conversion in the language that you can use to get the array type out of it.
It seems very odd that you want to do this, or that you have a non-terminated C-style string in the first place.
Why are you not using std::string?
whats the difference between C Strings and C++ strings. Specially while doing dynamic memory allocation
I hardly know where to begin :-)
In C, strings are just char arrays which, by convention, end with a NUL byte. In terms of dynamic memory management, you can simply malloc the space for them (including the extra byte). Memory management when modifying strings is your responsibility:
char *s = strdup ("Hello");
char *s2 = malloc (strlen (s) + 6);
strcpy (s2, s);
strcat (s2, ", Pax");
free (s);
s = s2;
In C++, strings (std::string) are objects with all the associated automated memory management and control which makes them a lot safer and easier to use, especially for the novice. For dynamic allocation, use something like:
std::string s = "Hello";
s += ", Pax";
I know which I'd prefer to use, the latter. You can (if you need one) always construct a C string out of a std::string by using the c_str() method.
C++ strings are much safer,easier,and they support different string manipulation functions like append,find,copy,concatenation etc.
one interesting difference between c string and c++ string is illustrated through following example
#include <iostream>
using namespace std;
int main() {
char a[6]; //c string
a[5]='y';
a[3]='o';
a[2]='b';
cout<<a;
return 0;
}
output »¿boRy¤£f·Pi»¿
#include <iostream>
using namespace std;
int main()
{
string a; //c++ string
a.resize(6);
a[5]='y';
a[3]='o';
a[2]='b';
cout<<a;
return 0;
}
output boy
I hope you got the point!!
The difference is speed in some operations, and encapsulation of places where common errors occur.
std::string maintains information about the content and length of the string. This means it is not prone to buffer overruns in the same way a const char * is. It will also be faster for most operations than a const char * because the length of the string is known.
Most of the cstring operations call strlen() under the hood to find out the length of the string before operating on it, this will kill performance.
std::string is compatible with STL algorithms and other containers.
Lastly, std::string doesn't have the same "gotcha!" moments a char * will have:
I have a C++ string. I need to pass this string to a function accepting a char* parameter (for example - strchr()).
a) How do I get that pointer?
b) Is there some function equivalent to strschr() that works for C++ strings?
To get the C string equivalent of
the C++ string object use c_str
function.
To locate the first occurence of a
char in a string object use
find_first_of function.
Example:
string s = "abc";
// call to strlen expects char *
cout<<strlen(s.c_str()); // prints 3
// on failure find_first_of return string::npos
if(s.find_first_of('a') != string::npos)
cout<<s<<" has an a"<<endl;
else
cout<<s<<" has no a"<<endl;
Note: I gave the strlen just an example of a function that takes char*.
Surprisingly, std:;string has far, far more capabilities than C-style strings. You probably want the find_first_of() method. In general, if you find yourself using the strxxx() functions on C++ std::strings, you are almost certainly doing something wrong.
Like much of the C++ Standard Library, the string class is a complex beast. To make the most of it, you really need a good reference book. I recommend The C++ Standard Library, by Nicolai Josuttis.
You can't get a char* from a string
string does not allow you free access to its internal buffer.
The closest you can get is a const char* using .c_str() if you want it null terminated or .data() if it doesn't have to be null terminated.
You can then cast the pointer returned by these functions to char* but you do this on your own risk. That being said this is a relatively safe cast to make as long as you make sure you're not changing the string. If you changed it then the pointer you got from c_str() may no longer be valid.
This code:
string str("Hello World!");
char* sp = (char*)str.c_str();
sp[5] = 'K';
is probably ok
However this:
string str("Hello World!");
char* sp = (char*)str.c_str();
str = "Chaged string";
sp[5] = 'K';
is most definitely not ok.
If you just want to assign a string literal to pw, you can do it like
char *pw = "Hello world";
If you have a C++ std::string object, the value of which you want to assign to pw, you can do it like
char *pw = some_string.c_str()
However, the value that pw points to will only be valid for the life time of some_string.
More here :
How to assign a string to char *pw in c++
GoodLUCK!!
std::string yourString("just an example");
char* charPtr = new char[yourString.size()+1];
strcpy(charPtr, yourString.c_str());
If str in your string use str.c_str() method to get the char* inside it.
Perhaps this exmaple will help you
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string str ("Replace the vowels in this sentence by asterisks.");
size_t found;
found=str.find_first_of("aeiou");
while (found!=string::npos)
{
str[found]='*';
found=str.find_first_of("aeiou",found+1);
}
cout << str << endl;
return 0;
}
The C++ Standard provides two member functions of claass std::basic_string that return pointer to the first element of the string. They are c_str() and data(). But the both return const char *, So you may not use them with a function that has parameter of type char *.
As for function strchr then its first parameter is const char *. So you may use c_str() and data() with this function. However it is much better to use member function find()of class sttd::basic_string instead of strchr.