Terrible Bugs

New to FreeBASIC? Post your questions here.
Post Reply
flavius717
Posts: 1
Joined: May 10, 2017 22:18

Terrible Bugs

Post by flavius717 »

Hi everyone. I watched a few youtube videos and then started off on my first programming experience. FBIDE is very nice and easy to use, but I seem to be encountering a terrible glitch. What could I be doing wrong? Is there something I simply don't understand about the nature of data?

Please take a look at the program and output below. I really am frustrated by this.

Code: Select all

dim i as integer
dim array(i) as string
dim array2(i) as string


for i = 1 to 3
    print i
    input array(i)
    input array2(i)
next i

print ""
print "OUTPUT"
print ""

for i = 1 to 3
    print array(i)
    print array2(i)
next i
sleep

end 

This is what happens when I run the program and input information:

1
? the
? cow
2
? jumps
? over
3
? the
? moon

OUTPUT

the
the
jumps
over
the
moon


That isn't even the worst of it! I have seen "the jumps over moon" before, and in another program I have using arrays in this way, I sometimes get nothing back. It varies from instance to instance, and I get different outputs each time I run the same program with the same input, and sometimes it simply crashes. I am running Windows 10 on a Surface Pro with an i5. I've only just begun programming at a very BASIC (haha) level, and I would like to continue to learn, except things don't seem to work.
jevans4949
Posts: 1186
Joined: May 08, 2006 21:58
Location: Crewe, England

Re: Terrible Bugs

Post by jevans4949 »

1. Initialise i to 3 (or some value) before using it to DIM arrays.
2. Use REDIM to define your arrays with dynamic sizes.
St_W
Posts: 1626
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: Terrible Bugs

Post by St_W »

Welcome!
You have to define the size of your arrays and jevans4949 has already suggested two ways how you could to that. In your program "i" equals zero at the point when the array is created using "Dim array(i) as String". You need to define the size of the array before using it, this can be either at compile time (e.g. by writing "Dim array(1 to 3) as String") or at runtime (e.g. by using REDIM, which also allows to resize arrays at runtime).

When you access array elements outside the defined range you'll cause memory corruption which may lead to crashes or undefined (often weird) behaviour - especially when you write data; reading usually just returns garbage.

To avoid such errors I'd suggest to compile your programs with the command line parameter "-exx", which enables some runtime error checking, including array bounds checking. You can add " -exx" to the compiler command line in the FBIde settings. In case an error is detected an error message is shown in the console and the program is terminated.
See also http://freebasic.net/wiki/wikka.php?wak ... ilerOptexx
owen
Posts: 555
Joined: Apr 19, 2006 10:55
Location: Kissimmee, FL
Contact:

Re: Terrible Bugs

Post by owen »

don't do dim array(i)
use dim array(3)

Code: Select all

Dim i as integer
dim array(3) as string
dim array2(3) as string


for i = 1 to 3
    print i
    input array(i)
    input array2(i)
next i

print ""
print "OUTPUT"
print ""

for i = 1 to 3
    print array(i)
    print array2(i)
next i
sleep

end 
badidea
Posts: 2591
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Terrible Bugs

Post by badidea »

Or with some constant:

Code: Select all

const as integer NUM_ENTRIES = 3

Dim i as integer
dim array(1 to NUM_ENTRIES) as string
dim array2(1 to NUM_ENTRIES) as string

for i = 1 to NUM_ENTRIES
    print i
    input array(i)
    input array2(i)
next i

print ""
print "OUTPUT"
print ""

for i = 1 to NUM_ENTRIES
    print array(i)
    print array2(i)
next i
sleep

end

MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Terrible Bugs

Post by MrSwiss »

owen wrote:

Code: Select all

Dim i as integer
dim array(3) as string	 ' <-- too large (4 elements: 0 to 3), correct: array(2) or array(1 to 3)
dim array2(3) as string


for i = 1 to 3	' 3 elements used, alternative 0 to 2 (if: array(2) used)
    print i
    input array(i)
    input array2(i)
next i
Please, if giving advice to others, do so, in a correct way.
owen
Posts: 555
Joined: Apr 19, 2006 10:55
Location: Kissimmee, FL
Contact:

Re: Terrible Bugs

Post by owen »

flavius717 wrote:

dim i as integer
dim array(i) as string
dim array2(i) as string

and by doing so caused an error and his confusion

he could have used

dim i as integer
i=2
dim array(i) as string
dim array2(i) as string

and in the for next loop
for i = 0 to 2
array(i)=
etc...

I responded to his confusion by using 3 instead of 2
because his example was that of 3 pieces of information to store in the array

I chose to not include or add any other details about arrays such as
dim array(0 to 2)
0 = first storage location
1 = second
2 = third
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Terrible Bugs

Post by MrSwiss »

owen wrote:I responded to his confusion by using 3 instead of 2
because his example was that of 3 pieces of information to store in the array

I chose to not include or add any other details about arrays such as
dim array(0 to 2)
0 = first storage location
1 = second
2 = third
If somebody is already confused, it isn't helpful, to introduce more confusion.
E.g. give a full correct answer, or none at all, still better, than introducing more confusion.
owen
Posts: 555
Joined: Apr 19, 2006 10:55
Location: Kissimmee, FL
Contact:

Re: Terrible Bugs

Post by owen »

MrSwiss is right. I should have used 0 to 2 in my post.

but how does this work?
part of this is from fb's help example of Lbound

Code: Select all

Dim array(-10 To 10, 5 To 15, 1 To 2) As Integer

Print LBound(array) 'returns -10
Print LBound(array, 2) 'returns 5
Print LBound(array, 3) 'returns 1

array(-10,5,1)=4
Print array(-10,5,1) 'prints 4

Sleep
End
jevans4949
Posts: 1186
Joined: May 08, 2006 21:58
Location: Crewe, England

Re: Terrible Bugs

Post by jevans4949 »

@owen:The array descriptor (a data type internal to the compiler, includes a "virtual origin", which is a pointer to the theoretical address of array(0,0,0).

To simplify, if you put "DIM X (2 TO 4) AS INTEGER", and the compiler allocates 12 bytes for the content at &HC000, the virtual origin would be &HBFF8. When you try to access X(3) at runtime, the generated code will multiply the element size (4 in this case) by 3, and add to the virtual origin, in this case giving the address &HC004.

With a 2D array, ( say DIM X(0 TO 5,0 TO 5) ) the descriptor will be set up with the size of the first dimension elements as 24 bytes (6 integers)

Arithmetic is usually done with unsigned integers, the virtual origin may be outside the address range of real memory, if for example the lbound is 1 million.
owen
Posts: 555
Joined: Apr 19, 2006 10:55
Location: Kissimmee, FL
Contact:

Re: Terrible Bugs

Post by owen »

I knew it had something to do with pointers. This is great. I'm still learning.
so what happens here:

Code: Select all

Dim As Integer x(2 To 4),i
x(0)=1
x(1)=2
x(2)=3
x(3)=4
x(4)=5
For i=0 To 4
	Print x(i);"= position";i
Next
Print "how much memory was allocated for x in the Dim statement?"
Print "does freebasic extend the memory for x upon x(0)=1 and x(1)=2?"
Sleep
End
jevans4949
Posts: 1186
Joined: May 08, 2006 21:58
Location: Crewe, England

Re: Terrible Bugs

Post by jevans4949 »

@owen: In the normal course of events, for the sake of speed, FreeBasic doesn't check that array subscripts are in the valid range, so your last example will stomp over memory in an unpredicatble way. EDIT: you may get a segment violation error at runtime if you try to write outside outside the memory allocated to the program at runtime.

If you add the compiler option -exx, the compiler will generate extra code to raise an error if this occurs. The idea is that you use this for testing, and put in proper code to check for invalid subscripts where necessary - e.g., if taken from user input.

FreeBasic doesn't automatically expand array bounds; you have to use REDIM. You can use REDIM ... PRESERVE, but this doesn't work well for multi-dimensional arrays, or if you change the LBOUND yalue.

Note that in the case of variable string arrays, or variable strings within TYPEs, (i.e. not STRING*n or ZSTRING*), what is contained in the array is not the strings but the string descriptors. The consequence of this is that if you say PUT #myfile, mystringarray(), you save the current string descriptors, which are basically useless.
sancho2
Posts: 547
Joined: May 17, 2015 6:41

Re: Terrible Bugs

Post by sancho2 »

jevans4949 wrote:Note that in the case of variable string arrays, or variable strings within TYPEs, (i.e. not STRING*n or ZSTRING*), what is contained in the array is not the strings but the string descriptors. The consequence of this is that if you say PUT #myfile, mystringarray(), you save the current string descriptors, which are basically useless.
This is not the case. Put an element of a string array to a file results in the string being written to the file. You cannot Put the array itself into a file.
The following code results in the file containing this:

Code: Select all

one
two
three
etc
Here is samople code:

Code: Select all

Dim As String s(1 To 4)
s(1) = "one"
s(2) = "two"
s(3) = "three"
s(4) = "etc"

Open "C:\Freebasic Stuff\mmmtestmmm.txt" For Binary As #1
	For x As Integer = 1 To 4
		Put #1,, s(x)
		Put #1,, Chr(13) + Chr(10)
	Next
	Put #1,,Chr(13)
	'Put #1,, s()	
Close #1 
jevans4949
Posts: 1186
Joined: May 08, 2006 21:58
Location: Crewe, England

Re: Terrible Bugs

Post by jevans4949 »

@sancho2: You are correct in saying you can't PUT a string array. It's a long time since I tried it. You can put a TYPE containing variable string descriptors; you get a warning from the compiler if you do, but it still runs.

And as you illustrated, If you want to emit the actual data, you have to write a loop PUTting (or PRINTing) each string individually.

You can PUT an array of STRING*n or ZSTRING*n
Post Reply