I've been trying to learn some C++ for a project of mine, but it is giving me quite a headache.
I have a function where I want to initialize an int array, do some calculations on it and then return it, but I'm having a hard time figuring out exactly how to do it.
So far I have this (just a test function):
But I get the warning: "Address of local variable 'x' returned". I've been reading up on that and I have an idea why but I can't see how to return the array then. I've been looking through tutorials and books and searched on Google, but I can't find anything about returning arrays from functions.Code:class Test { int* func() { int x[1]; x[0] = 2; return x; } }
Another problem I'm having, is with assigning an object to an array. Say for example that I have a class called Tile, and I want an array of Tiles, run through the array and create each new tile with the constructor Tile(int x). That would give me something like this:
But then I get the error: "expected unqualified-id at end of input".Code:#include "Tile.hpp" class Test { void func() { Tile tst[1]; tst[0] = Tile(5); } }
I am rather confused as how to create an object in C++. I tried out the previous approach, and looking in a book, it said to use tst[0] (5). Btw, I'm using 2 lines in this case, because in reality I have my "Tile tst[1]" in my header file, and want to create the objects in my cpp file.
Also, studying C++ and trying to fix previous errors, I have found out some things which I would like someone to tell me if I hav e understood them correctly. I am not certain I found the right way to do things.
It is especially pointers and arrays that confuse me. I've read that they are not the same, but I have also found out that I can apparently not use empty arrays as a return for function, or as a parameter, instead I need to use pointers. So not like this:
but like this instead:Code:class Test { int[][] func(int[][] x) { } }
Also, from what I've understood so far, whenever I make a variable with some object type, like Tile t; it automatically creates an object of the Tile class using the default constructor. Therefore, if I have made any constructors, I also need to add the default constructor for it to work. Is that also correct?Code:class Test { int** func(int** x) { } }
Thanks to whomever will help me, in advance.
Here's the problem, because x is a local variable, the space it occupies will be reclaimed and used for something else. Also, an array name is a pointer, so you are returning the address of a memory location that could be used for anything.
You need to declare the variable in the calling function and pass it as a parameter.
When you declare tst, each object in the array is created using the default constructor with no parameters. I would just create an initialization function and call it using tst[0].init(5);
Another problem I'm having, is with assigning an object to an array. Say for example that I have a class called Tile, and I want an array of Tiles, run through the array and create each new tile with the constructor Tile(int x). That would give me something like this:
But then I get the error: "expected unqualified-id at end of input".Code:#include "Tile.hpp" class Test { void func() { Tile tst[1]; tst[0] = Tile(5); } }
I am rather confused as how to create an object in C++. I tried out the previous approach, and looking in a book, it said to use tst[0] (5). Btw, I'm using 2 lines in this case, because in reality I have my "Tile tst[1]" in my header file, and want to create the objects in my cpp file.
An array such as int t[5] is NOT a pointer, however the name of the array, t, IS a pointer to the first element of the array. The difference is that if you try to increment t, you will get a compiler error, but if you declare a regular pointer and initialize it as t, you can increment the regular pointer.
Also, studying C++ and trying to fix previous errors, I have found out some things which I would like someone to tell me if I have understood them correctly. I am not certain I found the right way to do things.
It is especially pointers and arrays that confuse me. I've read that they are not the same, but I have also found out that I can apparently not use empty arrays as a return for function, or as a parameter, instead I need to use pointers. So not like this:
but like this instead:Code:class Test { int[][] func(int[][] x) { } }
Code:class Test { int** func(int** x) { } }
Don't feel bad about being confused. LOTS of people find arrays and pointers confusing.
That is correct.
Also, from what I've understood so far, whenever I make a variable with some object type, like Tile t; it automatically creates an object of the Tile class using the default constructor. Therefore, if I have made any constructors, I also need to add the default constructor for it to work. Is that also correct?
Thanks to whomever will help me, in advance.
When you make an array, or any local variable in a function, that object is destroyed when the function returns. So if you return a pointer to that object, after the function returns, the pointer points to invalid memory. That's what the warning tells you.But I get the warning: "Address of local variable 'x' returned".
If you want a function to return an array, the array has to exist outside of the function. In your class Test it might be like this:
x is a part of a Test object, so basically as long as you can call the method on that object, the array will exist and can be returned. Other options are making the array static within func, or making the array global. A common way around this is to take the array as a parameter and not worry about returning it:Code:class Test { int x[1]; public: int* func() { x[0] = 2; return x; } };
Arrays are passed by pointer, so you can change the elements and it'll still work as expected:Code:class Test { public: void func(int x[]) { x[0] = 2; } };
Code:#include <iostream> using namespace std; class Test { public: void func(int x[]) { x[0] = 2; } }; int main() { Test t; int a[1] = {5}; cout << a[0] << '\n'; t.func(a); cout << a[0] << '\n'; }Assuming the Tile class has both a default constructor and a one argument constructor, the only error in that code is not terminating the class definition with a semicolon:But then I get the error: "expected unqualified-id at end of input".
Code:#include "Tile.hpp" class Test { void func() { Tile tst[1]; tst[0] = Tile(5); } };That'll give you a syntax error. You had it the right way in your example. You can also use the array initialization list:looking in a book, it said to use tst[0] (5)
Code:class Test { void func() { Tile tst[1] = { Tile(5) }; } };You can't return an array in C++ period. The closest you can get is returning a pointer to the array:I have also found out that I can apparently not use empty arrays as a return for function, or as a parameter, instead I need to use pointers.
This isn't a common idiom because it's easier to pass the array as a parameter instead of adding a level of indirection so that you can return an array.Code:#include <iostream> using namespace std; int array[5] = {0, 1, 2, 3, 4}; int (*function())[5] { return &array; } int main() { int (*a)[5] = function(); int *b = *a; for (int i = 0; i < 5; i++) cout << b[i] << '\n'; }
You can also return an array by reference, and that drastically cleans up the syntax for using the return value, but the syntax for declaring the function is still obscure:
When passing an array to a function, the first dimension turns into a pointer. An array of int turns into a pointer to int, an array of arrays of int--a 2D array--turns into a pointer to an array of int, an array of arrays of arrays of int--a 3D array--turns into a pointer to a 2D array. Any more than 3 dimensions and you might have a design problem.Code:#include <iostream> using namespace std; int array[5] = {0, 1, 2, 3, 4}; int (&function())[5] { return array; } int main() { int *a = function(); for (int i = 0; i < 5; i++) cout << a[i] << '\n'; }
Here's those three in code:
But that's kind of hard to type, so C++ allows you to use a full array notation instead of manually converting the first dimension into a pointer. This is the exact same thing, just a different syntax:Code:const int MATS = 3; const int ROWS = 3; const int COLS = 3; void function1(int *array1D); void function2(int (*array2D)[COLS]); void function3(int (*array3D)[ROWS][COLS]); int main() { int a[ROWS]; int b[ROWS][COLS]; int c[MATS][ROWS][COLS]; function1(a); function2(b); function3(c); }
The size of the first dimension isn't needed because it's not used. Your compiler will just turn the second syntax into the first syntax and ignore any size you give for the first dimension.Code:const int MATS = 3; const int ROWS = 3; const int COLS = 3; void function1(int array1D[]); void function2(int array2D[][COLS]); void function3(int array3D[][ROWS][COLS]); int main() { int a[ROWS]; int b[ROWS][COLS]; int c[MATS][ROWS][COLS]; function1(a); function2(b); function3(c); }
Yes, in particular when you create an array, all of the elements of that array are default constructed, so your class has to have a zero argument constructor.Therefore, if I have made any constructors, I also need to add the default constructor for it to work. Is that also correct?
When you declare the function test every variable initialized inside are temporary. They are destroid once you leave the function. So you cannot return a variable that no longer exists. To solve this problem you have two aproaches.
You can declare the array before you call the function and pass a function as an argument.
example:
Or you can declare x inside the classCode:class Test { const int* func(const int *x) { x[0] = 2 return x; } }; int main() { Test t; int y[1]; t.func(y); return 0; }
The second question is that you are initialzing data with the wrong expression.Code:class Test { int x[1] const int* func(void) { x[0] = 2 return x; } }; int main() { Test t; cout << t.func(); // and cout << t.x; return 0; }
Code:class Tile { private: Tile(); int _x; public: Tile(int x) { _x = x; } }; class Test { void func() { Tile tst[1] = { Tile(5) }; // The right way } }; int main() { }
PS: Tip to the webmasters. You should have a warning system for threads that have been modified between posting as we can loose context or repeat ourselves.
Have a look at kpgen at sourceforge
Neither Emacs or Vi are my primary editors...
..and I'm not ashamed!!!
This is why I signed up for this place, good help from nice, friendly, understanding people.I think I can get it all to work with all this advice, but I have a question about something CPD said.
He mentions making my array static or global to overcome one of my problems. How will it being static help me? As far as I know, all static does is to make the array class dependant so that all objects of a class will share the same array. And as for global, isn't that exactly what I'm doing by putting the array outside any functions but inside the class, like this:
Oh, and birinight, if your P.S. was because you all posted similar answers to me, I have to say I rather like that. Not only does it tell me for sure how to do things or how not to, and what's possible and impossible, but it will also give me a lot of ways of solving a problem since different people usually come up with different solutions, and so I have the luxury of choosing the solution I find to fit my code best.Code:class Test { int x[1]; int* func() { x[0] = 2; return x; } }
static is an overloaded keyword, it means different things in different places. The static I was talking about is a local static variable:How will it being static help me? As far as I know, all static does is to make the array class dependant so that all objects of a class will share the same array.
When you make a local variable static, it says that the object will persist between calls of the function. This is a way to get around the problem of the array being destroyed when the function returns. If the array is required to persist between calls, you can safely return a pointer to it.Code:#include <iostream> using namespace std; int *function() { static int a[] = {1, 2, 3, 4, 5, -1}; return a; } int main() { int *p = function(); while (*p != -1) cout << *p++ << '\n'; }
It's the same idea, but having a static or non-static member of the class instead of a global variable is a better design. Global variables are immediately useful because they're visible everywhere, but maintaining them and troubleshooting problems that involve them are more difficult for the same reason.And as for global, isn't that exactly what I'm doing by putting the array outside any functions but inside the class
A static variable is a variable that doesn't have its memory reclaimed/overwritten when it goes out of scope. As a result, for example, you can have a static variable in a function that increments each time you enter so you can keep track of how many times the function was called.
I think, that the best solution is to use dynamic allocation:
But don't forget to free the memory outside the function.Code:class Test { int* func() { int x = new int[1]; x[0] = 2; return x; } }
That's why it's not necessarily the best solution. If you write a function that allocates memory and returns a pointer to it, you can't expect the caller to free that memory. This solution is convenient for you, but it's a high probability memory leak waiting to happen.But don't forget to free the memory outside the function.
The accepted "best" solution in general is requiring the caller to provide an array and then you work with it:
This is better because if the caller has to allocate memory, there's a better chance that the caller will also remember to free it.Code:class Test { int* func(int *x) { x[0] = 2; return x; } }
I do disagree. It's cool, if the caller knows how much memory the function needs, but in some cases It can break good OOP design, if we are talking about C++.
There are currently 1 users browsing this thread. (0 members and 1 guests)
Bookmarks