Good to see you back here in the forum @Bdigger 
Your modified updateBalance function is correct 
In order for your full smart contract to compile, you need to remove the empty constructor (which isn’t needed) and add view
to the getBalance function.
Changing memory to storage creates a pointer to users[id]
(to the User instance for that specific id
in the users
mapping). This means that the new balance can then be updated permanently in the mapping, and not just temporarily to a local variable.
You’ve got confused here…
… Local variables of type struct, string, or which are arrays (e.g. User memory user
in the initial version) are not located in storage by default. We have to specify either memory
or storage
by adding these keywords.
It is all state variables and mappings which are located in storage by default.
I hope that’s made things clearer. Just let us know if you have any questions 