May 15, 2024, 06:01:02 PM

News:

IonicWind Snippit Manager 2.xx Released!  Install it on a memory stick and take it with you!  With or without IWBasic!


Pointers

Started by Andy, November 12, 2015, 06:22:31 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Andy

Hi everyone,

After my failed attempt at using pointers, i'ts time to go back to basics whith this one.

Firstly, I don't use them, but would like to understand them better.

So, here is my first question....

Why when I define a udt as:

TYPE MYUDT
    def across as int
    def down as int 
    DEF name as STRING
ENDTYPE

DEF pUdt as POINTER

pUdt = NEW(MYUDT,100)

I only get the first letter of the strings or no letter at all, code here...


int y

TYPE MYUDT
    def across as int
    def down as int 
    DEF name as STRING
ENDTYPE

DEF pUdt as POINTER

pUdt = NEW(MYUDT,500)

SETTYPE pUdt, MYUDT

#pUdt.name[1] = "First entry."
#pUdt.name[2] = "Joe Smith"
#pUdt.name[3] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
#pUdt.name[4] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
#pUdt.name[5] = "cccccccccccccccccccccccccccccccccccccccccccccc"
#pUdt.name[6] = "dddddddddddddddddddddddddddddddddddddddddddddd"
#pUdt.name[7] = "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
#pUdt.name[8] = "ffffffffffffffffffffffffffffffffffffffffffffff"
#pUdt.name[9] = "gggggggggggggggggggggggggggggggggggggggggggggg"
#pUdt.name[10] = "Last entry."


openconsole
print

for y = 1 to 10
#pUdt.across[y] = y
#pUdt.down[y]   = y
   print y," = ",#pUdt.name[y]," - ",#pUdt.across[y],#pUdt.down[y]
next y

do:until inkey$ <> ""
closeconsole

DELETE pUdt

end


When I chage the string definition to...

TYPE MYUDT
    def across as int
    def down as int 
    DEF name[1] as STRING
ENDTYPE

or

TYPE MYUDT
    def across as int
    def down as int 
    DEF name[255] as STRING
ENDTYPE

i.e. any number,the program displays the full strings:

"aaaaaaaaaaaaaaaaaaaaaa"
"bbbbbbbbbbbbbbbbbbbbb" etc.

Why?

Thanks,
Andy.




Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

Egil

I have almost no experience using pointers myself, but some years ago Allan, who also is a member of this forum, posted this explanation on the MiniBASIC Forum:

Quote
RE: Need POINTER help  

Pointers are not difficult once they are understood.

I see them as a variable just like the other types. INT, UINT, FLOAT, CHAR, STRING, POINTER.

INT has numbers that can be negative or positive,
UINT has positive numbers
FLOAT has decimal numbers
CHAR has character
STRING has text
POINTER has Address.

INT num = 12 ' compiler puts 12 in the num variable - Num has an address in memory

POINTER ptr
ptr = &num

ptr holds an address - the address where Num is in memory,

PRINT num will print 12 as the compiler obtains the Address of num and retrieves the value.

PRINT #<INT>ptr will print 12 as the compiler will obtain the address stored in ptr and use it to go to num address rand retrieve the value.

That is how I look at pointers to understand how they work.
They really hold an address in memory.  


Hope this can help you solvle  your problems.


Egil
Support Amateur Radio  -  Have a ham  for dinner!

LarryMc

Andy
You are not using pointers properly.
It's sort of like you are comparing apples to oranges to peaches.
It's 1AM here now(I've been spending too much time with my new toy...a CNC machine.. and I'm going to bed)
Tomorrow I will explain(as best I can) what you are doing wrong and why it is causing you to see what you are seeing.
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

ckoehn

November 13, 2015, 09:06:36 AM #3 Last Edit: November 13, 2015, 09:52:39 AM by ckoehn
This is probably wrong, but here goes...

Take this for instance:

TYPE MYUDT
   int across
   int down
   string name 'allots a 254 char array
ENDTYPE

pointer p 'same as DEF p as pointer, this is less typing
MYUDT mUDT 'same as DEF mUDT as MYUDT

p=mUDT   'p is pointing to the mUDT variable, this is what the help file says.
'p=&mUDT 'this is what I would have thought it should be.  & means "address of".

'According to the help file this SHOULD work
SETTYPE p, MYUDT 'let pointer know what type

int curAcross, curDown 'variables to
string mystring '

curAcross=#p.across
curDown=#p.down
mystring=#p.name

DELETE p 'Delete pointer

I made some changes after I read the help file.. :-[

Later,
Clint

P.S.  I would like to see LarryMc explaination.

LarryMc

Before I get too far along in this let me say it took me a long, long time to accept the phrase " pointers are your friend ".  With pointers I have been able to do some things I would not have been able to do otherwise; like build IWB+ for one. Secondly, I am NOT an expert when it comes to pointers. I manage to figure out enough to do what I want to get done with them and that's about it.  That being said, my following explanation may not be pure text book in every case but it is in words that allows me to functionally understand what is going on and use pointers and I hope it will do the same for some of you.

I'll start with the simplest variation of the problem presented by Andy and picked up by Clint and build from there.
TYPE MYUDT
    int across
    int down
    string name 'allots a 254 char array
ENDTYPE

pointer p 'same as DEF p as pointer, this is less typing
MYUDT mUDT 'same as DEF mUDT as MYUDT

p=mUDT   'p is pointing to the mUDT variable, this is what the help file says.
'p=&mUDT 'this is what I would have thought it should be.  & means "address of".

'p=&mUDT      'this is what I would have thought it should be.  & means "address of".
Clint made the above comment - the reason we don't use this version of the statement is
because structure type variables are passed by reference(pointer to their memory location)
The same would be true if our variable was one of the string types

'According to the help file this SHOULD work
SETTYPE p, MYUDT 'let pointer know what type

SETTYPE is optional but it will sure save a bunch of typing
if you don't use it then everywhere you refer to the 'p' pointer you will have to type
   #<MYUDT>p.
if you do use it then can get by with typing
   #p.
like I said, it can save a lot of typing. There are some rules in using it.
SETTYPE has to be executed before any reference to the pointer is made.
The SETTYPE has to be re-executed across subroutine and module(file) boundaries.

int curAcross, curDown 'variables to
string mystring '

curAcross=#p.across
curDown=#p.down
mystring=#p.name

DELETE p 'Delete pointer

It is very important that when you are through with a pointer that you clean up memory.
Failure to do this will cause a "memory leak".
What I'm not sure of is whether or not DELETE is required for pointers that,
like this example, don't involve the NEW command.
I don't think it is required here but it doesn't hurt.

so, for a working example:

Compile as a Console Exec
TYPE MYUDT
    int across
    int down
    string name 'allots a 254 char array
ENDTYPE

pointer p 'same as DEF p as pointer
MYUDT mUDT 'same as DEF mUDT as MYUDT

p = mUDT    'p is pointing to the mUDT variable

SETTYPE p, MYUDT 'let pointer know what type

#p.across = 34
#p.down = 123
#p.name = "John Brown"

print
    print #p.across,#p.down," ",#p.name
print
print "Press any key to quit"

waitcon

DELETE p
end


I'll build upon this example in the next installment
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

ckoehn

Thanks LarryMc for your explanation. Makes sense to me.

I either didn't know or forgot that structure types were passed by reference like string types were.

Waiting for the next installment...

Later,
Clint

LarryMc

The next step we'll take in expanding our little sample program in the direction of Andy's original post is
the use of the NEW command

In the previous sample program we had this line
p = mUDT
we're now going to change it to
p = NEW(MYUDT,5)
--we no longer need this line
MYUDT mUDT
so it can be removed--
By definition when we use the NEW command in this manner we defining an array (p) of 5 pointers that point to 5 mUDT structures.
remembering that arrays are indexed starting at 0 we can initialize  the contents of our 5 structures
with the following routine:
int x
for x = 0 to 4
   #p[x].across = 34 + x
   #p[x].down = 123 + x
   #p[x].name = "John Brown"+str$(x)
next x

then to print the contents
for x = 0 to 4
   print #p[x].across, #p[x].down," ", #p[x].name
next x


so, for a working example:

Compile as a Console Exec
TYPE MYUDT
    int across
    int down
    string name 'allots a 254 char array
ENDTYPE

pointer p 'same as DEF p as pointer
MYUDT mUDT 'same as DEF mUDT as MYUDT

p = NEW(MYUDT,5)    'p is pointing to the mUDT variable

SETTYPE p, MYUDT 'let pointer know what type

int x
for x = 0 to 4
   #p[x].across = 34 + x
   #p[x].down = 123 + x
   #p[x].name = "John Brown"+str$(x)
next x

print
for x = 0 to 4
   print #p[x].across, #p[x].down," ", #p[x].name
next x
print
print "Press any key to quit"

waitcon

DELETE p
end


We'll build upon this example in the next installment
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Andy

Good explanation Larry thanks for taking your time to post it,
I now see why I was getting the array side of things wrong.

Andy.
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

Andy

December 05, 2015, 03:44:01 AM #8 Last Edit: December 05, 2015, 03:47:55 AM by andy1966
The above example is very good, and I have got it with pointers now.

But here is a question:
The above example is working with a UDT, and  
#p[x].name = "John Brown" - works.

When I'm using a fixed type STRING I have to use this notation:
#<STRING>astring[0,0] = "First"

Where [0 = entry / index number and 0] for the characters in the string.

I would have thought that maybe
#p[x].name = "John Brown"  

should be...
#p[x,0].name = "John Brown" ?

#p[x,0].name = "John Brown" does actually work, I can only assume the compiler "knows" that .name is a string and essentially does the same thing as #p[x,0] ?

Anyway it's just a question, and I'm happy with both:
#p[x,0].name = "John Brown AND
#<STRING>astring[0,0] = "First"

It's just the difference in notation between fixed type and udt I was wondering about and I will have to remember it.

Thanks,
Andy.



Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

LarryMc

Don't confuse the two.
think of it this way (which may not be technically correct but it's the way I keep it straight)
pointers to string arrays are handled the way they are because there has to be a way to distinguish between single and multi dimension arrays AND varying lengths
that's the first part that we learned from the previous discussion.

now with a UDT's things are just a bit more complicated(or can be)

let's start easy
TYPE MYUDT
    int a
    string name
ENDTYPE

pointer p
MYUDT mUDT

p = NEW(MYUDT,5)
SETTYPE p, MYUDT

int x
for x = 0 to 4
   #p[x].a = 34 + x
   #p[x].name = "John Brown"+str$(x)
next x

print
for x = 0 to 4
   print #p[x].a, " ", #p[x].name
next x
print
print "Press any key to quit"

waitcon

DELETE p
end

that's basically the same as we did before
now, let's make our 'a' element an array of 5 int
and things will look like this
TYPE MYUDT
    int a[5]
    string name
ENDTYPE

pointer p
MYUDT mUDT

p = NEW(MYUDT,5)
SETTYPE p, MYUDT

int x
for x = 0 to 4
   for y=0 to 4
      #p[x].a[y] = 34 + x+y
   next y
   #p[x].name = "John Brown"+str$(x)
next x

print
for x = 0 to 4
   for y = 0 to 4
      print #p[x].a[y],
   next y
   print " ", #p[x].name
next x
print
print "Press any key to quit"

waitcon

DELETE p
end

The thing to note is that the array index "x" has nothing to do with the index 'y'.
In other words what happens on the left side of the "." is the parent and on the right side is the child.
With that in mind we'll go back and change our structure back so 'a' is a simple int but we'll make  name a pointer to an STRING

TYPE MYUDT
    int a
    POINTER name
ENDTYPE
/*SEE IF YOU CAN FIGURE IT OUT FROM HERE----I'M GOING TO BED  ;D */
pointer p
MYUDT mUDT

p = NEW(MYUDT,5)
SETTYPE p, MYUDT

int x
for x = 0 to 4
   #p[x].a = 34 + x
   #p[x].name = "John Brown"+str$(x)
next x

print
for x = 0 to 4
   print #p[x].a, " ", #p[x].name
next x
print
print "Press any key to quit"

waitcon

DELETE p
end

LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Andy

Larry,

Thanks for all that, especially late at night!

Managed to read the strings:


string Text

TYPE MYUDT
    int a
    pointer name
ENDTYPE
/*SEE IF YOU CAN FIGURE IT OUT FROM HERE----I'M GOING TO BED  ;D */
pointer p
MYUDT mUDT

p = NEW(MYUDT,5)
SETTYPE p, MYUDT

int x
for x = 0 to 4
   #p[x].a = 34 + x
   #p[x].name = "John Brown"+str$(x)
next x

openconsole
print

for x = 0 to 4
   print #p[x].a, " ", #p[x].name
   Text = GetTheString(#p[x].name)
   print "Actual string is - ",Text
   print
next x

print
print "Press any key to quit"
waitcon

DELETE p
end

SUB GetTheString(pointer ToTheString),string
    string ActualString
    ActualString = #<string>ToTheString
RETURN ActualString
ENDSUB


I had to do that in a sub routine.

Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

Andy

I can also do it this way:

   pointer apointer
   apointer = #p[x].name
   print #<string>apointer


But not:
   print #<string>#p[x].name







Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

LarryMc

And the answer is ( drum roll......)
TYPE MYUDT
    int a
    pointer name
ENDTYPE
/*SEE IF YOU CAN FIGURE IT OUT FROM HERE----I'M GOING TO BED  ;D */
pointer p

p = NEW(MYUDT,5)
SETTYPE p, MYUDT

int x
string temp
for x = 0 to 4
   #p[x].a = 34 + x
temp = "John Brown"+str$(x)
/* the 'temp' variable is used to allocate memory for the string and get rid of the following warning
Warning: Temporary string assigned to POINTER, possible memory loss
*/
   #p[x].name = temp
next x

openconsole
print

for x = 0 to 4
   print #p[x].a, " ", #p[x].#<string>name   '<== name is a pointer so you have to tell it what type of data it contains
   print
next x

print
print "Press any key to quit"
waitcon

DELETE p
end


LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Andy

December 06, 2015, 10:14:56 PM #13 Last Edit: December 06, 2015, 11:50:27 PM by andy1966
Well that pulled a rabbit out of the hat.

Just one problem...

for x = 0 to 4
  print #p[x].a, " ", #p[x].#<string>name
  print
next x


Prints "a" correctly i.e. 34, then 35, and all the way up to 38.

"name" just returns "John Brown 4" five times? instead of
"John Brown 0"
"John Brown 1"
"John Brown 2" etc.

I changed the FOR to go to 3 instead of 4, and now it just prints
John Brown 3, so it's only ever printing the last string x number of times.

I can work out so far, the pointer remains the same, so all instances of "John Brown (x)" are being saved to the same memory location (the one for "temp").

If you change the code to:
int x
string temp[5]
openconsole

for x = 0 to 4
  #p[x].a = 34 + x
temp[x] = "John Brown"+str$(x)
  #p[x].name = temp[x]
next x


it works because each "temp x"  has a unique memory location.

Thanks,
Andy.

Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

LarryMc

you got it "Toyota"  ;D
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Andy

You're a good teacher Larry!

;D

Andy.
:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

LarryMc

we're still not through, though.

you hard coded (predefined)the 'temp' array

can you figure out how to do it defining the temp array with the NEW command?
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Andy

Larry,

I did wonder why you added string called temp when we were talking about pointers.

So hopefully this is the right answer:

POINTER temp
temp = NEW(string,5)

openconsole

for x = 0 to 4
   #p[x].a = 34 + x
   #temp[x,0]= "John Brown"+str$(x)
   #p[x].name = #temp[x,0]
   print #p[x].name
next x


and DELETE temp at the end.

Also, with the print command added, I can see pointers have a "gap" of 255 which is the correct amount of "space" for a string.

Andy.
:)



Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

LarryMc

POINTER temp
temp = NEW(string,5)

openconsole

for x = 0 to 4
   #p[x].a = 34 + x
   #<string>temp[x,0]= "John Brown"+str$(x)
   #p[x].#<string>name = #<string>temp[x,0]
   print #p[x].#name
next x
'.....

DELETE temp
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Andy

December 08, 2015, 05:15:03 AM #19 Last Edit: December 08, 2015, 05:31:34 AM by andy1966
Okay, I added the SETTYPE command to the code because....

QuoteSETTYPE is optional but it will sure save a bunch of typing
if you don't use it then everywhere you refer to the 'p' pointer you will have to type
  #<MYUDT>p.
if you do use it then can get by with typing
  #p.
like I said, it can save a lot of typing.

settype temp,string

And then did away with the <STRING> references, the program worked as it did before.

As far as my two brain cells allow me to try and understand the example we are talking about....

#p[x].name = #temp[x,0]

means to me, the string "John Brown 0" is placed in memory starting at "p
  • .name" (memory location start point) for 254 consecutive locations.

    With the last example you posted:
    1. There is a compiler error for the line...

    Quoteprint #p
    • .#name
    ... "Typecast must be specified"...

    When you change the notation to...

    print #p[x].#<string>name

    It prints "<null>".

    2. The line...
    #p[x].#<string>name = #<string>temp[x,0]

    confuses me, as "name" is a pointer and "temp" is a string.

    3. If you leave out out the "type" (<string>) for one pointer like this...
    #p[x].#name = #<string>temp[x,0]
    you get another Typecast error.

    4. If you leave out all references (in this section of code) to <string>, it compiles and runs correctly.

    5. If you then print
    for x = 0 to 4
       print "Output - ",#p[x].a, " ",#p[x].#<string>name   '<== name is a pointer so you have to tell it what type of data it contains
    next x


    You get "John Brown 0", "John Brown 1" etc....

    6. If you change it to...
    for x = 0 to 4
       print "Output - ",#p[x].a, " ",#p[x].#name   '<== name is a pointer so you have to tell it what type of data it contains
    next x

    You just get the pointer reference, which is what I would expect.

    So to recap, I'm not sure if my two brain cells answer is matching up to what you thought they would do, remember I only have two!

    Division by zero error!

    Thanks,
    Andy.
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

LarryMc

1st, the line in my previous post where there was a missing <string> before name was a typo on my part.

Aside from that typo, look carefully at your code you posted in your last post.

What can we learn from it?

In our structure we have defined two variables:
"a" with a type of "int".
"name" with a type of "pointer".

Then we have this line
p = NEW(MYUDT,5)
What exactly have we done at that point.
We've set aside memory to hold 5 copies of our structure and placed the starting location of that memory in p.
how much memory did we set aside?
well INT's take 4 bytes each so that's 20 bytes and pointers also take 4 bytes so that's another 20 for a  total of 40 bytes.

we know we want to use "name" to store string data but we sure have created enough memory for that yet.
you already know very well about string data being shuffled around by its memory address via a pointer.
but our extra pointer has thrown a monkey wrench in the works
If you look at your code there is no where that memory is being set aside for the string data to be stored in "name".
There's no NEW statement and to be honest I don't have a clue as to how to create a nested NEW statement to handle the structure itself and then a pointer to a variable inside the structure.

So the overall lesson to learn from this last little exercise is don't put POINTERs in structures unless you are using it just to just to pass a pointer created in one placed to another place.  And even then you'd probably be better served by making the POINTER a global variable.

That's my semi-skilled opinion anyway.
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Andy

Larry,

Thanks for your time on pointers.

Making name a pointer really threw me I must say.

I'ts a good lesson about not using pointers in a structure.

For my part, I will stick with ints and strings etc, I find that is mainly all I need, and I can my head around them.

Thanks again,
Andy.
:)



Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

LarryMc

But you understand pointers better than you did and that was the whole point, right?
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Andy

Correct!

And I can see myself using pointers a great deal more.

The beauty for me is that you can set the size with a variable instead of a number, this allows for creating just enough "space" for something like an array, rather than waisting memory on a static size which might not be enough.

You can also (if the size becomes insufficient) copy the details to another, delete it and use the NEW command to set the new size. You can then copy the details back.

It's good stuff!

Thanks very much for the walkthrough.

Andy.

Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

billhsln

To everyone, this is a great bunch of examples and documentation on how pointers work.  I wanted to say thanks to all of you for all the work you all did on this.  I still may not totally understand pointers, but I think with all the explanations here, I might get a much better understanding.

So, thanks to everyone who responded to this.

Bill
When all else fails, get a bigger hammer.