Variables y Constantes.


Como C es un lenguaje de programación que soporta exclusivamente el paradigma imperativo, las variables son la parte más importante de éste. Podría decirse que las variables son los bloques con los que se construyen los programas.


Los nombre usados para referirse a las variables, las constantes, las funciones y otros objetos definidos por el usuario se conocen como “identificadores”. En C, la longitud de un identificador debe estar comprendido entre 1 y 32 caracteres. El primer caracter debe ser obligatoriamente una letra o un signo de subrayado ( _ ). Los siguientes caracteres pueden contener también números. Por ejemplo, unos nombres correctos de variables serían: “_var”, “var”, “var2” y “VariableContadora_2”. Incorrecto sería: “1var”, “var..2”, “var!” o “var#” entre infinitos casos.


Otra cosa muy importante es que C es “case sensitive”, o sea, que es sensible a mayúsculas y minúsculas por lo que “var” es distinto de “Var”, lo que es distinto de “VAR”.


Los nombres de variables ( o cualquier otro identificador ), no puede llamarse como una palabra clave del compilador ni como una función ya escrita.


La forma de asignar un valor a una variable es tan sencillo como:


nombreVariable = 100; // Un signo de igual.


Tipos de Variables.


En Lenguaje C, existen diferentes tipos de variables. Éstas son:


1.- Variables tipo char. Estas variables ocupan 1 byte y comprenden los números entre 0 y 255. Estas variables son usadas principalmente para almacenar caracteres. Existe una tabla de caracteres conocida como tabla ASCII. Esta tabla contiene caracteres definidos entre los números 0 y 255. Por ejemplo, el número 65 de la tabla ASCII corresponde a la letra 'A'. La forma usada para definir estas variables es:


char ch;


Esta declaración, define una variable de tipo char llamada ch.


2.- Variables tipo int. Variable que define números enteros. Ocupa 2 bytes lo que representa los números entre -32.768 y 32.767 (216). Se declaran de la siguiente forma:


int i, j, k;


Esto declara tres variables de tipo entero llamadas i, j y k en una sola orden. Se observa que para declarar múltiples variables del mismo tipo en una sola sentencia, deben estar separadas por una coma.


3.- Variables de tipo float. Conocidas como variables de coma flotante, estas variables representan los números reales. Ocupan 4 bytes lo que representan los números entre 3.4E-38 y 3.4E+38. Estas variables y las de tipo double que se verán mas adelante, contienen dos componentes: un componente entero y otro fraccionario. Se declaran:

float f;


4.- Variables de tipo double. Coma flotante de doble precisión. Al igual que las float, representa a números Reales. Ocupan 8 bytes lo que se refleja en los números comprendidos entre 1.7E-308 y 1.7E+308. Su forma de declaración es:


double d;


5.- Por último tenemos otro tipo de variable llamada void que ocupa cero bytes y que sólo es usada para declarar que una función no recibe ningún parámetro o que no devuelve ninguno. Por ejemplo:


int funcion(void); // No recibe nada y devuelve un entero.

void funcion(int x); // Recibe un entero y no devuelve nada.

void funcion(void); // Obvio.



Modificadores de Variables.


Todas las variables pueden ser modificadas agregándoles una palabra reservada antes de la declaración. Estos modificadores son:


unsigned.

signed.

long.

short.


No todas los modificadores aplican a todas las variables y ya verán porqué. Su forma de uso es: “PalabraReservada TipoDeVariable NombreDeVariable;” Por ejemplo:


unsigned int i; // o incluso

unsigned long int i; // Se le aplicaron dos modificadores.


La palabra reservada unsigned le indica al al compilador que la variable que modificará será tomada como una variable sin signo ( o sea, que no se interpretara el bit mas significativo como un bit de signo ). Siendo así que:


unsigned int i;


le indica al compilador que la variable i será una variable entera sin signo ( aunque aún de 2 bytes ). Por lo tanto, la variable i comprenderá los números enteros entre 0 y 65535.


La palabra reservada signed le indica al compilador que la siguiente variable declarada será tomada como una variable con signo. Es por eso que decía que no todos los modificadores aplican siempre. Colocar una definición como: “signed int i;” realmente redunda ( aunque es permitido ) ya que esta variable ya es tomada como una variable con signo por el compilador. En realidad el uso de la palabra reservada “signed” es innecesario en el caso de variables enteras excepto en el caso de las variables de tipo char. “signed char ch;” declararía una variable que comprendería números entre -128 y 127 pero como estas variables son usadas principalmente para almacenar caracteres, prácticamente no se usa.

El modificador long le indica al compilador que la variable que está definida a continuación de ella, ocupará el doble de memoria que lo que ocuparía por defecto. Esto quiere decir que, por ejemplo en:


long int i;


i representaría un entero que ocupará 4 bytes ( el doble de lo normal ). Esto sería los números entre -2147483648 y 2147483647.


El modificador short es de poco uso ya que es la versión por defecto de las variables. Usar short no cambiará la característica de la variable ( yo diría que redunda ). Aún así, es permisible su uso.


Comentarios: Las variables también pueden ser inicializadas al momento de ser declaradas. Esto se realiza de la siguiente forma:


char ch = 'h';

int i = 100;

float porcentaje = 12.5;


Como último quedaría comentar nuevamente que, como vimos en el ejemplo de variables tipo int, se pueden declarar varias variables del mismo tipo en una misma sentencia. La única cosa necesaria es que éstas deben estar separadas por una coma.


Constantes.


La palabra const declara una constante. Este tipo de dato debería siempre ser inicializado desde su creación pero no es necesario. Luego de asignársele el valor, éste no puede variar. Ejemplo:


const float pi = 3.1415926;


Si la constante es de tipo entero ( únicamente para este tipo por lo que es preferible ser explícito siempre en las declaraciones ), basta con sólo hacer


const entero = 1234;


Existen unas constantes especiales conocidas como: “Constantes de caracter con barra Invertida”. Estas constantes son:


\b -> Espacio atrás

\f -> Salto de Pagina

\n -> Salto de linea

\r -> Retorno de carro

\t -> Tabulación

\" -> Comilla doble

\' -> Comilla simple

\0 -> Nulo

\\ -> Backslash

\v -> Tabulador Vertical

\a -> Alerta. Cuando se imprime, la computadora emite un pitido.

\o -> Constante Octal

\x -> Constante hexadecimal

Declaración de variables Locales, Globales y Especificadores.


Variables locales.


Toda variable que sea declarada dentro de una función, ya sea main() o alguna otra función definida por el usuario, son conocidas como variables locales y sólo son reconocidas dentro de su propio ámbito ( sea una función o un bloque ) y en todos los bloques dentro de éstas. Las variables son creadas al entrar al bloque y son destruidas al salir de él.


El caso más normal en el que se declaran variables locales es en la función. Consideremos el próximo ejemplo:


int main(void){

int x; // Estas variables son conocidas solo dentro de este bloque

char ch; // y en todos los bloques dentro de éste.

if (x==1) {

int i; // Aquí también puedo declarar variables. Lo más importante es considerar

// que no podremos usar una variable que ya sea válida dentro del bloque.

// Por lo tanto, no puedo usar el nombre 'x' ni 'ch'.

i = x; // x es reconocida aquí. Por eso no puedo usar el mismo nombre aquí dentro

// Aquí adentro 'i' es reconocido.

}

// aquí, la variable 'i' ya ha sido destruida por lo que ya queda sin efecto y es desconocida.

}


void funcion(void) {

int x, f1;

x = 1;

}


void otraFuncion(void) {

int x, f2;

x = -1;

}


La variable entera x es declarada en ambas funciones e incluso en el bloque main() pero éstas no tienen ninguna relación entre sí. Cada versión de la variable x es conocida sólo dentro de su propia función y son destruidas al salir de la misma. ( Aunque con el especificador indicado podemos conservar el valor de la variable entre llamadas a la misma función en caso de ser necesario. VER el especificador static más adelante ).


Como ya comentamos, aunque lo más conveniente es declarar las variables al principio, éstas pueden ser declaradas a cualquier altura. Este es el caso del bloque if{} de nuestro ejemplo. Allí, creamos una variable para ser usada sólo dentro del bloque de control durante un momento y ser destruida de inmediato al salir de él. Entiéndase esto último como que las variables pueden ser declaradas dentro de cualquier bucle de control ya sea if{}, while{}, etc y serían locales dentro del bloque. Repito, se crean dentro de él y son destruidas al salir del mismo. En nuestro ejemplo, 'x' y 'ch' son conocidas dentro del bloque main() y dentro de todos los bloques que el ámbito main() contenga pero 'i' sólo es conocida dentro del bloque if{} al igual que 'f1' y 'f2' son conocidas sólo dentro de sus respectivas funciones.

Variables globales.


A diferencia de las variables locales, las globales son conocidas en cualquier punto del código y pueden ser usadas en cualquier parte del programa. Las variables globales son declaradas al principio de los programas, fuera de todo bloque, para que así sea reconocida por todos. Así, la forma de declararlas es:


#include<stdio.h>


int variableGlobal; // Esta variable es global y es conocida dentro de todo el código.

const pi = 3.1415926; // Esta constante también es global.


main() {

// etc.

}


La variable “variableGlobal” y la constante “pi” son globales y son conocidas en cualquier punto del programa ya que están fuera de todos los ámbitos.


El uso de estas variables es perfectamente permitido y válido y de hecho existen casos en los que pueden ser muy útiles. Sin embargo, su uso debe limitarse a aquellos casos en que sean realmente necesarias ya que ocupan memoria durante toda la ejecución del programa, no ayudan a modularizar y que pueden generar efectos secundarios desconocidos debido a que pueden alterar el valor en cualquier punto del programa alterando así otros resultados. Esto es un dolor de cabeza en programas muy grandes generando fallas que no son fáciles de detectar.


Especificadores.


Otra cosa importante en la declaración de las variables son los llamados especificadores. Estos son :


extern

static

register

auto.


Su forma de uso es: especificador tipo nombre; p.ej:


extern int i;


El tipo auto es el predeterminado de todas las variables por lo que este especificador prácticamente no se usa.



Dado que C permite enlazar juntos distintos módulos de un mismo programa, que son compilados por separado ( lo que ayuda a la gestión de grades proyectos ), debe haber una forma de hacer conocer a todos los archivos las variables globales requeridas por el programa. El especificador extern se encarga de ésto. Indica que la declaración de una variable ya ha sido hecha en otra módulo del proyecto. Por lo tanto, si tienes la declaración de una variable global en un programa y debes usar la misma dentro de otro módulo, lo único que debes hacer es declararla dentro de los módulos que la requieran, eso si con el mismo nombre, como extern lo que le indica al compilador que esta variable ya ha sido declarada en un módulo externo y que debe usarse la misma. Así, si tenemos "archivo1" y éste incluye un módulo llamado "archivo2" ( quien también necesita de las variables globales definidas en "archivo1" ), se hace las declaraciones:


en archivo1 en archivo2

#include<archivo2>

int x,y; extern int x,y;


y así el compilador sabría que las variables 'x' e 'y' en “archivo2” ya han sido definidas en un módulo externo.


Las variables static son muy importantes. Son variables que sólo son reconocidas dentro de su propio ámbito pero que el valor de la misma permanece entre llamadas a la función, o sea que no se destruye el valor al salir del bloque. En otras palabras: las variables "static" son variables permanentes pero difieren de las globales en que no son conocidas fuera de su bloque ó función. Se puede declarar una variable global como static y esto lo que haría es impedir que dicha variable sea usada fuera del módulo en el que fue declarada ( no se reconocería en todo el proyecto). Un ejemplo sería:


#include<stdio.h>


void funcion(void) {

static int i;

if (primeraVezQueSeEjecuta) {

i=0;

} else {

i=i+1; // El valor de esta variable se conserva entre llamadas a la función

// ya que se definió como static.

}

printf(“%i”,i); // Por lo tanto la primera vez que se llame a esta función, se imprimirá

// 0, en la segunda llamada 1 y así el valor irá aumentando en

// cada nuevo llamado.

}


int main(void){


}


Como último tipo tenemos el muy especial register. Una variable de tipo register pide al compilador que coloque el valor de esta variable directamente dentro de un registro del CPU en lugar de en memoria para así poder tener acceso a esta mucho más rápido. Sólo se puede usar en variables locales. Estas variables son ideales para bucles en esos casos en los que la velocidad de proceso de información es crítica. Personalmente les recomiendo el acostumbrase a su uso en los casos en que se hagan muchas referencias a la misma variable como por ejemplo en los contadores. Recuerden que esta variable siempre estará ocupando un registro del CPU por lo que si la usan en el bloque main(), el registro usado por la variable se mantendrá ocupado durante toda la ejecución del programa así que úsenla si en realidad es necesaria.



Operadores.


Operadores aritméticos.


Los operadores aritméticos son:

Resta "-". Ejemplo x = x - 3;

Suma "+". Ejemplo x = x +2;

Multiplicación "*". Ejemplo x = x *5;

División "/". Ejemplo x = x /5;

División en módulo "%". Devuelve el resto de una división. Sólo puede aplicarse a enteros.

Ejemplo x = 10%3; asignará 1 a la variable x.

Decremento "--". Ejemplo x--; Es lo mismo que x=x-1. Decrementa en 1 el valor de x.

Incremento "++". Ejemplo x++; Es lo mismo que x=x+1. Incrementa en 1 el valor de x.


MUY IMPORANTE. OJO: Cuando se aplica la división a un entero o a un caracter, cualquier resto es truncado. Por ejemplo: 22/3 devolverá 7 en división entera.


Los operadores de incremento y decremento pueden ser usados tanto como x++ y x-- ó como ++x y –x. Sin embargo existe una diferencia entre estas dos últimas y es que si por ejemplo hacemos:


y=10;

x = ++y;


entonces y=11 y x= 11 ...Primero incrementa y luego asigna. Pero si hacemos:


y=10;

x = y++;


entonces y=11 y x =10 ... Primero asigna y luego incrementa. Ojo con ésto en los bloques for();


La precedencia de los operadores aritméticos es:


++ -- Se hace primero

- ( menos monario )

* / %

+ - Se hace de último


Operadores relacionales y lógicos.


Los relacionales son:


Mayor que ">". Ej: si ( x > 3 ) haz algo.

Mayor o Igual que ">="

Menor que "<"

Menor o Igual que "<="

Igual "==". Ej: if ( x == 100 ) entonces ...

Distinto "!="



y los lógicos son:


AND "&&". Se usa si se requiere que dos condiciones se cumplan.

OR "||". Se usa cuando se sólo es necesario que una de las condiciones se cumpla.

NOT "!". Es un operador monario e invierte el estado de la condición.


En realidad estos operadores se explican por sí sólos. La precedencia de estos es:


!

> >= < <=

== !=

&&

||

Operadores a nivel de bits.


AND (&)

OR (|)

XOR (^),

Complemento a uno (~)

Desplazamiento a la derecha (>>).

Desplazamiento a la izquierda (<<).


Ejemplos x = x << 3 desplazará el equivalente binario de x tres bits a la izquierda y lo asignará a 'x' nuevamente. x = x >> 2, desplazará el equivalente binario de x dos bit a la derecha y el resultado lo asigna a 'x'. En ambos casos, los nuevos bits son reemplazados por ceros. Por lo tanto, si x =5, entonces:


x = x << 3; x = 00000101, luego de desplazar: x = 00101000, x = 40.


Como el título lo indica, operan a nivel de bits. Ejemplo: x=3&1; entonces x=1. Porqué?


00000011

& 00000001

es 00000001


Otros operadores.


Otros operadores son ',', '?', '&' , '*', 'sizeof()', '.' y el '->'


1.- Los dos operadores monarios '&' y '*' se usan para los punteros. Acerca de estos operadores profundizaremos en el apartado dedicado a punteros.


2.- Los operadores "." y "->" se usan en las estructuras. A éstos también llegaremos.


3.- El operador ','. Este operador se encarga de encadenar varias expresiones. Por ejemplo puede usarse:


x = (y=3, y+1);

En este caso, y será 3 y x quedará con el valor 4. Los paréntesis son necesarios ya que el operador ',' tiene menor precedencia que el operador de asignación. Otro ejemplo sería:


y = 10;

x = ( y = y-5 , 25/y );


En esta caso 'y' quedaría con el valor de 5 y x también.


4.- El operador '?'. Este es un operador muy potente que puede usarse para sustituir sentencias del tipo if-then-else. Por ejemplo, si tenemos:


y = (x>9) ? 100 : 200;


es lo mismo que decir:


if (x>9) {

y=100;

} else {

y=200;

}


5.- El operador sizeof NombreVariable; retorna el tamaño de la variable. Esto se usa mucho para facilitar la portabilidad del código. Por ejemplo, si tenemos:


int i;

printf(“%i”, sizeof(i));


el programa presentará por pantalla el valor 2 ya que 'i' es una variable entera que ocupa 2 bytes.


Precedencia de los operadores de C.


La precedencia de los operadores en C es, de mayor a menor:


() [] ->

! ~ ++ -- * & sizeof() ( '*' y '&' se refieren a los usados en punteros )

- ( menos monario )

* / %

+ -

<< >>

< <= > >=

== !=

&

^

|

&&

||

?

= += -= *= /=

,

Por lo tanto, todo lo que está dentro de paréntesis o corchetes, se ejecutará primero que cualquier otra cosa. Por ejemplo:


3 + 4 * 5


ejecutará 4*5 ( ya que * tiene prioridad ) y luego le sumará 3. Resultado = 23. En cambio


(3+ 4)*5


resolverá primero 3 + 4 y luego multiplicará por 5. Resultado = 35.


Expresiones.


Los operadores, las constantes y las variables son lo que constituyen las “expresiones” en C. Una expresión en C es cualquier combinación válida de estos elementos. Como la mayoría de las expresiones tienden a seguir las reglas del álgebra, o menudo se dan por sabidas. Sin embargo, existen unos pocos aspectos de las expresiones relativos específicamente al lenguaje C. Los más importantes a resaltar son:


1.- Moldes: Es posible forzar a una expresión para que sea de un tipo determinado. Ésto se logra usando la forma:


(tipoQueQueremos) expresión;


así por ejemplo:


(float) x/2;


forzará a que la expresión sea evaluada como float aunque la variable x sea de otro tipo ( p. ej. entera ).


2.- Espaciado y paréntesis: Se usan para dar mayor legibilidad al programa. Pueden añadirse tabulaciones y espacios a discreción en una expresión sin que estos alteren el resultado de la misma. Por ejemplo:


x=y/3-5*z&127;


es perfectamente válido, pero también es cierto que es más fácil a simple vista:


x = y / 3 – 5 * z & 127;


El uso de paréntesis redundantes no produce errores ni disminuye la velocidad de ejecución de un programa. Lo único que hace es facilitar la lectura del código. Así, la expresión anterior también la podemos escribir como:


x = (( y / 3) – (5 * z)) & 127 ;


por lo que, gracias a la ayuda de los paréntesis, es mucho más fácil ver la precedencia de las operaciones.



3.- Abreviaturas en C.


Por último tenemos una abreviatura muy útil a la hora de escribir nuestro código ya que simplifican ciertas sentencias de asignación. Esta abreviatura consiste en que podemos escribir:


NombreVariable = NombreVariable operador expresión;


como:


NombreVariable operador= expresión;


Por ejemplo:


x = x + 5; podemos escribirla como: x+=5;

y = y – 3; podemos escribirla como y -= 3;

z = z *2; podemos escribirla como: z *= 2;