logo sinuh
 

Inicio arrow Conocimiento arrow Curso de programación en C desde cero arrow Entrega 15. Ámbito de las variables.
Entrega 15. Ámbito de las variables. Imprimir
Por Luis García Galván   
sábado, 03 mar 2007 10:51

CURSO DESDE 0 DE PROGRAMACIÓN C BAJO GNU/LINUX.


Entrega 15. Ámbito de las variables.

 

Tiempo de vida.


Todas las variables que creamos dentro de un programa tienen un ámbito donde su uso es válido, fuera de este ámbito la variable no puede ser usada por ninguna función ya que el compilador no la reconocerá. Esto es lo que se conoce como el tiempo de vida, y dependerá del lugar donde sean declarados aunque esto puede cambiarse haciendo uso de modificadores.


Todas las variables y objetos en general que definamos en C van a tener un tiempo de vida . Llamamos objetos en C a toda variable, función, puntero, array, cadena, estructura y unión.


El tiempo de vida puede ser global o local:

  • Global: Una vez definido el objeto permanece hasta el final del programa.

  • Local: Se le asigna memoria al objeto cada vez que el control del programa pasa a través del bloque de código en que el objeto está definido. Después de que el control sea devuelto por el bloque, la memoria se libera y el valor del objeto queda indefinido.


El tiempo de vida se determina de la siguiente forma:

  • El tiempo de vida de todas las funciones es global.

  • El tiempo de vida de las variables declaradas en un nivel externo (fuera de una función) es siempre global.

  • El tiempo de vida de las variables declaradas en un nivel interno (dentro de un bloque '{ ... }' ) es local.


Un bloque, dos bloques, tres bloques ...


Con este ejemplo vamos a digerir lo contado arriba:


#include <stdio.h>

float PI=3.1416; //Soy una variable Global.

/*

Las variables locales por convenio se definen con

mayusculas para diferenciarlas del resto.

*/

int main (int agc, char ** argv)
{
  int a,b;
  a=b=2;
  printf ("2 + 2 son %d y PI=%f\n",a+b,PI);
    {
      //bloque 2
      int b = 3;
      printf ("¿Pero por que ahora 2 + 2 son %d? y PI=%f\n",a+b,PI);
        {
          //bloque 3
          float PI=3.15;
          int a=3;
          printf ("Esto es de locos 2 + 2 son %d? y PI=%f\n",a+b,PI);
        }
      printf ("Ahora PI=%f\n",PI);
    }
  printf ("Uf vuelvo a la normalidad, 2 + 2 son %d y PI=%f\n",a+b,PI);
  return 0;
}


Y su ejecución:


matados2k@imperio:~/curso programacion$ ./ejemplo_15_1

2 + 2 son 4 y PI=3.141600

¿Pero por que ahora 2 + 2 son 5? y PI=3.141600

Esto es de locos 2 + 2 son 6? y PI=3.150000

Ahora PI=3.141600

Uf vuelvo a la normalidad, 2 + 2 son 4 y PI=3.141600

matados2k@imperio:~/curso programacion$


Curioso resultado, ¿verdad? Analicemos detenidamente el resultado. Lo primero que nos encontramos es que para usar comentarios de más de una línea usamos '/*' y '*/' , todo lo que esté contenido dentro se considera comentario.


Aun definiendo PI fuera de 'main' lo podemos usar, ya que no está dentro de ningún bloque, de hecho lo podríamos usar en cualquier función. Lo primero que el programa nos dice es lo lógico, no hay problema, aunque hay que resaltar que 'a' y 'b' sólo se pueden usar dentro de main ya que son locales, en otra función podremos crear otras variables que se llamen igual pero serán las 'a' y 'b' de otra función que no tendrían nada que ver.


Y en la segunda respuesta empieza la función. Según lo visto más arriba, 'El tiempo de vida de las variables declaradas en un nivel interno (dentro de un bloque '{ ... }' ) es local' , teniendo en consideración que se pueden definir bloques dentro de bloques, y si los bloques están contenidos dentro de otros pueden ver las variables de su bloques contenedores y en caso de identificadores repetidos cuentan los definidos de más interno a más externo, podemos analizar la situación.


¿Pero por que ahora 2 + 2 son 5? y PI=3.141600 Esto se produce en el bloque dos, donde existen las variables locales a y b definidas en el bloque 'main', ambas con valor 2, pero se define una nueva variable local 'b' con valor 3, como existe un mismo identificador para dos variables prima la más interna con valor 3.


Esto es de locos 2 + 2 son 6? y PI=3.150000 Ahora es más enrevesado, existen las variables locales a y b definidas en el bloque 'main', ambas con valor 2 y además una variable local 'b' con valor 3 definida en el bloque 2 pero se define una nueva variable local 'a' con valor 3 y una variable local 'PI' con valor 3.15. Se usará la variable 'a' con valor 3 porque prima la más interna y se usará 'b' con valor '3' porque es más interna que 'b' con valor 2, y por último prima el 'PI' definido como local sobre el 'PI' definido como global.


Ahora PI=3.141600 Como salimos del bloque 3, las variable locales 'PI' y 'a' que se definieron desaparecen y sólo existen 'a' y 'b' de main y 'b' del bloque 2 que es donde estamos, por lo que PI vuelve a tomar el valor de la global al no coincidir identificadores de variables.


Uf vuelvo a la normalidad, 2 + 2 son 4 y PI=3.141600 Como salimos del bloque 2 ahora desaparece la variable 'b' del bloque 2 con valor 3 y sólo existen los 'a' y 'b' originales. Todo vuelve a la normalidad.


Moraleja: No uses los mismos nombres de identificadores que hayan sido usados como globales o como locales en un bloque superior y te ahorrarás muchos problemas, ya que C no tiene mecanismos para resolver estos conflictos.


Tipos de almacenamiento.


El tipo de almacenamiento de una variable viene dado por cuatro palabras clave:


  1. 'auto' . Sólo se puede usar dentro de un bloque y define una variable como local, por lo cual es redundante y no se utiliza. Ejemplo:

     

    void funcion (void)
    {
      auto int i; //Que es lo mismo que 'int i;'
    }

     

  2. 'register'. Cuando tenemos variables locales que se usan mucho dentro de un bloque se puede mejorar el tiempo de ejecución del programa declarándolas como 'register' ya que serán almacenadas en los registros de la CPU en vez de hacerlo en memoria, con lo cual el tiempo de acceso a ellas es menor. Si no existieran registros libres en la CPU se cargarían en memoria y se usarían como si fueran de tipo 'auto'. Ejemplo:

     

    void funcion (void)
    {
      register int i;
      for (i=0;i<1000;i++)
        {
          ...
        }
    }

     

  3. 'static'. A veces es necesario que una variable conserve su valor de una llamada a otra, pero si queremos que se comporte como una constante hay que inicializarlas a la misma vez que las definimos, ya que si no:

     

    static int i;
    i=1;

     

    No nos valdría de nada, puesto que cada vez que se llamara a una función se volvería a realizar la asignación. Para que sólo se pueda asignar la primera vez que se invoca en una función, la solución sería:

     

    static int i=1;

     

  4. 'extern'. Como hemos visto es bueno usar la programación modular, y dado que el ámbito de las variables se reduce al módulo (fichero .c con su .h) donde han sido declaradas, si necesitamos una variable definida en el fichero fuente actual debemos definirlo indicando que la variable es externa:

     

    extern int i;

     

    Con esto indicamos al compilador que la variable ha sido declarada en otro archivo fuente y que no es necesario que vuelva a reservar espacio físico. Si una variable debe ser compartida por varios ficheros fuentes, todos ellos excepto uno deben contener la declaración 'extern'.


Así que vamos a ver un ejemplo todo en uno:


ejemplo_15_2.c

#include "matematicas.h"

extern iteracion;

int main (int arc, char **argv)
{
  iteracion=55;
  printf ("La suma es %d\n",suma_cien_veces (10));
  return 0;
}


matematicas.h

#include <stdio.h>

int suma_cien_veces (int numero);

void imprimo_cuando_llego_a (int numero);


matematicas.c

#include "matematicas.h"

int iteracion=50;

int suma_cien_veces (int numero)
{
  register int i,aux;
  aux=0;

   for (i=0;i<100;i++)
    {
      aux=aux+numero;
      imprimo_cuando_llego_a (i);
    }

    return (aux);
}


void imprimo_cuando_llego_a (int numero)
{
  static int num;
  if (numero==iteracion) printf ("He llegado a la iteración %d y la anterior fue %d\n",numero,num);
  num=numero;
}


De ejecución:


matados2k@imperio:~/curso programacion$ cc -o ejemplo_15_2 ejemplo_ticas.cmatemat

matados2k@imperio:~/curso programacion$ ./ejemplo_15_2

He llegado a la iteración 55 y la anterior fue 54

La suma es 1000

matados2k@imperio:~/curso programacion$


Usamos todo menos 'auto' que es redundante, usamos 'register' para mejorar la ejecución del bucle de 'suma_cien_veces', observamos cómo con 'static' se conservan los valores de 'num' de una ejecución para otra ya que si fuera local (auto) el número que nos diera sería algo indeterminado al no estar inicializada, puesto que sería creada y destruida en cada iteración (probarlo), y cómo necesitamos 'extern' para poder usar en 'main' la variable 'iteracion' definida en 'matematicas.h'.


Despedida.


Sin más con esto nos despedimos hasta la semana que viene, en la que empezaremos a ver los Arrays. Y como nadie ha respondido al ejercicio de la semana anterior, espero que lo contestéis para la próxima, aunque al final lo tendré que poner yo.


Agradecimientos:

· Revisión del documento: Karuchi (Carolina García).



Página oficial y dominio de mi propiedad http://matados2k.es

Matados'2k Usuario y moderador de www.sinuh.org

Matados'2k Moderador de foro.noticias3d.com


matados2k (arroba) gmail (punto) com


Este documento está sometido a la licencia de creative commons en su variante “Reconocimiento-NoComercial-SinObraDerivada 2.1 España” . Es de agradecer que se comunique al autor el uso de este documento en otro medio y se debe incluir de forma obligatoria este recuadro y los agradecimientos.

 

Comentario[s]

Sólo los usuarios registrados pueden escribir comentarios.
Por favor valídate o regístrate.

Powered by AkoComment 2.0!




© 2002-2005 SINUH - Comunidad GNU/Linux de Extremadura
Este portal utiliza Mambo
DHTML / JavaScript Tree by TwinHelix Designs

Para contactar con nosotros envía un correo a
info
Licencia Creative Commons
Los contenidos de este portal, salvo indicación en contra, están sujetos a una licencia de Creative Commons.

Los logotipos y marcas que aparecen son propiedad de sus respectivos dueños.

Las opiniones y declaraciones de las personas reflejadas en los foros y comentarios son propiedad y responsabilidad de sus autores, no identificando la opinión de SINUH y excluyendo de cualquier responsabilidad a esta asociación.
Ahora 11 visitantes
Advertisement