illegal instruction occur while using pointer and reference - c++

when reading the source codes of realtime_tools::RealtimeBuffer, I got lots of questions about the pointer and reference. The related codes are shown below:
void writeFromNonRT(const T& data)
{
// get lock
lock();
// copy data into non-realtime buffer
*non_realtime_data_ = data;
new_data_available_ = true;
// release lock
mutex_.unlock();
}
To figure out, I tried to code the similar code like:
#include <iostream>
using namespace std;
void pt_ref(int& data)
{
int *ptr;
ptr = &data; // ptr points to "data"
cout << "data's addres: "<< ptr <<"\n"; // print address
}
int main()
{
int x = 3;
pt_ref(x);
cout << "x's address: " << &x;
}
\\ output:
\\ data's addres: 0x7ffe05c17c4c
\\ x's address: 0x7ffe05c17c4c
This code runs well, but it's still different to the source code.
// these 2 lines are different.
*non_realtime_data_ = data;
ptr = &data;
So I tried to change ptr = &data; to *ptr = data;, and ran again the code, the error("illegal instruction") occurred.
Hope someone can answer me, thanks a lot.
PS: I ran the code on the replit online compiler.

I tried to change ptr = &data; to *ptr = data;, and ran again the code, the error("illegal instruction") occurred.
The problem is that the the pointer ptr was uninitialized(and does not point to any int object) and so dereferencing that pointer(which you did when you wrote *ptr on the left hand side) leads to undefined behavior.
int *ptr; //pointer ptr does not point to any int object as of now
*ptr = data;
//-^^^^--------->undefined behavior since ptr doesn't point to any int object
To solve this make sure that before dereferencing ptr, the pointer ptr points to some int object.
void pt_ref(int& data)
{
int var = 10; //int object
//-------------vvvv-------->now ptr points to "var"
int *ptr = &var;
//--vvvv------------------->this is fine now
*ptr = data;
}

Related

Why can this kind of declaration work in C++?

Passing an int to an uninitialized pointer cannot work. But passing a reference to an uninitialized pointer can work.
What's the mechanism behind this?
int a = 1;
int &r = a;
cout << &a << " " << &r << endl; // 0x61ff10 0x61ff10
// can work
int *p1;
*p1 = r;
cout << p1 << endl; // 0x61ff60
// cannot work
int *p2;
*p2 = a;
return 0;
The code below is how I tested these strange concepts page 400 of cpp primer plus.
const free_throws & clone(free_throws & ft)
{
free_throws * pt;
*pt = ft; // copy info
return *pt; // return reference to copy
}
P.S.: I tried changing the value of a and cout << *p1 always outputs the correct value:
int a = 3;
int &r = a;
cout << &a << " " << &r << endl;
// can work
int *p1;
*p1 = r;
cout << p1 << endl;
cout << *p1; // always the right value
This Code from C++ Primer Plus (You shoudln't confuse "C++ Primer" a recommended book with "C++ Primer Plus") is not valid:
const free_throws & clone(free_throws & ft)
{
free_throws * pt;
*pt = ft; // copy info
return *pt; // return reference to copy
}
The text in the book above the shown code says:
A second method is to use new to create new storage. You’ve already seen examples in
which new creates space for a string and the function returns a pointer to that space.
Here’s how you could do something similar with a reference
So the code meant to look like that (in an early revision of the book the new was there):
const free_throws & clone(free_throws & ft)
{
free_throws * pt = new free_throws();
*pt = ft; // copy info
return *pt; // return reference to copy
}
If new is missing then it is undefined behavior.
After the code the book also mentions that:
This makes jolly a reference to the new structure. There is a problem with this
approach: You should use delete to free memory allocated by new when the memory is no longer needed.
So even with the new it is a really bad code style.
i tried to change the value of a and cout << *p1 can always output the correct value
int *p1; *p1 = r; is undefined behavior, the compiler could make wrong assumptions about the code due to that, resulting in the compiler or optimizer create an unexpected/unpredictable machine code.
But what will most likely happen in practice for the shown code is: You don't initialize int *p1; so p1 holds an undetermined value, this means it points to an arbitrary location in memory. If you are lucky it points to a valid memory address of currently not used memory. With *p1 = r; you write to the memory at that memory address, if you are lucky nothing important is at that address so nothing bad happens, but you still write at a "random" position in memory. So you might get the correct result, but your code is still not valid.
But that's just one possible outcome that could happen.
int a = 1;
int &r = a;
cout << &a << " " << &r << endl;
This is ok as every variable is initialized.
int *p1;
*p1 = r;
cout << p1 << endl;
This is incorrect because p1 is uninitialized. Accessing it (i.e. *p1 in your example) causes the program to have Undefined Behavior. Undefined behavior means anything can happen: the program can segfault, it can appear to work, it can print gibberish, really anything.
int *p2;
*p2 = a;
Same as previous. Access of uninitialized variable resulting in Undefined Behavior.
free_throws * pt;
*pt = ft;
Same as previous. Access of uninitialized variable resulting in Undefined Behavior.
It is an undefined behavior in both cases, as *p1 and *p2 are uninitialized.
Check the instructions generated:
int a = 1; Variable a is stored and initialized in rbp-28:
mov DWORD PTR [rbp-28], 1
int &r = a; Then, alias r is stored in rbp-8, which is initialized reading &a using lea instruction:
lea rax, [rbp-28]
mov QWORD PTR [rbp-8], rax
int *p1; *p1 = r; Pointer *p1 is stored in rbp-16. The last mov assigns *p1 = a without initializing p1 to any value:
mov rax, QWORD PTR [rbp-8] # rax = address of r
mov edx, DWORD PTR [rax] # edx = value of a (deferences r)
mov rax, QWORD PTR [rbp-16] # rax = address of p1
mov DWORD PTR [rax], edx # rax = p1, [rax] = *p1, edx = a
int *p2; *p2 = a; Pointer *p2 is stored in rbp-24. As with p1, p2 is assigned a value without pointing first to any valid address:
mov edx, DWORD PTR [rbp-28] # edx = value a
mov rax, QWORD PTR [rbp-24] # rax = address of p2
mov DWORD PTR [rax], edx # rax = p2, [rax] = *p2, edx = a
Link To alias Pointers
int a = 1;
int &r = a; // alias pointers reference above
cout << &a << " " << &r << endl; // 0x61ff10 0x61ff10 (Both address are same)
// It will also not work because you are not initializing p1
int *p1;
*p1 = r;
cout << p1 << endl; // Segmentation Fault
// Same but working code
int *p1 = &r;
cout << p1 << endl; // 0x61ff60
// cannot work (Because you have not initialized p2)
int *p2;
*p2 = a;
// Initialize p2 with a directly
int *p2 = &a;
cout << p2 << endl; // This time same address as of a
// or
int *p2 = new int;
*p2 = a;
cout << p2 << endl; // This time different address but same value of a

The lifetime of a pointer reference in C++

I wrote some code that involves moving and changing variables in C++. Below is what I have wrote.
#include <iostream>
void six(int*& ptr) {
int s = 6;
ptr = &s;
}
int main() {
int f = 5;
int* ptr = &f;
std::cout << *ptr << '\n';
six(ptr);
if (ptr) {
std::cout << *ptr;
}
else {
std::cout << "null\n";
}
return 0;
}
so this prints:
5
6
I tried another code, adding a single line:
#include <iostream>
void six(int*& ptr) {
int s = 6;
ptr = &s;
free(&s); // added line
}
int main() {
int f = 5;
int* ptr = &f;
std::cout << *ptr << '\n';
six(ptr);
if (ptr) {
std::cout << *ptr;
}
else {
std::cout << "null\n";
}
return 0;
}
Obviously, this gives an error after printing 5 because what the modified pointer is pointing is not available when called the second time.
However, I am confused at the first case. When calling six in the main function, variable s is not in the main scope, but the value itself still continues to remain in the memory to be referenced. Doesn't C++ automatically destroy variables and clean them when it goes out of the scope? Is this a memory leak?
The first case is not a memory leak, but an undefined behaviour because your variable go out of scope.
In this case you don't know when the memory will be cleaned(replaced) o reallocated.
So in some case the result can be correct but it's a pure question of luck.

pass unigue_ptr as shared_ptr into a vector

Here is a test to understand more about shared_ptr and unique_ptr:
#include <string>
#include <memory>
#include <vector>
std::vector<std::shared_ptr<int> > vec_ptr;
int* get()
{
for (size_t i = 0; i < 1; ++i)
{
vec_ptr.push_back(std::make_unique<int>());
}
return vec_ptr.back().get();
}
int main()
{
int obj = 5;
int* ptr = get();
ptr = &obj;
std::cout << *ptr << std::endl;
std::cout << *vec_ptr[0].get() << std::endl; //expect: 5, but it is 0
}
Apparently nothing is assigned to the vec_ptr. Could someone please explain it to me?
It seems you wanted to do:
*ptr = obj;
instead of
ptr = &obj;
The former copies the integer obj into the space pointed to by ptr. The latter (which you're doing) re-points ptr to point at obj.
Here is what you have in this program:
vec_ptr contains 3 elements, each of them is 0.
obj, with a value of 5.
ptr, which points to obj.
So the program prints the correct values of 5 and 0. If you want to change the value of one of the pointers, then you should assign it like this:
*ptr = obj;
Then, ptr will point to the last element of vec_ptr (as returned by get()), which will have the value of 5. However, your last line will still print 0, because that prints the first element of the vector, not the last.

pointer based linked list gives segmentation error

#include "AirlineReservationSystem.h"
struct test{
int num;
test* tNext;
};
int main()
{
test* a;
a = new test;
a->num = 8;
a->tNext = new test;
test* ptr = a;
ptr = ptr->tNext;
ptr->num = 9;
cout << ptr->num;
ptr = a;
cout << ptr->num;
while ( ptr->tNext != NULL){
ptr = ptr->tNext;
}
cout << ptr->num;
return 0;
}
I am trying to understand here why this code gives a segmentation error. Disregard the include at the start, It does nothing.
I am very very very new at this and trying to understand pointers and linked lists better and make some practice yet i am unable to see what i am doing wrong.
Program itself prints the first two couts but crashed at while statement which means there must be some problem with it, if someone could explain to me what that problem really is and what i am missing, it would be great. Thanks.
You have initialized ptr->num = 9, but you have not initialized ptr->tNext to anything.
Now let's examine the following piece of code:
while ( ptr->tNext != NULL){
ptr = ptr->tNext;
}
Iteration #1:
Most likely ptr->tNext != NULL, so you enter the loop and set ptr = ptr->tNext.
Now ptr is most likely pointing to an invalid memory address.
Iteration #2:
ptr is most likely pointing to an invalid memory address.
Therefore, ptr->tNext would most likely yield an illegal memory access.
When you create the second test, you do not initialize the pointer member in the struct.
This means that it points to some random memory address which is not a test instance (although I heard that some compilers will automatically make it point to NULL, never seen this in action though). Mostly the memory that is reserved for the struct is not cleared by default, so any content that was there remains "in the struct" until you assign it with something else.
If you don't assign it a new value the application will break when trying to dereference the memory.
So to fix this:
struct test{
test() : tNext(NULL) {} // ADD THIS AND ...
~test() { if(tNext) delete tNext; } // ADD THIS AND ...
int num;
test* tNext;
};
int main()
{
test* a;
a = new test;
a->num = 8;
a->tNext = new test;
test* ptr = a;
ptr = ptr->tNext;
ptr->num = 9;
cout << ptr->num;
ptr = a;
cout << ptr->num;
while ( ptr->tNext != NULL){
ptr = ptr->tNext;
}
cout << ptr->num;
delete a; // ADD THIS
return 0;
}
The first line is a constructor that sets the pointer to NULL which will prevent the pointer to point to random memory. The second line is the destructor which will clean up your nested structure recursively.
This behavior is desired because your code will exit from the while giving segmentation fault as your ptr->tNext!=NULL condition is not met at the last node also. So for the last node the ptr is set with a garbage value and hence when ptr->tNext!=NULL is executed, it gives segmentation fault error.
To avoid this, add the following line after ptr->num = 9;
ptr->tNext = NULL;
(1) Probably you are missing initialization of tNext to NULL.
Try changing your definition to:
struct test{
int num;
test* tNext;
test():num(0),tNext(NULL) {} // contructor initializing the members to default values
};
(2) You dont know if ptr is NULL or not inside while condition and in that case it is likely to give segmentation fault. Add null check on ptr in while () as well like this:
while (ptr && ptr->tNext != NULL){ // ptr->tNext is executed only when ptr is valid
ptr = ptr->tNext;
}

How to access the addresses after i get out of the loop?

#include<iostream>
using namespace std;
struct data {
int x;
data *ptr;
};
int main() {
int i = 0;
while( i >=3 ) {
data *pointer = new data; // pointer points to the address of data
pointer->ptr = pointer; // ptr contains the address of pointer
i++;
}
system("pause");
}
Let us assume after iterating 3 times :
ptr had address = 100 after first loop
ptr had address = 200 after second loop
ptr had address = 300 after third loop
Now the questions are :
Do all the three addresses that were being assigned to ptr exist in the memory after the program gets out of the loop ?
If yes , what is the method to access these addresses after i get out of the loop ?
Well the memory is reserved but you have no pointer to the memory so that's whats called a memory leak (reserved memory but no way to get to it). You may want to have an array of data* to save these pointers so you can delete them when you are done with them or use them later.
For starters, there will be no memory allocated for any ptr with the code you have.
int i = 0;
while( i >= 3)
This will not enter the while loop at all.
However, if you are looking to access the ptr contained inside the struct then you can try this. I am not sure what you are trying to achieve by assigning the ptr with its own struct object address. The program below will print the value of x and the address assigned to ptr.
#include<iostream>
using namespace std;
struct data {
int x;
data *ptr;
};
int main() {
int i = 0;
data pointer[4];
while( i <=3 ) {
pointer[i].x = i;
pointer[i].ptr = &pointer[i];
i++;
}
for( int i = 0; i <= 3; i++ )
{
cout<< pointer[i].x << endl;
cout<< pointer[i].ptr << endl;
}
}
OUTPUT:
0
0xbf834e98
1
0xbf834ea0
2
0xbf834ea8
3
0xbf834eb0
Personally, when I know the number of iterations I want to do, I choose for loops and I use while only when I am looking to iterate unknown number of times before a logical expression is satisfied.
I cannot guess what you are trying to achieve...
But Me thinks, you are trying to achieve similar to this....
But, If you want to make linked list using your implementation, you can try this...
#include<iostream.h>
struct data {
int x;
data *ptr;
data()
{
x = -1;
ptr = NULL;
}
};
data *head = new data();
data *pointer = head;
int main() {
int i = 0;
while( i <=3 ) {
data *pointer = new data();
pointer->x = /*YOUR DATA*/;
::pointer->ptr = pointer;
::pointer = pointer;
i++;
}
i=0;
data* pointer = head->next;
while( i <=3 ) {
cout<<pointer->x;
pointer = pointer->ptr;
i++;
}
system("pause");
}
This will print , the elements in the linked list;