This question already has answers here:
Where exactly does C++ standard say dereferencing an uninitialized pointer is undefined behavior?
(7 answers)
Closed 4 years ago.
#include <iostream>
using namespace std;
int main() {
int *a;
int *b;
int c=12;
a=&c;
*b=*b;
cout << *b << endl;
}
The above code works fine, but the following code returns a segmentation fault error
#include <iostream>
using namespace std;
int main() {
int *a;
int *b;
int c=12;
//a=&c;
*b=*b;
cout << *b << endl;
}
Why?
gcc (Ubuntu 8.2.0-7ubuntu1) 8.2.0
Here's a step-by-step breakdown of what your code is doing:
int *a;
int *b;
This declares two pointers to int named a and b. It does not initialize them. That means that their values are unspecified, and you should expect them to be complete garbage. You can think of them as "wild" pointers at this moment, which is to say that they don't point to valid objects, and dereferencing them will cause Undefined Behavior and introduce a plethora of weird bugs, if not a simple crash.
int c=12;
This creates a simple local variable c of type int, which is initialized, with a value of 12. If you hadn't initialized it, as in int c; then it would also be full of garbage.
a=&c;
This snippet sets the pointer a to point to c, which is to say that the address of c is assigned to a. Now a is no longer uninitialized, and points to a well-defined location. After this, you can safely dereference a and be assured that there is a valid int at the other end.
*b=*b;
Here, you are dereferencing b, which means that you are reaching into your programs memory to grab whatever is pointed to by b. But b is uninitialized; it is garbage. What is it pointing to? Who knows? To read from the address it points to is like Russian roulette, you might kill your program immediately if you get really unlucky and the Operating System or runtime environment notices you doing something that's obviously wrong. But you also might get away with it, only for weird and unpredictable bugs to emerge later. This weirdness and unpredictability is why a good C++ programmer avoids Undefined Behavior at all costs, and ensures that variables are initialized before they are used, and makes sure that pointers are pointing to valid objects before dereferencing them.
Why does there appear to be a difference depending on a=&c;?
As to why your program apparently crashes or doesn't crash depending on how you initialize the other pointer, the answer is that it doesn't matter. In both cases, you're causing Undefined Behavior; you are breaking the language's rules and you should not expect the language to behave correctly for you thereafter, and all bets are off.
"*b=*b" - Is broken code. b is uninitialised, so you are dereferencing an uninitialised pointer. That's Undefined Behaviour. The program is broken and has no meaning according to the standard and the compiler is allowed to generate whatever code it feels like (no diagnostic required).
Related
This question already has answers here:
Why is the phrase: "undefined behavior means the compiler can do anything it wants" true?
(2 answers)
Why don't I get a segmentation fault when I write beyond the end of an array?
(4 answers)
C++ Impossible nullptr call mystery [duplicate]
(2 answers)
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 7 months ago.
I understand the concept of dangling pointers, func2 returns address of deallocated memory.
In func1 instead of returning the address we store by passing a double pointer. Isn't this also a case of dangling pointer ?
#include <iostream>
void func1(int **x){
int z = 10;
*x = &z;
}
int *func2(){
int z=11;
return &z;
}
int main() {
int *a;
func1(&a);
std::cout << *a << std::endl;
int *b = func2();
std::cout << *b << std::endl;
return 0;
}
OUTPUT:
10
seg fault
In both cases, you are dereferencing a dangling pointer, which invokes undefined behavior.
This means that you cannot rely on any specific behavior. You may get a segmentation fault or your program may work as intended, or something else might happen. The behavior may be different on different compilers. Even on the same compiler the behavior may be different, depending on the compiler settings, such as the optimization level. Also, simply updating your compiler to a new version may cause the behavior to change.
Asking why you are not getting a segmentation fault when you are invoking undefined behavior is not a meaningful question. It is like driving your car through an intersection when you have a red light and then asking the question why you did not collide with another car. When you break the rules, you cannot rely on anything specific to happen.
You may want to read this similar question:
Can a local variable's memory be accessed outside its scope?
Yes, both a and b are dangling pointers when you dereference them and either dereference therefore makes the program invalid.
But dereferencing a dangling pointer causes undefined behavior. That means that there is no guarantee for any particular behavior whatsoever. There is no guarantee for a segfault. There is no guarantee for a particular output. There is no guarantee that it won't look as if accessing the dangling pointer to the out-of-lifetime variable "worked".
I am new to programming and am currently studying about address typecasting. I don't seem to understand why I am getting this : *** stack smashing detected ***: terminated Aborted (core dumped) when I run the following code??
#include<iostream>
using namespace std;
void updateValue(int *p){
*p = 610 % 255;
}
int main(){
char ch = 'A';
updateValue((int*)&ch);
cout << ch;
}
Here's what I understand about the code:
The address of ch is typecasted to int* and passed into the function updateValue(). Now, inside the updateValue() stack, an integer pointer p is created which points to ch. When p is dereferenced, it interprets ch as an int and reads 4(or 8) bytes of contiguous memory instead of 1. So, 'A'(65) along with some garbage value gets assigned to 610%255 i.e. 20.
But I don't understand, what and where things are going wrong?
when p is dereferenced, it interprets ...
When you indirect through the reinterpreted p and access an object of the wrong type, the behaviour of the program is undefined.
what and where things are going wrong?
Things started going wrong when you reinterpreted a pointer to one type as a pointer to an unrelated type.
Some rules of thumb:
Don't use reinterpret casts until you know what it does. They are difficult to get right, and are rarely useful.
Don't use reinterpret casts when it would result in undefined behaviour.
Don't use C-style casts at all.
If you think that you need to reinterpret cast, then take a few steps back, and consider why you think that you need it.
The problem is that you're typecasting a char* to an int* and then dereferencing p which leads to undefined behavior.
Undefined behavior means anything1 can happen including but not limited to the program giving your expected output. But never rely(or make conclusions based) on the output of a program that has undefined behavior. The program may just crash.
So the output that you're seeing(maybe seeing) is a result of undefined behavior. And as i said don't rely on the output of a program that has UB. The program may just crash which happens in your case.
For example, here the program crashes, but here it doesn't crash.
So the first step to make the program correct would be to remove UB. Then and only then you can start reasoning about the output of the program.
1For a more technically accurate definition of undefined behavior see this where it is mentioned that: there are no restrictions on the behavior of the program.
But I don't understand, what and where things are going wrong?
In this statement
*p = 610 % 255;
the memory that does not belong to the object ch that has the type char is overwritten. That is instead of one byte occupied by the object ch there are overwritten 4 bytes that correspond to the allocated memory for an object of the type int.
To be clear, I am aware of pointer to pointer concept in C and of dereferencing double, triple pointers. The only doubt I have is in the following program which I wrote:
#include<stdio.h>
int main(){
int a;
int* p;
a=5;
p=&a;
int **q;
printf("*p=%d\n",*p);
printf("*q=%d\n",*q);
}
Now I know, the program is quite stupid and makes no sense, but that's not the problem. The question is WHY?
Why is the Output like this:
*p=5
*q=1
Why is *q=1 on every run?
Also it is to keep in mind, if I now declare a ***r;
And add the following line:
printf("*r=%d\n",*r);
Now the output is :
*p=5
*q=-40821602 //garbage
*r=1
Now, *r=1. WHY?
Same goes for ****s. In that case, *q,*r is a garbage and *s=1. Why?
Evaluation of an uninitialized pointer is undefined behavior, and that is what you did. cppreference states the following on undefined behavior:
Undefined Behavior:
undefined behavior - there are no restrictions on the behavior of the program. Examples of undefined behavior are memory accesses outside of array bounds, signed integer overflow, null pointer dereference, modification of the same scalar more than once in an expression without sequence points, access to an object through a pointer of a different type, etc. Compilers are not required to diagnose undefined behavior (although many simple situations are diagnosed), and the compiled program is not required to do anything meaningful.
Hence, you cannot expect anything meaningful coming out of your program. It may print 1, but it could also do anything else. In my case, for example, it simply crashed.
So the question "why?" is simply not a valid question.
this is my first question in this forum, sorry my bad english.
I have a question about pointers and dynamic memory in c++.
Example, this code:
#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
int *a = new int;
for (int i = 0; i < 5; i++)
cout << a++ << endl;
return 0;
}
Output:
0x11d4c20
0x11d4c24
0x11d4c28
0x11d4c2c
0x11d4c30
My question, is why can I move more than that 'single' block of memory that I created with new.
What is a pointing to?
Same occurs with new int[], even if I specific the size:
#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
int *a = new int[2];
for (int i = 0; i < 5; i++)
cout << a++ << endl;
return 0;
}
Output:
0x2518c20
0x2518c24
0x2518c28
0x2518c2c
0x2518c30
Again, what is happening?
What is a pointing to?
Does all of this mean I'm violating memory?
a is an int*, not an int. What you are printing is actually the pointer, i.e. the memory address of the pointed object. Use the dereference operator * whenever you want to modify the pointed value, i.e.
cout << (*a)++ << endl;
NB: Likewise, you can get a pointer to an int using the reference operator, &, not to be mixed up with a reference (e.g. a int& type).
This may print 0 1 2 3 4. may because you are not initializing the new int created in dynamic memory. This means reading from *a (dereferenced a) is undefined behavior, which means your program may misbehave. You have to change your line using new:
int *a = new int();
This will initialize *a to 0 and now 0 1 2 3 4 will be printed correctly.
Note that int *a = new int[2]; does create a dynamic array of 2 entries in dynamic memory, which means *(a + 1) can be used as well (as if it was a regular array). It does not initialize *a to 2.
Do remember to delete a; when you've done using it. In a real application, you could get a memory leak if you don't - i.e. your program would still use memory it doesn't need anymore. Caution, when you have to delete a dynamically-allocated array (i.e. new int[2]), you need to use delete[] a; instead, or you will trigger undefined behavior.
You may also use a unique_ptr (or a shared_ptr) in C++11 as an alternative to this kind of memory allocation, i.e. :
#include <memory>
// ...
std::unique_ptr<int> a = std::make_unique<int>(0);
Thanks to this solution, you do not need to delete a because the unique_ptr will do this for you, when itself dies (i.e. out of the scope, here).
Edit: Bonus:
0x2518c20
0x2518c24
0x2518c28
Why is the number incremented by 4 if you just used ++?
Using ++ on an address will actually increment it by sizeof(T), which here is sizeof(int) and not 1. This explains why you can, as previously stated, use *(a + 1) if you used new int[2].
i think that it is ,because a points to an integer , the size of an integer is 4 bytes (sizeof(int) == 4) after executing a++ ,a points to the next integer,try char *a, and a++ to be more sure
It is legal to point at an object or the spot right after an object. A new int[2] creates two adjacent objects (in an array) and returns a pointer to the first one.
So yes, what you did above is not permitted. The behaviour of adding 5 to a pointer to a single object is not defined by the C++ standard; the compiler can generate assembly that does anything at all.
As it happens, on a flat memory architecture, pointers are basically unsigned integers. And incrementing a pointer by 1 is just incrementing it by the size of the pointed-to object.
So what often happens is you just get pointers to whatever happens to be there.
Now this is not guaranteed and should not be relied upon. Many of the rules of C++ that make actions undefined permit certain optimizations to occur over the "naive" mapping you might think the compiler does. For example, pointers to short can never point to an int and change its value in a defined way, which means if a function has both an int and short pointer it can assume that a write to the short does not modify the int.
The naive "write to the two words in an int" method of using shorts can work, then not work for seeming no reason, because the behaviour was undefined and the compiler was free to optimize assuming it could not happen.
In short, your actions are not legal, the behaviour you got is not surprising, but you can never rely on it.
Pointers are not just unsigned integers, even if that is what your compiler implements them with. They are an abstraction. Their behaviour is determined not by their implementation, but rather what the standard permits you do with them. When you act in ways the standard does not permit, the behaviour you get is undefined by the standard. Compilers can, and have been known to, exploit that fact to assume undefined behaviour cannot and does not occur. The program could behave unexpectedly on lines of code prior to the undefined behaviour as the compiler reorders and optimizes based on the assumption your code has well defined behaviour.
Pointers in c++ (and c) are just addresses to the memory (32/64bit numbers). There is no problem with increasing them or decreasing any way you want and you are not violating the memory or any other rule. You would be however violating the memory if you tried to read or write to the address pointed to by A after going through the for cycle.
As for what it is pointing to, most likely it's just some more space allocated to you by the new (and malloc under it) because it tends to give more space than you ask for, though this behaviour is not guaranteed. It might also point to heap data or just unassigned memory.
int func() {
int a;
++a; // is this safe?
printf("%d\n", a);
}
I know when I printf a I get undefined behavior, but is ++a safe in C++ standard? Will this assign "another" uninitialized value to a without side effects (throwing exceptions or crashing the program)?
Using an uninitialized variable in anyways gives you Undefined behavior. So,
No incrementing an uninitialized int is not safe in C++.
Your program might not crash but it is certainly not safe. You should always initialize your variables. The worst that can happen is your program will appear to work but will crash at random times without you knowing the cause or simply behave in a strange way.
What do you mean by "undefined behaviour"? In my opinion your program should print some int without any exceptions and so on.
++(uninitizalized int) is absolutely legal, I guess. It will just increment the current value, no matter whether the var was initialized or not.
But anyway, uninitialized vars are EVIL.