I run this test:
TEST_F(CHAR_TESTS, wtf){
char letter[3] = {'A','B','C'};
char types[2] = {'o','s'};
char tmp[3];
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
for(int k=0;k<2;k++){
tmp[0]=letter[i];
tmp[1]=letter[j];
tmp[2]=types[k];
std::string combination(tmp);
std::cout << combination << std::endl;
}
}
}
}
For some reason, this print this:
AAo~
AAs~
ABo~
ABs~
ACo~
ACs~
BAo~
BAs~
BBo~
BBs~
BCo~
BCs~
CAo~
CAs~
CBo~
CBs~
CCo~
CCs~
I do not think it is an issue with the printing itself, as I ended up doing this after noticing some tests comparing strings generated from char arrays were not passing, and I could not figure out why. So it feels like indeed the "combination" strings do not end up having the expected content.
The same code in a "regular" executable (not a gtest) print out what is expected (the 3 chars without the weird supplementary chars).
Unfortunately std::string does not have a constructor that takes a reference to array of char. So you end up invoking the const char* constructor, and this one requires the pointer to point to the first element of a null terminated string. Your char arrays aren't null-terminated, so you end up with undefined behaviour.
You should null-terminate tmp, which you can do by declaring it with one extra character, and setting it to '\0'. You can achieve that like this
char tmp[4] = {};
The constructor in std::string combination(tmp); only works if tmp is nul terminated. Otherwise the constructor cannot find the length of the string.
However, you can help std::string by explicitly providing the size of the buffer:
std::string combination(tmp, sizeof(tmp));
This constructor is primarilly intended to construct a std::string from a part of a C-style string, but also works if given the full length.
char tmp[3]; is not null-terminated use char tmp[4] = {0};
Related
I'm using the XOR encryption so when I'm going to decrypt my string I need to get the length of that string.
I tried in this way:
string to_decode = "abcd\0lom";
int size = to_decode.size();
or in this way:
string to_decode = "abcd\0lom";
int size = to_decode.lenght();
Both are wrong because the string contain \0.
So how can I have the right length of my string?
The problem is with the initialisation, not with the size. If you use the constructor taking a const char *, it interprets that argument as a NUL-terminated string. So your std::string is only initialised with the string abcd.
You need to use a range-based constructor:
const char data[] = "abcd\0lom";
std::string to_decode(data, data + (sizeof data) - 1); // -1 to not include terminating NUL
[Live example]
However, be careful with such strings. While std::string can deal with embedded NULs perfectly fine, the result of c_str() will behave as "truncated" as far as all NUL-terminated APIs are concerned.
When you initialize the std::string, with a \0 in the middle, you loose all data ahead of it. If you think about it, a std::string is just a wrapper for a char*, and that gets terminated by a null termination \0. If the \0, doesn't have any meaning in the string, then you could escape it, like this:
string to_decode = "abcd\\0lom";
and the size would be 9. Otherwise, you could a container (eg: std::vector), of char's for the data storage
As others have said, the problem is that the code uses the constructor that takes const char*, and that only copies up to the \0. But, by a very strange coincidence, std::string has a constructor that can handle that case:
const char text[] = "abcd\0lom";
std::string to_decode(text, sizeof(text) - 1);
int size = to_decode.size();
The constructor will copy as many characters as you tell it to.
I'm just starting c++ and am having difficulty understanding const char*. I'm trying to convert the input in the method to string, and then change the strings to add hyphens where I want and ultimately take that string and convert it back to char* to return. So far when I try this it gives me a bus error 10.
char* getHyphen(const char* input){
string vowels [12] = {"A","E","I","O","U","Y","a","e","i","o","u","y"};
//convert char* to string
string a;
int i = 0;
while(input != '\0'){
a += input[i];
input++;
i++;
}
//convert a string to char*
return NULL;
}
A: The std::string class has a constructor that takes a char const*, so you simply create an instance to do your conversion.
B: Instances of std::string have a c_str() member function that returns a char const* that you can use to convert back to char const*.
auto my_cstr = "Hello"; // A
std::string s(my_cstr); // A
// ... modify 's' ...
auto back_to_cstr = s.c_str(); // B
First of all, you don't need all of that code to construct a std::string from the input. You can just use:
string a(input);
As far as returning a new char*, you can use:
return strdup(a.c_str()); // strdup is a non-standard function but it
// can be easily implemented if necessary.
Make sure to deallocate the returned value.
It will be better to just return a std::string so the users of your function don't have to worry about memory allocation/deallocation.
std::string getHyphen(const char* input){
Don't use char*. Use std::string, like all other here are telling you. This will eliminate all such problems.
However, for the sake of completeness and because you want to understand the background, let's analyse what is going on.
while(input != '\0'){
You probably mean:
while(*input != '\0') {
Your code compares the input pointer itself to \0, i.e. it checks for a null-pointer, which is due to the unfortunate automatic conversion from a \0 char. If you tried to compare with, say, 'x' or 'a', then you would get a compilation error instead of runtime crashes.
You want to dereference the pointer via *input to get to the char pointed to.
a += input[i];
input++;
i++;
This will also not work. You increment the input pointer, yet with [i] you advance even further. For example, if input has been incremented three times, then input[3] will be the 7th character of the original array passed into the function, not the 4th one. This eventually results in undefined behaviour when you leave the bounds of the array. Undefined behaviour can also be the "bus error 10" you mention.
Replace with:
a += *input;
input++;
i++;
(Actually, now that i is not used any longer, you can remove it altogether.)
And let me repeat it once again: Do not use char*. Use std::string.
Change your function declaration from
char* getHyphen(const char* input)
to
auto hyphenated( string const& input )
-> string
and avoid all the problems of conversion to char const* and back.
That said, you can construct a std::string from a char_const* as follows:
string( "Blah" )
and you get back a temporary char const* by using the c_str method.
Do note that the result of c_str is only valid as long as the original string instance exists and is not modified. For example, applying c_str to a local string and returning that result, yields Undefined Behavior and is not a good idea. If you absolutely must return a char* or char const*, allocate an array with new and copy the string data over with strcpy, like this: return strcpy( new char[s.length()+1], s.c_str() ), where the +1 is to accomodate a terminating zero-byte.
I have a char array with known size (say 10) and I want to convert it to a strng. The main point is the array is not NULL terminated so this technique that used in the following sample code can not be used.
char arr[ ] = "This is a test";
string str(arr);
I can do this:
char * array=getArray();
string output;
for(int I=0;i<10;i++)
{
output.append(array[I]);
}
or even better one is:
char * array=getArray();
string output;
output.append(10,array);
But is there any better way to do this?
If you don't have a nul-terminated string, but you know its length, you can use either the two iterator constructor:
string str(arr, arr + len);
or the appropriate count constructor:
string str(arr, len);
First of all, "This is a test" is NIL-terminated and the first sample just works - the compiler implicitly stores string literals with zero termination.
If your array really is not NIL-terminated, the third approach will be good while the second is rather inefficient because it appends piecewise. std::string also has a constructor that takes a count: std::string(array, 10).
I'm trying to make something similar to the strlen(str,str) function (I have a return string) to learn using pointers and the new operator, here is my code:
char* strcat(char str1[], char str2[]){
int len=strlen(str1)+strlen(str2);
char* sfin = new char[len];
int i=0;
for (i=0;i<strlen(str1);i++)
*(sfin+i)=*(str1+i); //this could be *(sfin+i)= str1[i]
for (int j=0;j<strlen(str2);j++)
*(sfin+j+i)=*(str2+j); //this could be *(sfin+i+j)= str2[j]
return sfin;
}
It works, except for the thing that the new operator allocates too much memory (or is it right?), as seen from variables watcher:
P.S. in the main() function I retrieve str1 and str2 using gets(char*) and put them using puts(char*). len has the right content (9).
Results can be various: sometimes it puts the correct string and sometimes only two "strange" characters, depending on parametres.
Null-terminated strings need to be, well, null-terminted. You only copy all the characters up to the null-terminator but not the null-terminator itself. That is, if a program looks at the content of you string, it will continue looking until it finds a null-terminator. Make sure you add a null-terminator and also make sure the memory is deleted, e.g., using
std::unique_ptr<char[]> strcat(char const* str1, char const* str2) {
// ...
std::unique_ptr<char[]> ptr(new char[len]);
// ...
return ptr;
}
BTW, your use of strlen() in each iteration of the loop is likely to result in rather bad performance, especially if you have long strings.
In c and c++, strings have to be null terminated. The resulting string contains the values of string1 and string2 but it is not null terminated. The resulting string's length should be equal to strlen(strin1)+strlen(string2)+1 and the plus 1 char can be assigned the null terminator '\0'
Learning C++. I just want to grab the first character in a string, then make a new string based on such character, and then print it out:
#include <iostream>
using namespace std;
int main(int argc, const char * argv[]) {
string name = "Jerry";
char firstCharacter = name.at(0);
string stringOfFirstCharacter = string(&firstCharacter);
cout << stringOfFirstCharacter;
return 0;
}
The output is:
J
Jerry
I don't really know why is it also printing Jerry. Why is that?
Your code has undefined behavior. The signature of the constructor that takes a pointer to char requires that it is a pointer to a null terminated string, which it is not in your case since it is a single character.
My guess is that the implementation you have uses the small object optimization, and that "Jerry" is small enough that it is stored inside the std::string object rather than dynamically allocated. The layout of the two objects in the stack happens to be first firstCharacter, then name. When you call std::string(&firstCharacter) it reads until it hits the first null character (inside the std::string buffer) and stops there.
You are constructing an std::string object from a char* (because you are taking the address of firstCharacter). A pointer to a character is not interpreted as a character itself by the constructor of std::string, but rather as a null-terminated string.
In this case, your program has Undefined Behavior, because the address of firstCharacter is not the address of the first character of a null-terminated string.
What you should be doing is:
string stringOfFirstCharacter(1, firstCharacter);
cout << stringOfFirstCharacter;
If you really want to create a one-character string. However, notice that in order to print the character to the standard output, you could have simply written:
cout << firstCharacter;
Or even:
cout << name.at(0);
With string(&firstCharacter), you are using the std::string constructor of the form
std::string( const char* s, const Allocator& alloc = Allocator() );
That form expects a pointer to a null-terminated array of characters. It is incorrect to pass a pointer to character(s) that are not null-terminated.
With your intention of initializing the string with 1 char, you should use the form:
string( 1, firstCharacter )
The string constructor you're using (the one that takes a char * argument), is intended to convert a C-style string into a C++ string object - not a single character. By passing it a single character you cause undefined behaviour.
In your specific case, there appears to not be a zero byte in memory after firstCharacter, so the constructor runs through and includes all of name along with it!