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.
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
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.
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.
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
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
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
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.
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.
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
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.
I can also do it this way:
pointer apointer
apointer = #p[x].name
print #<string>apointer
But not:
print #<string>#p[x].name
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
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.
you got it "Toyota" ;D
You're a good teacher Larry!
;D
Andy.
:)
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?
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.
:)
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
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
... "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.
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.
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.
:)
But you understand pointers better than you did and that was the whole point, right?
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.
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
Bill,
That's very kind of you, but Larry must really take the credit, all I did was scratch my head a few times and tried to follow what Larry was telling me or hinting at.
I am thinking of writting a few little example programs which I can bunch together to help anyone who wants to understand pointers (at least some of the basics).
I would of course run it past "a bigger brain" than mine first!
Thanks,
Andy.
If you have problem with space or unknown size one of
options is Linked List (of pointers or UDT)
There is no problem if you use pointer as member of UDT if
you properly cast this pointer when is used.
So back to Linked List ....each member of linked list can be added by runtime
and because of automatic mangment of linked list size is not problem.