Pointers and references: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|Perl}}: Wiki optimalization.)
m (Spelling/grammar/aesthetics.)
Line 17: Line 17:
Var : Integer;
Var : Integer;
Var_Address : Address := Var'address;
Var_Address : Address := Var'address;
Addresses support operations of comparison, addition, and subtraction
Addresses support operations of comparison, addition, and subtraction. Ada also supports conversion between address types and a predefined subtype of Integer named Integer_Address. This accommodates the conversion to a linear addressing of any hardware address scheme including address:offset used in
Ada also supports conversion between address types and a pre-defined subtype of
Integer named Integer_Address. This accomodates the conversion to a linear
addressing of any hardware address scheme including address:offset used in
the 8086 processor.
the 8086 processor.


Line 102: Line 99:
pMyPointer : Pointer ;
pMyPointer : Pointer ;


Simple pointer to a ''pre-defined'' type:
Simple pointer to a ''predefined'' type:


Variable Declaration
Variable Declaration
Line 108: Line 105:
pIntPointer : ^Integer ;
pIntPointer : ^Integer ;


A pointer to a ''Record''. This is the equivilent to a ''Struct'' in C
A pointer to a ''Record''. This is the equivalent to a ''Struct'' in C


Type Defintion
Type Defintion
Line 130: Line 127:
- Dereferencing a Pointer -
- Dereferencing a Pointer -


Pointers are dereferenced using the caret '^' symbol. Dereferencing will cause the compiler or RTL to reveal the data that the pointer points to:
Pointers are dereferenced using the caret '^' symbol. Dereferencing will cause the compiler or RTL to reveal the data that the pointer points to:


IntVar := pIntPointer^ ;
IntVar := pIntPointer^ ;


Dereference with a type cast of an ''untyped'' pointer. It is not legal syntax to simply dereference an untyped pointer, since there is nothing to designate its type. It must therefor be "Type Cast" when the dereference takes place as below.
Dereference with a type cast of an ''untyped'' pointer. It is not legal syntax to simply dereference an untyped pointer, since there is nothing to designate its type. It must therefor be "Type Cast" when the dereference takes place as below.


IntVar := integer(MyPointer^);
IntVar := integer(MyPointer^);
Line 140: Line 137:
- Pushing a Pointer -
- Pushing a Pointer -


Many programmers are familiar with C's ability to increment pointers of any type by using the '''++''' or '''--''' operators. Delphi has a very limited implementation of this when using pointers to char. Delphi can use the Inc() & Dec() procedures to increment or decrement a pointer to char. This is the only special case. To increment all other pointers you must use a "Type Cast". The syntax for doing this is:
Many programmers are familiar with C's ability to increment pointers of any type by using the '''++''' or '''--''' operators. Delphi has a very limited implementation of this when using pointers to char. Delphi can use the Inc() & Dec() procedures to increment or decrement a pointer to char. This is the only special case. To increment all other pointers you must use a "Type Cast". The syntax for doing this is:


p := Inc(integer(p)+1);
p := Inc(integer(p)+1);


This will increment the pointer by one byte. Since all pointers are actualy 32 bit numbers. Additionaly, if you have a typed pointer you can increment the pointer by the size of the type it points to:
This will increment the pointer by one byte. Since all pointers are actually 32 bit numbers. Additionally, if you have a typed pointer you can increment the pointer by the size of the type it points to:


pInt := Inc(integer(pInt)+sizeof(Integer)) ;
pInt := Inc(integer(pInt)+sizeof(Integer)) ;
Line 178: Line 175:
=={{header|Forth}}==
=={{header|Forth}}==


Forth is an untyped language, and treats pointers in much the same way that assembly language does. In Forth, memory is addressable in characters, cells and double cells. Cells are the native word size of the host processor, and are usually either 16 or 32 bits in size. Double cells are twice that size. Address alignment requirements depend on the processor being used to host the Forth system.
Forth is an untyped language, and treats pointers in much the same way that assembly language does. In Forth, memory is addressable in characters, cells and double cells. Cells are the native word size of the host processor, and are usually either 16 or 32 bits in size. Double cells are twice that size. Address alignment requirements depend on the processor being used to host the Forth system.


To declare a variable that lives in memory:
To declare a variable that lives in memory:
Line 185: Line 182:
2variable my2var \ stores 2 cells
2variable my2var \ stores 2 cells


This creates the word "myvar", which when executed leaves the address of a cell of memory on the stack. This address may be accessed with @ (fetch) or ! (store):
This creates the word "myvar", which when executed leaves the address of a cell of memory on the stack. This address may be accessed with @ (fetch) or ! (store):
1 myvar ! \ place the value 1 into myvar
1 myvar ! \ place the value 1 into myvar
myvar @ . \ prints the value stored in myvar
myvar @ . \ prints the value stored in myvar
Line 201: Line 198:
20 to myval \ Changes myval to return 20 instead of 10
20 to myval \ Changes myval to return 20 instead of 10


Forth also has a concept analogous to function pointers - the "execution token". ETs are the address of a word's executable code. The ' character, pronounced "tick", returns the execution token of the next word in the input stream. "Execute" calls the XT on the stack. XT's are cells and can be stored and operated on as desired.
Forth also has a concept analogous to function pointers - the "execution token". ETs are the address of a word's executable code. The ' character, pronounced "tick", returns the execution token of the next word in the input stream. "Execute" calls the XT on the stack. XT's are cells and can be stored and operated on as desired.
' myval \ Leaves the XT of myval on the stack
' myval \ Leaves the XT of myval on the stack
' myval execute \ Equivalent to just typing "myval"
' myval execute \ Equivalent to just typing "myval"


For pointer arithmetic, standard integer math operations may be used. There are some words that are specifically designed to enable portable pointer arithmetic:
For pointer arithmetic, standard integer math operations may be used. There are some words that are specifically designed to enable portable pointer arithmetic:
cell \ Puts the number of bytes in one cell on the stack
cell \ Puts the number of bytes in one cell on the stack
cell+ \ Adds one cell
cell+ \ Adds one cell
Line 279: Line 276:


Pop11 uses reference model, conceptually all Pop11 data consists
Pop11 uses reference model, conceptually all Pop11 data consists
of references. Therefore, normally there is no need for explicit
of references. Therefore, normally there is no need for explicit
references:
references:


Line 356: Line 353:
=={{header|Tcl}}==
=={{header|Tcl}}==


Tcl does not have pointers, however if required a similar level of indirection can be had by storing a variable name in another variable, eg.
Tcl does not have pointers, however, if required, a similar level of indirection can be had by storing a variable name in another variable, eg.


set var 3
set var 3

Revision as of 01:13, 15 January 2008

Task
Pointers and references
You are encouraged to solve this task according to the task description, using any language you may know.

Basic Data Operation
This is a basic data operation. It represents a fundamental action on a basic data type.

You may see other such operations in the Basic Data Operations category, or:

Integer Operations
Arithmetic | Comparison

Boolean Operations
Bitwise | Logical

String Operations
Concatenation | Interpolation | Comparison | Matching

Memory Operations
Pointers & references | Addresses

In this task, the goal is to demonstrate common operations on pointers and references.

Ada

Ada does not have pointers, only access types.

Create a pool specific access type for an integer

 type Int_Access is access Integer;
 Int_Acc : Int_Access := new Integer(5);

Create a general access type for an integer

 type Int_Ptr is access all Integer;
 Ref : Int_Ptr;
 Var : aliased Integer := 3;
 Ref := Var'access;

Ada does not provide pointer arithmetic, but does allow evaluation of the address

 Var : Integer;
 Var_Address : Address := Var'address;

Addresses support operations of comparison, addition, and subtraction. Ada also supports conversion between address types and a predefined subtype of Integer named Integer_Address. This accommodates the conversion to a linear addressing of any hardware address scheme including address:offset used in the 8086 processor.

Ada allows the specification of a starting address for any object

 -- Demonstrate the overlay of one object on another
 A : Integer;
 B : Integer;
 for B'address use A'address;
 -- A and B start at the same address

C and C++

The following code creates a pointer to an int variable

 int var = 3;
 int* pointer = &var;

Access the integer variable through the pointer:

 int v = *pointer; /* sets v to the value of var (i.e. 3) */
 *pointer = 42; /* sets var to 42 */

Change the pointer to refer to another object

 int othervar;
 pointer = &othervar;

Change the pointer to not point to any object

 pointer = NULL; /* needs having stddef.h included */

or

 pointer = 0; /* actually any constant integer expression evaluating to 0 could be used, e.g. (1-1) will work as well */

or

 pointer = (void*)0; /* C only, not allowed in C++ */

Get a pointer to the first element of an array:

 int array[10];
 pointer = array;
 /* or alternatively: */
 pointer = &array[0];

Move the pointer to another object in the array

 pointer += 3; /* pointer now points to array[3] */
 pointer -= 2; /* pointer now points to array[1] */

Access another object in the same array through the pointer

 v = pointer[3]; /* accesses third-next object, i.e. array[4] */
 v = pointer[-1]; /* accesses previous object, i.e. array[0] */
 /* or alternatively */
 v = *(pointer + 3); /* array[4] */
 v = *(pointer - 1); /* array[0] */

C++

With pointers: See 'C' example above.

C++ specific alternative to "The following code creates a pointer to an int variable":

 int* pointer2(&var);

With references:

The following code create a reference to an int variable:

 int var = 3;
 int& ref = var;
 // or alternatively:
 int& ref2(var);

Access the integer variable through the reference

 int v = ref; // sets v to the value of var, that is, 3
 ref = 42; // sets var to 42

References cannot be changed to refer to other objects, and cannot (legally) made to refer to no object.

Get a reference to the first element of an array:

 int array[10];
 int& ref3 = array[0];

Changing the reference to refer to another object of the array is not possible.

Accessing another object of the array through the reference:

 v = (&ref)[3]; // read value of array[3]; however doing this is bad style

Delphi

Delphi ( Object Pascal / Turbo Pascal ) fully supports both typed and untyped pointers. All pointers have 32 bit. However for older, 16-bit code, they had the form segment:offset, while on 32 bit code, they only contain the 32 bit offset.

Examples of pointers

Simple untyped pointer variable:

Variable Declaration

 pMyPointer : Pointer ;

Simple pointer to a predefined type:

Variable Declaration

 pIntPointer : ^Integer ;

A pointer to a Record. This is the equivalent to a Struct in C

Type Defintion

 MyRecord = Record
             FName : string[20];
             LName : string[20];
            end;

Variable Declaration

 pMyRecord : ^MyRecord ;

Note that when defining a pointer type, unless otherwise, you may refer to the pointed to type before defining it. For example the following is legal despite tFoo not being defined at the pointer definition:

 type
   pFoo = ^tFoo; { allowed despite tFoo not yet being defined }
   tFoo = record
            value1, value2: integer;
          end;

- Dereferencing a Pointer -

Pointers are dereferenced using the caret '^' symbol. Dereferencing will cause the compiler or RTL to reveal the data that the pointer points to:

  IntVar := pIntPointer^ ;

Dereference with a type cast of an untyped pointer. It is not legal syntax to simply dereference an untyped pointer, since there is nothing to designate its type. It must therefor be "Type Cast" when the dereference takes place as below.

  IntVar := integer(MyPointer^);

- Pushing a Pointer -

Many programmers are familiar with C's ability to increment pointers of any type by using the ++ or -- operators. Delphi has a very limited implementation of this when using pointers to char. Delphi can use the Inc() & Dec() procedures to increment or decrement a pointer to char. This is the only special case. To increment all other pointers you must use a "Type Cast". The syntax for doing this is:

  p := Inc(integer(p)+1);

This will increment the pointer by one byte. Since all pointers are actually 32 bit numbers. Additionally, if you have a typed pointer you can increment the pointer by the size of the type it points to:

 pInt := Inc(integer(pInt)+sizeof(Integer)) ;
 pMyRecord := inc(integer(pMyRecord)+SizeOf(MyRecord));

E

E is a memory-safe object-graph language, and as such uses only object references; there are no non-reference values. Mutable storage always consists of an object; in particular, an assignable variable has, if necessary, an underlying "slot" object which can be retrieved.

var x := 0
def slot := &x # define "slot" to be x's slot

x := 1         # direct assignment; value is now 1
slot.put(2)    # via slot object; value is now 2

There are also mutable data structures:

def flexList := [].diverge()
flexList.push(1)
flexList.push(2)
flexList.snapshot() # returns [1, 2]

User-defined objects can have state by containing it:

var open := true
def door {
    to open()  { open := true }
    to close() { open := false }
    to walkThrough() { require(open) }
}

Forth

Forth is an untyped language, and treats pointers in much the same way that assembly language does. In Forth, memory is addressable in characters, cells and double cells. Cells are the native word size of the host processor, and are usually either 16 or 32 bits in size. Double cells are twice that size. Address alignment requirements depend on the processor being used to host the Forth system.

To declare a variable that lives in memory:

 variable myvar   \ stores 1 cell
 fvariable myfvar \ stores 1 floating point number (often 8 bytes)
 2variable my2var \ stores 2 cells

This creates the word "myvar", which when executed leaves the address of a cell of memory on the stack. This address may be accessed with @ (fetch) or ! (store):

 1 myvar !  \ place the value 1 into myvar
 myvar @ .  \ prints the value stored in myvar
 1 myvar +! \ add 1 to the value stored in myvar

Other fetch and store operations:

 c@ c!  \ fetch/store a single character
 @  !   \ fetch/store one cell
 2@ 2!  \ fetch/store two cells
 f@ f!  \ fetch/store a floating point value

Forth also has "value", which is a construct similar to other languages' "reference":

 10 value myval  \ create a new word that returns the value 10
 myval .         \ prints 10
 20 to myval     \ Changes myval to return 20 instead of 10

Forth also has a concept analogous to function pointers - the "execution token". ETs are the address of a word's executable code. The ' character, pronounced "tick", returns the execution token of the next word in the input stream. "Execute" calls the XT on the stack. XT's are cells and can be stored and operated on as desired.

 ' myval         \ Leaves the XT of myval on the stack
 ' myval execute \ Equivalent to just typing "myval"

For pointer arithmetic, standard integer math operations may be used. There are some words that are specifically designed to enable portable pointer arithmetic:

 cell        \ Puts the number of bytes in one cell on the stack
 cell+       \ Adds one cell
 10 cells +  \ adds 10 cells
 aligned     \ rounds the address up to the next cell

As an example, here is some code to add together an array of cells, expanded and commented:

 : add-cells ( addr n -- sum )
    0 -rot      \ make stack into ( 0 addr n )
    bounds ?do  \ bounds converts an <address count> pair into a <high, low> range
       i @      \ using the current loop index as an address, fetch the cell
       +        \ Add it to the top number on the stack
    cell +loop  \ Advance the loop index by the size of one cell
 ;

Java

Java's pointers aren't as controllable as they are in C/C++ (and probably not even technically "pointers"), but they are still predictable. The best examples are call-by-value and call-by-reference functions. Primitive types (int, char, byte, double, etc.) are never pointers, and functions will not be able to change them remotely.

public void add2(int a){
   a += 2;
}

This function will never change the value of a. However, if a function tries to change a String (or any other Object) in a similar way, it will show up outside the function:

public void addA(String msg){
   msg += "A";
}

This function will append a letter A to whatever String is passed into it, and the change will show up anywhere that variable does.

Data members of Objects can be changed in the same way:

public void expand(Circle c){
   c.radius++;
}

This function (which assumes a Circle object has been created) will increase the radius even if it is a primitive data type, because it is part of an Object.

Perl

Interpeter: Perl v5.x

Perl does not have pointers, but references. You may think of them as pointers with the insane stuff removed. Any scalar, array element or hash value can contain a reference to a data structure.

# start with some var definitions
my $scalar = 'a string';
my @array = ('an', 'array');
my %hash = ( firstkey => 'a', secondkey => 'hash' );

# make references
my $scalarref = \$scalar;
my $arrayref = \@array;
my $hashref = \%hash;

Using a reference

# printing the value
print ${$scalar};
print $arrayref->[1];          # this would print "array"
print $hashref->{'secondkey'}; # this would print "hash"

# changing the value
${$scalar} = 'a new string';       # would change $scalar as well
$arrayref->[0] = 'an altered';     # would change the first value of @array as well
$hashref->{'firstkey'} = 'a good'; # would change the value of the firstkey name value pair in %hash

You may also create anonymous references.

my $scalarref = \'a scalar';
my $arrayref = ['an', 'array'];
my $hashref = { firstkey => 'a', secondkey => 'hash' }

Pop11

Pop11 uses reference model, conceptually all Pop11 data consists of references. Therefore, normally there is no need for explicit references:

vars vec1, vec2;
;;; Create a vector and assign (reference to) it to vec1
consvector("a", "b", "c", 3) -> vec1;
;;; Copy (reference to) vector
vec1 -> vec2;
;;; Print value of vec1
vec1 =>
;;; Change first element of vec2
"d" -> vec2(1);
;;; Print value of vec1 -- the value changes because vec1 and
;;; vec2 reference the same vector
vec1 =>

However, if one needs extra indirection one can get it:

vars ref1, ref2;
;;; Allocate a reference to number 42
consref(42) -> ref1;
;;; Copy reference
ref1 -> ref2;
;;; print value
cont(ref2) =>
;;; Change referenced value
17 -> cont(ref2);
;;; print value of first reference
cont(ref1) =>

Standard Pop11 does not allow pointer arithmetics or address operator. There is a low-level extension (Syspop11) which has C-like pointers (with pointer arithmetics), but those does not count as "basic data operation".

Python

Python does not have pointers and all Python names (variables) are implicitly references to objects. Python is a late-binding dynamic language in which "variables" are untyped bindings to objects. (Thus Pythonistas prefer the term name instead of "variable" and the term bind in lieu of "assign").

# Bind a literal string object to a name:
a = "foo"
# Bind an empty list to another name:
b = []
# Classes are "factories" for creating new objects: invoke class name as a function:
class Foo(object):
    pass
c = Foo()
# Again, but with optional initialization:
class Bar(object):
    def __init__(self, initializer = None)
        # "initializer is an arbitrary identifier, and "None" is an arbitrary default value
        if initializer is not None:
           self.value = initializer
d = Bar(10)
print d.value
# Test if two names are references to the same object:
if a is b: pass
# Alternatively:
if id(a) == id(b): pass
# Re-bind a previous used name to a function:
def a(fmt, *args):
    if fmt is None:
        fmt = "%s"
     print fmt % (args)
# Append reference to a list:
b.append(a)
# Unbind a reference:
del(a)
# Call (anymous function object) from inside a list
b[0]("foo")  # Note that the function object we original bound to the name "a" continues to exist
             # even if its name is unbound or rebound to some other object.

[Note: in some ways this task is meaningless for Python given the nature of its "variable" binding semantics].


Tcl

Tcl does not have pointers, however, if required, a similar level of indirection can be had by storing a variable name in another variable, eg.

 set var 3
 set pointer var; # assign name "var" not value 3
 set pointer;     # returns "var"
 set $pointer;    # returns 3
 set $pointer 42; # variable var now has value 42

In practice it's safer and more convenient to use array keys, eg.

 set arr(var) 3
 set pointer var
 set arr($pointer);    # returns 3
 set arr($pointer) 42; # arr(var) now has value 42

Toka

Toka is an untyped language, and treats pointers in a manner similar to that of assembly language. In Toka, memory can be addressed in characters and cells. Cells are the native word size of the host processor, and are generally either 32 or 64 bits in size. Address alignment is dependent on the host processor.

To declare a variable that lives in memory:

variable myvar   #! stores 1 cell

This creates the word "myvar", which when executed leaves the address of a cell of memory on the stack. This address may be accessed with @ (fetch) or ! (store):

1 myvar !  #! place the value 1 into myvar
myvar @ .  #! prints the value stored in myvar
1 myvar +! #! add 1 to the value stored in myvar

Other fetch and store operations:

c@ c!  \ fetch/store a single character
@  !   \ fetch/store one cell

Toka also has an optional "value", which is a construct similar to other languages' "reference":

needs values
10 value myval  #! create a new word that returns the value 10
myval .         #! prints 10
20 to myval     #! Changes myval to return 20 instead of 10

Toka has a concept similar to that of function pointers. The word ` returns the address of a quote which can be invoked or passed around.

` myval         #! Leaves the address of myval on the stack
` myval invoke  #! Equivalent to just typing "myval"

For pointer arithmetic, standard integer math operations may be used. There are some words that are specifically designed to enable portable pointer arithmetic:

cell-size   #! Puts the number of bytes in one cell on the stack
cell+       #! Adds one cell
10 cells +  #! Adds 10 cells
char-size   #! Puts the number of bytes in one character on the stack
char+       #! Adds one char
10 chars +  #! Adds 10 chars