Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » address of local variable returned warning

Credits go to Jonatan Hedborg, ReyBrujo, and Tobias Dammers for helping out!
This thread is locked; no one can reply to it. rss feed Print
address of local variable returned warning
Ricardo Santos
Member #6,609
November 2005
avatar

Hi there!

[Warning] address of local variable `coords' returned

I'm having this warn from compiler. I need to have a function returning 2 values, so (as a newbie) i did this:

int *get_gif_coords(int num) {
   int coords[2];
   int line = num/30;
   int col = num%30;
   coords[0] = (TILE_W*col)+col+1;
   coords[1] = (TILE_H*line)+line+1;
   return coords;
}

So then i could set a variable to *coords and *(coords+1). Is it bad idea?
I'm having one of those stupid bugs that are a pain to find could it be because of this?

Thanks!

Jonatan Hedborg
Member #4,886
July 2004
avatar

coords is a reference (or is it a pointer?) put in the stack and is removed when the function returns. Make it an array and return the adress or put it in a a struct and return normally. The struct is prolly easier as you dont have to free it afterwards.

EDIT: oh and you could also add (oslt)

void get_gif_coords(int num, int &coords[2]) {
   int line = num/30;
   int col = num%30;
   coords[0] = (TILE_W*col)+col+1;
   coords[1] = (TILE_H*line)+line+1;
}

Tobias Dammers
Member #2,604
August 2002
avatar

Quote:

int &coords[2]

Or else just:

void get_gif_coords(int num, int *coords) {
   int line = num/30;
   int col = num%30;
   coords[0] = (TILE_W*col)+col+1;
   coords[1] = (TILE_H*line)+line+1;
}

Or, to make absolutely sure the array you pass has at least 2 members:

void get_gif_coords(int num, int *coords, int num_coords) {
   assert(num_coords >= 2);
   int line = num/30;
   int col = num%30;
   coords[0] = (TILE_W*col)+col+1;
   coords[1] = (TILE_H*line)+line+1;
}

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

ReyBrujo
Moderator
January 2001
avatar

Or return a int pointer with the address of your parameter, like

int *get_gif_coords(int num, int *coords) {
   int line = num/30;
   int col = num%30;
   coords[0] = (TILE_W*col)+col+1;
   coords[1] = (TILE_H*line)+line+1;
   return coords;
}

Or just declare the array as static:

int *get_gif_coords(int num) {
   static int coords[2];

   int line = num/30;
   int col = num%30;
   coords[0] = (TILE_W*col)+col+1;
   coords[1] = (TILE_H*line)+line+1;
   return coords;
}

--
RB
光子「あたしただ…奪う側に回ろうと思っただけよ」
Mitsuko's last words, Battle Royale

Ricardo Santos
Member #6,609
November 2005
avatar

Wow, so many ways!

Ok, thanks guys

Paul Pridham
Member #250
April 2000
avatar

Here's another one.

typedef struct
{
   int x, y;
}COORDS;

COORDS get_gif_coords(int num) {
   COORDS coords;
   int line = num/30;
   int col = num%30;
   coords.x = (TILE_W*col)+col+1;
   coords.y = (TILE_H*line)+line+1;
   return coords;
}

Arthur Kalliokoski
Second in Command
February 2005
avatar

WHAT??? coords is a local stored on the stack, when the function returns a hardware interrupt could blow it away before you use it. It needs to be static at least.

They all watch too much MSNBC... they get ideas.

Fladimir da Gorf
Member #1,565
October 2001
avatar

The returned value is a copy in this case.

OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori)

Tobias Dammers
Member #2,604
August 2002
avatar

Exactly. You return by value, just like you'd return an int. An "interrupt" that happens while in the function isn't a problem anyway, because the intr code restores the stack after execution, and jumps back to the exact same place in your function. Your code won't even notice.
However, if speed is a concern, then returning by value (for anything larger in size than a pointer) is usually frowned upon, for two reasons:
- passing readily-allocated memory space for your function to fill avoids allocating temporary memory space
- you avoid the stack access overhead for allocating the local variable
- you only pass a single pointer (4 bytes on 386+ cpu's) once, instead of returning the full-blown structure (in this case 8 bytes, but can be a lot more with larger structs or arrays)

And for the fun of it, here's another solution (C++ only):

struct COORDS {
   int x, y;

// should probably provide some ctors here...

COORDS& get_gif_coords(int num) {
   int line = num/30;
   int col = num%30;
   x = (TILE_W*col)+col+1;
   y = (TILE_H*line)+line+1;
   return *this;
}
};

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Felipe Maia
Member #6,190
September 2005
avatar

There's another way, the simplest and the better:

void get_gif_coords(int num, int *x, int *y) {
   int line = num/30;
   int col = num%30;
   &x = (TILE_W*col)+col+1;
   &y = (TILE_H*line)+line+1;
}

From tobias post you can absolutely figure this out, but it's the easier and cleaner way.

Tobias Dammers
Member #2,604
August 2002
avatar

Cleanest way, imo, is this:

typedef struct
{
   int x, y;
}COORDS;

COORDS* get_gif_coords(int num, COORDS* coords) {
   assert(coords);
   int line = num/30;
   int col = num%30;
   coords->x = (TILE_W*col)+col+1;
   coords->y = (TILE_H*line)+line+1;
   return coords;
}

This way, you pass one pointer instead of 2. The speed difference is absolutely negligible, but since it comes for free, and renders cleaner code, might as well use it. But what Felipe said is good too.
Of course, in C++ you'd use references instead of the pointer and get rid of the assert (since C++ will slap you anyway if you manage to create a NULL reference).

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Milan Mimica
Member #3,877
September 2003
avatar

Yet another ::) C++ way:

struct Coords
{
   Coords(int lx; int ly) : x(lx), y(ly) {}
   int x, y;
};

Coords* get_gif_coords(int num) {
   int line = num/30;
   int col = num%30;
   return new Coords((TILE_W*col)+col+1, (TILE_H*line)+line+1);
}

Tobias Dammers
Member #2,604
August 2002
avatar

New, but not better, nor safer. You'll be leaking memory all over before you know what hit you...

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Milan Mimica
Member #3,877
September 2003
avatar

You'll be making segmention faults if you use C/C++ before you know what hit you... Use VisualBasic if you're unable to write good C/C++ code. :P

Tobias Dammers
Member #2,604
August 2002
avatar

Nah, he's not accessing unallocated memory, he's allocating memory without freeing it. Leak, not segv. And may I suggest BASIC?

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Milan Mimica
Member #3,877
September 2003
avatar

I know. I'm saying that to write good C/C++ you need to follow some rules. Otherwise you'll end up with a leaking and segfaulting code. Memory leaks and segfaults are the consequences of the same cause - lack of coding discipline. You can't say don't use dynamic memory allocation because your memory will leak. But you can say not to use it if not necessary, like here ;D

Michael Faerber
Member #4,800
July 2004
avatar

There have been written 11 (!) solutions for this problem!

--
"The basic of informatics is Microsoft Office." - An informatics teacher in our school
"Do you know Linux?" "Linux? Isn't that something for visually impaired people?"

Paul Pridham
Member #250
April 2000
avatar

Here's one in Forth:

: get_gif_coords 
  dup 30 / 
  swap 30 mod 
  TILE_H over * + 1+
  swap TILE_W over * + 1+
;

Tobias Dammers
Member #2,604
August 2002
avatar

Quote:

There have been written 11 (!) solutions for this problem!

Hah, and we're only just getting started!

1class COORDS {
2 public:
3 COORDS(_x, _y): x(_x), y(_y) {}
4 COORDS(): x(0), y(0) {}
5 int x, y;
6};
7 
8class COORD_BUILDER {
9 public:
10 COORDS operator() (int num) {
11 int line = num/30;
12 int col = num%30;
13 return COORDS (
14 (TILE_W*col)+col+1,
15 (TILE_H*line)+line+1);
16 }
17};
18 
19COORDS get_gif_coords(int num) {
20 COORD_BUILDER cb;
21 return cb(num);
22}

Now if this isn't bloated...

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Paul Pridham
Member #250
April 2000
avatar

Tobias Dammers
Member #2,604
August 2002
avatar

You asked for it:

1#include <vector>
2 
3using namespace std;
4 
5vector<int> get_coords(int num) {
6 vector<int> result;
7 
8 int line = num/30;
9 int col = num%30;
10
11 result.push_back((TILE_W*col)+col+1);
12 result.push_back((TILE_H*line)+line+1);
13 
14 return result;
15}

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Carrus85
Member #2,633
August 2002
avatar

Another STL (probably less overhead than vector)

#include <utility>

std::pair<int,int> get_coord(int num) 
{
   return std::pair<int,int>(num/30, num%30);
}

Boost.org Tuple

#include "boost/tuple/tuple.hpp"

boost::tuples::tuple<int, int> get_coord ( int num )
{
    return boost::tuples::make_tuple(num/30, num%30);
}

Yet another possibility (assuming int is exactly half the size of a long, bitwise). This should work, but it would definately be a bad idea, portability-wize.

unsigned long get_coord ( int num )
{
    unsigned long ret = num%30;
    ret = ret << 32;
    ret = ret | (num/30);

    return ret;
}

These are all untested, but just thought I'd put up some more options...

Jonatan Hedborg
Member #4,886
July 2004
avatar

I always thought that a on most 32 bit systems, an int is the same as a signed long.

Go to: