Troubleshooting File Copying and Removing Items in Visual Basic Function

In summary: It's only deleting the last item in the list, no matter what item I want deleted.Sounds like... something is wrong with your code.
  • #36
phion, there were so many suggestions to check what happens in the code, why don't you follow them? You keep running the whole code and describing the output with words that can be unclear. That is very inefficient.
 
Technology news on Phys.org
  • #37
phion said:
I mean, it's pretty clear that the issue resides in the loops I'm using.

When I remove the arrays and the for loop and do as you say, the same exact behavior results. Regardless of the name I type to be removed, the last name in the list is removed instead.
So get the computer to step through the code one instruction at a time. You'll be able to see what's going on in the middle of program execution.

Dumb question - does inFile.ReadLine() strip the newline character? Does Console.ReadLine()? If one is stripping it and one isn't, that would mean that the two strings never match.
 
  • #38
mfb said:
phion, there were so many suggestions to check what happens in the code, why don't you follow them? You keep running the whole code and describing the output with words that can be unclear. That is very inefficient.
I don't know how!
 
  • #39
Ibix said:
Dumb question - does inFile.readLine() strip the newline character? Does Console.readLine()?
I couldn't tell you the answer to that, but it seems important.
 
  • #40
You don't know how to add output to your code? You already have that, just not at the places suggested here.
Using a debugger would be even better, with the descriptions how given above. It is not necessary here, however.

"How to test and debug my code" should be the second step after getting a hello world program running.
 
  • #41
phion said:
I couldn't tell you the answer to that, but it seems important.
Text processing is a pain because of details like this. It may or may not be relevant.

Seriously - open the program you just posted in Visual Studio, display the "locals" window, set a breakpoint on the first line and then step through the program. Each time you go round the loop you'll be able to see what's being read in from the file and see if it is what you expected.

The problem at the moment is that you don't know where to look. There's a bug in there...somewhere. If you step through the program you can see what it's got in memory at the point when something goes wrong. That'll help a lot to tell you why it's going wrong.
 
  • #42
Some of your functions are making changes to playerList array. By default Visual Basic passes variables by value. That means that the playerList array in the function is just a copy of the playerList array that was sent in the argument list, and any changes made within the function affect only that copy of the original. When the program exits the function the copy is lost. I'm not sure if this is what's causing the problem you're having, but it appears that some of your functions should be passing the playerList array by reference instead of by value.
 
  • #43
TurtleMeister said:
Some of your functions are making changes to playerList array. By default Visual Basic passes variables by value. That means that the playerList array in the function is just a copy of the playerList array that was sent in the argument list, and any changes made within the function affect only that copy of the original. When the program exits the function the copy is lost. I'm not sure if this is what's causing the problem you're having, but it appears that some of your functions should be passing the playerList array by reference instead of by value.
That could be the problem.
It certainly would explain the behavior of removePlayer described at the start of the thread:
phion said:
Now what it's doing is deleting the last item in the list regardless of what name I specify to be deleted. Strange.
The last item in the list is deleted because he substracts 1 from numPlayers in removePlayers, but the array itself is unchanged..

But it then begs the question why his other methods (that also use the array as a "ByVal" argument) apparently work correctly.

EDIT: Apparently, when you pass an array as argument (even as ByVal), you can still modify the array element apparently.
This means that when you pass a reference type by value, the procedure code has a pointer to the underlying element's data, even though it cannot access the underlying element itself. For example, if the element is an array variable, the procedure code does not have access to the variable itself, but it can access the array members.
And specifically for an array passed "ByVal":
The procedure cannot change the variable but can change members of the instance to which it points.
https://msdn.microsoft.com/en-us/library/eek064h4.aspx

There really is no alternative but for @phion to correct the obvious errors in his code, and then debug the program using one of the techniques mentioned above.
 
Last edited:
  • #44
phion said:
I mean, it's pretty clear that the issue resides in the loops I'm using.
That may be the case, but don't assume it, debug to make sure.
phion said:
When I remove the arrays and the for loop and do as you say, the same exact behavior results. Regardless of the name I type to be removed, the last name in the list is removed instead.

Code:
Console.WriteLine("Which player would you like to remove?")

        player = Console.ReadLine()

        While Not inFile.EndOfStream

            copyPlayer = inFile.ReadLine()

            If player <> copyPlayer Then

                outFile.WriteLine(copyPlayer)

            End If

        End While
This makes sense. You don't touch your array in this modified code. Now this is not the whole removePlayer function. If your modified version still contains the updatedPlayers = numPlayers - 1 instruction, this will obviously make it appear as if the last name of the array is removed, as you won't reach it when you loop the array.

I know you hope someone here will post a working removePlayer function.
Problem is we don't know what removePlayer is supposed to do exactly: reload the file and remove a name from that list, remove a name from the array already in memory, something else?

What you could do is first clarify for yourself (in words, not in code), what removePlayer is supposed to do exactly.

Then you can adapt your code and start debugging.
One way to debug could be to first hard code the name to be removed instead of using user input. Say the list is "John", "Rita", "Jim", "Alex".
Set the name to be deleted from the list to "Rita". Now run your program and adapt it until it does what you want.
Once it works for "Rita", test if for "John" (first name on the list), "Alex" (last name on the list) and "Samy" (name not on the list). In each case correct the code if it doesn't work.
When you correct the code, don't just try something until it works. Be sure you understand why the program didn't work in this specific case and why your modification will solve the present problem without breaking the code that worked before.

Once you are done with a hard coded name, try it with a name entered by the user. If now it again doesn't work, you have isolated the problem and can deal with it.
 
Last edited:
  • #45
phion said:
[...]

I'm not even sure where to look for VB debugging tutorials. Any advice?
https://support.microsoft.com/en-us/kb/142999

An array requires a fixed size of a contiguous block of memory. So if the input element number is less than the array size, all the unused elements are assigned to "Nothing" and that (long) block of memory becomes redundant. .
Instead of using arrays, why don't you try out either List (Of String) or ArrayList which is more easy to handle and would free you from such an overhead. You can also use a Collection as in the following code I rewrite for you. This is worse than that being used with either List or ArrayList though.

PHP:
Module Module1

    Dim numPlayers As Integer
    Dim playerListTmp As New Collection
    Sub Main()
        Dim playerList, tempPlayerList As New Collection()

        numPlayers = loadList(playerList)

        numPlayers = addPlayers(playerList, numPlayers)

        displayList(playerList, numPlayers)

        numPlayers = removePlayer(playerList, numPlayers)

        displayList(playerList, numPlayers)

        saveList(playerList, numPlayers)

        Console.WriteLine("List saved successfully!")

    End Sub

    Function loadList(playerList As Collection
                   ) As Integer

        Dim fileName As String = "playerList.txt"

        numPlayers = 0

        If File.Exists(fileName) Then

            Dim inFile As New StreamReader(fileName)

            While Not inFile.EndOfStream

                playerList.Add(inFile.ReadLine(), numPlayers)

                numPlayers += 1

            End While

            inFile.Close()

        Else
            Console.WriteLine("Could Not Open " & fileName)
        End If

        Return numPlayers
    End Function

    Function addPlayers(playerList As Collection, numPlayers As Integer) As Integer
        Dim newPlayer As String

        Dim fileName As String = "playerList.txt"
        Dim inFile As New StreamWriter(fileName, True)

        Console.Write("Enter player name ('exit' to quit): ")

        newPlayer = Console.ReadLine()

        While newPlayer <> "exit"

            inFile.WriteLine(newPlayer)
            playerList.Add(newPlayer, numPlayers)

            numPlayers += 1

            Console.Write("Enter player name ('exit' to quit): ")

            newPlayer = Console.ReadLine()

        End While
        inFile.Close()
        Return numPlayers

    End Function

    Sub displayList(playerList As Collection, numPlayers As Integer)
        Dim i As Integer
        For i = 1 To numPlayers
            Console.WriteLine("Player " & i & ": " & playerList.Item(i).ToString())
        Next
    End Sub

    Function removePlayer(playerList As Collection, numPlayers As Integer) As Integer
        Dim player As String
        Dim fileName As String = "playerList.txt"
        Dim tempFileName As String = "tempPlayerList.txt"
        Dim inFile As New StreamReader(fileName)
        Dim outFile As New StreamWriter(tempFileName)
        Dim playerTmp As String
        Dim count As Integer = 0

        Console.WriteLine("Which player would you like to remove?")

        player = Console.ReadLine()        For i = 1 To numPlayers

            playerTmp = inFile.ReadLine()

            If player <> playerTmp Then
                playerListTmp.Add(playerTmp, i)
                outFile.WriteLine(playerTmp)
                count += 1
            End If

        Next

        inFile.Close()
        outFile.Close()

        File.Delete("playerList.txt")

        My.Computer.FileSystem.RenameFile("tempPlayerList.txt", "playerList.txt")

        File.Create("tempPlayerList.txt")
        playerList.Clear()
        For i = 1 To count
            playerList.Add(playerListTmp.Item(i), i)
        Next

        Return count
    End Function

    Sub saveList(playerList As Collection, numPlayers As Integer)
        Dim fileName As String = "playerList.txt"
        Dim outFile As New StreamWriter(fileName)

        For i = 1 To numPlayers

            outFile.WriteLine(playerList(i))

        Next

        outFile.Close()
    End SubEnd Module
 
Last edited by a moderator:
  • #46
Samy_A said:
What you could do is first clarify for yourself (in words, not in code), what removePlayer is supposed to do exactly.
I'm sorry, I thought this was made clear. This code is for a VB console program designed to manipulate data, namely "wins," "losses," "skill," "name," etc. which are stored in both arrays and text files. The remove player function should modify the playerList text file, and the playerList array I suppose, so that a player specified by the user is removed from the list, as well as all of their other corresponding data stored in separate arrays. This way, when the user chooses the menu option to view records of all the players, the proper data is displayed.
 
  • #47
Ok, I think I just figured it out. I need to sort the list such that the player specified by the user is in the last position of the list before copying over the contents of the file. Does this make sense?
 
  • #48
phion said:
I'm sorry, I thought this was made clear. This code is for a VB console program designed to manipulate data, namely "wins," "losses," "skill," "name," etc. which are stored in both arrays and text files. The remove player function should modify the playerList text file, and the playerList array I suppose, so that a player specified by the user is removed from the list, as well as all of their other corresponding data stored in separate arrays. This way, when the user chooses the menu option to view records of all the players, the proper data is displayed.
Do you see the ambiguity in your reply? "The remove player function should modify the playerList text file, and the playerList array I suppose".

Your current code doesn't use the array in memory, but reads the file into the array, including the player to be removed. It the saves the list without the removed player to the file (at least that is what it seems to do, but you say it doesn't work).
Try to define precisely what you want removePlayer to do, and then write and test the procedure as has been suggested by a number of people in this thread.

phion said:
Ok, I think I just figured it out. I need to sort the list such that the player specified by the user is in the last position of the list before copying over the contents of the file. Does this make sense?
Not really, no.
Try to analyze your code and understand why it doesn't do what you want.
Sorting the list with the player in the last position has nothing to do with what you want to achieve or with the reason it doesn't work.
 
  • #49
Samy_A said:
Do you see the ambiguity in your reply?
Yes, I am aware. You're probably pretty used to customers being frustratingly ambiguous I bet. ?:)

I'm working on the others suggestions, but I do feel like keeping this thread alive in the process. Setting breakpoints is something I have not yet done.
 
Last edited:
  • #50
phion said:
Yes, I am aware. You're probably pretty used to customers being frustratingly ambiguous I bet. ?:)

I'm working on the others suggestions, but I do feel like keeping this thread alive in the process. Setting breakpoints is not something I have not yet done.
No problem. Just try to be systematic in your work.
 
  • #51
Samy_A said:
No problem. Just try to be systematic in your work.
I appreciate the guidance.
 
  • #52
Ok, it works now. Duh.
 
  • #53
Samy_A said:
EDIT: Apparently, when you pass an array as argument (even as ByVal), you can still modify the array element apparently.
Yes, that is true. My post #42 is incorrect. ByVal only applies to value types. Arrays are reference types. And I guess it's a good thing because it would be pretty inefficient to copy an entire array and all it's elements every time you passed it as an argument.
 
Back
Top