This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 9 years ago.
Is my function has undefined behavior? Becouse there is local variable c, so its in automatic location so it will be destruct after execution of function? (end of scope)
int* calculate(int* a,int* b)
{
int c=(*a)+(*b); //local variable c
return &c;
}
int main()
{
int a=12;
int b=23;
int* ptr=calculate(&a,&b);
std::cout<<*ptr<<endl;
}
Yes, returning a pointer to a temporary local object and dereferencing that is undefined behavior.
Because after exiting the function calculate, that object goes out of scope and automatically will be destroyed, then the provided pointer, points to an invalid address and it's a dangling pointer. After that, you can use dereference and use it (for example: *ptr).
In your case, you can use a normal variable, remove those *:
int calculate(int *a, int *b)
{
int c = (*a)+(*b);
return c;
}
since you have nothing reasonable to pass them by pointer, it's better to remove more *:
int calculate(int a, int b)
{
int c = a + b;
return c;
}
You can pass an int declared in the main, to calculate, like this::
void calculate(int* a,int* b, int* c)
{
*c=(*a)+(*b);
return ;
}
int main()
{
int a=12;
int b=23;
int c=0;
calculate(&a,&b,&c);
std::cout<<c<<endl;
return 0;
}
The much more simpler way is::
int Calculate( int a, int b )
{
return a+b ;
}
int main( void )
{
int a=12, b=23;
std::cout<<Calculate(a,b)<<endl;
return 0;
}
Related
This question already has answers here:
Type qualifier appear in multiple item declaration (exhibiting strange behavior with pointer)
(2 answers)
Closed last month.
I know
int* p, k;
declares k to be int and p to be int*, but how about:
static int a, b;
const int c, d;
and other declarators. Is it the same for all of them? Obviously for pointers, arrays, and indirection it would be.
I'm not asking if it compiles; I'm asking for rules regarding these declarations, preferably quoted from the standard.
It doesn't take much to test this. The following does not compile because p has been declared const. https://godbolt.org/z/P7bj85aWx
int main() {
const int k = 1, p = 5;
p++;
return 0;
}
For static, consider the following which outputs 67 rather than 66. The latter would be expected if b were not static.
https://godbolt.org/z/E58azYdfe.
#include <iostream>
int foo() {
static int a, b = 5;
b++;
return b;
}
int main() {
std::cout << foo() << foo() << std::endl;
return 0;
}
When I store a plain int in A and perform a simple get function:
#include <iostream>
class A
{
int p;
public:
void setint(int p_x);
int getint();
};
void A::setint(int p_x) {p = p_x;} // set p (type int)
int A::getint() {return p;} // get p (type int)
int main()
{
A arr_a[5];
arr_a[0].getint();
}
it compiles and exits with code 0. However when I change int to int* and try to do the same:
#include <iostream>
class A
{
int* p;
public:
void setint(int p_x);
int getint();
};
void A::setint(int p_x) {*p = p_x;} // set int pointed to by p (type int)
int A::getint() {return *p;} // get int pointed to by p (type int)
int main()
{
A arr_a[5];
arr_a[0].getint();
}
it compiles fine but exits with code 3221225477. Why is this so and is there still a way I can store pointers in A and store A in arrays?
In your 2nd case A arr_a[5] just create a array that contains 5 A. but
for every A, the pointer is an undefined number (maybe 0x0), so *p is a undefined behavior. You should add A::A() and A::~A() to manage your pointer in your class
just like this:
#include <iostream>
class A
{
int *p;
public:
A();
~A();
void setint(int p_x);
int getint();
};
A::A() : p(new int) {}
A::~A() { delete p; }
void A::setint(int p_x) { *p = p_x; } // set int pointed to by p (type int)
int A::getint() { return *p; } // get int pointed to by p (type int)
int main()
{
A arr_a[5];
arr_a[0].getint();
}
Your program has a serious flaw. Both of your given code snippets (case 1 and case 2 in your question) have undefined behavior. Lets see how it is
Case I: Code Snippet 1
In your code snippet 1, since the data member p is a built in type and you've not initialized it, so p has a garbage value and using(accessing) this value can lead to undefined behavior which is exactly what is happening in your case.
When you wrote:
A arr_a[5];//this creates a 1D array of size 5 having elements of type `A` but the elements are default initialized
arr_a[0].getint();//this result in undefined behavior
The above statement creates a 1D array of size 5 having elements of type A. The problem is that since you have not initialized this array, its elements are default initialized which means that the value of data member p is also default initialized. But since you didn't use in-class initializers for variable p, p has garbage value and this leads to undefined behavior.
You can confirm this by looking at the output here.
Solution to Case I
You can solve this by initializing the data member p using in-class initializer as shown below:
#include <iostream>
class A
{
int p = 0;//USE IN-CLASS INITIALIZER
public:
void setint(int p_x);
int getint();
};
void A::setint(int p_x) {p = p_x;} // set p (type int)
int A::getint() {return p;} // get p (type int)
int main()
{
A arr_a[5];
std::cout<<arr_a[0].getint();//now ok because we have initilaized p
}
Case II: Code Snippet 2
In this case the only difference is that now the data member p is a pointer to int that is int*. Similar to last case the pointer variable has a garbage value which can lead to undefined behavior if you try to use it as you did inside your main function by writing:
A arr_a[5];//create a 1D array of objects `A` but the elements(A objects) are default initialized
arr_a[0].getint();//this result in undefined behavior
Solution to Case II
You can solve this by initializing the data member p using in-class initializer as shown below:
#include <iostream>
class A
{
int* p = nullptr;//USE IN-CLASS INITIALIZER
public:
void setint(int p_x);
int getint();
//other members like constructor and destructor to allocate and deallocate memory
//so that getint and setint doesn't dereference nullptr
};
void A::setint(int p_x)
{ if(p!=nullptr)// add a check here to see p isn't null
{
*p = p_x;
}
else
{
std::cout<<"WARNING: Dereferencing a nullptr can lead to UB";
}
}
int A::getint() // add a check here to see p isn't null
{ if(p!= nullptr)
{
std::cout<<"yes"<<std::endl;
return *p;
}
else
{
std::cout<<"WARNING: Dereferencing a nullptr can lead to UB";
return -1;
}
}
int main()
{
A arr_a[5];
arr_a[0].getint();//now ok(assuming `p` isn't nullptr) because we have initilaized p
}
Summary
Both of the code snippets that you gave have undefined behavior. You can solve both of them by using in-class initilaizers to initialize data member p to a default value.
For example, I have the following codes:
int a = 1;
int b = 2;
int *c = &a;
int &d = *c;
c = &b;
d++;
What is behaviour of line 4? If i want a reference to a pointer,is it correct to use
int *&e = c;
Is there any reason why to choose a reference to a pointer?
This declaration
int &d = *c;
declares a reference that refers the object pointed to by pointer c.
When this declaration was executed pointer c pointed to object a
int *c = &a;
So the referecne d refers object a. References may not be reassigned. They shall be initialized when they are declared.
Thus the expression in statement
d++;
increases object a.
You may declare a reference to a pointer.
This declaration
int *&e = c;
is valid.
Constant references can be bound to a temporary object. You may not take an address of a temporary object. Refrences alow to use more simple expressions.
Consider for example a simplified function swap that swaps two integers.
Using pointers the function would look like
void swap( int *a, int *b )
{
int tmp = *a;
*a = *b;
*b = tmp;
}
and it could be called like
int a = 5;
int b = 10;
swap( &a, &b );
Using references you could write the function the following way
void swap( int &a, int &b )
{
int tmp = a;
a = b;
b = tmp;
}
and its call would look simpler than the call of the function with pointers.
int a = 5;
int b = 10;
swap( a, b );
regarding the meaning of line 4
int a = 1;
int*c = &a; // okay: pointer to int, points to a
int&d = *c; // okay; reference to int, refers to *c=a;
A reference to a pointer is useful as argument to a function that may alter its value (=address pointed to), for example
void allocate(int*&p)
{ p=new int[10]; }
Why is there a difference in the results when I call an array inside a void function and when I call a scalar inside a void function:
Pass an array into a void function:
#include <iostream>
const int n_cells = 1;
using namespace std;
void function1(int c[n_cells], int a, int b)
{
c[0] = a + b;
}
int main(){
int a = 3;
int b = 4;
int c[n_cells];
function1(c, a, b);
cout<<"c = "<<c[0];
return 1;
}
Result:
c = 7
Pass a scalar into a void function
#include <iostream>
using namespace std;
void function1(int c, int a, int b)
{
c = a + b;
}
int main(){
int a = 3;
int b = 4;
int c;
function1(c, a, b);
cout<<"c = "<<c;
return 1;
}
Result:
c = 2130567168 //Some trash value
P.S. Any comments on why I receive the same trash value as given above every single time?
void function1(int c[n_cells], int a, int b)
effectively passes a pointer to the caller's array. function1 then operates on the caller's array meaning that any updates are available to the caller.
void function1(int c, int a, int b)
passes a copy of c. It does not have access to the caller's variable so cannot update it. main never assigned c so you print out an uninitialised value.
If you want to update an integer argument, you can pass it by reference instead
void function1(int& c, int a, int b)
// ^
Rather than passing a copy of the caller's c, this now passes a pointer to the caller's variable, allowing function1 to update it.
The array parameter is actually transformed to the type int*, so what you're actually doing is passing a pointer to the first element of the array declared in main. So when you assign to the first element of this array, you are modifying the array in main.
However, when you pass an int, the int is copied into the function and you modify that copy. This modification will not be seen in main.
You could get the same result in the second program if you would define the function the following way
void function1(int *c, int a, int b)
{
c[0] = a + b;
}
When you pass an array by value it is converted implicitly by the compiler to pointer to its first element. So these function declarations are equivalent and declare the same function
void function1(int c[n_cells], int a, int b);
void function1(int c[10], int a, int b);
void function1(int c[], int a, int b);
void function1(int *c, int a, int b);
Compare the last declaration with the declaration I showed you for the second program.
In the second program the function gets a copy of its argument. Its parameter is a local variable of the function. So any changes of this local variable will be discarded after exiting the function that is the local variable will be destroyed.
In the first program the function gets the address of the first element of the array. It makes changes at this address. So the corresponding element of the original array will be changed.
I just wanted to clarify something, imagine we have the function signature:
1) int* X(){}
2) int Y(){}
3) int& Z(){}
I am trying to work out the exhaustive possibilities of types of values I can return for the above. The below show possible implementations for the above function bodies:
1)
int* X(){
int* b = new int(6);
return b;
}
2)
int Y(){
int b = 6;
return b;
}
or
int Y(){
int* b = new int(6);
return *b;
}
EDIT: 2) not good because of memory leak if b isn't deleted.
3)
int& Z(){
int b = 6;
return b;
}
EDIT: 3) not good because b will go out of scope once function returns.
Is there anything I have missed out which could be returned from any of the above 3 function signatures? Getting a bit more adventurous, what about:
int* X(){
int b = 6;
return reinterpret_cast<b>;
}
and
int X(){
int* b = new int(6);
return reinterpret_cast<b>;
}
? (My understanding of reinterpret_cast may be wrong...)
int Y(){
int* b = new int(6);
return b*;
}
This has a syntax error. To dereference b, you would do *b. Nonetheless, this is a very bad implementation because it leaks memory. The dynamically allocated int will never be destroyed.
int& Z(){
int b = 6;
return b;
}
This is also bad because you are returning a reference to a local variable. The local variable b will be destroyed when the function returns and you'll be left with a reference to a non-existent object.
int* X(){}
when you have to return address which is pointing to integer
int Y(){}
for returning simple integer
int& Z(){}
this is something different,
you don't have any argument in Z() thus it is useless.
It must be like
int& Z(int &a)
{
//code body
return (a);
}
and return this to reference variable