Some examples using Modula-2, a Mesa's successor.
How it allows for all the C pointer features, while adding a little bit more safety.
MODULE examples;
IMPORT Terminal, SYSTEM;
(* procedure with reference parameter, no need for pointers *)
PROCEDURE ChangeParam (VAR changeMe: CARDINAL);
BEGIN
changeMe := 25;
END ChangeParam;
(*
procedure with a slice, bounds given by HIGH(changeMe) and LOW(changeMe).
also a string in this case
no need for explicit pointers
*)
PROCEDURE DumpLetters (VAR letters: ARRAY OF CHAR);
VAR
i : CARDINAL;
BEGIN
FOR i := 0 TO HIGH(letters) DO
WriteChar(letters[i]);
WriteLn;
(* Or just use *)
WriteString (letters);
END DumpLetters;
VAR
anInt : CARDINAL := 12 ;
aPtr : POINTER TO CHAR;
aBuffer : ARRAY [1..2] OF CHAR;
anAddr : ADDRESS; (* think void* *)
aPtr2 : POINTER TO CHAR;
BEGIN
WriteInt(anInt); (* writes 12 *)
ChangeParam (anInt);
WriteInt(anInt); (* writes 25 *)
DumpLetters ('A simple string');
NEW(aPtr); (* The compiler knows the size, no need for sizeof, but you can use ALLOCATE(aPTR, SIZE(CHAR)) if you want *)
(* This is where it shares the same problems with C, due to manual memory control *)
DISPOSE(aPtr);
(* do pointer arithmetic if really required *)
anAddr := SYSTEM.ADDADR (SYSTEM.ADR(aBuffer), SIZE(CHAR) * 1);
aPtr2 := SYSTEM.CAST(POINTER TO CHAR, anAddr); (* aPtr2 now points to aBuffer(2) *)
END examples;
So the compiler will mark this module as unsafe since the meta-package SYSTEM is being used.All Modula-2 successors, have GC support, as such the DISPOSE() would have to be written as SYSTEM.DISPOSE() and could only be applied to untraced pointers.