This is my test code.
string str=string("def");
const char* c_str=str.c_str();
char* charString=(char*)"abc";
char* target;
cout << "str : "<< str<< endl;
cout << "c_str : "<< c_str << endl;
cout << "charString : " << charString << endl << endl;
cout << "string length : " << str.length() << endl;
cout << "c_str length : " << strlen(c_str) << endl;
cout << "c_str array length : " << (sizeof(c_str)/sizeof(*c_str)) << endl;
cout << "charString length : " << strlen(charString) << endl;
cout << "charString array length " << (sizeof(charString)/sizeof(*charString)) << endl<< endl;
target = (char*) malloc(sizeof(char)*2);
target = (char*)"ab";
cout << "target : " << target << endl;
cout << "target strlen : " << strlen(target) << endl;
cout << "target arr length : " << (sizeof(target)/sizeof(char)) << endl;
This is result of above code.
str : def
c_str : def
charString : abc
string length : 3
c_str length : 3
c_str array length : 8
charString length : 3
charString array length 8
target : ab
target strlen : 2
target arr length : 8
In str, c_str, charString case, strlen is 3 and array length is 8.
8 includes encoding and '\0' character at last. Right?
So, I really don't understand target case.
I allocate memory 2 byte.
And allocate 2 characters.
strlen is right.
But why target array length is 8 like array length of c_str and charString? Why target's array length isn't less than c_str and charString ?
Last question, I send message char* including message length in message header. If I want to calculate the message length from string.c_str(), do I have to calculate like (sizeof(target)/sizeof(*target)) ?
sizeof(x)/(sizeof(*x)
is basically a mistake. The only way this basic construct makes sense is if x
is an array--but in this case, *x
only makes sense by converting the name of the array to a pointer to its first element (which, yes, does happen implicitly), then dividing by the size of that item.
At least theoretically, sizeof(x)/sizeof(x[0])
is a little better. There's no observable difference in actual use, but at least to somebody looking at it, the use of [0]
might provide some indication that this is really intended to be applied (only) to an array, not a pointer.
Assuming they are applied to arrays, they still have an effect that's fundamentally different from strlen
. strlen
assumes its argument is a NUL-terminated byte sequence. That means it counts bytes starting from the address you pass, until it encounters a byte containing the value '\0'
. That might be shorter than the array, or (if the array doesn't contain an NTBS) potentially much longer. In short, strlen
tries to tell you the current length of a string, whereas the sizeof(x)/sizeof(x[0])
attempts to tell you the maximum string size a particular array could potentially hold. These will coincide primarily when applied to an initialized array, like: char foo[] = "Something";
.
One other minor difference as well: strlen
only includes the number of characters before the terminating NUL, where sizeof(x)/sizeof(x[0])
includes all the storage of the array, one larger than the maximum length of NUL-terminated string you can store there.
If you apply either of these to a pointer instead of an array, you can plan on normally getting bad results (the "normally" weasel wording being to cover the corner case: if you happen to have an array exactly the same size as a pointer, it'll work, much like a broken clock giving the right time twice a day).
In C++, you're usually better off with something like this:
template <class T, size_t N>
constexpr size_t elements(T (&array)[N]) {
return N;
}
This requires that you pass it an array by reference. If you attempt to pass a pointer instead of an array, you'll get a compiler error instead of an incorrect answer.
Of course, in C++ you generally want to avoid using strlen
as well--you can normally use std::string
(or std::string_view
) and use its length()
or size()
member.
The line const char* c_str=str.c_str()
means:
- Get the pointer/address (a 32 or 64 bits integer) of the memory used for storing the sring "def" (inside the str object).
- Store this pointer/address (a 32 or 64 bits integer) inside
c_str
.
c_str
never contains the string but it contains a pointer/address (a 32 or 64 bit integer)
The sizeof(c_str)
returns the size used in memory by c_str
. In your case, you use a 64 bits compiler (so address are 64 bits). So c_str
returns 8
(we need 8 bytes of memory for storing 64 bits number).
Then *c_str
will give you the first character (ascii value) stored in the string. An ascii value is stored in a char and the memory needed for storing a char is 1
.
So sizeof(*c_str)
will always returns 1
.
It's why it's make no sense to write sizeof(c_str)/sizeof(*c_str)
. This expression is constant and will always returns 8/1 => 8 (nothing to do with the size of the string).
When you work with C string, it's better to use (strlen
, strcopy
, etc). Those functions will return you the excepted result.