-1

I can not understand why cout does not work in this code:

#include<iostream>
using namespace std;

int main() {
    int v = 65;
    int* q = &v;
    char** o = (char**)&q;
    cout <<  o << endl;  // output: 012FFCAC
    cout <<  *o << endl; // output: A
    cout << **o << endl; // output: A
    printf("%c",*o);     // cause an error
    printf("%p",*o);    // works and the output=&v

And cout does not work else in this code

#include<iostream>
using namespace std;

int main() {
    char v = 65;
    cout <<  &v << endl;  // output: A╠╠╠╠▀?╞«4°O 
Fady Hany
  • 77
  • 6
  • 3
    Your compiler should be giving you a warning. If it isn't, adjust your warning options. – chris Sep 27 '21 at 02:29
  • -chris no wrning – Fady Hany Sep 27 '21 at 02:33
  • I get a warning here: [https://godbolt.org/z/x7fWT3KE9](https://godbolt.org/z/x7fWT3KE9) – drescherjm Sep 27 '21 at 02:35
  • Your new code `cout << &v << endl;` has undefined behavior. The pointer in this case is supposed to be a null terminated c-string. – drescherjm Sep 27 '21 at 02:37
  • -drescerjm i know that printf cause an error but i ask why cout do not cause an error? – Fady Hany Sep 27 '21 at 02:39
  • 3
    Operator `<<` for streaming a `const char *` to an output stream ASSUMES that the pointer points at the first character of a nul terminated string (such as a string literal) - i.e. an array of char with a nul (zero) terminator marking the end. Passing `&v` means the pointer is not the first character of a nul terminated string, since there is no guarantee about what is in memory immediately after `v`. The behaviour is therefore undefined. – Peter Sep 27 '21 at 02:40
  • -drescerjm why? – Fady Hany Sep 27 '21 at 02:41
  • [https://stackoverflow.com/questions/501816/why-does-cout-print-char-arrays-differently-from-other-arrays](https://stackoverflow.com/questions/501816/why-does-cout-print-char-arrays-differently-from-other-arrays) – drescherjm Sep 27 '21 at 02:42
  • -Peter Is that mean cout do not support char type? – Fady Hany Sep 27 '21 at 02:43
  • 3
    There is an overload of `operator<<()` that supports output of a single `char`, and another that supports output of a `char *` (with the assumptions about what that `char *` points at, as I mentioned in previous comment). Pass something it doesn't expect, and the behaviour is undefined. Similarly, `printf("%c", *o)` in your example has undefined behaviour, since `*o` is a `char *`, and `%c` tells `printf()` that a `char` (which is not a `char *`) is passed. – Peter Sep 27 '21 at 02:48
  • 1
    No need for a special overload. If you want the address you can cast `&v` to a different type, typically `void *`, that doesn't do the string thing. – user4581301 Sep 27 '21 at 03:10
  • @FadyHany to tag someone you need to use `@`, not `-`, otherwise people won't see the notification. And **always enable all warnings** when compiling. You need to check for the options for your compiler, for example `/W4` in MSVC and `-Wall -Wextra` in gcc – phuclv Sep 27 '21 at 06:53
  • @Peter Can you write the overload that is supporting char? – Fady Hany Sep 27 '21 at 07:17
  • @FadyHany No one can because there is already an overload for `char *` that assumes printing a null-terminated string. You can't have two of the same overload. All you can do it tell the compiler to look at the data differently. `cout << static_cast(&v) << endl;` -> instruct compiler to treat the address of a character the same way it would an anonymously typed address. – user4581301 Sep 27 '21 at 17:16
  • Useful reading: [Why would you use a void pointer in this code?](https://stackoverflow.com/questions/25969242/why-would-you-use-a-void-pointer-in-this-code) – user4581301 Sep 27 '21 at 19:33

1 Answers1

2

Because an int is (usually) 4 bytes 65 will fit quite neatly into just the first byte and the rest of the memory allocated for the int will be 0 this byte pattern happens to match up very closely to how strings are stored in memory.

So when the memory is accessed through a char* it will print A most of the time even though most of the prints were ill formed

int v = 65;  // Byte pattern on most machines [65,0,0,0] 
int* q = &v; 
char** o = (char**)&q; // *o now points to [65,0,0,0] ==> ['A','\0','\0','\0'] ==> "A"
std::cout <<  o << std::endl;  
    // input:      char** 
    // printed as: pointer 
    // result:     012FFCAC

std::cout <<  *o << std::endl;  // Undefined Behaviour
    // input:      char*
    // printed as: null terminated string
    // result:     "A"

std::cout <<  **o << std::endl; // Undefined Behaviour 
    // input:      char
    // printed as: single character
    // result:     'A'

printf("%c",*o);    // %c expects a [char] type but is given [pointer to char]      ERROR
printf("%p",*o);    // %p expects a [pointer] type and is given a [pointer to char] OK

Since a char is (usually) 1 byte there is no null terminand to stop the printing once it starts and it keeps printing whatever is around in memory until it runs into a 0 or an access violation

char v = 65;
std::cout << &v << std::endl;  // &v is not a well-formed null terminated string: Undefined Behaviour
    // input:      char*
    // printed as: null terminated string
    // result:     "A<whatever other data is around v in memory>"
Fiskmans
  • 203
  • 1
  • 11
  • char** o = (char**)&q; // *o now points to [65,0,0,0] ==> ['A','\0','\0','0'] ==> "A" here i guess you need to change ['A','\0','\0','0'] the last one '0' to '\0' right? And i want to ask you does (Undefined Behaviour) mean that no one know it may work and may not? @Fiskmans – Fady Hany Sep 28 '21 at 01:55
  • Yeah thanks that was supposed to be a \0 – Fiskmans Sep 28 '21 at 07:53
  • Undefined behaviour (UB) just means that its not well defined in the standard. In many cases it will behave as expected but a compiler vendor can at their discretion change how things work (intentionally or unintentionally) and you'll be SOL. It also means your code may work differently depending on what you're compiling it for, as an example if you build your code for a little-endian machine the 65 will be laid out the other way around in memory ['\0','\0','\0','65'] and your code will print something completely different – Fiskmans Sep 28 '21 at 08:00
  • what i understood from your comment that UB means that the code (the programme) always will run (will work) but no one know how it will work (will run) it may run (work) as the writer of the code expects and may run (work) but not as the writer of the code expects Is that what did you mean? @Fiskmans – Fady Hany Sep 28 '21 at 09:41
  • Pretty much, but there are no guarantees that the program will actually run at all. it's usually not too bad but a compliant compiler is allowed to do whatever it wants, everything from "what you expected it to do" to "delete important files, brick the device or call the white house". Its usually not that bad but writing UB code intentionally is a pretty bad practice – Fiskmans Sep 28 '21 at 11:30
  • what i understood from your comment that UB means that the code (the programme) always will run (will work) but no one know how it will work (will run) it may run (work) as the writer of the code expects and may run (work) but not as the writer of the code and it may not work (run) and any thing may happen Is that what did you mean ? and Is that the completely definition of UB ? And i am sorry for bothering you @Fiskmans – Fady Hany Sep 28 '21 at 12:31
  • Yeah, thats pretty much it, you can read the specifics on https://en.cppreference.com/w/cpp/language/ub – Fiskmans Sep 28 '21 at 13:06