6.3.- Variables automáticas y apuntadores


Las variables automáticas se crean en tiempo de compilación y se destruyen al terminar la ejecución del módulo donde fueron declaradas.
Aunque no es estrictamente necesario, se pueden manejar las variables automáticas por medio de apuntadores, como se muestra en el listado 6.1.

 #include <iostream.h>                                     
 #include <conio.h>                                          
                                                               
  void main()                                                  
  {                                                            
    int automatica ; // Se declara la variable automatica.     
    int *apunt   ;  // Se declara el apuntador apunt, que apun-
	            	 // tará a objetos de tipo int.            
                                                               
    automatica = 100 ; // Se asigna el valor 100 a la variable 
                      // automatica.                           
                                                               
    apunt = &automatica ; // Se asigna a apunt la dirección de 
                          // automatica ó apunt apunta a       
                          // automatica.                       
    clrscr();                                                  
                                                               
    cout << "VALOR=" << automatica << " \n"; // 100 *apunt="200" ; // Se asigna el valor 200 al objeto apunta- // do por apunt. cout << "VALOR=" << automatica << " \n"; // 200 getch(); } 

Listado 6.1.- Ejemplo de variables automáticas y apuntadores.

Las instrucciones del listado 6.1 se traducen en la siguiente secuencia, donde los apuntadores se representan con una flecha (para simular que "apuntan hacia" ó "señalan" un objeto) y los objetos apuntados se representan por un cuadro (para simular un recipiente).

    INSTRUCCION                     REPRESENTACION GRAFICA
 
    int automatica ;                automatica
                                    |----------------|
                                    |       ?        |
                                    |----------------|
                                             
                                    
    int *apunt ;                     ----> ?               
                                                            
                                                           
    automatica = 100 ;              automatica
                                    |----------------|
                                    |      100       |
                                    |----------------|

                                                           
    apunt = &automatica ;           automatica, *apunt 
                                    |----------------|
                         apunt ---->|      100       |
                                    |----------------|

                                                           
    *apunt = 200 ;                  automatica, *apunt
                                    |----------------|
                        apunt  ---->|      200       |
                                    |----------------|

El estado final de la zona de memoria correspondiente al objeto apuntado y al apuntador se representa en la figura 6.5.

Figura 6.5.- Visualización del objeto apuntado y del apuntador en la memoria RAM.

Nótese que tanto el apuntador como el objeto apuntado se almacenan en la pila.

Las direcciones de memoria FFF0 , FFF2 , FFF4 , son hipotéticas.

Un apuntador es una variable que solo puede contener un valor a la vez, por lo que solo puede apuntar a un objeto al mismo tiempo.

Por otro lado, una variable cualquiera puede ser apuntada por varios apuntadores, ya que su dirección de memoria puede ser almacenada en distintas variables a la vez.

Al declarar un apuntador, se está especificando el tipo de variable al que va a apuntar.

Por ejemplo, no podrá declararse un apuntador a objetos de tipo int y después intentar utilizarlo para apuntar a objetos de tipo float.

Cuando se desee manejar un apuntador a cualquier tipo de objeto, se puede declarar de tipo void, como en:

              void *multiusos ; 

En el listado 6.2 se muestra un ejemplo de aplicación de un apuntador de tipo void.

 #include <iostream.h>                                     
 #include <conio.h>                                       
  #define NL cout << "\n" void main() { int varent="0" ; float varflot="0.0" ; void *apmulti="&varent;" // apmulti APUNTA A varent *(int *)apmulti="2" ; // ASIGNA 2 AL OBJETO NL; // APUNTADO POR apmulti cout << varent ; apmulti="&varflot" ; // apmulti APUNTA A varflot *(float *)apmulti="1.1" ; // ASIGNA 1.1 AL OBJETO APUNTADO // POR apvoid NL; cout << varflot ; NL; getch(); } 

Listado 6.2.- Utilización de apuntadores de tipo void.

Del listado 6.2, analicemos la instrucción:

*(int *)apmulti = 2 ;

en donde:

apmulti es un apuntador de tipo void.

(int *)apmulti está forzando a que apmulti apunte a objetos 
               de tipo int.

*(int *)apmulti se refiere a un objeto de tipo entero apuntado
                por apmulti.

En los ejemplos manejados hasta aquí se ha supuesto el modelo de memoria SMALL, por lo que los apuntadores son near por predeterminación.

El hecho de que sean near significa que solo disponen de dos bytes para almacenar una dirección de memoria. Al disponer de dos bytes, el número entero sin signo más grande que pueden almacenar es 65535, el cual corresponde a la dirección más alta de un segmento de memoria.

Cuando se está utilizando el modelo de memoria SMALL y se quiere accesar una dirección de memoria de otro segmento, se debe utilizar el modificador far al declarar el apuntador correspondiente. Un apuntador far dispone de cuatro bytes; en los dos primeros bytes almacena la dirección del segmento y en los otros dos la dirección del desplazamiento. De esta forma se puede accesar una dirección de memoria que se encuentre en un segmento diferente al segmento de datos en uso.

En el listado 6.3 se muestra el manejo de un apuntador far para rellenar la pantalla con el caracter tecleado. La ejecución del programa termina cuando se pulsa la tecla .

 #include <iostream.h>                                     
 #include <conio.h>                                           
                                                               
  void main()                                                  
  {                                                            
    int far *aplej ; // Declara un apuntador far a enteros     
    char c ;                                                   
    int ren, col ;                                             
                                                               
    clrscr();                                                  
    cout << "Teclee caracteres ( < Enter >="Salida" ) : " ; aplej="(int" far *) 0xB8000000 ; while(( c="getche())" !="\r" ) for( ren="0" ; ren < 25 ; ren ++ ) for( col="0" ; col < 80 ; col++ ) *(aplej + ren*80 + col )="c" | 0x0700 ; clrscr(); } 

Listado 6.3.- Utilización de un apuntador far a enteros.

A continuación, se explican algunas lineas del listado 6.3.

En:

     int far *aplej ;

se declara un apuntador lejano a objetos de tipo entero. Observe que la sintaxis que rige la declaración es:

  
     tipo  far *identif ;

En la linea:

     aplej = (int far *) 0xB8000000 ;

la parte

      (int far *) representa un forzamiento de tipo para que la
                  constante hexadecimal sea manejada por un
                  apuntador lejano.

       0xB8000000 representa la direccón de memoria reservada para
                  uso exclusivo en los modos de video CGA y EGA.
  

En este caso, B800 es la dirección del segmento, y 0000 es la dirección del desplazamiento.

Por último, en la linea:

        *(aplej + ren*80 + col ) = c | 0x0700 ;

la parte:
           
          aplej + ren*80 + col  calcula la dirección de memoria 
                                correspondiente a cada caracter. 


         *(aplej + ren*col +80 ) representa al objeto apuntado
                                 (un caracter).

mientras que:

          c | 0x0700

es una operación OR a nivel de bits para asegurar que el caracter c tendrá los atributos de caracter normal.

Página anterior Página siguiente