-6

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?

Skeletor
  • 3
  • 4
  • 1
    You did not allocate any memory to return!! So that is a bad practice. However, if you would have used `malloc()` to allocate memory, then since `malloc`ed memory can be used in between function calls, then it would not have been a bad practice. – Haris Jul 12 '16 at 18:51
  • `*ret_val = 1234;` is bad all by itself. As far as you question goes if you do not use `new` then it is a dupe of http://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope – NathanOliver Jul 12 '16 at 18:52
  • 1
    Yes, to return dynamically allocated object is a bad practice, as it is more difficult to keep track of possible memory leaks – meJustAndrew Jul 12 '16 at 18:52
  • 1
    If this (returning allocated memory, not failing to allocate it) were bad practice, then `malloc` would be the worst offender. – Scott Hunter Jul 12 '16 at 18:52
  • 3
    You should pick a language because good practice in `C` can be bad practice in `C++`. Two very different languages. – Galik Jul 12 '16 at 18:59
  • I updated it to show code to demonstrate my question better and removed the C tag. Didn't realize a question could get me down votes. Thought it was a valid question. – Skeletor Jul 12 '16 at 19:28

6 Answers6

2

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.

dbush
  • 205,898
  • 23
  • 218
  • 273
2

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.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • 2
    Why would you do that? Don't teach beginners to abuse `static` like that, it's terrible practice unless you know exactly what you're doing. – interjay Jul 12 '16 at 18:58
  • @interjay I hesitated to close this as a dupe for [Can a local variable's memory be accessed outside its scope?](http://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope), because the question doesn't exactly match the situation. – πάντα ῥεῖ Jul 12 '16 at 19:01
  • Yeah, it doesn't seem like the same question. But in your answer you should probably mention that your proposed code creates a singleton (all callers share the same pointee), which is not what most functions returning a pointer are expected to do. – interjay Jul 12 '16 at 19:04
0

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.

Mattia F.
  • 1,720
  • 11
  • 21
  • I would consider returning raw pointer to dynamically allocated memory a bad practice in C++ – Slava Jul 12 '16 at 18:57
  • Yes, it is, instead he should use STL containers (instead of raw arrays) or other solutions. – Mattia F. Jul 12 '16 at 18:57
  • Well there is the tag 'c' in his answer, so i used it. Also that function is tipical in C, in C++ you should use STL. Anyway I don't any reason of downvoting this answer because of it. – Mattia F. Jul 12 '16 at 19:05
  • Yes OP should either ask C or C++ question. This is not my downvote though. – Slava Jul 12 '16 at 19:07
  • Well I was not replying to you, but to someone who just deleted his answer, saying "why malloc and not new?". – Mattia F. Jul 12 '16 at 19:09
0

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
alter_igel
  • 6,899
  • 3
  • 21
  • 40
0

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.

nosbor
  • 2,826
  • 3
  • 39
  • 63
0

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.

CygnusX1
  • 20,968
  • 5
  • 65
  • 109