Memory & Pointers
On 8-bit machines, PEEK(address) read a byte of memory and POKE address, value wrote one.
29.1 Historical PEEK and POKE
On 8-bit machines, PEEK(address) read a byte of memory and POKE address, value wrote one. Hardware (video, sound, input) was memory-mapped, so POKE was how BASIC programs controlled it:
On the IBM PC, QBasic used segmented memory: DEF SEG = segment then PEEK(offset)/POKE offset, v. Text screen memory started at segment &HB800 (color) and SCREEN 13 video memory at &HA000:
QB64 emulates common legacy addresses (screen memory, keyboard flags at DEF SEG = 0: PEEK(1047)) for compatibility, but cannot touch real hardware.
10 REM COMMODORE 64
20 POKE 53280, 0: POKE 53281, 0 : REM BLACK BORDER AND BACKGROUND
30 POKE 1024, 1 : REM PUT SCREEN CODE 1 ("A") IN THE TOP-LEFT CELL
40 PRINT PEEK(197) : REM CODE OF THE KEY CURRENTLY PRESSED
50 SYS 64738 : REM JUMP TO MACHINE CODE (RESET)' QBasic / QB64 (QB64 emulates these legacy memory areas)
DEF SEG = &HB800
POKE 0, ASC("Q") ' character in the top-left cell
POKE 1, &H1E ' attribute: yellow on blue
DEF SEG ' restore the default segment29.2 VARPTR, VARSEG, SADD
Returns (QBasic) offset address of a variable segment address of a variable offset of a string's data address encoded as a string, for DRAW/PLAY "X" commands
They were used with CALL ABSOLUTE (run machine code stored in an array), BLOAD/BSAVE (load/save raw memory, e.g., screen images), and interrupts (CALL INTERRUPT in QuickBASIC). QB64 keeps VARPTR/VARSEG for compatibility within its emulated memory; for real memory work it provides _OFFSET and _MEM.
29.3 QB64 _MEM blocks
A _MEM variable describes a memory region (offset, size, type) safely, with bounds checking:
_MEM(var) / _MEM(arr()) / _MEM(offset, size) block for a variable, array, or raw address allocate a new block block covering an image's pixels _MEMGET, _MEMPUT read / write values _MEMFILL, _MEMCOPY fill a range / copy between blocks release the block
.OFFSET, .SIZE, .ELEMENTSIZE, .TYPE _OFFSET type, _OFFSET(var)
DIM arr(1 TO 10) AS LONG
FOR i = 1 TO 10: arr(i) = i * i: NEXT
DIM m AS _MEM
m = _MEM(arr()) ' memory block covering the whole array
PRINT "Bytes:"; m.SIZE; " Element size:"; m.ELEMENTSIZE
DIM v AS LONG
_MEMGET m, m.OFFSET + 4 * 2, v ' read the third element (zero-based offset)
PRINT "arr(3) ="; v
_MEMPUT m, m.OFFSET, 999 AS LONG ' write the first element
PRINT "arr(1) ="; arr(1)
PRINT "arr(4) ="; _MEMGET(m, m.OFFSET + 12, LONG) ' function form
_MEMFREE m
DIM buf AS _MEM
buf = _MEMNEW(1024) ' allocate 1 KB
_MEMFILL buf, buf.OFFSET, buf.SIZE, 0 AS _UNSIGNED _BYTE
_MEMFREE buf ' always free what you allocate29.4 Fast pixel access with _MEMIMAGE
This is far faster than PSET for full-screen effects (plasma, fire, image filters). $CHECKING:OFF ... $CHECKING:ON around hot loops removes safety checks for extra speed — use only on debugged code.
SCREEN _NEWIMAGE(640, 480, 32)
DIM m AS _MEM, o AS _OFFSET, x AS LONG, y AS LONG
m = _MEMIMAGE(0) ' 0 = the screen image
FOR y = 0 TO 479
o = m.OFFSET + y * 640 * 4 ' 4 bytes per 32-bit pixel
FOR x = 0 TO 639
_MEMPUT m, o, _RGB32((x XOR y) AND 255, x MOD 256, y MOD 256) AS _UNSIGNED LONG
o = o + 4
NEXT
NEXT
_MEMFREE m
SLEEP29.5 Safety rules
Never write outside a block; _MEM checks help, raw _OFFSET arithmetic does not.
Free every _MEMNEW and _MEMIMAGE block; free images and sounds you load.
Dynamic arrays and strings can move in memory when resized — re-acquire their _MEM after REDIM.
FreeBASIC: true C-style pointers: Dim p As Integer Ptr = @x, *p = 5, p[3], Allocate/Deallocate, Peek/Poke on real addresses, StrPtr(s), VarPtr(x), ProcPtr(MySub) for function pointers. VB.NET: managed memory and garbage collection; unsafe pointers are not available in VB (unlike C#). Interop uses IntPtr, Marshal.AllocHGlobal, Marshal.Copy, and Span(Of T) for efficient buffers.