Q65478: 7.10 Memory Lost If Reassign $DYNAMIC String Array to STRING$
Article: Q65478 Product(s): See article Version(s): 7.00 7.10 | 7.00 7.10 Operating System(s): MS-DOS | OS/2 Keyword(s): ENDUSER | SR# S900816-176 buglist7.00 buglist7.10 | mspl13_basic Last Modified: 26-DEC-1990 In a compiled .EXE file, assigning a $DYNAMIC variable-length-string array element directly to a BASIC intrinsic string function (such as STRING$) creates an internal temporary string that may fail to be deallocated. Repetitive reassignments can cause "Out of String Space" or "Out of Memory" errors. This article documents this problem with Microsoft BASIC Professional Development System (PDS) versions 7.00 and 7.10 and shows two examples of the problem. Microsoft has confirmed this to be a problem with BASIC PDS versions 7.00 and 7.10 for MS-DOS and MS OS/2. This problem does not occur in the QBX.EXE environment, or in earlier versions of Microsoft BASIC Compiler or QuickBASIC. We are researching this problem and will post new information here as it becomes available. The problem can occur for dynamic variable-length-string array element assignments of the form A$(x)=STRING$(n). But this form of assignment may not give the problem in some cases, such as in Code Example 1 where A$(x)=STRING$(n) appears within a FOR...NEXT loop. Any one of the following code modifications works around the problem: 1. Use a $STATIC array instead of a $DYNAMIC array, -or- 2. First assign a temporary variable such as temp$ to the BASIC string function (STRING$), then assign the array element to temp$: temp$=STRING$(12000) A$(1)=temp$ temp$="" -or- 3. Use the CLEAR statement to erase the memory wasted by the internal temporary string (but CLEAR also erases all other variables). -or- 4. In some cases, surrounding the assignment with a FOR...NEXT structure may eliminate the problem, such as in Code Example 1. This problem is not affected by any compiler options that limit optimizations (BC /D, /X, etc.). The problem occurs with both near and far strings (BC /Fs, /Fn). Code Example 1 -------------- The following code example shows one case (in a FOR...NEXT block) that reclaims memory properly and three cases that fail to return the string memory. In the cases that fail, the a$()=SPACE$() statement fails to release an amount of string space equal to the length of the string assigned (due to an internal unreleased temporary string). Repeated assignments will decrease string memory until string memory eventually runs out. Compile and LINK as follows (compile and LINK options do not affect the problem): BC STRING; LINK STRING; REM $DYNAMIC CLS DIM a$(10) PRINT "FRE(a$(1)) at start of program: ", FRE(a$(1)) PRINT "Case #1: memory recovered if string deallocated in FOR loop." PRINT "For loop works fine -- memory restored" FOR i% = 12000 TO 0 STEP -12000 a$(1) = SPACE$(i%) PRINT "Free during FOR loop: ", FRE(a$(1)) NEXT PRINT "Case #2: Prompt user for size of string." INPUT "Input big number (try 12000):", big% a$(1) = SPACE$(big%) 'Both A$(1) & internal string consume memory: PRINT "FRE(a$(1)) after allocation: ", FRE(a$(1)) INPUT "Input a small number (0):", small% a$(1) = SPACE$(small%) 'Internal temporary string still wastes memory: PRINT "FRE(a$(1)) after deallocation: ", FRE(a$(1)) PRINT PRINT "Case #3. String of 12000 bytes assigned." big% = 12000 a$(1) = SPACE$(big%) PRINT "FRE(a$(1)) after allocation: ", FRE(a$(1)) small% = 0 a$(1) = SPACE$(small%) PRINT "FRE(a$(1)) after deallocation: ", FRE(a$(1)) PRINT "Case #4: Another string of 12000 bytes assigned." a$(1) = SPACE$(12000) PRINT "FRE(a$(1)) after allocation: ", FRE(a$(1)) a$(1) = SPACE$(0) PRINT "FRE(a$(1)) after deallocation: ", FRE(a$(1)) END Code Example 2 -------------- The program below shows that the problem also occurs in $DYNAMIC arrays in SUBprograms. Compile and link as follows: BC STRING2.BAS ; LINK STRING2 ; DECLARE SUB sub1 () CALL sub1 END SUB sub1 DIM s(2) AS STRING 'This array is dynamic, since SUB is non-STATIC PRINT "FRE before string allocation: "; FRE(s(0)) s(1) = STRING$(1000, 255) PRINT "FRE after string allocation: "; FRE(s(1)) s(1) = "" PRINT "FRE after string deallocation: "; FRE(s(2)) END SUB
THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.
Copyright Microsoft Corporation 1986-2002.