I am failed to understand this to deep details as to why program1 would segfault and program2 would not.
program1:
void cpy(char* p, char* q) {
while(*p++ = *q++);
}
int main() {
char* p;
char* q = "Bhargava";
cpy(p, q);
std::cout << "p = " << &p << std::endl;
}
Program2:
void cpy(char* p, char* q) {
while(*p++ = *q++);
}
int main() {
char* p;
char* q = "Bhargava";
cpy(p, q);
std::cout << "p = " << p << std::endl;
}
What is the harm while printing the address of the variable 'p' here in program1?
Both programs have undefined behavior already at the call
cpy(p, q);
because p is of type char* and default-initialized with automatic storage duration, meaning that its value is indeterminate. Copying an indeterminate value (here into the function parameter) that is not of type std::byte or unsigned narrow character type has already undefined behavior.
The arithmetic on and dereferencing of this indeterminate value in cpy then continues to cause operations with undefined behavior, which is probably of more practical relevance than the undefined behavior mentioned above, given that it is clear that if p is considered to have some random value, accessing the memory at that random address should not be allowed by the operating system (the cause of a segmentation fault).
Undefined behavior means that you have no guarantee on the program behavior. The program might fail with an error or it might not and it might produce seemingly correct output or it might not.
In practice, the compiler is probably optimizing away the dereferencing of p in one of the programs, but not the other, so that there never will be memory access in the compiled program that will cause the segmentation fault, but as mentioned above you have no guarantees and the compiler can output anything.
The line
char* q = "Bhargava";
is not allowed since C++11 and should at least be producing a compiler diagnostic to that effect. Even before C++11, it was always deprecated in standard-C++. "Bhargava" has type const char[N] for some N, so it can be assigned to const char*, but not to char*. The latter was just allowed by the language initially for backwards-compatibility reasons with C.
Both programs exhibit Undefined Behavior because p is not pointing at any valid memory, its value is uninitialized and thus indeterminate, so calling cpy() with p as the destination will write to random memory, if not just crash outright.
That being said, the reason why << &p works is because &p is the address of the p variable itself, which is a valid address. The type that &p returns is char**, which operator<< does not have a specific overload for, but it does have an overload for void*, which char** is implicitly convertible to. That overload simply prints out the address as-is.
The reason why << p does not work is because operator<< does have a specific overload for char*. That overload treats the address as the start of a C-style null-terminated string, and will print out characters starting at the address until a '\0' character is reached. But, since p does not point to a valid C string, the behavior is undefined.
To make both programs work correctly, you need to do this instead:
Program1:
void cpy(char* p, const char* q) {
while(*p++ = *q++);
}
int main() {
char buffer[10];
char* p = buffer;
const char* q = "Bhargava";
cpy(p, q);
std::cout << "p = " << &p << std::endl;
}
Program2:
void cpy(char* p, const char* q) {
while(*p++ = *q++);
}
int main() {
char buffer[10];
char* p = buffer;
const char* q = "Bhargava";
cpy(p, q);
std::cout << "p = " << p << std::endl;
}
Related
I wrote the following code:
#include <iostream>
using namespace std;
const int * myFunction()
{
int * p = new int(5);
return p;
}
int main()
{
int * q = myFunction();
cout << "*q=" << *q;
cout << endl;
return 0;
}
I purposely wrote the above code to receive an error. The mistake I made is that I stated the return type of function myFunction() as const int * but when I called myFunction() in main(), the pointer variable q was not declared const. The return type of myFunction() must match exactly to the type of variable which is going to receive its return value (am I correct here? This is what I have understood).
So, I fixed the error by correcting line 11 as const int * q = myFunction();. Now the type of the (pointer)variable q, which is const int *, matched exactly to the return type of myFunction() and the code compiled without error, producing output as *q=5 (is my understanding up to this point correct?).
Then, I wrote the following code:
#include <iostream>
using namespace std;
const int * const myFunction()
{
int * p = new int(5);
cout << "p: " << p;
return p;
}
int main()
{
int a;
const int * q = myFunction();
cout << "\nq=" << q;
cout << "\n*q=" << *q;
delete q;
q = &a;
cout << "\nq: " << q;
cout << endl;
return 0;
}
I was expecting an error here, too. Because now the return type of myFunction() is const int * const but the (pointer)variable q had type const int *. q was not declared as a constant pointer. But the program compiled and I got output as follows:
p: 0x36cb8
q=0x36cb8
*q=5
q: 0x61ff08
I am confused why the second code compiles and runs. What I thought is whoever is going to receive the return value from myFunction() should always take care of it (i.e. it cannot be allowed to take a different memory address), but the pointer variable q took a different memory location.
The return type of myFunction must match exactly to the type of variable which is going the receive it's return value. (Am I correct here? This is what I have understood.)
No, the return type must not match exactly to the type of the variable. But it must be possible to implicitly convert the return type to the type of the variable.
For example something like this will compile:
int someInt = getMeAFloat();
If getMeAFloat returns a float, this will compile because a float can be implicitly converted to an int. (Note that this gives you a warning and is bad because you lose the extra information of the float, but I am just trying to bring my point across)
Your first example does not compile because normally a const int* can not be converted to a int*.
As pointed out by user4581301 the second const in your second example does not matter, because only the value of the pointer, which is returned, gets assigned to the pointer in the main function. The second const makes the pointer itself constant, which has no effect on the value.
That means that const int * const myFunction() is equal to const int * myFunction()
In the 2nd code, q is a const int * - a non-const "pointer to a const int". Since q itself is not const, it can be re-assigned to point at a new address.
The compiler allows q = &a; because an int* (ie, what &a returns since a is an int) can be assigned to a const int*. In other words, a "pointer to non-const data" can be assigned to a "pointer to const data", effectively making read-only access to otherwise-writable data.
The reverse is not true - a "pointer to const data" cannot be assigned to a "pointer to non-const data", as that would allow writable access to read-only data - which is why the 1st code fails to compile.
So i want to point a pointer to a character and then output the address put it outputs this weird thing: t+ a. Any help?
#include <iostream>
using namespace std;
int main() {
char a = 't';
char* p = &a;
cout << p;
return 0;
}
You are printing a char* type, which the cout tries to interpret as a string.
Print the value of the pointer (The address it points to) using:
cout << (void *)p;
-- OR --
cout << static_cast<void *>(p);
The problem is that char * is conventionally not just used as a pointer to a char, but a pointer to a null-terminated C-string instead. cout will then print all the characters pointed to by p until it finds a '\0', so you get to see the t and then it prints invalid memory which is undefined behavior which may crash or print garbage or something else.
The way to fix this is to use void * or maybe const void * instead which is just a pointer with an address but no type information attached. void *p = &a; would be one fix. void *p2 = p; and then using std::cout << p2; would be another. You can also use a cast as shown in the other answer, except you should be using a C++ cast like static_cast<const void*>(p) instead of a C cast like (void *)p because once you get used to them they become easier to read and reason about.
If you want address of the pointer, either cast it to void pointer
std::cout << (void *)p;
or use printf with %p option
printf("%p", p);
Otherwise it will be treated as null terminated string, which it is not.
I apologize in advance for the silliness of this question. But I couldn't find the way of understanding this outcome. I'm trying to figure out what the pointer really is in C++. Following is just a simple code printing an address in different ways.
int a = 15000;
char *b = reinterpret_cast<char*>(a); //equivalent of char *b = (char *)a
int *m = &a;
//(1)
printf("&a:%p\n",&a); //0x7fff5fbff878
printf("&*m:%p\n",&*m); //0x7fff5fbff878
printf("m:%p\n",m); //0x7fff5fbff878
//(2)
printf("a:%p\n",(int*)a); //0x3a98
printf("&*b:%p\n",&*b); //0x3a98
printf("b:%p\n",b); //0x3a98
printf("*m:%p\n",(int*)*m); //0x3a98
printf("&b:%p\n",&b); //0x7fff5fbff870
printf("&m:%p\n",&m); //0x7fff5fbff868
//(3)
std::cout << "b:" << b << std::endl; //error: Segmentation fault: 11
So the question is
why the address of (1) and (2) are different
why the size(length of address) of (1) and (2) are different
what happened when an int is cast to a char*
how 'b' could contain an address of 'a'
why the error (3) has occurred while 'printf("b:%p\n",b)' is working.
why the address of (1) and (2) are different
Because in the first example (1), you use the & address of operator, which gives you the address where the "a" variable is stored, example 0x50302040.
But the second example (2), you are using the value that address (0x50302040) points to, which returns 15000 which equals to 0x3a98 in hexadecimal.
what happened when an int is cast to a char*
If int has a value of 15000, now char* points to the address 15000, which is clearly wrong.
why the error (3) has occurred while 'printf("b:%p\n",b)' is working.
Because your pointer is a char* pointer, therefore the character sequence overload (ostream& operator<< (ostream& os, const char* s); is used, and since your pointer doesn't point to a character sequence (in fact, it doesn't point to anything since you assigned an invalid value to it), your program crashes.
Theres a ostream& operator<< (void* val); overload that will just print the address of the pointer, but you need to explicitly cast your char* pointer to a void* pointer to use it:
std::cout << "b:" << (void*)b << std::endl; // Prints 0x3a98 (15000)
How is it possible that the value of *p and the value of DIM are different but the have the same address in memory?
const int DIM=9;
const int *p = &DIM;
* (int *) p = 18; //like const_cast
cout<< &DIM <<" "<< p << '\n';
cout << DIM << " " << *p << '\n';
You're changing the value of a const variable, which is undefined behavior. Literally anything could happen when you do this, including your program crashing, your computer exploding, ...
If a variable is supposed to change, don't make it const. The compiler is free to optimise away accesses to const variables, so even if you found a successful way to change the value in memory, your code might not even be accessing the original memory location.
It is a compiler optimization. Given that DIM is a constant, the compiler could have substituted its known value.
The code below does what you meant to do... as mentioned in other posts, if you mean to change the value of an variable, do not define it as const
#include <stdio.h>
int main()
{
int d= 9;
int *p_d=&d;
*p_d=18;
printf("d=%d\np_d=%d\n",d,*p_d);
return 0;
}
This code prints
d=18
p_d=18
Here is my test code:
#define print(A) cout << #A << " = " << A << endl;
int main()
{
const int e = 2;
int *p = (int *)&e;
*p = 4;
print(e);
print(*p);
print(&e);
print(p);
}
Result:
e = 2;
*p = 4;
&e = 0xbfc6b458;
p = 0xbfc6b458;
Since "p" points to "e" according to their identical address, how can *p and "e" be different??? This can be dangerous, right?
Casting away const is legal; using the pointer (or reference) thus acquired to (attempt to) modify a const object is illegal.
Your code results in undefined behaviour; it can do anything and it doesn't have to make any sense.
Modifying a constant variable in any way results in an Undefined Behavior.
So yes this is dangerous.
An Undefined Behavior means that any behavior is possible and you cannot expect any valid behavior. The compiler is free to give you any results and it is allowed by the Standard to do so. Once an UB is invoked the program is not a valid program anymore.So best is to avoid any code which causes an UB.
They can be different because "e" is a const, so any decent compiler will plug in the value at compile time instead of reading it from memory.
Since you take the address there's still a "real" variable for it, but it's not actually used in your case.
And you're "lucky" that you could modify the value at all; since it was declared "const", the compiler could have placed it into readonly memory.
Either way, modifying a const value yields "undefined behavior". Lucky for us, you didn't destroy the world with your foolish game.
You're attempting to write to a constant variable (yes, the name is pretty oxymoron but I digress) which is undefined behavior.
You are casting away const. which is giving you wrong value which is Undefined behaviour.
It should be either
int e = 2;
int* p = (int *)&e;
*p = 4;
or
const int e = 2;
const int* p = (const int *)&e;
*p = 4;
latter one will give you compilation error as you are writting to a const.
Define variable:
const int e = 2;
directive const tell c/c++ compiler check whether L-value of e variable, compiler will prevent your code assign new value for e.
int* p = (int *)&e;
p is a pointer (also int 4 bytes), can be assigned any value , p = (((int *) e ) -2)+2. The compiler no need to check *p whether *p is constant. I think that is a flexible of c/c++ languages, the better way is avoiding pointer.