Pages: 1
  Print  
Author Topic: Question on variables and arrays (important)  (Read 2077 times)
Offline (Unknown gender) Darkstar2
Posted on: May 09, 2014, 06:40:09 PM
Member
Joined: Jan 2014
Posts: 1244

View Profile Email
Ok now I understand all about variable types and how one must declare variables and the different ways to do so.
I also know that variables take memory and by declaring them it reserves memory for them at runtime right ?

Example

int a[100]

Would initialize an array of a with 99 blocks contiguous memory allocations right?

My questions are as follows.
Now this would be a static array if not mistaken.

1. What if I don't know in advance the size of my array and would like to leave it dynamic how would I go about?

2. Let's say I do not need the array anymore but want to free the memory used of a[0] to a[99]  (the array I declared), how would I do this ?

3. IS it necessary to manually free all variable and arrays before my program exits or is it done automatically ?

Logged
Offline (Male) Benxamix2
Reply #1 Posted on: May 09, 2014, 07:49:20 PM

Member
Location: Chile
Joined: Mar 2012
Posts: 69

View Profile WWW Email
I'm guessing you need to know about EDL?
If so:


1. This is done by simply not declaring the array itself, but declaring its variables within. For other languages it's different, e.g. Lua 5.1 uses "array = { }".

2. That's not quite simple. The only way to delete variables in first place is to declare local's; when the scope where you declare that local var ends, said var goes away from memory.

3. It's done automatically. This is a global method (I don't really know if it's done by the app itself or the OS): when your program shuts down, all of the memory allocated for your application becomes free. Do not confuse a program with a window, though: I'm talking about the program's process here, not its widget.



If you were asking about C++, check this link for your first 2 questions:
http://www.cplusplus.com/doc/tutorial/dynamic/
Logged
Offline (Unknown gender) Darkstar2
Reply #2 Posted on: May 09, 2014, 11:11:23 PM
Member
Joined: Jan 2014
Posts: 1244

View Profile Email
I was talking about C++ since ENIGMA is a C++ engine and your project.

Yes I was aware that that when the array loses cope it is freed, in C++. 

let's say I have Obj1 in LGM, in create event I declare a variable array a[100].  This is for obj1.  Let's say obj1 is destroyed, does that mean the memory allocated to a[100] is freed with it?

I don't want to be in a situation where I make use of extensive arrays in a program, and that when the user exits the memory is still reserved, and re-run the program, new memory is allocated, whilst the old memory allocation is still active ,etc........eventually  draining memory.

I don't know if this make sense, but don't see any other way of explaining it.
Logged
Offline (Unknown gender) Darkstar2
Reply #3 Posted on: May 09, 2014, 11:13:46 PM
Member
Joined: Jan 2014
Posts: 1244

View Profile Email
Thanks for the link, I used that site a lot in the past.

BTW, if for example I want to allocate an array of a[1000], is there a function that can tell me how much memory is reserved by a[0] to a[1000] and how much memory is used by this range as well ?

Logged
Offline (Unknown gender) TheExDeus
Reply #4 Posted on: May 10, 2014, 07:46:11 AM

Developer
Joined: Apr 2008
Posts: 1872

View Profile
Quote
1. What if I don't know in advance the size of my array and would like to leave it dynamic how would I go about?
If you want dynamic then don't use static arrays. Using "new" and "delete" is even a lot worse idea, so just use data structures instead. In ENIGMA they are like ds_grid or ds_list, while in C++ they are std::map or std::vector (vector especially being useful, as that is a dynamic array).

Quote
2. Let's say I do not need the array anymore but want to free the memory used of a[0] to a[99]  (the array I declared), how would I do this ?
If you use a ds, then there is ds_..._free or ds_..._destroy function. In C++ you CANNOT (and need not) delete a static array. It will be deleted when it gets out of the scope. Be it function (in ENIGMA called script), loop or class (in ENIGMA called object). So if you type "int a[100]" in create then it will be deleted at the end of create code (because that is how you define a temporary variable). If you type "local int a[100]" then it will only be deleted when the instance is deleted. If you want to have dynamic arrays, then use data structures. Don't use "new" or "delete" as they most often cause memory leaks.

Quote
3. IS it necessary to manually free all variable and arrays before my program exits or is it done automatically ?
No it's done automatically, as usually none of them are declared via "new", then they are all destroyed by C++ runtime when you close the process. Even if they we declared with "new" they would still be deleted, but would be called a memory leak.

Quote
let's say I have Obj1 in LGM, in create event I declare a variable array a[100].  This is for obj1.  Let's say obj1 is destroyed, does that mean the memory allocated to a[100] is freed with it?
Yes. But you have to declare it "local int a[100];" or otherwise ("int a[100]") will free the memory at the end of the Create event (or more precisely at the end of the code).

Quote
I don't want to be in a situation where I make use of extensive arrays in a program, and that when the user exits the memory is still reserved, and re-run the program, new memory is allocated, whilst the old memory allocation is still active ,etc........eventually  draining memory.
That cannot really happen. Even if you don't free any memory, the OS and the runtime will free it for you when the program ends. So it's impossible for a program to reserve memory when the process is ended. That is true universally in all modern OS's (windows, mac, linux, android), but there could still be some which doesn't do that (maybe some embedded real-time OS's specific for micro-controllers or something). http://stackoverflow.com/questions/2213627/when-you-exit-a-c-application-is-the-malloc-ed-memory-automatically-freed

Quote
I don't want to be in a situation where I make use of extensive arrays in a program, and that when the user exits the memory is still reserved, and re-run the program, new memory is allocated, whilst the old memory allocation is still active ,etc........eventually  draining memory.
If you declare a static array, then the reserved amount is the same as the memory used. So if char is 1 byte, then "char a[1000]" will reserve and automatically take 1000bytes. In C++ you can use sizeof() to determine sizes of arrays or types. http://www.cplusplus.com/faq/sequences/arrays/sizeof-array/

Also note, ENIGMA's parser is very broken now and it doesn't support pure C++ or even parts of EDL. So declaring an array with a type will probably not work (like this will probably error "int a[5]; a[0] = 0;"). So everything said in this topic applies to C++ (and the ds part applies to ENIGMA), but they are not yet interchangeable.
« Last Edit: May 10, 2014, 07:51:49 AM by TheExDeus » Logged
Offline (Male) Benxamix2
Reply #5 Posted on: May 10, 2014, 09:20:40 AM

Member
Location: Chile
Joined: Mar 2012
Posts: 69

View Profile WWW Email
If you type "local int a[100]" then it will only be deleted when the instance is deleted.

That's one thing I needed to understand, thank you!
Logged
Offline (Unknown gender) Darkstar2
Reply #6 Posted on: May 10, 2014, 11:28:48 AM
Member
Joined: Jan 2014
Posts: 1244

View Profile Email
Good stuff ! Thanks Harri.

Indeed I was declaring my variables inside create
as follows

a[300];
b[300];

So they were being disposed of at the end of the create code.

Yet my experiment still worked.   I played with arrays a little and made from scratch in GML in one step event a mini platform with recording and playback capability.  Recording would record up to 10 seconds of gameplay and playback would playback what was recorded.  Each step's x and y value would be stored in 2 arrays a and b.  So despite the array being destroyed at the end of create, how come my program worked ?

So I should have done it

local a[300]
local b[300]
instead right ?

So in other words I should NOT be using anything
in the create event that is variable declaration
such as

a = 30;
etc. 

Was I right to use this type of array for what I needed done above ? or are there better ways ?

Also what happens to variables declared in room creation code, and those created in scripts, do the ones in scripts remain active as long as the game is running, and room creation code as long as the room is active ?

« Last Edit: May 10, 2014, 11:51:10 AM by Darkstar2 » Logged
Offline (Unknown gender) TheExDeus
Reply #7 Posted on: May 10, 2014, 07:16:52 PM

Developer
Joined: Apr 2008
Posts: 1872

View Profile
There is a difference between "int a;" and "a;". So there is the same difference between "int a[300];" and "a[300];". By default (if you don't specify anything - including type) the variable (or array) is in object local scope. So when you typed "a[300];" you created an array local to the object. If you typed "int a[300];" it would be an integer array local to the script. If you typed "local int a[300];" it would be an integer array local to the object again.

Quote
local a[300]
local b[300]
instead right ?
No. Typing "a[300]" is essentially the same as saying "local a[300]" (although I think that could even be an error if you can declare it that way). You have to specify "local" only when declaring type, because in GM when you declare a type the variable becomes automatically temporary to the script (GM has only one type "var").

Quote
So in other words I should NOT be using anything
in the create event that is variable declaration
such as

a = 30;
etc. 
You can use that just fine. The only way to declare anything temporary to the script it to declare it with a type, but without "local". So if you say "a = 30;", then it will work fine and will be local to the object. If you type "var a = 30;" (or any type like "int" instead of "var") then it will be local to the script. If you type "local int a = 30;" then it will be local to object again.

Quote
Was I right to use this type of array for what I needed done above ? or are there better ways ?
No, it's ok. I usually use data structures instead of arrays. That would allow me to easily change the size (while running the game) and iterate the values easier (and/or safer).

Quote
Also what happens to variables declared in room creation code, and those created in scripts, do the ones in scripts remain active as long as the game is running, and room creation code as long as the room is active ?
Variables in room creation code are temporary to that code and are deleted when the creation ends (unless the variables are global of course). Scripts on the other hand are usually ran by objects, so if you type "a = 5;" in a script, and then execute that script from obj_a create event (or any event), then "a" would become a variable for obj_a (and its value would be 5). If you made the variable temporary (like "var a = 5;") then of course it will be temporary for the script.
Logged
Offline (Unknown gender) Darkstar2
Reply #8 Posted on: May 10, 2014, 08:19:42 PM
Member
Joined: Jan 2014
Posts: 1244

View Profile Email
So in terms of performance would I be better off using data structs ? I notice with the ds you can insert, move, copy, delete individual, find, etc, far more efficient than the arrays,
but if you have huge ds's would it be slower ?
Logged
Offline (Unknown gender) TheExDeus
Reply #9 Posted on: May 11, 2014, 06:43:13 AM

Developer
Joined: Apr 2008
Posts: 1872

View Profile
Quote
So in terms of performance would I be better off using data structs ? I notice with the ds you can insert, move, copy, delete individual, find, etc, far more efficient than the arrays,
They just have functions for that. In case of regular arrays you would have to do that yourself, so depending on your own implementation it can be both slower and faster. Usually regular arrays are faster than ds, because data structures are classes with their own overhead. So if you just want to store stuff, then regular arrays would probably be faster (even if the array is big). If you want to remove/add elements, shuffle or sort, then using a data structure would be better (mostly because they already have those functions). There is problem with current data structures though - for GM compatibility they usually don't use a regular class (the std container), but some custom one. So the performance of ds_list, for example, could be worse than using std::list in C++.

You can see std containers here: http://www.cplusplus.com/reference/stl/
They have a good information on differences between them. So you can see how std::list (which is a dynamic array) is different from std::vector (which is also a dynamic array). One is fast at inserting, other is fast at lookup, the third is fast at sorting. So depending on your need you would take the one works fastest. In ENIGMA most of the ds are std::map as far as I remember. And that is actually quite slow.
Logged
Offline (Male) Josh @ Dreamland
Reply #10 Posted on: May 11, 2014, 09:34:59 AM

Prince of all Goldfish
Developer
Location: Pittsburgh, PA, USA
Joined: Feb 2008
Posts: 2958

View Profile Email
The local and global keywords in ENIGMA, when followed by a type, begin a C++-style declaration at the instance-local or global scope, respectively.

I am still deliberating on the sanity of this behavior when it comes to arrays. Presently, local int my_int[100]; declares in the instance a C++-style array of 100 integers. This means that indices [0] - [99] are valid, while indices outside that range will cause an immediate, unrelenting, undetectable segmentation fault, in the best case. In the worst case, you'll silently break your whole game by assigning out of bounds.

What should be done about this is modifying the way arrays are treated in debug mode. That is, use a hidden, fixed-size array class behind the scenes while in debug mode. This class would report undefined behavior through the show_error mechanism.

Now that I think about it, an elegant way of dealing with it might be to create a distinction between int a[100] and int[] a;, regardless of whether we allow (unlike most languages) specifying the size in the prefix [].

As for data structures, be aware that var is a sparse matrix. This means that you can use it efficiently as an array, or a 2D map. Assigning to myvar[100000, 200000] will not significantly increase your memory usage. That said, you probably don't want local var a[100];, as this creates an array of 100 sparse matrices. You could then say [snip=EDL]a[10][10000, 15000] = 20;[snip], but the first bound would have the same limitations and dangers as previously discussed with integer arrays. Plus, it just looks weird.
« Last Edit: May 11, 2014, 09:40:15 AM by Josh @ Dreamland » Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
Offline (Unknown gender) Darkstar2
Reply #11 Posted on: May 11, 2014, 11:42:08 AM
Member
Joined: Jan 2014
Posts: 1244

View Profile Email
They just have functions for that. In case of regular arrays you would have to do that yourself, so depending on your own implementation it can be both slower and faster. Usually regular arrays are faster than ds, because data structures are classes with their own overhead.

Ok so for the example where I want to record game footage or make self playing demos, where I would store x/y for each step, and access would be sequential, then arrays would be best. 

Quote
So if you just want to store stuff, then regular arrays would probably be faster (even if the array is big). If

So let's say I want to use a big array inside a controller obj (self playing demo), and once I don't need the array anymore I destroy the controller obj instance, the memory reserved and used up by the array would be freed up right if I understood correctly ? if the array was local to the object only and not global array ?

Quote
is fast at lookup, the third is fast at sorting. So depending on your need you would take the one works fastest. In ENIGMA most of the ds are std::map as far as I remember. And that is actually quite slow.

lol.  yeah, compatibility comes with a price too! :D

But we are talking CPU cycles not GPU so the fact ENIGMA is compiled and not an interpreted runner like on GMS, would that make any significant speed difference for arrays and ds ?

Thanks Robert & Josh for the explanations :D

Using arrays 1D and 2D is something I've worked a lot with in BASIC.

« Last Edit: May 11, 2014, 11:45:34 AM by Darkstar2 » Logged
Pages: 1
  Print