Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Variables acting weird 1

Status
Not open for further replies.

IsmAvatar

Programmer
Sep 6, 2005
5
US
Hey, I seem to run into a problem with variables every now and then. Generally, when I run a loop and read from a file, I *might* get a problem.
The snippit of code I've narrowed it down to is below:

for l := 1 to 9 do
begin
write(l,' ');
blockread(f,bi,4); //bug here
end;

whereas l and bi are both integers, and f is a file opened for reading. Logically, this would give the output "1 2 3 4 5 6 7 8 9", yet, instead it gives the output "1 1 1 1 1".
L and BI are both recycled variables. Here's the kicker. LL is also a recycled variable, and if I switch L with LL, I get "1 5 5 5 ...... 1 1 1 .......<endless loop of 1's>".
POS is another recycled variable, and if I substitute that in, I get the desired result.
I can also change up the BI variable and get all kinds of strange results. I've seen it do "0 0 0".

I use recycled variables all the time, and when I do get a problem, it's normally once every 5 or 6 programs, and it's very similar to this. Making a new variable does solve the problem, but it's kind of a very last resort.

I don't know if you want to see the whole code or not. It's 500 lines, although a lot of it has been commented out to isolate the problem. It's open source, so I have no problem giving it to anyone, along with a sample file or 2 that it is used to read from.

If anyone could explain why my variables aren't acting the way I have explicitly told them to, it would be greatly appreciated.

Thanks
-Ism

Dev-Pascal, Latest version. Compiles with Free Pascal. Successfully compiles. Changing compiler options has no effect on the outcome apart from the obvious.
 
You have to watch how you recycle variables. For example, if l in this code is used further up in the code and this loop is within another loop using l, your code will not work. A good rule is to never recycle variables unless you know the scope is not going to change it.

As for what you posted, does this code occur in isolation? If so, bi is not set or incremented in what you have shown. So it's not going to change and will be what you originally set it (1 evidently). l will change, however, because the loop is incrementing the value after each occurrence in the loop. So from what you've shown, it's acting exactly as you told it to.

Suggestion too. Don't use lowercase L as a variable. It's too easily confused with the number 1. Same with uppercase O and 0.

for l := 1 to 9 do
begin
write(l,' ');
blockread(f,bi,4); //bug here
end;
 
I know about nesting loops and stuff like that - i'm always careful of that. That's why I have LL, for the occasional time when I do nest a loop. In this case, as well as most other times, the loop is fairly isolated. I even have the entirety of the loop noted as a specific section (using a comment). At other times when I do decide to nest, I normally run it through a few times in my mind and run a few tests to ensure that it will run fine, and then note the results. However, again, this is isolated.

Earlier on up in the code, in another isolated section, the variable is used as the buffer to read 4 bytes as an integer from a file. It was my original intention to then count down from that, reading more 4-byte integers from the file (into bi), occasionally increasing the countdown based on what is read from the file. I now see that a while loop would have been more appropriate than a for loop. I have changed the code, yet the problem persists.

{for the sake of this instance, L := 9; and the next 4-byte integer that shall be read from the file is 3}
while l > 0 do
begin
write(l,' ');
l -= 1;
blockread(f,ll,4);
//blockread(f,bi,4); //bug
end;

It works fine, but then uncomment the line or even leave it commented but serve the previous line's buffer with BI and it will print "9" alone. If you don't know what the code would look like that would throw this problem, here it is:

//l := 9;
while l > 0 do
begin
write(l,' ');
l -= 1;
blockread(f,bi,4);
end;
//prints "9"

Also, I'm quite capable of telling my l's from my 1's. Especially with Dev's Syntax Highlighting which turns all numbers a blue colour.
Thanks for your help and suggestions anyways, but the problem is still unsolved.

-Ism
WinXP Home SP2, 'emachines'
 
Could you show us the assign and reset you used to open the file f?

It looks to me as though you are overwriting variables. Blockread will overwrite if it disagrees with you about the record length. You have written your code for a record length of 1, but unless you stated that specifically with reset(f, 1), then the default record length is more likely to be 32, in which case blockread(f, bi, 4) will read 128bytes, overwriting all sorts of data.
 
I made sure to get as much information as possible on reading from files before attempting this project. It is an untyped file.

var
bs,p1,p2 : string;
bi : integer;
pos : longint;
f : file;
...

assign(f,p1);
reset(f,1);

While most of the file does consist of 4-byte integers, there are parts of the file that will store strings of variable length (length determined by a 4-byte integer prior to the string) which is why I have to use a size of 1. For those strings, if I intend to skip them, I will simply use this method:
blockread(f,bi,4);
pos += 4 + bi;
seek(f,pos);

If I intend to read it, I will use this method:
bs := '';
blockread(f,bi,4); //length
for ll := 1 to bi do //name
begin
blockread(f,bi,1);
bs := bs + chr(bi);
end;

Which, let it be noted, occurs once in the entirety of the script (tho I intend to use a string-reading method again later, once I fix this bug), in the segment immediately prior to this bug segment.

It will then compare the string with a parameter stored in p2, and set the variable L to the next byte if they match up.

if p2 = bs then //compare
begin
pos += 8 + ll; //immediately after contents
blockread(f,l,4); //contents
break; //break free of a WHILE search loop
end;
//other loop conditions
seek(f,pos);
//begin bug code


Although what you have said is of interest. Perhaps a variable is being overwritten or something. This would certainly explain why it's not quite acting as I am telling it to. If so, I will need to find out where it's being overwritten and how to prevent that.
 
Your reset is good; there is no problem in working with byte-sized untyped data in the file.

What compiler are you using? In Turbo pascal, an integer is only 16 bits long, which would be a disaster for your code. Having said that, strings in TP are also limited (unlike C strings) so I presume you're not in TP??

A few other points:

(1) You use a variable pos. TP includes a function pos...

(2) I'm not sure about your seek. Seek finds the absolute position, so I'm not sure about your skip code.

(3) I think you're unnecessarily complicating the string-read code. You don't need to read into a variable, type-cast it as char and add it to a string somewhere else; you can just read into the string. For random-length collections of text you can do things like:

var
mylength : word;
myplace : pointer;

begin
blockread(myfile, mylength, 2);
getmem(myplace, mylength);
blockread(myfile, myplace^, mylength);
end;
 
As I said before, I'm using the latest version of Dev-Pascal as my IDE, which comes with FreePascal as the compiler.

However, it appears that I misread the documentation and tutorials when learning Pascal and assumed that an integer was 32 bits. Now that I look over it again, it appears that an integer is indeed only 16 bits, and a longint is 32 bits, which is why pos was working (pos was the only variable I tried that was a longint).
I have now turned all of my integers into longints and the problem is no longer occurring. Thank you very much.

I'll now address the rest of your post, tho.
The string that I am reading in is not much longer than 16 bytes. Hopefully it supports strings up to the length of 255, because that's the maximum length of a string in the file.
1) The documentation for the system unit makes no mention of a pos function, and thusfar it has not shown any signs of acting up. In fact, it was the one variable that I was able to use to avoid the bug.
2) Pos is the variable that I use to keep track of the current position in the file. I update it using things like pos += 4; and pos += 4 + bi { for string lengths };
and C operations are enabled on the compiler (so it can read things like += and -=). So far seek has never failed me with the pos variable.
3) i've never used memory and pointers before, and at first glance in the documentation, it appears like something that may require a tutorial to learn, so I will look into that now. I was initially using the following:
blockread(f,bi,4); //get the length of string
blockread(f,bs,bi); //read a string of length bi
and that was unreliable. Then I recalled that blockread generally returns ords, so I decided to read each individual ord with a loop, and then add the char of it to the string. This was the only other way I knew, and it was fast enough to get the job done without any appearent slowdown. The code is intended to be run-once and done, so speed is not really too much of a consideration for me, as long as it doesn't take a minute to run. So far it skims through a 450KB file in less than a second, and a 4mb file in a couple of seconds, which is way more than fast enough for me.

Thanks again. If I run into the problem again, I'll be back. Until then, I believe the problem is solved.
-IsmAvatar
 
Good luck!

Yes, Turbo strings are OK to 255 bytes, the reason being that they are actually up to 256 bytes long but the first byte is the length of the rest. This is also why I was a bit reticent about reading from your file straight into a string, because it would actually write into the place where turbo stores its string-length.

Sounds like you're sorted, though. I agree entirely, there's no point in making something faster when it's already quite fast enough.

I haven't a clue how much of Turbo is common to other pascals; I've never actually learnt the ANSII definitions etc.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top