Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Another issue: Changing one variable instantly changes the value of another variable
#1
I have a short subroutine that takes a path and removes the quotes if the path is enclosed in quotes. It then removes any trailing backslash from the path if one exists.

I was getting some unexpected results, so into debug mode I went to find the problem. As I step through the code one line at a time, I find this problem:

As soon as I execute the line that reads Temp$ = "" not only does Temp$ get set to "" but in that very moment Path$ also gets set to "" (an empty string). For the life of me, I cannot make sense of why this happens.

A few notes:

1) Path$ is not defined outside of this subroutine, so it is local to the subroutine only.

2) Temp$ is DIMed at the start of my program as a SHARED string, so that variable should be available globally.

I apologize for not supplying the full code. The problem is that this is a part of a program almost 15,000 lines long now.

Can anyone give me anything to look for here? I simply cannot see how changing one variable would instantly change another variable as well.



Code: (Select All)
Sub CleanPath (Path$)

    ' Remove quotes and trailing backslash from a path

    ' To use this subroutine: Pass the path to this sub, the sub will return the path
    ' without quotes and a trailing backslash in Temp$.

    Dim x As Integer

    ' start by stripping the quotes

    Temp$ = ""

    For x = 1 To Len(Path$)
        If Mid$(Path$, x, 1) <> Chr$(34) Then
            Temp$ = Temp$ + Mid$(Path$, x, 1)
        End If
    Next x

    ' Remove the trailing backslash, if present

    If Right$(Temp$, 1) = "\" Then
        Temp$ = Left$(Temp$, (Len(Temp$) - 1))
    End If

End Sub
Reply
#2
Hmm, I gave it a try by making a simple program to call `ClearPath()`, but even with Temp$ as shared I can't get it to do what you're describing.

If you're able, it would help a lot is if you could zip up your `./internal/temp/` folder after compiling the program and attach it to a post. The particular file I'm interested in is `./internal/temp/main.txt` but some others may be relevant too. That file contains the produced C++ code, so if it's an issue with the code generation that would tell us. If you want to look yourself, it's a matter of finding `void SUB_CLEANPATH` in it and then viewing the behavior, but it's a bit hard to read if you don't know what you're looking at Smile
Reply
#3
I think that I solved this. I need to verify this back on my original system where I encountered to issue, but on my laptop I changed the variable named Path to Path1 and that seems to have solved the issue. Maybe Path is a reserved name that cannot be used as a variable name?
Reply
#4
First thing I'd try is to pass via a temp variable:

SUB CleanPath (tempPath$)
Path$ = tempPath$

The issue is probably from a call such as :

ClearPath temp$

With passing matching types with SUB/FUNCTION, we pass the offsets to the variable and not the value of the variable. If temp$ is passed, Path$ **IS** temp$.
Reply
#5
Uhmmm, unless temp$ is shared (which would be kinda odd) your sub doesn't do anything to the state of the program outside the sub???

It certainly doesn't change Path$, you would need a final line Path$ = Temp$.
b = b + ...
Reply
#6
Like Steve said, watch what you do with variables passed to FUNCTIONS AND SUBs. Because you do manipulate the original values within the routine. Which if your careful can be a big and powerful feature, if your not careful it can be a living nightmare.

In QB4.5 you could do this with FUNCTIONs alone, but in QB64 it happens in both.
Reply
#7
Steve, it seems that you were correct. Creating a temporary variable did the trick, although I would love to know where the problem was originating from.

For now, I'll take the win, but I may eventually try to figure out the source of the problem. It's not going to be easy because the flow of the code in this particular are calls a subroutine, which then in turn calls another subroutine, which then finally calls a third subroutine. Following the variables through all those levels may be a little tricky.

In any case, thanks for the idea. I've now modified several of my subroutines to put temp variables in place and hopefully avoid other similar situations.
Reply
#8
(06-17-2022, 03:12 AM)bplus Wrote: Uhmmm, unless temp$ is shared (which would be kinda odd) your sub doesn't do anything to the state of the program outside the sub???

It certainly doesn't change Path$, you would need a final line Path$ = Temp$.

As per opening post:  2) Temp$ is DIMed at the start of my program as a SHARED string, so that variable should be available globally.

So let's say there's a point in that program that looks like this:

ClearPath Temp$


Now the SUB uses Path$ as the variable name, but they'll share the same offset.  For all intents and purposes Path$ *IS* Temp$...  When Temp$ = "" a few lines into the sub, Path$ will = "" as well.  <-- This is the glitch we're seeing at work.

Now, with the issue diagnosed, I don't think finding it inside the program will be as simple as looking for a ClearPath Temp$.  From my personal experience, I'd imagine the issue to come from something like:

SUB SetSlashes (Link$)
 DO  UNTIL INSTR(Link$, "/") = 0
     MID$(Link$, INSTR(Link$, "/") = "\"
 LOOP
 ClearPath Link$
END SUB

At this point the program then does a SetSlashes Temp$, so Link$ = Temp$, which calls ClearPath which makes Path$ = Temp$, which leads to the roundabout issue of changing Temp$ changing Path$.

Best advice I can give to avoid this issue:
  **Unless you need a return value via your SUB or FUNCTION parameter, pass to a temp variable and only use it to assign to a different value for the sub's exclusive use.  **

Don't change your original variable, and you'll never have to worry about corruption of data that those changes might cause.  Wink
Reply
#9
(06-17-2022, 03:12 AM)bplus Wrote: Uhmmm, unless temp$ is shared (which would be kinda odd) your sub doesn't do anything to the state of the program outside the sub???

It certainly doesn't change Path$, you would need a final line Path$ = Temp$.

Dang you did DIM Shared Temp$, sorry I suck at reading!

IMHO this is how I would handle this function:
Code: (Select All)
' don't share temp$, temp$ is supposed to be temporary!!!
test$ = "C:\Dir1\Dir2\"
Print CleanPath$(test$)

Function CleanPath$ (Path$) ' this is clearly a Function in my opinion!

    ' Remove quotes and trailing backslash from a path

    ' To use this subroutine: Pass the path to this sub, the sub will return the path
    ' without quotes and a trailing backslash in Temp$.

    Dim x As Integer

    ' start by stripping the quotes

    Temp$ = ""

    For x = 1 To Len(Path$)
        If Mid$(Path$, x, 1) <> Chr$(34) Then
            Temp$ = Temp$ + Mid$(Path$, x, 1)
        End If
    Next x

    ' Remove the trailing backslash, if present

    If Right$(Temp$, 1) = "\" Then
        Temp$ = Left$(Temp$, (Len(Temp$) - 1))
    End If
    CleanPath$ = Temp$
End Function


How do you get double quotes in a path or filename? (Just really curious!)
b = b + ...
Reply
#10
(06-17-2022, 02:08 PM)bplus Wrote: IMHO this is how I would handle this function:
Code: (Select All)
' don't share temp$, temp$ is supposed to be temporary!!!
test$ = "C:\Dir1\Dir2\"
Print CleanPath$(test$)

Function CleanPath$ (Path$) ' this is clearly a Function in my opinion!

    ' Remove quotes and trailing backslash from a path

    ' To use this subroutine: Pass the path to this sub, the sub will return the path
    ' without quotes and a trailing backslash in Temp$.

    Dim x As Integer

    ' start by stripping the quotes

    Temp$ = ""

    For x = 1 To Len(Path$)
        If Mid$(Path$, x, 1) <> Chr$(34) Then
            Temp$ = Temp$ + Mid$(Path$, x, 1)
        End If
    Next x

    ' Remove the trailing backslash, if present

    If Right$(Temp$, 1) = "\" Then
        Temp$ = Left$(Temp$, (Len(Temp$) - 1))
    End If
    CleanPath$ = Temp$
End Function


How do you get double quotes in a path or filename? (Just really curious!)

You'd still end up with the same root issue though when you did a return$ = ClearPath(Temp$).   If I was going the way you're mentioning, I'd do it like so:


Code: (Select All)
Function CleanPath$ (Path$) ' this is clearly a Function in my opinion!


    STATIC Temp$ 'Make certain that Temp$ is local to the sub and we don't use the global variable by accident


    ' Remove quotes and trailing backslash from a path

    ' To use this subroutine: Pass the path to this sub, the sub will return the path
    ' without quotes and a trailing backslash in Temp$.

    Dim x As Integer

    ' start by stripping the quotes

    Temp$ = ""

    For x = 1 To Len(Path$)
        If Mid$(Path$, x, 1) <> Chr$(34) Then
            Temp$ = Temp$ + Mid$(Path$, x, 1)
        End If
    Next x

    ' Remove the trailing backslash, if present

    If Right$(Temp$, 1) = "\" Then
        Temp$ = Left$(Temp$, (Len(Temp$) - 1))
    End If
    CleanPath$ = Temp$
End Function

Notice that Temp$ is now a STATIC variable, forced to be localized to the Function itself, and thus can't ever be corrupted via the global variable named Temp$.  There's a reason why QBASIC offered STATIC and local variables, even if most people never bothered to use them.  Wink
Reply




Users browsing this thread: 2 Guest(s)