0

I am trying to copy a string which might contain null characters in the middle to a char array. I have constructed the following function.

 void SaveStringToChar(string &mystring,const char * &ArrChar)
 {//begin function

   std::string str;
   char * writable = new char[str.size() + 1];
   std::copy(str.begin(), str.end(), writable);
   writable[str.size()] = '\0';
   ArrChar = writable;

 }//end function

my question is this method guarantees that I wont lose the characters after a null element. and my other question is I get this linker error which I don't know what it means.

/tmp/ccUpCRaz.o: In function `Parser::RuleParser(char const*)': Parser.cpp:(.text+0x3f6): undefined reference to Parser::SaveStringToChar(std::basic_string, std::allocator >&, char const*&)' collect2: ld returned 1 exit status

anyhint please.

this is the function I pass things to compare.

  void Search( size_t TextLength, const char *Text, const vector<const char *> &patterns );
11
  • Out of curiosity, why don't you use std::string::c_str() ? Commented Mar 2, 2012 at 12:21
  • I happen to used them but my string might contain null in the middle which I suspected that they are lost as I push them to a vector of type const char * because I rechecked the data in the vector after that and I found them lost Commented Mar 2, 2012 at 12:24
  • I'm not al all sure if the result of the c_str() function is guaranteed to contain all characters past the first \0. Even if you test it with one compiler, it may not behave in the same way on another. Commented Mar 2, 2012 at 12:28
  • I doubt they are really lost. However, since c_str() return a null-terminated string, you indeed have no way of telling if you really reached the end of the string when displaying it. Now an important question is: why would you want to deal with null-terminated strings if you know for sure they can contain null characters ? Sticking with std::string seems far less risky. Commented Mar 2, 2012 at 12:29
  • @MrLister: I don't have a copy of the standard at my disposal right now, but I'm fairly confident that it is guaranteed for c_str() to return all the characters of the string, null or not, in the resulting array. Could anyone confirm/infirm ? Commented Mar 2, 2012 at 12:32

4 Answers 4

2

You need to define the function as a member of Parser::. It is currently defined as:

void SaveStringToChar(string &mystring,const char * &ArrChar)

Change to:

void Parser::SaveStringToChar(string &mystring,const char * &ArrChar)

The std::copy() will copy all the characters. However, the caller will not know how many characters ArrChar actually points to as functions like strlen() will stop counting at the first null character. You could change the signature of SaveStringToChar() to accept another argument size_t& ArrCharLen that would be populated with the number of characters in ArrChar. Of course, mystring will have the length of ArrChar so maybe you are already storing this prior to the call to SaveStringToChar().

EDIT (after vector<const char*> comment):

The true number of bytes is lost once the const char* is added to the vector. Why not use a vector<std::string> and you have std::string::length() to know how many characters there are actually stored in std::string.

EDIT2 (after comparison function .c_str() with text.length():

Instead of passing .c_str() and .length() to compare against elements in a vector<const char*> just pass the std::string to the compare function and compare against elements of a vector<std::string>: the std::string::operator==() will correctly compare strings will embedded null characters. You could then use std::find() to search the vector<std::string> for the std::string read from the file.

Sign up to request clarification or add additional context in comments.

3 Comments

will you have a point but this is not just simple comparison the search function is actually an algorithm that is built on those parameters so I can't just change my parameters like that (and to tell you the truth I tried to change it to string but it gave me a heap of errors that I couldn't fix).
What do you use to compare the Text and TextLength to entries in the vector? You need to store the length of the elements of the vector somewhere: changing to vector<std::string> seems the simplest approach.
You can still access each individual character using std::string[] if required.
1

Your string copy seem fine, but if you are doing it to pass a char* to a function there are better ways see:

std::string str;
//...
my_func(str.c_str());

hmjd has your link error.

Comments

0

my question is this method guarantees that I wont lose the characters after a null element

The whole string will be copied into the buffer, even if it does contain null characters. std::copy does not interpret the data it copies in any way, it just copies the number of elements you tell it to.

However, if the string does contain null characters, then you can't use it with any function that works with null-terminated strings (such as those in <cstring>); they will interpret the first null character as the end of the string.

Also, at least in the code you posted, you are returning the pointer as const char *, implying that you won't be modifying the copy. In that case, do you actually need a copy of the string's data, or is it enough to return str.c_str() instead?

my other question is I get this linker error

It looks like you're missing the definition of Parser::SaveStringToChar. I'm guessing that the code you've posted is from a source file, and not a function defined inline inside the Parser class. If that's the case, then you've forgotten to specify that it's a member function, and defined a non-member instead; change it to

void Parser::SaveStringToChar(string &mystring,const char * &ArrChar)
     ^^^^^^^^

Comments

0

See hmjd's answer for the link error.

As to the copied characters, you won't actually lose any characters, because they're all safely copied to the output buffer. However, if there are really \0 characters in the middle of the string, none of the C-style string functions (like printf) will work correctly on it.
And also the calling routine won't know what the length of the string was, and therefore what the newly allocated size of the buffer is. You should return the string length too (either as the return value, or in another reference argument).

3 Comments

ok but as an array they will be there if I traverse it like A A null B C null null
as I am not using it to printout I am using it for comparison purposes
If you know what the exact length is, OK. Otherwise, C-style comparison functions won't function right either. By the way, it's possible to do comparison between std::strings; no need to copy them into character arrays first.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.