Is returning a pointer declared inside the function considered bad practice? Example:
int* foo(void)
{
int * ret_val = 1234;
return ret_val;
}
I believe you're suppose to use:
static int * ret_val = 1234;
But then again, wouldn't it still be considered bad practice to return memory outside of your scope?
Returning a pointer isn't a problem as long as it points to memory that is still in scope, such as dynamically allocated memory, global data, or local variables that still exist further up the call stack.
The problem with the above code is that you're dereferencing a pointer without assigning anything to it. This: *ret_val = 1234; assigns the value 1234 to the address that ret_val points to, but ret_val wasn't assigned anything.
If on the other hand you did this:
int* foo(void)
{
int * ret_val;
ret_val = malloc(sizeof(int));
*ret_val = 1234;
return ret_val;
}
That is fine since you're returning a pointer to dynamically allocated memory.
The primary culprit is
*ret_val = 1234;
is applied with an uninitialized pointer.
I believe you're suppose to use:
static int* ret_val;
No, to fix that you could use
int* foo() {
static int_val = 1234;
return &int_val;
}
But it's arguable if that's what you really want. All callers of that function will share the same instance of int_val.
It's a really bad practice if your return a pointer to a local variable, because you will have a dangling pointer.
int* foo(void)
{
int a = 1337;
return &a; //Don't do this!
}
But sometimes it could be useful:
int* copy_array(int *array, int size)
{
int *v = (int*) malloc (size * sizeof (int));
//..copy the array..
return v;
}
Anyway, you should avoid returning pointers, so there is no risk of memory leaks.
Aside from your use of ret_val without it being allocated, returning a pointer from a function is fair practice, though it takes special care:
Don't return a pointer to a local variable, as it will be destroyed when the function exits and cause undefined behavior if dereferenced
If the function allocates memory, it is the responsibility of the caller function to ensure that the pointer is deallocated when it is no longer needed, to avoid memory leaks
If the function is processing an array in the form of a pointer, it needs to be aware of the size of the array to avoid undefined behavior, typically as an extra size parameter or a global constant
A pointer is like a shortcut or a hyperlink. Creating just a shortcut does not install a program. Creating a hyperlink does not magically sets up the whole website.
Same with a pointer: a int* is a pointer to an integer. It is not the integer itself. As such you must make sure that the pointer points to something meaningful before you try to follow the pointer.
One way of doing so is to create an integer and the sets a pointer to point to it:
int* ret_val = new int;
This will create an integer (the new operator), and then sets the ret_val pointer to point to it.
Objects created through new exist until you explicitly destroy them through delete or when your application ends. For that reason, if you have new int in a function, it is safe to access it even if the function ends.
What would be dangereous, and probably caused your concern, is if you would set the pointer ret_val not to a new integer, but to an existing local variable, i.e.
int myInteger;
int* ret_val = &myInteger;
In such scenario, ret_val points to a local variable myInteger which gets destroyed when the scope containing the declaration ends. You end up with a dangling pointer, referencing stuff that does not exist (think: broken hyperlink). Using such a pointer can lead to undefined behavior. It may crash your program, but it may as well silently accept it, modifying some random space in memory.
So, a function of the shape:
int* foo(void)
{
int* ret_val = new int;
*ret_val = 1234;
return ret_val;
}
is safe to use. It is not necessarily a good practice: the user of such function must know that it creates a new integer, that later - at some point - someone should delete. Functions that do that typically highlight such behavior in some way, e.g. through its name. For example, allocateInt() makes it clear that it created something that later should be delete. In contrast, getInt() suggests that the integer already exists and nothing new is created.
You should consider:
int *foo() {
int *ret_val = new int(1234);
return ret_val;
}
instead of (bad code):
int* foo(void)
{
int * ret_val;
*ret_val = 1234;
return ret_val; // dangling pointer!
}
otherwise you will have dangling pointer (the second example).
Obviously don't forget to release the memory.
You should also consider using smart pointers:
https://en.wikipedia.org/wiki/Smart_pointer
As you specified both C++ and C languages the above code is in C++ (operator new), please refer to (e.g.) #Mattia F. answer for ANSI C.
Related
I have noticed that if i create a pointer in a function, it won't let me set a value to it.
for example:
int func() {
int* pointer;
*pointer = 0 //error I get: "Exception: STATUS_ACCESS_VIOLATION"
return *pointer;
}
I get that not letting you set a pointer in the function because if I use a normal int it works:
int func() {
int notAPointer;
notAPointer = 0;
return notAPointer;
}
Can anyone explain to me why that is?
You haven't assigned any memory for your pointer to point to.
That means that dereferencing the pointer (*pointer) causes undefined behavior (like a crash in your case). You need to initialize the pointer before dereferencing it:
int* pointer = new int;
(And afterwards, delete pointer; to not leak the memory. Always delete everything you get from new.)
Also, pointers don't have to point to dynamically allocated data (acquired by a call to new), you can point to automatic (stack) variables too:
int func() {
int valueOnStack = 42;
int* pointer = &valueOnStack;
*pointer = 0;
return *pointer;
}
Because when you declare pointer it is pointing to a completely arbitrary memory location. You can't just write to any old piece of memory.
You need to allocate memory for it first:
int* pointer = new int;
*pointer = 0;
Or just:
int* pointer = new int();
The pointer pointer is uninitialized and points to a random location in memory when you declare it. It could be pointing into the system stack, or the global variables, or into the program's code space, or into the operating system. When you say *pointer = 0;, the program will simply try to write a 0 to whatever random location pointer points to.
The program may explode immediately, or may wait half an hour and then explode, or it may subtly corrupt data in another part of your program and you may never realize it. This can make this error very hard to track down. Make sure you initialize all pointers to a valid address before dereferencing them.
pointer does not point to anything following int* pointer;
So the behaviour of dereferencing it is undefined.
If you'd written
int n;
pointer = &n;
then you could dereference it.
Altenatively, you can allocate memory to it from the heap:
pointer = new int;
But you must remember to call delete pointer; else you'll leak memory.
This code is completely valid inside a function:
int *pointer = 0;
BUT, it would be the same as setting a pointer to the NULL macro.
If you try to set another value the compiler is going to complain that there is no valid conversion from int to int*:
int *pointer = 1; // Error
However, if you want to assign a value to the pointer, follow TartanLlama's answer using new and delete. Allocate memory first and then assign a value:
int *pointer = new int;
*pointer = 1; // OK
// delete when appropriate
I'm very new to C++ (and studying Java). This is from HW but I think I've answered the HW issue and I'm just trying to get a better sense of pointers.
Say I have the following method:
int cubed(int a) {
int * ptr;
*ptr = a * a * a;
return *ptr;
}
This compiles and works fine with the following:
int test = cubed(3);
I'm trying to get a sense of why it's bad to return a dereferenced pointer.
This question says that memory leak is a problem but I'm not sure why. Maybe because I don't understand what happens to a dereferenced pointer.
Does the lvalue just hang around indefinitely at that point? Do you have to actually delete the pointer? Any insight would be appreciated.
The question you read is different. Say you had this code:
int cubed(int a) {
int* ptr = new int;
*ptr = a * a * a;
return *ptr;
}
Now, you'd be leaking the dynamically-allocated int, because you'd return a copy of it and never delete the original.
Your code is actually worse because, instead of allocating with new, you're simply writing through an uninitialised pointer to memory that is not yours. In effect, you're writing to an int that does not exist.
What you should be doing is this:
constexpr int cubed(const int a)
{
return a*a*a;
}
Or just invoke std::pow(value, 3) at the call site.
There is no memory link in your code, but there is another big bug.
You declare int * ptr; inside the function int cubed(int a), so it is a local variable.
The value of ptr will be random - might be NULL, might point to garbage, might point to some perfectly valid address. You don't initialize the variable ptr, so your code will sometimes crash.
int* func(int *ptr)
{
static int a = 5;
ptr = &a;
return ptr;
}
Someone asked me this question in an interview. Now the point is, the variable 'a' is static, so, unlike ordinary variables which are declared, which loses it's value (popped from stack) once the function returns, this variable retains it's value as it is a static one.
Then i didn't understand, what's the issue with this piece of code?
There is no point in having ptr as a parameter. The passed value is not used. You could change this to
int* func()
{
static int a = 5;
return &a;
}
There is no issue. a is static so it exists through the lifetime of the execution. It is syntactically invisible outside func. You are just returning the address of some "hidden" global variable.
The value (address you're pointing to) of ptr that you are passing in is NOT changing outside the function as you are changing a locally scoped copy of ptr
It needs to be passed in by reference or pointer to pointer for it to change.
int* func(int **ptr)
{
static int a = 5;
*ptr = &a;
return *ptr;
}
I'm bringing back your attention for local static variables. All time the variables will be remain same from last call. So, if you increase the variable a=a+1 then next time the value is remain 6. Here come how it happens. Each local declare new space in memory in each call. But in static variable you are telling to use same memory for every time. So, pointer will remain same. That why you are getting same address. This is not unexpected.
There isn't an issue, unless the caller doesn't understand what the function does. This is quite possible, given that people may assume the function modifies the value pointed to by the parameter.
For instance, if somebody writes code like
int foo = 0;
func(&foo);
assert(foo == 5);
They will have an issue.
The interviewer may have been looking for a solution like:
int *func(int *ptr) {
static int a = 5;
*ptr = a; //modify value being pointed to by argument
return ptr;
}
There is a thread-safety issue: returning a non-constant pointer to a makes it possible that some thread will modify the value while another thread is reading it. Data races have undefined behavior.
I'll also toss in that returning a raw pointer is horrible practice, since I haven't seen it in the other answers. int& func() should be preferred.
If I have the following for example:
int *x;
x = func(a);
For the statement: x = func(a);, do we say that we are returning an address to x? Or, how exactly do we read it?
EDIT: Is it eligible to say that we are returning a pointer to x? If so, can you explain how this is done exactly? I mean, how are we returning a pointer?
x is a pointer to an int, so in other words it is the address of a memory location where an int is stored. So x = func(a) means that func returns the address of an int and stores it in the variable x.
Take care not to return the address of a local variable whose contents would be undefined after func returns.
RE: Your edit:
EDIT: Is it eligible to say that we are returning a pointer to x? If so, can you explain how is this done exactly? I mean, how are we returning a pointer?
Yes, it is certainly eligible. Try and think of and treat pointers as any other data type. Under the hood, they are just memory addresses. A pointer can be returned the same way any other data type can be returned.
Take this code for example:
int* giveMeAPointer() {
return y;
}
int* x = giveMeAPointer();
Say that "y" is declared globally as: "int* y = ...". Now the memory address being pointed to by "x" is the same as the memory address being pointed to by "y".
Now let's say that "y" was -not- declared as a pointer, but instead as a normal int (e.g. "int y = 5"). The function could do this and still be valid:
int* giveMeAPointer() {
int* result = &y;
return result;
}
*x is points to int typed variable in memory. So function func should return address to int.
int *x;
x = new int; // create your own int
*x = 5; // access - set it's value
delete x; // delete int - free memory
x = getGlobalCounter();
(*x)++; // increment global pointer
For example the getGlobalCounter function:
static int counter;
int *getGlobalCounter() {
return &counter; // return address of counter
}
But isn't always good idea to delete objects returned from functions. In that case it should result in runtime error, because of counter isn't dynamically allocated int as in top example.
If you are assigning a variable's value to the return-type of a function, then that return-type must match the variable's type. This goes the same for pointers.
So, if you have:
int* myPointer;
And...
int* func();
Then setting myPointer equal to func() will change the memory address which "myPointer" points to, to the memory address returned by func().
x is a pointer, specifically to an int. So it should be obvious that there are two memory locations used. One for the pointer and one for the memory it's pointing to (assuming the pointer is not null).
The pointer itself holds a memory address, specifically the location of the memory it's pointing to. Something like 0xa456e4fa.
Yes, func() is returning a pointer. The prototype of func would look like the following..
int * func(someObj a); //I don't know the datatype of your parameter,
//so I'm just making something up.
Notice the return type is a pointer to an int. From this and what I said previously, it should be obvious what this will return. Something of the form 0xyyyyyy, or a memory address/pointer. That memory address goes into your x pointer.
Remember that the pointer itself is not holding the data that it's pointing to, it is only the address. There's really no reason you CAN'T return a pointer. However, you do need to be careful in WHAT you return. You do not want to return the address of a local variable because that variable will go out of scope once the function has completed its execution. You'll then be returning the address of something invalid. Returning the VALUE of a local pointer however, is fine because the value you returned (the address) will be preserved as will the memory it's pointing to.
I also just realized I wrote you a book. Damn, I sure do ramble when I'm tired.
The statement just reads that x is assigned the value returned by function func. For the code to compile without errors , the func should return an address though . And for the code to execute as expected as AlexFZ pointed out , you should take care that func does not return the address of a variable local to the function.
It means that func() returns a variable of type int*.
Is it eligible to say that we are returning a pointer to x?
No, we are returning a pointer to an integer and assigning it to x since it is a pointer.
This is an example code which returns an int pointer
int* func(int a)
{
int *y = &a;
return y;
}
Okay i've seen this done somewhere before where you have a function that takes a pointer parameter and returns a pointer.
However you can choose not to pass a parameter and it will return a dynamically allocated pointer but if you do pass a pointer then it just fills it in instead of creating one on the heap. This is a single function not overloaded.
My question is how is this safely done?
I had a guess it was something like this:
point* funct(point *p = some_value)
{
if p == some_value
//create a point *p on the heap
else
//create use the given *p and fill it in
return p
}
Now i can't think if this is right way to do it and if it is then what could be a good some_value? it can't be NULL because when you pass empty pointer it will also be NULL and not sure if it is safe to have it greater than 0. Also you can't have negative numbers on pointers either, so whats a good safe value?
Any good way to do this that is also PORTABLE across platforms?
EDIT:
Okay maybe i didn't explain properly basically i want the function to be used like this:
point *x;
point *y;
x = func();
func(y);
Not
x = func(NULL);
if I use NULL i get an error segmentation fault only when i do func(y);
The reason for this is:
either the user passes a pointer he manages such as one created on the stack OR the function will give a dynamic one back if none is given. I don't want to force the return of only dynamic memory or only accepting a pointer to fill.
I know I have seen this done somewhere before.
Normal solution is to have 'if NULL allocate' - that's what 'c' realloc does.
It looks like you want to have a function that uses existing memory if provided or else allocates it's own.
It's not clear what you should return if you are passed a valid pointer.
Should it return that pointer?
Or should it be null to ensure that there aren't two copies of pointers to the same bit of memory - which will cause problems if they are freed.
It might be safer to pass a **pointer into the function and require an argument - even if that arguement is a pointer to null.
Well obviously if a someone ever was to call funct(NULL) then it would result in a crash anyway. so why not have some_value=NULL so to make
if(p==NULL){
p=dynamic_memory;
}
where dynamic_memory is allocated in the constructor(not thread-safe!) or replace dynamic_memory with a call to new
Edit:
Or. If you must have 3 states in your function, one for if no argument is supplied, one for if a valid pointer is passed, and one for if NULL is passed, then you can use pointer-to-pointers.
like
void *func(void** p=NULL){
if(p==NULL) ...//user supplied no argument
if(*p==NULL) ...//user supplied NULL
else //user supplied valid pointer
This doesn't seem to be what you want however and then people would have to pass pointers with '&' to your function.. (is &NULL even valid?)
My guess would be more along the lines of:
point* funct(point *p = NULL)
{
if (p == NULL) {
// create a point *p on the heap
// and use it
return(p);
}
else {
//use the given *p and fill it in
return(NULL);
}
}
Not too sure about having the possibility of the pointer to your point object passed in though. Could be quite hard to check for, and checking the type of an object passed in, i.e. "looking under the covers" using RTTI, is not the best OO practice.
You get an error when you call func(y) because y is not initialized. It contains random bits that point to a random location in memory. You need to initialize y to NULL.
point *x, *y;
x = func();
y = NULL;
y = func(y); // so it can be deleted later you need to assign the return value
delete x;
delete y;
Why not do this? And avoid the heap allocation completely.
point x, y;
func(&x);
func(&y);
Or:
point *x;
point *y = new point();
x = func();
func(y);
delete x;
delete y;
As I said in the comment above, memory ownership is confusing in your function. Functions that dynamically allocate their results should do so every time or none of the time. When they do so some of the time, the potential for a memory leak is much higher.
Personally, I would go even further and avoid all allocations, pass by reference:
void func(point& p)
{
//do stuff
}
point x, y;
func(x);
func(y);
something like this:
T* func(T* p) {
if(!p) {
p = new T;
}
// do whatever with p
return p;
}
then you can either do:
T* x = func(NULL);
// whatever
delete x;
or:
T x;
func(&x);
EDIT:
There is a non-thread safe option which several libraries use. Basically it works like this:
T* func(T* p) {
static T buf;
if(!p) {
p = buf;
}
// do whatever with p
return p;
}
then you can either do:
T* p = func(NULL);
or:
T x;
T* p = func(&x);
There are often "reentrant" versions of these as well which are often tied to the non-thread safe versions like this:
T* func(T* p) {
// behaves as above example, except now we can
// use func_r in a thread safe way if we need to
static T buf;
return func_r(p, buf);
}
T* func_r(T* p, T *buf) {
if(!p) {
p = buf;
}
// do whatever with p
return p;
}
You have to ask yourself why passing NULL us giving you a seg-fault. It is certainly not because NULL is not an appropriate value, it will be caused by whatever your code does when NULL is passed. However you chose not to show that code.
Haver you stepped through this code in your debugger?
Apart from that, in C++ do not use NULL. It is a macro and open to incorrect redefinition. Use plain zero (0). The language places guarantees that a zero literal constant when converted to a pointer will not be a valid address. The chances are that your NULL macro is in fact defined as zero.
If you attempt to dereference a null pointer you will get a fault.
What's the problem with using NULL? That's the general way this is handled. If you really need to distinguish between "caller passed nothing" and "caller passed NULL", then use 0xFFFFFFFF on a 32-bit system or 0xFFFFFFFFFFFFFFFF on a 64-bit system.
point * funct(point * p = (point *)(-1))
{
if (p == (point *)(-1))
{
p = new point();
}
if (p == NULL)
{
// special case handling
return NULL;
}
// fill in p
return p
}
The '-1' cast will always be the maximum pointer value as long as you are on a two's-compliment architecture. Feel free to substitute the C-style cast with a reinterpret cast if you prefer.
You should pass it NULL (have null be default...) if you want to allocate, and pass an empty pointer if you want to fill in.
As jeffamaphone commented, there is a difference between an empty pointer and NULL, use your conditional statements to check if it is an empty pointer or NULL
However you can choose not to pass a parameter and it will return a dynamically allocated pointer but if you do pass a pointer then it just fills it in instead of creating one on the heap. This is a single function not overloaded.
Instead of using default arguments, you could overload the function:
point* funct(point *p = some_value)
{
// fills p
}
point* funct()
{
return funct(new point());
}
It might not be the right way but somewhere I think in the linux libraries there was a function that works exactly like above not sure how it is allocated internally though
I'm not aware of any such function. I would guess you're thinking of realloc which takes a pointer and a size_t and then decides whether to allocate memory, adjust already allocated memory, or free memory.
Now i can't think if this is right way to do it and if it is then what could be a good some_value? it can't be NULL because when you pass empty pointer it will also be NULL and not sure if it is safe to have it greater than 0. Also you can't have negative numbers on pointers either, so whats a good safe value?
I think your confusion comes from a fundamental misunderstanding of the NULL pointer.
Observe:
int x = 5;
int* px = &x;
int* p_null = NULL;
int* p;
int* p_new = new int();
px points to x, so it's not NULL. p_null begins life as NULL which means it doesn't point to anything.
I think you're using the term "empty pointer" to refer to something like p or p_new. However, although p doesn't point to a valid object it wasn't set to NULL either. It's effectively an invalid pointer, and there is no portable way to tell that it's invalid (on some machines it may be possible to tell if something is obviously not valid, but even then it's not possible to catch all invalid pointers -- see note -- and you probably don't want to anyway -- second half).
And p_new points to a valid address in dynamic memory. It's not NULL. It's not empty. In fact, new will initialize the int to 0.
In other words, NULL is the value you pass to functions that expect a pointer to tell them you don't have a pointer. That's what it is. And there isn't really the idea of an empty pointer. Dangling pointers (either uninitialized pointers, or pointers to memory that you don't have access to) aren't NULL, because if they were NULL they wouldn't dangle. And it's impossible to validate pointers in all cases to determine if they are valid.
NOTE
Consider:
int* p_new2 = new int();
delete p_new2;
delete does not set p_new2 to NULL. So after the delete, p_new2 will have an address in the correct range for a valid pointer (meaning that Windows' VirtualQuery method will say "sure, a pointer could point there"), but will not have permission to actually dereference that memory address.
NOTE 2
This is a terribly bad idea, don't do it:
int* funct()
{
int y = 5;
return &y;
}
int* x = funct();
y ceases to exist after funct() returns. So the the pointer to y that funct() hands you points to something that doesn't exist. So you get a dangling pointer. You're not talking about doing this, but it's a common mistake, and it will bite you.
Default value is what it is — default value. There's no such thing like not passing value here. It may only happen with variable parameters count, but that's different story.
And what is an "empty pointer"?
Are you looking for this:
point* funct(point *p = some_value)
{
if (p == NULL)
return NULL;
if (p == some_value)
p = new point;
return p;
}
Okay I've decided not to use that idiom seems bad although I know one of the unix or linux system libraries had a function like that.
I'm not answering my own question but I just remembered the ctime idiom which is probably a much safer way to do what I want. I'm talking about the time() function.
Where it takes a pointer or returns a object by value.
I think it probably even gives better flexibility of returning by value, heap or stack allocation with pointer thats user controlled. I don't know why I didn't think of this before.
What do you guys thing, the ctime idiom is much better right?
Edit: Does that idiom use NULL check?
If you really wish to split them in such a way you can't accidentally provide the default function, you ought ot overload the functions.
point* funct() {
//alocate a point* p here
return funct(p);
}
and
point* funct(point *p) {
//do stuff
}