| Versión 3.0 |
| 800x600 mínimo |
|
En esta lección: Definición ----- Punteros y arrays ----- Punteros y funciones ----- Puntero a una función ----- Otras secciones: Conceptos básicos ----- Programando en C ----- Programando en C++ ----- Programando Windows 9x. ----- Teoría electrónica ----- Circuitos electrónicos ----- Actividades adicionales ----- Hipervínculos ----- Contácteme: Dudas y comentarios ----- |
DefiniciónDicho simplemente, un puntero es una dirección en memoria. Como es costumbre en este tutorial, los conceptos se explican mejor por sí mismos, el código es el siguiente:
En primer lugar podemos ver una variable estática llamada almacen y una más que lleva un asterisco al principio llamada *puntero, por el momento no se fije en este detalle, lo explicaremos mas adelante. En la línea 7 se le asigna a la variable almacen el valor de 45 tal y como lo hemos hecho en los programas vistos hasta ahora. En la línea 8 se aprecia una forma de asignar un valor extraño a la variable llamada puntero, se trata del operador de dirección ampersand &, que se utiliza en C para acceder a la direccion en memoria de una variable, de aquí salen dos puntos muy importantes:
Como su nombre lo indica, decimos, refiriendonos a la línea 4 del código de ejemplo, que la dirección de memoria señalada por *puntero corresponde a una variable de tipo int, por lo tanto *puntero es un puntero a una variable de tipo int. Un puntero debe definirse para señalar a un tipo específico de variable y por lo tanto no deberá utilizarse en el mismo programa para señalar a una variable diferente pues esto produce errores de incompatibilidad de código. Como se puede ver en el código de arriba, es posible conocer el contenido de la variable almacen de dos formas diferentes, utilizando el nombre de la variable directamente, o bien con un puntero que señale a la dirección de almacen.
Es común en el estudio de punteros utilizar algunos gráficos para comprender este importante tema de la programación en C. Un rectángulo representa a la variable estática almacen, en tanto que un rectángulo con un punto en su interior representa a un puntero, en nuestro ejemplo, el llamado a su vez puntero. Este diagrama representa el programa en el punto correspondiente a la línea 5 en donde aún no se le ha asignado valor alguno a las variables, observe que el puntero en este momento no apunta a ningún lado y la variable almacen no tiene asignado aún un valor determinado.
Siguiendo la ejecución del programa, en la línea 7 asignamos a almacen el valor de 45, en tanto que en la línea 8 indicamos que puntero guarde la dirección de almacen. En la línea 9 utilizamos la instrucción printf( ) para demostrar los dos importantes conceptos estudiados hasta ahora, en primer lugar indicamos desplegar el valor hexadecimal correspondiente a la dirección en memoria ocupada por la variable almacen y posteriormente desplegamos el valor almacenado en la variable en sí, que en este caso es 45. Aunque en apariencia tenemos dos variables, en realidad se trata de una sola, en este caso almacen, solo que se hace uso del puntero para desplegar los valores mencionados. Es importante que observe detenidamente la instrucción printf( ) y que además compile y ejecute el código de ejemplo para un mejor entendimiento de estos conceptos. Punteros y arraysEn el siguiente código de ejemplo se han definido algunas variables y dos punteros. El primer puntero llamado alla es un puntero a una variable de tipo char y el segundo llamado pt apunta a una variable de tipo int. También se han definido dos arrays llamados cadena y lista, los utilizaremos para demostrar la correspondencia entre punteros y los nombres de los arrays. El nuevo código es el siguiente:
Utilizaremos un dibujo para representar la condición inicial de nuestro programa. Se puede observar que tenemos tres variables, dos punteros, una cadena y un array de enteros, ó también podríamos decir que tenemos tres variables, dos punteros y dos arrays. Cada array está compuesto por el array en sí y un puntero que señala al inicio del array de acuerdo a la definición de un array en C, esto quedará completamente aclarado en el siguiente párrafo. Cada array está compuesto de un número idéntico de elementos de los cuales solo unos cuantos al principio y al final son mostrados para mayor claridad del dibujo. En la línea 14 se ha asignado a la variable primera el valor del noveno caracter de la cadena (recuerde que en C los índices empiezan en 0) en tanto que a segunda se le asigna el mismo valor porque hemos permitido que el puntero señale más allá del principio de la cadena, en la línea 15 dice que se debe sumar 8 al valor del puntero cadena, entonces obtener el valor almacenado en aquella locación y almacenarlo en la variable segunda. Es muy recomendable que Usted compile y ejecute este segundo programa de ejemplo ya que además de los conceptos tratados en los párrafos anteriores a su vez demuestra el concepto de la aritmética de punteros, experimentar con el código nos hará más familiar el manejo de los punteros y a la vez aportará nuevos elementos a lo ya visto en materia de arrays, es importante tener en cuenta que C maneja de forma automática la organización de los punteros de acuerdo al tipo de variable que señalan, esto dependiendo a su vez de la forma en que el compilador defina los diferentes tipos de variables, este concepto quedará más claro cuando en una lección posterior estudiemos el concepto de las estructuras, por lo pronto estudie detenidamente la última parte del código y observe como el sistema ajusta automáticamente el índice cuando utilizamos un puntero a una variable de tipo int. El resultado de la ejecución del programa es el siguiente: ![]()
Punteros y funcionesRecordará que en la lección Funciones mencionamos que había dos maneras de obtener datos provenientes de una función. Una era a través de un array y la otra es utilizando un puntero, demostramos este concepto en el siguiente programa de ejemplo:
En este programa tenemos dos variables declaradas en el programa principal, pernos y rondanas, ninguna fué declarada como puntero. Enseguida asignamos valores a ambas y las desplegamos en pantalla y entonces llamamos a la función llamada reparar ( ) tomando ambos valores, a la variable pernos simplemente la enviamos como parámetro a la función, pero en cambio tomamos la dirección de la variable rondanas como segundo parámetro de la función. Ahora tenemos un problema. Los dos argumentos no son iguales ya que el segundo es un puntero a una variable. De alguna manera debemos alertarle a la función que recibirá una variable entera y un puntero a una variable de tipo int, esto se hace de una manera simple. En la línea 19 vemos que la función declara como primer parámetro a una variable de tipo int llamada tuercas y a un puntero a una variable de tipo int llamado tornillos, por tanto la llamada a la función en el programa principal está acorde con el encabezado de la misma. En el cuerpo de la función desplegamos los valores pasados como parámetros luego los modificamos y desplegamos los nuevos valores. Hasta este momento las cosas están lo suficientemente claras, la sorpresa viene cuando regresamos a la función principal main ( ) y desplegamos los valores una vez más. Encontramos que el valor de pernos se restaura al valor que tenía antes de la llamada a la función reparar, esto es así porque C hace una copia de la variable en cuestión y lleva la copia a la función llamada, dejando a la variable original intacta tal y como lo explicamos anteriormente. En el caso de la variable rondanas hacemos una copia del puntero a la variable y llevamos la copia a la función. Como tenemos un puntero a la variable original, aún y cuando el puntero es una copia local, sigue señalando a la variable original por lo tanto podemos cambiar el valor almacenado en rondanas desde el interior de la función reparar. Cuando regresamos al programa principal, encontramos a la variable rondanas con un nuevo valor. En el ejemplo no existe un puntero en el programa principal porque enviamos simplemente la dirección de la variable a la función reparar. El resultado de este programa es este: ![]()
Puntero a una funciónEn el siguiente programa mostramos como utilizar un puntero a una función, en la línea 7 el programa define puntero_a_funcion como un puntero a una función y no solo a cualquier función, señala a una función con un solo parámetro de tipo float, la función además no retorna nada, tal y como lo especifica la palabra clave void antes de la definición del puntero. El paréntesis en el nombre del puntero es necesario para evitar una posible confusión con una definición de prototipo para una función que regrese un puntero a void. Este es el código:
Observe los prototipos dados en las lineas 3 a 6 que declaran tres funciones que utilizan el mismo parámetro y regresa nada (void) al igual que el puntero. Como son similares, es posible utilizar el puntero para referirse a las funciones como lo demuestra la parte ejecutable del programa. En la línea 14 contiene una llamada a la función despliega_cosas y la línea 15 asigna el valor de despliega_cosas a puntero_a_funcion. Como el nombre de la función está definido como un puntero a esa función, su nombre puede ser asignado a una variable puntero hacia la función. Recordará que el nombre de un array es en realidad un puntero constante al primer elemento del array, de la misma manera, el nombre de una función es en realidad un puntero constante el cual señala a la función misma. El puntero es sucesivamente asignado a la dirección de cada una de las tres funciones y cada una es llamada una ó dos veces a manera de ilustración de cómo se utiliza un puntero a una función. El resultado de la ejecución del programa es el siguiente:
Un puntero a una función no es utilizado a menudo pero es una construcción muy poderosa cuando se utiliza, continuaremos estudiando el uso de los punteros examinando los programas que veremos en las siguientes lecciones. |