Los «punteros» en C#

Un «puntero» es una dirección de memoria. Normalmente un puntero tendrá un tipo de datos asociado: por ejemplo, un
«puntero a entero» será una dirección de memoria en la que habrá almacenado (o podremos almacenar) un número entero.

El hecho de poder acceder directamente al contenido de ciertas posiciones de memoria da una mayor versatilidad a un programa, porque permite hacer casi cualquier cosa, pero a cambio de un riesgo de errores mucho mayor.

En lenguajes como C, es imprescindible utilizar punteros para poder crear estructuras dinámicas, pero en C# podemos «esquivarlos», dado que tenemos varias estructuras dinámicas ya creadas como parte de las bibliotecas auxiliares que acompañan al lenguaje básico.

También es correcto escribir

El valor que guarda «posicion» es una dirección de memoria. Generalmente no podremos hacer cosas como posicion=5; porque nada nos garantiza que la posición 5 de la memoria esté disponible para que nosotros la usemos. Será más habitual que tomemos una dirección de memoria que ya contiene otro dato, o bien que le pidamos al compilador que nos reserve un espacio de memoria (más adelante veremos cómo).

Si queremos que «posicion» contenga la dirección de memoria que el compilador había reservado para la variable «numero», lo haríamos usando el símbolo «&», así:

Como los punteros son «peligrosos» (es frecuente que den lugar a errores muy difíciles de encontrar), el compilador nos obliga a que le digamos que sabemos que esa zona de programa no es segura, usando la palabra «unsafe»:

Podemos reservar espacio para una variable dinámica usando «stackalloc». Por ejemplo, una forma alternativa de crear un array de enteros sería ésta:

Si aumentamos o disminuimos el valor de un puntero, cambiará la posición que representa … pero no cambiará de uno en uno, sino que saltará a la siguiente posición capaz de almacenar un dato como el que corresponde a su tipo base. Por ejemplo, si un puntero a entero tiene como valor 40.000 y hacemos «puntero++», su dirección pasará a ser 40.004 (porque cada entero ocupa 4 bytes).

Fixed

C# cuenta con un «recolector de basura», que se encarga de liberar el espacio ocupado por variables que ya no se usan. Esto puede suponer algún problema cuando usamos variables dinámicas, porque estemos accediendo a una posición de memoria que el entorno de ejecución haya previsto que ya no necesitaríamos… y haya borrado.

Por eso, en ciertas ocasiones el compilador puede avisarnos de que algunas asignaciones son peligrosas y obligar a que usemos la palabra «fixed» para indicar al compilador que esa zona «no debe limpiarse automáticamente».

Esta palabra se usa antes de la declaración y asignación de la variable, y la zona de programa que queremos «bloquear» se indica entre llaves:

Como se ve en el programa anterior, en una zona «fixed» no se puede modificar el valor de esa variables; si lo intentamos recibiremos un mensaje de error que nos avisa de que esa variable es de «sólo lectura» (read-only). Por eso, para cambiarla, tendremos que empezar otra nueva zona «fixed».