lunes, 22 de septiembre de 2014

La sentencia if

La sentencia if se utiliza para comprobar una condición y si la condición es verdadera entonces procesaremos un bloque de sentencias (llamado bloque if), u otro bloque de sentencias alternativas (llamadobloque else). La cláusula else es opcional.

Empleando la sentencia if

Example 6.1. Empleando la sentencia if
#!/usr/bin/python
# Nombre de Fichero : if.py

numero = 23
adivina = int(raw_entrada('Ingresa un numero entero : '))

if adivina == numero:
 print 'Felicitaciones, haz adivinado.' # el nuevo bloque comienza aqui
 print "(pero no ganaste ningun premio!)" # el nuevo bloque termina aqui
elif guess < number:
        print 'No, el numero es mayor.' # otro bloque
        # Puedes hacer lo que deseas en un bloque ...
else:
 imprime 'No, el numero es menor.' 
 # debes adivinar...
print 'Hecho'
# Esta ultima sentencia siempre se ejecuta, después de que la sentencia if
# es ejecutada.
        

Salida

$ python if.py
Ingresa un numero entero : 50
No, el numero es menor.
Hecho
$ python if.py
Ingresa un numero entero : 22
No, el numero es mayor.
Hecho
$ python if.py
Ingresa un numero entero : 23
Felicitaciones, haz adivinado.
(pero no ganaste ningun premio!) 
Hecho
        

Cómo trabaja?

En este programa, tomamos intentos del usuario y comprobamos si es el número que tenemos. Fijamos la variable numero con cualquier entero que deseemos, en este caso, decimos 23. Entonces, tomamos el intento del usuario empleando la función raw_input(). Las funciones no son más que pedazos reutilizables de programas.
Asignamos una cadena a la función incorporada raw_input que después la imprime en pantalla esperando una entrada. Una vez que ingresamos un número y presionamos enter, la función regresa lo ingresado; en el caso de la función raw_string() esta siempre es una cadena. Entonces convertimos esta cadena a un número entero usando int y después la almacenamos en la variable adivina. Realmente, int es una clase, pero todo lo que necesitas saber por ahora es que puedes utilizarlo para convertir una cadena en un número entero.
Entonces, comparamos los intentos del usuario con el número que tenemos. Si son iguales, imprimimos un mensaje de éxito. Fíjate que utilizamos niveles de indentación para decir a Python que sentencias pertenecen a cada bloque. Esta es la razón por la cual la indentación es tan importante. Confío en que estés apegándote a la regla de 'un tabulado por nivel de indentado'.
Nota como la sentencia if contiene dos puntos en el extremo, esto le indica a Python que continua un bloque de sentencias.
Entonces, comprobamos si el intento es menor que el número y de ser así, le informamos al usuario que intente con un valor más alto. Utilizamos la sentencia elif que combina realmente dos sentencias relacionadas if else-if else en una sentencia combinada if-elif-else. Esto hace al programa más legible y claro, reduciendo -también- la cantidad de indentados necesarios.
La sentencia elif y else también deben tener dos puntos en el extremo de la línea lógica seguida por un bloque correspondiente de sentencias (con un nivel más alto de indentado, por supuesto).
Puedes tener otra sentencia if dentro del bloque de una sentencia if, a esto lo llamamos if anidado.
Recuerda que las partes elif y else son opcionales. Una sentencia mínima if es:
if True:
        print 'Si, es verdad!'
        
Después de que Python acabó de ejecutar completamente la sentencia if junto con las cláusulas asociadas elif y else se moverá a la siguiente sentencia del bloque que contiene la sentencia if, en este caso, es el bloque principal donde la ejecución del programa comienza y entonces se dirige a la sentencia print 'Hecho', después considera que es el final del programa y sale.
Aunque este es un programa muy simple, he incluido muchas de las cosas que debemos tomar en cuenta. Todas éstas son bastante directas (y asombrosamente simples para aquellos que vienen de C/C++) y requieren que las conozcas desde un principio, para luego emplearlas confortablemente.
Programa equivalente en C
Ahora veremos un programa equivalente al mostrado y que está escrito en C, de esta manera ayudaremos a los novatos a entender cuan fácil resulta Python en comparación a un lenguaje como C, y a los programadores experimentados, les ayudará a ver las diferencias entre la familia de lenguajes C/C++ y Python
Puedes saltar esta sección si lo deseas.
Observa que el indentado no importa en C. Una de las razones por las que los programas de C son (generalmente) mas difíciles de entender es que no son escritos claramente. Sin embargo, un buen programador siempre tiene un estilo de indentado bueno y consistente. Cuando estamos en Python, los programas siempre son escritos claramente!
Example 6.2. Programa Equivalente en C
#include <stdio.h>
/* Filename: if.c */

/* La ejecucion de un programa en C comienza siempre desde la funcion principal() */int main ()
int main()
{
    /* declara las variables antes de usarlas,
       tambien hay que especificar el tipo de datos de las variables.

    int numero, adivina;

    /* el numero que debemos adivinar */
    numero = 23;

    /* ingresa el intento del usuario */
    printf("Ingrese un Entero : ");
    scanf("%d", &adivina);

    if (adivina == numero) /* expresion entre paréntesis */
    {                    /* bloque delimitado entre corchetes */
        printf("Felicitaciones, haz adivinado.\n");
        printf("(pero no has ganado ningun premio!)\n");
    }
    else
        if (adivina < numero)
        {
            printf("No, es un numero mayor.\n");
        }
        else
        {
            printf("No, es un numero menor.\n");
        }

    printf("Hecho.\n");
 
    return 0; /* regresa y retorna un valor al shell */
}
              

Nota para Programadores C/C++

No existe una sentencia switch en Python. Debes usar una declaración if..elif..else para lograr lo mismo.

Expresiones y operadores

Expresiones

Una expresión es una combinación de operadores y operandos de cuya evaluación se obtiene un valor. Los operandos pueden ser nombres que denoten objetos variables o constantes, funciones, literales de cualquier tipo adecuado de acuerdo con los operadores u otras expresiones más simples. La evaluación de una expresión da lugar a un valor de algún tipo, una expresión se dice que es del tipo de su resultado. Ejemplos de expresiones:
a + 5*b
(a >= 0) and ((b+5) > 10)
a
-a * 2 + b
-b + sqrt(b**2 - 4*a*c)
length(s) > 0
Las expresiones se evalúan de acuerdo con la precedencia de los operadores. Ante una secuencia de operadores de igual precedencia, la evaluación se realiza según el orden de escritura, de izquierda a derecha. El orden de evaluación puede modificarse usando paréntesis.

Operadores.

Ada agrupa los operadores en 6 categorías, de menor a mayor precedencia. Los operadores binarios se usan en formato infijo (<operando_izquierdo> <operador> <operando_derecho>), como en "a + b". Los operadores unarios se usan en formato prefijo (<operador> <operando> ), como en "-5".

Operadores lógicos.

Están predefinidos para cualquier tipo, T, que designe un booleanomodular o un array monodimensional de componentes booleanos:
function "and"(Left, Right : T) return T
function "or" (Left, Right : T) return T
function "xor"(Left, Right : T) return T
Ejemplo de uso  en expresiones (sean A, B y C de tipo T):
if A and B then ...
C := A or B;
return (A xor B);
Su significado es el convencional (para los tipos modulares son operaciones bit a bit):
AB(A and B)(A or B)(A xor B)
True
True
False
False
True
False
True
False
True
False
False
False
True
True
True
False
False
True
True
False
Para los tipos booleanos, existen versiones de los operadores "and" "or", llamadas "and then" "or else" que tienen el mismo significado, pero realizan una "evaluación en cortocircuito" consistente en que evalúan siempre primero el operando izquierdo y, si el valor de éste es suficiente para determinar el resultado, no evalúan el operando derecho.
La evaluación en cortocircuito resulta muy útil si la correcta evaluación del operando derecho depende del valor del operando izquierdo, como en el siguiente ejemplo:
    if   i <= Vec'last and then Vec(i) > 0   then ...
(Evaluar Vec(i) produciría un error si i tiene un valor superior al límite máximo del vector).

Operadores relacionales.

Los operadores de igualdad están predefinidos para todos los tipos no limitados. Sea un tipo con estas características:
function "=" (Left, Right : T) return Boolean
function "/="(Left, Right : T) return Boolean
Los operadores de ordenación están predefinidos para todos los tipos escalares y los arrays de elementos discretos. Sea un tipo con estas características:
function "<" (Left, Right : T) return Boolean
function "<="(Left, Right : T) return Boolean
function ">" (Left, Right : T) return Boolean
function ">="(Left, Right : T) return Boolean
Existe también un operador de pertenencia ("in", "not in") que determina si un valor pertenece a un rango o a un subtipo: if i in 1..10 then ...
Todos los operadores relacionales devuelven un resultado de tipo Boolean.
Ejemplo de uso  en expresiones (sean A, B de tipo T y C de tipo Boolean):
if A = B then ...
C := (A <= B);
return (A >= B);

Operadores binarios de adición.

Los operadores de adición predefinidos para cualquier tipo numérico, T, son:
function "+"(Left, Right : T) return T
function "–"(Left, Right : T) return T
Ejemplo de uso  en expresiones (sean A, B y C de tipo T):
C := A + B;
return (A - B);
También pertenecen a esta categoría los operadores de concatenación, predefinidos para cualquier tipo de array monodimensional no limitado, T, de elementos de tipo C:
function "&"(Left : T; Right : T) return T
function "&"(Left : T; Right : C) return T
function "&"(Left : C; Right : T) return T
function "&"(Left : C; Right : C) return T

Operadores unarios de adición.

Los operadores unarios de adición predefinidos para cualquier tipo númerico, T, son la identidad y la negación:
function "+"(Right : T) return T
function "–"(Right : T) return T
Ejemplo de uso  en expresiones (sean A y B de tipo T):
B := -A;
Cuando se aplica a un tipo modular, el operador de negación ("-") tiene el efecto de restar el valor del operando, si es distinto de cero, al módulo. Si el valor del operando es cero, el resultado es cero.

Operadores multiplicativos.

Los operadores de multiplicación y división están predefinidos entre diversas combinaciones de enteros y reales:
function "*" (Left, Right : T) return T
function "/" (Left, Right : T) return T
function "*"(Left : T; Right : Integer) return T
function "*"(Left : Integer; Right : T) return T
function "/"(Left : T; Right : Integer) return T
function "*"(Left, Right : root_real) return root_real
function "/"(Left, Right : root_real) return root_real
function "*"(Left : root_real; Right : root_integer) return root_real
function "*"(Left : root_integer; Right : root_real) return root_real
function "/"(Left : root_real; Right : root_integer) return root_real
function "*"(Left, Right : universal_fixed) return universal_fixed
function "/"(Left, Right : universal_fixed) return universal_fixed
Ejemplo de uso  en expresiones (sean A, B y C del mismo tipo entero o real):
C := A * B;
return (A / B);
Los operadores módulo y resto están definidos para cualquier tipo entero, T:
function "mod"(Left, Right : T) return T
function "rem"(Left, Right : T) return T
La relación entre el resto y la división entera viene dada por la expresión: A = (A/B)*B + (A rem B), donde (A rem B) tiene el mismo signo que A, y es menor que B en valor absoluto.
El operador módulo se define de manera que (A mod B) tiene el mismo signo que B, un valor absoluto menor, y existe un número entero, N, tal que: A = B*N + (A mod B).
Ejemplo de uso  en expresiones (sean A, B y C de tipo T):
C := A rem B;
return (A mod B);

Operadores de máxima prioridad.

Los operadores de máxima prioridad son: el operador de cálculo del valor absoluto, definido para cualquier tipo numérico, T1, el operador de negación lógica, definido para cualquier tipo booleano, modular o array monodimensional de componentes booleanos, T 2, y el operador de exponenciación, definido para cualquier tipo entero, T3, o para cualquier tipo real en coma flotante, T4. Cada uno, de acuerdo con las siguientes especificaciones:
function "abs"(Right : T) return T
function "not"(Right : T) return T
function "**"(Left : T; Right : Natural) return T
function "**"(Left : T; Right : Integer'Base) return T
Ejemplo de uso  en expresiones (sean A, B de tipo T1; C, D de tipo T2 y E de tipo T3):
A := abs(B);
C := not D;
return (E ** 3); -- E elevado al cubo

Sobrecarga de operadores.

Ada permite que el programador sobrecargue los operadores del lenguaje, esto es, que pueda redefinirlos dándoles nuevos significados. Para sobrecargar un operador, simplemente hay que definir una función cuyo nombre sea el operador entre comillas y que tenga los parámetros adecuados. Por ejemplo, dado el siguiente tipo:
type Complejo is record
    PReal, PImag: float;
end record;
podemos sobrecargar el operador de suma ("+") para utilizarlo con el fin de sumar números complejos:
function "+"(A, B : in Complejo) return Complejo is
    Suma: Complejo;
begin
    Suma.PReal := A.PReal + B.PReal;
    Suma.PImag := A.PImag + B.PImag;
    return Suma;
end "+";
Una vez definida esta función, se puede aplicar el operador entre variables del tipo definido en los parámetros, devolviendo un valor del tipo definido como resultado.
...
S, X, Y: Complejo;
...
S := X + Y;
Sólo se pueden redefinir los operadores del lenguaje (no se pueden inventar operadores) y manteniendo siempre su cardinalidad (los binarios se redefinirán con funciones de dos parámetros y los unarios con funciones de un parámetro).
El operador de desigualdad ("/=") devuelve siempre el complementario de la igualdad ("="), por lo que, en caso necesario, sólo hay que sobrecargar este último. De hecho, el operador de desigualdad sólo se puede sobrecargar si se le atribuye un resultado que no sea de tipo Boolean.

ALCANCE DE LAS VARIABLES

El alcance , o vida, de una variable determina qué comandos de secuencia de comandos pueden tener acceso a dicha variable. Una variable declarada dentro de un procedimiento tiene alcance local ; la variable se crea y se destruye cada vez que se ejecuta el procedimiento. No se puede tener acceso a ella desde fuera del procedimiento. Una variable declarada fuera de un procedimiento tiene alcance global ; su valor es accesible y modificable desde cualquier comando de secuencia de comandos de una página ASP.
Nota: Al limitar el alcance de la variable a un procedimiento mejorará el rendimiento.
Si declara variables, una variable local y una variable global pueden tener el mismo nombre. La modificación del valor de una de ellas no afecta al valor de la otra. Sin embargo, si no declara las variables, podría modificar inadvertidamente el valor de una variable global. Por ejemplo, los siguientes comandos de secuencia de comandos devuelven el valor 1 incluso aunque haya dos variables llamadas Y:
<% Option Explicit Dim Y Y = 1 SetLocalVariable Response.Write Y Sub SetLocalVariable Dim Y Y = 2 End Sub %>
Por el contrario, los comandos siguientes devuelven el valor 2 porque las variables no se han declarado de forma explícita. Cuando la llamada al procedimiento asigna a Y el valor 2, el motor de secuencias de comandos da por supuesto que el procedimiento pretende modificar la variable global:
<% Option Explicit Dim Y = 1 SetLocalVariable Response.Write Y Sub SetLocalVariable Y = 2 End Sub %>
Para evitar problemas , adquiera el hábito de declarar explícitamente todas las variables. Lo cual es especialmente importante si utiliza la instrucción #include para incluir archivos en su archivo ASP. La secuencia de comandos incluida está contenida en un archivo aparte, pero se trata como si formara parte del archivo contenedor. Es muy fácil olvidarse de que hay que utilizar nombres de variables diferentes en la secuencia de comandos principal y en la secuencia de comandos incluida, a menos que declare las variables.
Asignar a las variables alcance de sesión o de aplicación
Las variables globales sólo son accesibles en un mismo archivo ASP. Para hacer que una variable sea accesible en varias páginas, asigne a la variable alcance de sesión o de aplicación. Las variables con alcance de sesión están disponibles en todas las páginas de una aplicación ASP que pida un mismo usuario. Las variables con alcance de aplicación están disponibles en todas las páginas de una aplicación ASP que pida cualquier usuario. Las variables de sesión son una buena manera de almacenar información para un único usuario, como sus preferencias o el nombre o la identificación del usuario. Las variables de aplicación son una buena manera de almacenar información para todos los usuarios de una determinada aplicación, como los saludos específicos o los valores generales necesarios en la aplicación.
ASP proporciona dos objetos integrados en los que puede almacenar variables: el objeto Session y el objeto Application .
También puede crear instancias de objetos con alcance de sesión o de aplicación. Para obtener más información, consulte Establecer el alcance de los objetos.

Declaración de variables

^
Una característica de C++, es la necesidad de declarar las variables que se usarán en un programa. Esto resulta chocante para los que se aproximan al C++ desde otros lenguajes de programación en los que las variables de crean automáticamente la primera vez que se usan. Se trata, es cierto, de una característica de bajo nivel, más cercana al ensamblador que a lenguajes de alto nivel, pero en realidad una característica muy importante y útil de C++, ya que ayuda a conseguir códigos más compactos y eficaces, y contribuye a facilitar la depuración y la detección y corrección de errores y a mantener un estilo de programación elegante.
Uno de los errores más comunes en lenguajes en los que las variables se crean de forma automática se produce al cometer errores ortográficos. Por ejemplo, en un programa usamos una variable llamada prueba, y en un punto determinado le asignamos un nuevo valor, pero nos equivocamos y escribimos prubea. El compilador o interprete no detecta el error, simplemente crea una nueva variable, y continúa como si todo estuviese bien.
En C++ esto no puede pasar, ya que antes de usar cualquier variable es necesario declararla, y si por error usamos una variable que no ha sido declarada, se producirá un error de compilación.

Cómo se declaran las variables

^
Ya hemos visto la mecánica de la declaración de variables, al mostrar la sintaxis de cada tipo en el capítulo 2.
El sistema es siempre el mismo, primero se especifica el tipo y a continuación una lista de variables y finalmente un punto y coma.
La declaración de variables es uno de los tipos de sentencia de C++. La prueba más clara de esto es que la declaración terminará con un ";". Sintaxis:
<tipo> <lista de variables>;
También es posible inicializar las variables dentro de la misma declaración. Por ejemplo:
int a = 1234;
bool seguir = true, encontrado;
Declararía las variables aseguir y encontrado; y además iniciaría los valores de a y seguir con los valores 1234 y true, respectivamente.
En C++, contrariamente a lo que sucede con otros lenguajes de programación, las variables no inicializadas tienen un valor indeterminado (con algunas excepciones que veremos más tarde), y contienen lo que normalmente se denomina "basura". Cuando se declara una variable se reserva un espacio de memoria para almacenarla, pero no se hace nada con el contenido de esa memoria, se deja el valor que tuviera previamente, y ese valor puede interpretarse de distinto modo, dependiendo del tipo.

Ámbitos

^
Llamamos ámbito a la zona desde que cierto objeto es accesible.
En C++ solemos referirnos a dos tipos de ámbitos: temporal y de acceso. Así, el ámbito temporal indica el intervalo de tiempo en el que un objeto existe o es accesible. El ámbito de acceso nos dice desde donde es accesible.
En este capítulo hablaremos un poco sobre el ámbito de las variables, pero no entraremos en muchos detalles todavía, ya que es un tema largo.
Por otra parte, las funciones (y otros objetos de los que aún no hemos hablado nada), también tienen distintos ámbitos.

Ámbito de las variables

^
Dependiendo de dónde se declaren las variables, podrán o no ser accesibles desde distintas partes del programa. Es decir, su ámbito de acceso y temporal dependerá del lugar en que se declaren.
Las variables declaradas dentro de un bucle, serán accesibles sólo desde el propio bucle, esto es, tendrán un ámbito local para el bucle. Esto es porque las variables se crean al inciar el bucle y se destruyen cuando termina. Evidentemente, una variable que ha sido destruida no puede ser accedida, por lo tanto, el ámbito de acceso está limitado por el ámbito temporal.
Nota: En compiladores de C++ antiguos, (y en algunos modernos y mal implementados), no existe este ámbito, que sin embargo está descrito en la norma ANSI.
En estos compiladores, las variables declaradas dentro de un bucle tienen el mismo ámbito temporal y de acceso que las variables locales. Es decir, existen y son accesibles desde el punto en que se declaren hasta el final de la función.
Si usamos uno de esos compiladores no será posible, por ejemplo, usar varios bucles con declaraciones de variables locales de bucle con el mismo nombre.

for(int i=0; i < 100; i++) HacerAlgo(i);
for(int i=0; i > -100; i--) DeshacerAlgo(i);


Este código daría un error al intentar redefinir la variable local i.
Las variables declaradas dentro de una función, y recuerda que main también es una función, sólo serán accesibles para esa función, desde el punto en que se declaran hasta el final. Esas variables son variables locales o de ámbito local de esa función.
Al igual que ocurre con las variables locales de bucle, en las de función, las variables se crean al inciar la función y se destruyen al terminar.
Las variables declaradas fuera de las funciones, serán accesibles desde todas las funciones definidas después de la declaración. Diremos que esas variables son globales o de ámbito global.
El ámbito temporal de estas variables es también global: se crean junto con el programa, y se destruyen cuando el programa concluye.
Las variables globales son las únicas que son inicializadas automáticamente con valor cero cuando se declaran. Esto no sucede con ninguna variable local.
En todos los casos descritos, el ámbito temporal coincide con el de acceso: las variables que no pueden ser accedidas es porque no existen todavía o porque han sido destruídas. Más adelante veremos casos en que estos ámbitos no coinciden.
Una variable global declarada después de la definición de una función no será accesible desde esa función, por eso, normalmente se declaran las variables globales antes de definir las funciones.
Pero esto es hablando de forma general, en realidad, en C++ está mal visto usar variables globales, ya que se consideran poco seguras.
Ejemplo:
int EnteroGlobal; // Declaración de una variable global

int Funcion1(int a); // Declaración de un prototipo

int main() {
   // Declaración de una variable local de main:
   int EnteroLocal;

   // Acceso a una variable local:
   EnteroLocal = Funcion1(10); 
   // Acceso a una valiable global:
   EnteroGlobal = Funcion1(EnteroLocal); 

   return 0;
}

int Funcion1(int a) 
{
   char CaracterLocal; // Variable local de funcion1
   // Desde aquí podemos acceder a EnteroGlobal, 
   // y también a CaracterLocal 
   // pero no a EnteroLocal
   if(EnteroGlobal != 0)   
      return a/EnteroGlobal;
   return 0;
}
De modo que en cuanto a los ámbitos locales tenemos varios niveles:
<tipo> funcion(parámetros) // (1)
{
   <tipo> var1;             // (2)
   for(<tipo> var2;...)     // (3)
   ...
   <tipo> var3;             // (4)
   ...
   return var;
}
(1) Los parámetros se comportan del mismo modo que variables locales, tienen ámbito local a la función.
(2) Las variables declaradas aquí, también.
(3) Las declaradas en bucles, son de ámbito local en el bucle.
(4) Las variables locales sólo son accesibles a partir del lugar en que se declaren. Esta variable: var3, es de ámbito local para la función, pero no es accesible en el código previo a su declaración.
Es una buena costumbre inicializar las variables locales.
Los ámbitos pueden ser alterados mediante ciertos modificadores que veremos en otros capítulos.

Enmascaramiento de variables

^
Generalmente no es posible, y no suele ser necesario, declarar dos variables con el mismo nombre, pero hay condiciones bajo las cuales es posible hacerlo.
Por ejemplo, podemos declarar una variable global con un nombre determinado, y declarar otra variable (del mismo tipo o de otro diferente) de forma local en una función, usando el mismo nombre.
En ese caso decimos que la segunda declaración (la local), enmascara a la primera (la global). Con eso queremos decir que el acceso a la variable global está bloqueado o enmascarado por la local, que es a la única que podemos acceder directamente.
Por ejemplo:
int x;

int main() {
   int x;
   
   x = 10;
   return 0;
}
En este programa, cuando asignamos 10 a x estamos accediendo a la versión local de la variable x. En la función main, la variable global x está enmascarada, y no puede accederse a ella directamente.
Del mismo modo, una variable de ámbito de bucle o de ámbito de bloque puede enmascarar a una variable global o local, o a una de un bloque o bucle más externo:
   int x = 10;
   {
      int x = 0;
      for(int x = 0; x < 10; x++) HacerAlgoCon(x);
   }
En este caso la declaración de x dentro del bloque enmascara la declaración anterior, y a su vez, la declaración dentro del bucle for enmascara a la declaración del bloque.
Otra cuestión sería qué utilidad pueda tener esto.

Operador de ámbito

^
Existe un método para acceder a una variable global enmascarada por una variable local. Se trata del operador de ámbito, que consiste en dos caracteres de dos puntos seguidos (::).
Veremos este operador con más detalle en el capítulo dedicado a los espacios con nombre, pero veamos ahora cómo lo podemos usar para acceder a una variable global enmascarada:
int x; // Variable global

int main()
{
   int x; // Variable local que enmascara a la global
   
   x = 10; // Accedemos a la variable local
   ::x = 100; // Mediante el operador de ámbito accedemos a la global
   return 0;
}
El operador de ámbito, usado de este modo, permite acceder al espacio de variables global. Pero este no es más que un uso restringido del operador, que tiene muchas más aplicaciones.

Las variables en C


Todos los programas necesitan, en algún momento, almacenar números o datos ingresado por el usuario. Estos datos son almacenados en variables, y en C++ como en otros lenguajes estas variables deben tener un tipo. 

1. Los tipos de variables

Existen varios tipos de variables, y cada uno corresponde a un tamaño máximo de un número, un carácter o incluso una verdad. Cuanto mayor sea el número que pueda admitir, mas espacio en memoria ocupará. 

1.1 bool

Por lo general utiliza 1 byte de memoria, valores: true o false

1.2 char

Utiliza generalmente 1 byte de memoria, permite almacenar un carácter, valores; 256 caracteres. 

1.3 unsigned short int

Utiliza generalmente 2 bytes de memoria, valores: de 0 a 65 535 

1.4 short int

Utiliza generalmente 2 bytes de memoria, valores: de -32768 a 32767

1.5 unsigned long int

Utiliza generalmente 4 bytes de memoria, valores: de 0 a 4 294 967 295

1.6 long int

Utiliza generalmente 4 bytes de memoria, valores: de -2 147 483 648 a 2 147 483 647

1.7 int (16 bits)

Utiliza generalmente 2 bytes de memoria, valores: de -32 768 a 32 767

1.8 int (32 bits)

Utiliza generalmente 4 bytes de memoria, valores: de -2 147 483 648 a 2 147 483 647

1.9 unsigned int (16 bits)

Utiliza generalmente 2 bytes de memoria, valores: de 0 a 65 535

1.10 unsigned int (32 bits)

Utiliza generalmente 2 bytes de memoria, valores: de 0 a 4 294 967 295

1.11 double

Utiliza generalmente 8 bytes de memoria, valores: de 2.2e-308 a 3.4e-38

1.12 float

Utiliza generalmente 4 bytes de memoria, valores: de 1.2e-308 a 3.4e-38
Atención! 
El tamaño de las variables en memoria puede variara de un PC a otro. 

2. Declaración y asignación de variables

2.1 Declaración

Para declarar una variable, basta con indicar su tipo y su nombre. Existen ciertas convenciones en cuanto al nombre de las variables. Algunos prefieren separar las partes de un nombre con '_', otros prefieren escribir una mayúscula para separarlas. Ejemplo: 

int recetaDelMes;




int receta_del_mes;


Lo importante es que utilices siempre la misma convención para tus programas. 

2.2 Asignar un valor

Es posible asignar un valor a una variable al momento de declararla: 

int recetaDelMes = 12301;


También es posible declarar varias variables en una misma línea, pero en este caso, todas las variables de la línea tendrán el mismo tipo. 

int recetaDelMes = 12301, recetaDelAño = 45644545;

3. Error al definir un tipo de variable (Enteros con signo)

¿Qué pasa si el tipo que hemos elegido es muy pequeño? Si el número es mayor al máximo admitido por el tipo, entonces el valor de la variable será el valor mínimo admitido por este tipo. 

unsigned short int numero = 65535;
cout << numero << endl;
numero++;
cout << numero << endl;


Si ejecutamos este código, la segunda línea no escribirá 65536, sino 0. 
Esto es idéntico para todos los tipos. 

4. Error al definir un tipo de variable(Enteros sin signo)

Para enteros sin signo, sucede lo mismo, una vez que el tipo alcanza su tamaño máximo, pasa a su valor mínimo. 

short int numero = 32767;
cout << numero << endl;
numero++;
cout << numero << endl;


Si ejecutamos este código, la segunda línea no escribirá 32768, sino -32768. 

Consulta este artículo sin tener que estar conectado, descárgalo gratis aquí en formato PDF:
Las-variables-en-c.pdf

Aspectos Importantes del lenguaje

Tipos de datos básicos

Un tipo de datos es una propiedad de un valor que determina su dominio (qué valores puede tomar), qué operaciones se le pueden aplicar y cómo es representado internamente por el computador.
A continuación revisaremos los tipos de datos más básicos. Además de estos, existen muchos otros, y más adelante aprenderemos a crear nuestros propios tipos de datos.

Números enteros

El tipo int permite representar números enteros.
Los valores que puede tomar un int son todos los números enteros: ...-3-2-10123, ...
El nombre int viene del inglés integer, que significa «entero».
Todas las operaciones aritméticas y relacionales pueden ser aplicadas sobre valores del tipo int:
>>> 524 + 891
1415
>>> (1524 // 100) % 10
5
Los números enteros literales se escriben con un signo opcional seguido por una secuencia de dígitos:
1570
+4591
-12
Más adelante veremos otras formas de representar enteros literales. Por ejemplo, el número 123 puede ser representado de varias maneras:
>>> 0o173
123
>>> 0x7b
123
>>> 0b1111011
123
>>> 123 == 0x7b
True
Por ahora, preocupémonos sólo de la forma más común 123.

Números reales

El tipo float permite representar números reales.
El nombre float viene del término punto flotante, que es la manera en que el computador representa internamente los números reales.
Todas las operaciones aritméticas y relacionales pueden ser aplicadas sobre valores del tipo float.
Hay que tener mucho cuidado, porque los números reales no se pueden representar de manera exacta en un computador. Por ejemplo, el número decimal 0.7 es representado internamente por el computador con la aproximación 0.69999999999999996. Todas las operaciones entre valores float son aproximaciones. Esto puede conducir a resultados algo sorpresivos:
>>> 1/7 + 1/7 + 1/7 + 1/7 + 1/7 + 1/7 + 1/7
0.9999999999999998
Los números reales literales se escriben separando la parte entera de la decimal con un punto. Si la parte decimal es cero, puede ser omitida:
>>> 881.9843000
881.9843
>>> -3.14159
-3.14159
>>> 1024.
1024.0
Otra representación es la notación científica, en la que se escribe un factor y una potencia de diez separados por una letra e. Por ejemplo:
>>> -2.45E4
-24500.0
>>> 7e-2
0.07
>>> 6.02e23
6.02e+23
>>> 9.1094E-31
9.1094e-31
Los dos últimos valores del ejemplo son iguales, respectivamente, a6.02×1023 y 9.1094×1031.
Cuando se combinan valores reales y enteros en una operación, el entero es convertido a un número real antes de evaluarla. Por ejemplo,5.3 + 2 primero es convertido a 5.3 + 2.0, y el resultado es real:
>>> 5.3 + 2
7.3
La regla general es: si en una expresión aritmética aparece algún float, el resultado es de tipo float.

Valores lógicos

Los valores lógicos True y False son de tipo bool, que representa valores lógicos.
El nombre bool viene del matemático George Boole, quien creó un sistema algebraico para la lógica binaria. Por lo mismo, a True y Falsetambién se les llama valores booleanos.
Las operaciones lógicas andor y not pueden ser aplicadas sobre valores booleanos, y entregan como resultado un valor booleano:
>>> not True or (True and False)
False
Las operaciones relacionales <>==, etc., pueden ser aplicadas sobre valores de tipos comparables, pero siempre entregan como resultado un valor booleano:
>>> 2 + 2 == 5
False
>>> x = 95.4
>>> 50 < x < 100
True

Texto

A los valores que representan texto se les llama strings, y tienen el tipo str.
Los strings literales pueden ser representados con texto entre comillas simples o comillas dobles:
"ejemplo 1"
'ejemplo 2'
Los operadores aritméticos no pueden ser aplicadas sobre strings, salvo dos excepciones:
  1. El operador + aplicado a dos strings no representa la suma, sino laconcatenación, que significa pegar los strings uno después del otro:
    >>> "hola " + 'mundo'
    'hola mundo'
    
  2. El operador * aplicado a un string y a un número entero no representa la multiplicación, sino la repetición, es decir, el string es repetido tantas veces como indica el número:
    >>> "lo" * 5
    'lololololo'
    
Las operaciones relacionales permiten comparar strings alfabéticamente:
>>> "ala" < "alamo" < "bote" < "botero" < "boteros" < "zapato"
True
Para conocer el largo de un string, se utiliza la función len():
>>> len('universidad')
11
La función input(), que usamos para leer la entrada del usuario, siempre entrega como resultado un string. Hay que tener la precaución de convertir los valores que entrega al tipo adecuado. Por ejemplo, el siguiente programa tiene un error de incompatibilidad de tipos:
n = input('Escriba un número:')
cuadrado = n * n
print('El cuadrado de n es', cuadrado)
Es importante entender que los strings no son lo mismo que los valores que en él pueden estar representados:
>>> 5 == '5'
False
>>> True == 'True'
False

Nulo

Existe un valor muy especial que se llama None.
None es un valor que se utiliza en contextos en que ningún valor es válido. En inglés, none significa «ninguno».
El valor None tiene su propio tipo, que es diferente al de todos los demás valores.

Conversión de tipos

Los tipos de los valores indican qué operaciones pueden ser aplicadas sobre ellos.
A veces es necesario convertir valores de un tipo a otro para poder operar sobre ellos. Existen dos tipos de conversiones: implícitas y explícitas.
Las conversiones implícitas son las que se hacen automáticamente según el contexto. Las más importantes son las siguientes:
  • cuando se utiliza un entero en un contexto real, el entero es convertido al real correspondiente:
    >>> 56 * 8.0
    448.0
    
  • cuando se utiliza cualquier valor en un contexto booleano, es convertido al valor True, excepto por los siguientes casos, en que es convertido al valor False:
    • el valor 0,
    • el string vacío '',
    • None.
    Por ejemplo:
    >>> not 0
    True
    >>> not 10
    False
    >>> not 'hola'
    False
    >>> bool(3.14)
    True
    
    Con los operadores and y or ocurre algo más extraño:
    >>> 4 and 7
    7
    >>> 0 and 7
    0
    >>> 5 or 6
    5
    >>> 0 or 6 or 7
    6
    
    Ejercicio: deducir cómo funcionan and y or cuando los operandos no son booleanos.
  • cuando se utiliza un valor lógico en un contexto entero, True es convertido a 1 y False a 0:
    >>> True * 4 + False * 8
    4
    >>> True + True
    2
    >>> n = 5
    >>> "el número es " + ((n % 2 != 0) * "im") + "par"
    'el número es impar'
    
Las conversiones explícitas se realizan usando el nombre del tipo de destino como si fuera una función.
Por ejemplo, para convertir un valor al tipo entero, se utiliza la funciónint:
>>> int('45')
45
>>> int(3.891)
3
>>> int(True)
1
>>> int(None)
TypeError: int() argument must be a string or a number, not 'NoneType'
>>> int('abc')
ValueError: invalid literal for int() with base 10: 'abc'
>>> int('doscientos')
ValueError: invalid literal for int() with base 10: 'doscientos'
Ya veremos qué significan los errores.
Para convertir un valor en un string, se utiliza la función str:
>>> str(87)
'87'
>>> str(True)
'True'