Why can std::cout print a char[]? [duplicate]
Because of operator<< (basic_ostream<charT,traits>& os, const char* s);
(#2 "character sequence" in that list) (slightly more technical list). test
decays to a pointer, or char*
, which then gets printed as a C-string.
It's the exact same reason cout << "Jeff";
works (instead of printing the address of "Jeff"
).
Why does streaming a char pointer to cout not print an address?
Overload resolution selects the ostream& operator<<(ostream& o, const char *c);
which is used for printing C-style strings. You want the other ostream& operator<<(ostream& o, const void *p);
to be selected. You are probably best off with a cast here:
cout << static_cast<void *>(cptr) << endl;
How does std::cout work with char pointers?
This happens because the compiler checks the type of the argument and calls the overloaded version of the operator that receives that type.
In the C language, strings are implemented as char
arrays terminated with the ’\0’
(nul) character, and arrays are referred to using pointers. So, when the argument received is c
, the overloaded operator that receives a char*
prints the content of the array up to the nul terminator.
When the argument received is *c
, this dereferences the pointer to access its data, and since this is a pointer to char
, the overloaded operator that receives a char
prints it as a single char
.
To print the address of the string array, you can cast the char*
pointer to void*
, like follows:
std::cout << (void*) c << std::endl;
cout char* printing address instead of value
char *
is a special case. For any other pointer, unless you have some specialization you implemented yourself, outputting a pointer outputs that pointer, not what it points to.
Getting different output with printf and cout - C++
it's because rawname is defined as a std::string. You need to use
printf("rawname: %s", rawname.c_str());
The reason is that printf with the %s is expecting a null terminated C string in memory. Whereas a std::string stl string isn't exactly raw - it eventually null terminates in your situation, not sure if that's even a guarantee, since the length is internally managed by stl container class.
Edit:
As pointed out in a comment, internally it's guaranteed to be null terminated. So what you're seeing as 'squiggly lines' is an output of all the allocated but not utilized (or initialized) memory in that string up until the null terminator character.
What happens when running (int *)some string
On this statement:
std::cout << (int *)"Home of the jolly bytes";
It is indeed printing the starting address of the characters in the string literal. A string literal is a const char[N]
array (in this case, N=24
), and an array decays into a pointer to its 1st element.
std::istream
does not have any operator<<
that accepts an int*
pointer, but it does have one that accepts a char*
pointer to print a null-terminated string, and one that accepts a void*
pointer to print the address being pointed at.
int*
is implicitly convertible to void*
, so the code is printing the address of the string literal, rather than printing its contents. But, it is unusual to cast a char*
pointer to an int*
in this situation, void*
would make more sense, eg:
std::cout << (const void *)"Home of the jolly bytes";
In any case, on this statement:
std::cout << (char)*(int *)"Home of the jolly bytes";
It is reinterpreting the starting address of the characters as-if it were the starting address of an int
instead. Thus, dereferencing that int*
pointer will read the 1st 4 characters together as a single int
value (assuming char
is 8 bits in size, and int
is 32 bits in size):
--------------------------------------------------------------------------------------------
| H | o | m | e | | o | f | | t | h | e | | j | o | l | l | y | | b | y | t | e| s |
--------------------------------------------------------------------------------------------
|___|
|
char*
|_______________|
|
int*
Thus, the dereferenced int
will consist of these bytes in memory:
H o m e
*int = 0x48 0x6F 0x6D 0x65
The code is then truncating that int
value to a 1-byte char
value.
On a little-endian system, that will yield the value of the H
character:
H o m e
*int = 0x48 0x6F 0x6D 0x65
= 0x656D6F48 (decimal 1701670728)
= 0x48 when truncated to char
On a big-endian system, it will yield the value of the e
character instead:
H o m e
*int = 0x48 0x6F 0x6D 0x65
= 0x486F6D65 (decimal 1215262053)
= 0x65 when truncated to char
C++ char* as a function parameter
A string literal is a const char[N]
array in read-only memory (where N
is the number of characters in the literal, plus 1 for the null terminator, so in your case 11+1=12
). You can't point a char*
pointer (ie, a pointer to non-const
data) at a string literal, as that would allow for the possibility of altering read-only data, which is undefined behavior.
Simply change your pointer type to const char*
instead (ie a pointer to const
data), eg.
#include <iostream>
using namespace std;
void func(const char *var)
{
cout << var;
}
int main()
{
const char* test = "Hello World";
func(test);
}
Otherwise, as you say you have no control over the function declaration, then if you really want to pass a string literal to a char*
pointer, you should copy the characters into a separate writable char[]
buffer first, and then point at that instead, eg:
#include <iostream>
using namespace std;
void func(char *var)
{
cout << var;
}
int main()
{
char test[] = "Hello World";
func(test);
}
Or, if you know for sure that the function will never modify the characters, you can just cast off the const
-ness using const_cast
(though this is highly NOT recommended, I'm including it for completeness), eg:
#include <iostream>
using namespace std;
void func(char *var)
{
cout << var;
}
int main()
{
char* test = const_cast<char*>("Hello World");
func(test);
/* alternatively:
const char* test = "Hello World";
func(const_cast<char*>(test));
*/
}
Related Topics
How to Install (V142) Build Tools in Visual Studio
Why Is Iostream::Eof Inside a Loop Condition (I.E. 'While (!Stream.Eof())') Considered Wrong
Templated Check For the Existence of a Class Member Function
Sorting a Vector of Custom Objects
Why Is Integer Assignment on a Naturally Aligned Variable Atomic on X86
How to Find the Length of an Array
What Does T&& (Double Ampersand) Mean in C++11
How to Expand a Tuple into Variadic Template Function'S Arguments
Is There a Standard Sign Function (Signum, Sgn) in C/C++
C++ - Initializing Variables in Header VS With Constructor
When Should Static_Cast, Dynamic_Cast, Const_Cast, and Reinterpret_Cast Be Used
Easiest Way to Convert Int to String in C++
How to Automatically Generate a Stacktrace When My Program Crashes