Confusion regarding Pointers (SOLVED)

Started by Quintaros, Mon 20/11/2006 14:10:17

Previous topic - Next topic

Quintaros

I'm still fumbling my way through the use of pointers, structs, and arrays trying to follow some of the tutorials that have been written on the subjects.  Currently I'm stuck with the following error:
Quote
---------------------------
Adventure Game Studio
---------------------------
An internal error has occurred. Please note down the following information.
If the problem persists, contact Chris Jones.
(ACI version 2.71.894)

Error: run_text_script1: error -6 running function 'interface_click':
Error: Null pointer referenced
in Global script (line 1091)


---------------------------
OK   
---------------------------

These are the relevant sections of code:
Code: ags

//module global script
View vView[50];
export vView;



//module script header
managed struct BoxNum{
  int x1;
  int y1;
  int x2;
  int y2;
}
;

managed struct BoxType{
  BoxNum *boxnum[4];
}
;

managed struct Frame{
  BoxType *boxtype[1];  
}
;

managed struct Loop{
  Frame *frame[19];  
}
;

struct View{
  Loop *loop[15];  
}
;

import View vView[50];


And this is line 1091 that crashes the game when it runs:
Code: ags

//within global script interface-click
vView[vw].loop[lp].frame[frm].boxtype[0].boxnum[HB].x1=X1;        


Can anyone explain to me what I'm doing wrong?

SSH

AFAIK, managed structs are only applicable for plugins, not script-only code.
12

Quintaros


Janik

Try removing the "managed" keyword as well as the pointer declaration (the * ).

There is no "new" keyword in the script language so you can't make your own objects (other than by using a plug-in).
Play pen and paper D&D? Then try DM Genie - software for Dungeons and Dragons!

SSH

Basically, you can't declare pointers to user-defined types, only to built-in ones. Which means you cannot have a struct of structs, like you're trying to do.

Yes, it sucks, but there you go.
12

Quintaros

Dang...

So a plug-in is possible to handle user defined structs within structs?

monkey0506

Yes it's possible to write a plug-in to create new managed data types so that you can create pointers to your own structs (and put pointers to your structs inside of other structs as well). You'd need to read the plug-in documentation as well as know your way around a real programming language (such as C++) to write one.

As for pointers, you may find this of some use. Though it should possibly have a note added to the effect that you can't create a pointer to custom-defined structs (ATM it only says that you can create them to point to managed types and doesn't specify either way on non-managed types).

Also regarding the managed keyword, you can't actually create a real managed type within AGS scripts, some people (when writing modules; such as myself) just use the keyword to prevent users from creating instances of structs that are meant to be used statically.

Quintaros

I used your Pointers for Dummies tutorial while writing this code but I guess it wasn't quite dumbed down enough for me.Ã,  Ã,  I try to emulate sample code without truly understanding what everything does.

I don't really follow the difference between a struct and a managed struct.

Writing a plugin to address these issues is probably too far beyond my current level of understanding.

monkey0506

#8
AGS's managed types are struct types managed internally by AGS. The user cannot create new instances of these types (DynamicSprite, Overlay, and ViewFrame are exceptions, but any new instances must be created using the struct's static functions). The engine handles all the creation and deletion of these items (except DynamicSprite for which the user must explicitly release the memory by calling DynamicSprite.Delete() and/or setting all pointers to the sprite to null). The engine also sets and updates all properties of these types as necessary (though the user can also set the value for certain properties).

A non-managed struct is a custom-defined struct that the user manages. The user can create as many or as few instances of the struct as he wants or needs (within physical memory limitations). The engine won't automatically set or update any of the properties for these types (except for initializing the properties; (AFAIK) bool, char, short, int, and any enumerated types initialize to 0, Strings and pointers initialize to null); the user must explicitly set and update them within the script.

Writing a plug-in is an advanced feature, so it would probably be best to try and find an alternate method to achieve your goal.

Since you can't currently have structs within structs or multidimensional arrays, you might consider a large struct/array defined like this:

Code: ags
// module script header
#define MYVIEW_MAX 50
#define LOOP_MAX 15
#define FRAME_MAX 19
#define BOXNUM_MAX 4
#define VBOX_MAX 1140 // LOOP_MAX * FRAME_MAX * BOXNUM_MAX -- currently you can't create an array using multiplication to determine the array size, it must be defined as a constant

struct MyView {
  int x1[VBOX_MAX];
  int y1[VBOX_MAX];
  int x2[VBOX_MAX];
  int y2[VBOX_MAX];
  import bool SetX1(int loop, int frame, int boxnum, int value);
  import bool SetY1(int loop, int frame, int boxnum, int value);
  import bool SetX2(int loop, int frame, int boxnum, int value);
  import bool SetY2(int loop, int frame, int boxnum, int value);
  import int GetX1(int loop, int frame, int boxnum);
  import int GetY1(int loop, int frame, int boxnum);
  import int GetX2(int loop, int frame, int boxnum);
  import int GetY2(int loop, int frame, int boxnum);
  };

import MyView vView[MYVIEW_MAX];

// module script
MyView vView[MYVIEW_MAX];
export vView;

bool MyView::SetX1(int loop, int frame, int boxnum, int value) {
  if ((loop < 0) || (loop >= LOOP_MAX) || (frame < 0) || (frame >= FRAME_MAX) || (boxnum < 0) || (boxnum >= BOXNUM_MAX))
    return false;
  this.x1[(((loop * FRAME_MAX) + frame) * BOXNUM_MAX) + boxnum] = value;
  return true;
  }

bool MyView::SetY1(int loop, int frame, int boxnum, int value) {
  if ((loop < 0) || (loop >= LOOP_MAX) || (frame < 0) || (frame >= FRAME_MAX) || (boxnum < 0) || (boxnum >= BOXNUM_MAX))
    return false;
  this.y1[(((loop * FRAME_MAX) + frame) * BOXNUM_MAX) + boxnum] = value;
  return true;
  }

bool MyView::SetX2(int loop, int frame, int boxnum, int value) {
  if ((loop < 0) || (loop >= LOOP_MAX) || (frame < 0) || (frame >= FRAME_MAX) || (boxnum < 0) || (boxnum >= BOXNUM_MAX))
    return false;
  this.x2[(((loop * FRAME_MAX) + frame) * BOXNUM_MAX) + boxnum] = value;
  return true;
  }

bool MyView::SetY2(int loop, int frame, int boxnum, int value) {
  if ((loop < 0) || (loop >= LOOP_MAX) || (frame < 0) || (frame >= FRAME_MAX) || (boxnum < 0) || (boxnum >= BOXNUM_MAX))
    return false;
  this.y2[(((loop * FRAME_MAX) + frame) * BOXNUM_MAX) + boxnum] = value;
  return true;
  }

int MyView::GetX1(int loop, int frame, int boxnum) {
  if ((loop < 0) || (loop >= LOOP_MAX) || (frame < 0) || (frame >= FRAME_MAX) || (boxnum < 0) || (boxnum >= BOXNUM_MAX))
    return -1;
  return this.x1[(((loop * FRAME_MAX) + frame) * BOXNUM_MAX) + boxnum];
  }

int MyView::GetY1(int loop, int frame, int boxnum) {
  if ((loop < 0) || (loop >= LOOP_MAX) || (frame < 0) || (frame >= FRAME_MAX) || (boxnum < 0) || (boxnum >= BOXNUM_MAX))
    return -1;
  return this.y1[(((loop * FRAME_MAX) + frame) * BOXNUM_MAX) + boxnum];
  }

int MyView::GetX2(int loop, int frame, int boxnum) {
  if ((loop < 0) || (loop >= LOOP_MAX) || (frame < 0) || (frame >= FRAME_MAX) || (boxnum < 0) || (boxnum >= BOXNUM_MAX))
    return -1;
  return this.x2[(((loop * FRAME_MAX) + frame) * BOXNUM_MAX) + boxnum];
  }

int MyView::GetY2(int loop, int frame, int boxnum) {
  if ((loop < 0) || (loop >= LOOP_MAX) || (frame < 0) || (frame >= FRAME_MAX) || (boxnum < 0) || (boxnum >= BOXNUM_MAX))
    return -1;
  return this.y2[(((loop * FRAME_MAX) + frame) * BOXNUM_MAX) + boxnum];
  }

//within global script interface-click
vView[vw].SetX1(lp, frm, HB, X1);


That emulates your idea fairly decently though the syntax is different (not quite as readable :()

See Also: struct and multi-dim arrays, 2D arrays [A large field with interactive tiles], 3D array

[EDIT:]

Actually...seeing as a lot of the built-in structs have View properties, I'm not entirely sure this would complie. You may have to rename your struct, but aside from that it should be fine.

Of course renaming the struct would mean you would have to rename the function definitions, i.e., View::SetX1 would need to be changed to, say MyView::SetX1 (if you choose to rename the struct to MyView).

...And I decided to just rename it for you. ;)

Quintaros

Wow, Monkey.Ã,  Thank you for putting in so much effort to help me with this.

I'll try implementing your solution tonight and let you know tomorrow how it worked out. 
It seems closer to my original intent that the workaround that I'd been devising today.

I also appreciate the linked threads as it would be nice to achieve a better overall understanding of these things.

monkey0506

#10
Actually I linked them because I had to look up the formula myself. :D

For an array like:

Code: ags
int arr[5][10];


You make it:

Code: ags
int arr[50]; // 5 * 10


Then to access arr[ a ][ b ]:

Code: ags
arr[(a * 10) + b]; // (A_INDEX * B_MAX) + B_INDEX


For a 3D array the forumla is like this:

(((A_INDEX * B_MAX) + B_INDEX) * C_MAX) + C_INDEX

Etc., etc. for each additional array dimension needed.

And I'm always glad to help whenever I can. It makes me feel useful and all warm and fuzzy inside! ;)

[EDIT:]

I've added further description of what managed types are to the pointer tutorial:

QuoteAGS's managed types are those discussed in the next section. You cannot create a new managed type within AGS's scripts; to create a new managed type you would need to write a plugin. Some module writers may use the keyword managed to prevent users from creating instances of structs that are meant to be used statically. This does not however make the type managed. Only AGS's built-in managed types and any managed types created via plugins are actually managed, and therefore are the only types that can have pointers to them.

Quintaros

Just thought I'd let you know that your code worked perfectly when I cut and paste it into my script.Ã, 

When I tried to tweak it a little, it stopped compiling properly so there is still some gaps in my understanding but I think the example will serve well in the future.

Thanks again.

Khris

It's possible to shorten that code a bit:
Code: ags
// module script
MyView vView[MYVIEW_MAX];
export vView;

bool invalid(int loop, int frame, int boxnum) {
  if ((loop < 0) || (loop >= LOOP_MAX) || (frame < 0) || (frame >= FRAME_MAX) || (boxnum < 0) || (boxnum >= BOXNUM_MAX))
    return true;
  return false;
}

bool MyView::SetX1(int loop, int frame, int boxnum, int value) {
  if (invalid(int loop, int frame, int boxnum))
    return false;
  this.x1[(((loop * FRAME_MAX) + frame) * BOXNUM_MAX) + boxnum] = value;
  return true;
}

...


It should even be possible to use
Code: ags
bool invalid(int loop, int frame, int boxnum)
  return ((loop < 0) || (loop >= LOOP_MAX) || (frame < 0) || (frame >= FRAME_MAX) || (boxnum < 0) || (boxnum >= BOXNUM_MAX));

monkey0506

I don't know that you can define functions without braces...I've never seen it done that way in any case.

But seeing as I prefer keeping things together:

Code: ags
struct MyView {
  // blah
  import static bool IsIndexInvalid(int loop, int frame, int boxnum);
  };

static bool MyView::IsIndexInvalid(int loop, int frame, int boxnum) {
  return ((loop < 0) || (loop >= LOOP_MAX) || (frame < 0) || (frame >= FRAME_MAX) || (boxnum < 0) || (boxnum >= BOXNUM_MAX));
  }

bool MyView::SetX1(int loop, int frame, int boxnum, int value) {
  if (MyView.IsIndexInvalid(loop, frame, boxnum)) return false;
  this.x1[(((loop * FRAME_MAX) + frame) * BOXNUM_MAX) + boxnum] = value;
  return true;
  }

// etc.


That's just a matter of preference though, not actually any difference in the way it works (except Khris accidentally put "if (invalid(int loop, [etc.]" instead of "if (invalid(loop, [etc.]").

Quintaros if you need help figuring out how to customize it, post here or PM me and I'll see what I can do to help you out. ;)

SMF spam blocked by CleanTalk