Can't find the information you are looking for here? Then leave a message over on our WinBatch Tech Support Forum.
Keywords: Pinter Pointers Scope
Pointers can sometimes be used to create more compact and efficient code.
Variables that are declared at the top level of the program (outside of any user-defined functions) have program-level or "global" scope. They are visible from all top-level (program-level) code, from any user-defined subroutines called from top-level code, and from any external scripts called from top-level code using the "Call" function. These all share the same variable space, so that if you declare a variable "x" and then call a user-defined subroutine, the user-defined subroutine can change the value of "x" and it will keep its new value even after the user-defined subroutine has completed.
Each user-defined function executing within a WinBatch program has its own variable space, with function-level or "local" scope. A user-defined function does not see variables declared in the program (or user-defined function) that called it, so a variable "x" declared in a user-defined function is a different variable than the variable "x" declared in the program above it, and they can each have different values. Local variables within a user-defined function are visible from within the user-defined function itself, from any user-defined subroutines called from that user-defined function, and from any external scripts called from that user-defined function using the "Call" function.
A user-defined subroutine shares the same variable space as the code that called it. An external script called using the "Call" function also shares the same variable space as the code that called it.
A user-defined function has its own variable space, and does not share the same variable space as the code that called it.
In conclusion, scope basically refers to the visibility of variables. In other words, which parts of your program can see or use it. Normally, every variable has program-level scope. Once defined, every part of your program can access a variable (except for UDFs).
However, sometimes it is very useful to be able to limit a variable's scope to a single function. In other words, the variable will have function-level scope. This way changes inside the function can't affect the main program in unexpected ways.
For example:
#DefineFunction FirstUDF() local_var = "FUNCTION-LEVEL SCOPE" Message("FirstUDF", StrCat("local_var =" , local_var)) SecondUDF() Return #EndFunction #DefineFunction SecondUDF() Message("SecondUDF", StrCat("local_var =" , local_var)) Return #EndFunction main_var = "PROGRAM-LEVEL SCOPE" Message("Main Code", StrCat("main_var = " , main_var)) FirstUDF() Exit
This program displays:
Main Code main_var = "PROGRAM-LEVEL" FirstUDF local_var = "FUNCTION-LEVEL"Then errors with:
2058: Function syntax error in Routine SecondUDF On line: Message("SecondUDF", StrCat("local_var =" , local_var))The 'Additional Error Info' button displays:
Uninitialized variable or undefined function local_varThe output from this example shows that SecondUDF() could not access the local_var variable that was defined inside FirstUDF(). WIL displays an error message that warns about the uninitialized value.
In order to work with pointers some new operators have been defined:
You may notice that the '&' operator and the '*' operator are involved in using pointers. Initially this may be confusing, as the '&' looks like a bitwise 'AND' operator and the '*' looks like the multiply operator. But this is the way C does it and we are just copying C's methodology. Winbatch (and C) can tell by the context whether the '&' and the '*' are math or pointer related operators.
Here is some sample code that demonstrates the use of pointers:
a = 15 ; Define a standard variable. ptr_a = &a ; Create a link that is then stored in the 'ptr_a' pointer. Message("Value of ptr_a", ptr_a) ; Show the link stored in 'ptr_a'. Message("Dereference ptr_a", *ptr_a) ; Dereference 'ptr_a' to get contents of variable 'a'.
b = 30 ; Define a standard variable. ptr_b = &b ; Create a link that is then stored in the 'ptr_b' pointer. *ptr_b = 99 ; Redefine the variable 'b' via a dereference of pointer 'ptr_b'. Message("Updated Value of b", b) ; Show the current value of variable 'b'.
PtrGlobalDefine(variable-name)
(s) variable-name specifies a variable name.
(s) pointer a pointer string.This function can only be called from the main script, not from a User Defined Function. If "variable-name" does not already exist, it will be created.
PtrGlobal is used to retrieve a "pointer" to a global variable already defined by PtrGlobalDefine. PtrGlobal can be used to access a variable defined in the main section of code from within a User Defined Function. It can also be used to update values of variables in the main code.
PtrGlobal (variable-name)
(s) variable-name specifies a variable name.
(s) pointer a pointer string."variable-name" must have been previously been marked as global using PtrGlobalDefine.
#DefineFunction CheckGlobalValue() ; Retrieve "pointers" to global variables. Ptr_Global_A = PtrGlobal( Global_A ) Ptr_Global_B = PtrGlobal( Global_B ) ; If the dereferenced value of Ptr_Global_A is not equal to 'potatoes' then error If *Ptr_Global_A != "Potatoes" Message("Error","Global_A is not the expected value") EndIf ; Update the value of the variable Global_B referenced by Ptr_Global_B *Ptr_Global_B = 1234 #EndFunction ;Declare Global Variables PtrGlobalDefine( Global_A ) PtrGlobalDefine( Global_B ) Global_A = "Potatoes" retvalue = CheckGlobalValue() ; Check if Global_B was updated by the UDF If Global_B != 1234 Message("Error","Global_B is not the expected value") EndIf
Finally, PtrPersistent marks a variable as Persistent. If called from a UDF, the variable will retain its value after the UDF returns. If variable does not already exist, it will be created. If it already exists, its value will not be changed.
A "Persistent" variable is defined and used in a single UDF. But unlike other UDF variables, it "stays around". Kind of like a private global variable that no other UDF's can see. For example, if a UDF wants to save away some information that it needs, it can use a Persistent variable. The next time the UDF is called, its persistent variable is still there, with what ever value was left over from the previous call to it.
PtrPersistent(variable-name, value)
(s) variable-name specifies a variable name which CANNOT be longer than 25 characters. (s/i) value specifies a value which will be assigned to "variable-name" if the variable does not already exist.
(s) pointer a pointer string.
#DefineFunction IncMyCounter(flag) ; flag = 0 will report on current value of counter ; flag = 1 will increment counter first ;Creates a "pointer" to a persistent variable. Ptr_MyCounter = PtrPersistent(MyCounter,0) If flag==1 ; report on number of calls ;increment persistent variable *Ptr_MyCounter = *Ptr_MyCounter + 1 EndIf ;Return the value of the persistent variable Return *Ptr_Mycounter #EndFunction ;Create a random number r=Random(100) ;Loop a random number of times For xx = 1 To r ;Call IncMyCounter UDF to increment counter IncMyCounter(1) Next ;Call IncMyCounter UDF to report on current value of counter cnt=IncMyCounter(0) Message("Counter Value is",cnt)
#DefineFunction ShowCName() ; Note that this function is not passed the company name via parameters ; It uses the ptrGlobal function to reach out and acquire a pointer ; to the global company name variable, which it then displays via ; a dereference of the previously acquired pointer. ptr_CName = PtrGlobal(companyname) Message('Company Name Is', *ptr_CName) Return #EndFunction companyname = 'Wilson WindowWare Inc' ; Defined and initialize a company name variable. PtrGlobalDefine(companyname) ; Mark variable as being Global. ShowCName() ; Note: Companyname information is not passed to the UDF. ; Without use of global pointers the UDF could not otherwise access ; the company name information. Exit
Lets say you want to create a variable that you can access from anywhere in your script. A scope-less variable is any variable defined at the program-level scope of the script (i.e. Not defined in a UDF), and marked as a global variable with the ptrGlobalDefine function. Once the variable is defined using ptrGlobalDefine. You can access the contents of that variable from any scope level in the script.
For Example:
#DefineFunction CheckGlobalValue( ) ; Pre-define variable ret for success (@true) ret = @TRUE ; Retrieve a "pointer" to a global variable. Ptr_Global_A = PtrGlobal( Global_A ) ;Check if the dereferenced value of the Global_A is 999 If *Ptr_Global_A != 999 Then ret = @FALSE ;Returns the result to program level scope. Return ret #EndFunction ;Create a global variable PtrGlobalDefine( Global_A ) ;Define the global variable Global_A's value Global_A = 999 ;Execute UDF that checks Global_A's value is 999 retvalue = CheckGlobalValue( ) ;Check return value from CheckGlobalValue UDF If retvalue == @TRUE Message( "Check Global Value", "Expected Value" ) Else Message( "Check Global Value", "Un-Expected Value" ) EndIf
The above example :
#DefineFunction SetGlobalValue( ) Ptr_Global_B = PtrGlobal( Global_B ) *Ptr_Global_B = 1234 Return #EndFunction PtrGlobalDefine( Global_B ) SetGlobalValue( ) If Global_B != 1234 Message( "Error", "Global_B is not the expected value" ) Else Message( "Error", "Global_B is the expected value" ) EndIf Exit
The above example :
The PtrPersistent function can be used to define a persistent variable. If called from a UDF, the variable will retain its value after the UDF returns.
A "persistent" variable is defined and used in a single UDF. But unlike other UDF variables, it "stays around". Kind of like a private global variable that no other UDF's can see. For example, if a UDF wants to save away some information that it needs, it can use a persistent variable. The next time the UDF is called, its persistent variable is still there, with what ever value was left over from the previous call to it.
Persistent variables are handy when used in a UDF to keep track of what the UDF may have done on a previous call. For example, using a persistent variable, a UDF can easily keep track of how many times it was called.
#DefineFunction GetRandom(task) ; Note this function keeps track of how many times it was ; called by using a persistent varaible accessed via persistent ; pointer, returned by the ptrPersistent function. ptr_Count = PtrPersistent(my_counter, 0) If task == "GET" *ptr_Count = *ptr_Count+1 Return(Random(1000)) EndIf If task == "REPORT" Return *ptr_Count EndIf Return #EndFunction a1 = GetRandom("GET") a2 = GetRandom("GET") a3 = GetRandom("GET") a4 = GetRandom("GET") a5 = GetRandom("GET") count = GetRandom("REPORT") Message("GetRandom Report", StrCat("GetRandom function was used ",count," times")) Exit
#DefineFunction UpdateProgress(flag) ; Flag: ; @False - Initializes the Progress Meter Dialog Box ; @True - Updates the Progress Meter Dialog Box ; 2 - Kill Progress Meter Dialog Box ; Load Shell Operations Extender AddExtender("wwsop34i.DLL") ; Retrieve Pointers to Global Variables. ptr_g_allrecs = PtrGlobal(allrecs) ptr_g_donerecs = PtrGlobal(donerecs) ; Define Maximum Range maxrange = 100 ; Check Parameter Passed Switch flag Case @FALSE ; Initialize Progress Meter Dialog Box aStatusbar(flag, "Monitoring Progress...", "", maxrange, 0) Break Case @TRUE ; Update the Progress Meter Dialog Box percentdone=(100.0*(*ptr_g_donerecs))/(*ptr_g_allrecs) percentdone=Int(percentdone) aStatusbar(flag, "Monitoring Progress.", StrCat("Processing ",*ptr_g_allrecs, " Records..."), maxrange, percentdone) Break Case 2 ; Kill Progress Meter Dialog Box aStatusbar(flag, "", "", 0, 0) Break EndSwitch Return #EndFunction ;############################################################ ;# MAIN ;############################################################ ;Mark Variable as Being Globally Accessible. PtrGlobalDefine(allrecs) PtrGlobalDefine(donerecs) ;Initialize the Progress Meter Dialog Box UpdateProgress(@FALSE) ;Define Total Number of Records to "Process" allrecs=999 donerecs=0 ;"Process" code For xx = 1 To allrecs donerecs=donerecs+1 UpdateProgress(@TRUE) Next UpdateProgress(2) Message("Notice!","'Process' Complete!") Exit
Article ID: W17355
File Created: 2008:04:10:15:08:20
Last Updated: 2008:04:10:15:08:20