14.14.1.14 Pointers

###
14.14.1.14 Pointers

Pointer instances are created by calling the `pointer` function on a `ctypes` type:

    >>> from ctypes import *
    >>> i = c_int(42)
    >>> pi = pointer(i)
    >>>

Pointer instances have a `contents` attribute which returns the object to which the pointer points, the `i` object above:

    >>> pi.contents
    c_long(42)
    >>>

Note that `ctypes` does not have OOR (original object return), it constructs a new, equivalent object each time you retrieve an attribute:

    >>> pi.contents is i
    False
    >>> pi.contents is pi.contents
    False
    >>>

Assigning another `c_int` instance to the pointer's contents attribute would cause the pointer to point to the memory location where this is stored:

    >>> i = c_int(99)
    >>> pi.contents = i
    >>> pi.contents
    c_long(99)
    >>>

Pointer instances can also be indexed with integers:

    >>> pi[0]
    99
    >>>

Assigning to an integer index changes the pointed to value:

    >>> print i
    c_long(99)
    >>> pi[0] = 22
    >>> print i
    c_long(22)
    >>>

It is also possible to use indexes different from 0, but you must know what you're doing, just as in C: You can access or change arbitrary memory locations. Generally you only use this feature if you receive a pointer from a C function, and you know that the pointer actually points to an array instead of a single item.

Behind the scenes, the `pointer` function does more than simply create pointer instances, it has to create pointer types first. This is done with the `POINTER` function, which accepts any `ctypes` type, and returns a new type:

    >>> PI = POINTER(c_int)
    >>> PI
    <class 'ctypes.LP_c_long'>
    >>> PI(42)
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
    TypeError: expected c_long instead of int
    >>> PI(c_int(42))
    <ctypes.LP_c_long object at 0x...>
    >>>

Calling the pointer type without an argument creates a `NULL` pointer. `NULL` pointers have a `False` boolean value:

    >>> null_ptr = POINTER(c_int)()
    >>> print bool(null_ptr)
    False
    >>>

`ctypes` checks for `NULL` when dereferencing pointers (but dereferencing non-`NULL` pointers would crash Python):

    >>> null_ptr[0]
    Traceback (most recent call last):
        ....
    ValueError: NULL pointer access
    >>>

    >>> null_ptr[0] = 1234
    Traceback (most recent call last):
        ....
    ValueError: NULL pointer access
    >>>