Cómo trabajar con variables, tipos de datos y expresiones aritméticas en el lenguaje de programación C

C tiene una rica variedad de operadores matemáticos que puede utilizar para manipular sus datos. En este capítulo de Programming in C, 4th Edition, Stephen G. Kochan cubre los tipos de datos int, float, double, char y _Bool, la modificación de los tipos de datos con short, long y long long, las reglas para nombrar las variables, los operadores matemáticos básicos y las expresiones aritméticas, y el casting de tipos.

El verdadero poder de los programas que usted crea es su manipulación de datos. Para aprovechar realmente este poder, necesita entender mejor los diferentes tipos de datos que puede utilizar, así como la forma de crear y nombrar variables. C tiene una rica variedad de operadores matemáticos que puedes usar para manipular tus datos. En este capítulo cubrirás:

  • Los tipos de datos int, float, double, char y _Bool
  • Modificar los tipos de datos con short, long, y long long
  • Las reglas para nombrar variables
  • Operadores matemáticos básicos y expresiones aritméticas
  • Casting de tipos

Entender los tipos de datos y las constantes

Ya ha conocido el tipo de datos básico de C int. Como recordará, una variable declarada de tipo int sólo puede utilizarse para contener valores integrales, es decir, valores que no contienen decimales.

El lenguaje de programación C proporciona otros cuatro tipos de datos básicos: float, double, char y _Bool. Una variable declarada de tipo float puede utilizarse para almacenar números de punto flotante (valores que contienen decimales). El tipo double es el mismo que el tipo float, sólo que con aproximadamente el doble de precisión. El tipo de datos char puede utilizarse para almacenar un solo carácter, como la letra «a», el carácter numérico «6» o un punto y coma (‘;’) (más adelante). Por último, el tipo de datos _Bool puede utilizarse para almacenar sólo los valores 0 o 1. Las variables de este tipo se utilizan para indicar una situación de encendido/apagado, sí/no, o verdadero/falso. Estas opciones de uno u otro también se conocen como opciones binarias.

En C, cualquier número, carácter único o cadena de caracteres se conoce como una constante. Por ejemplo, el número 58 representa un valor entero constante. La cadena de caracteres «Programar en C es divertido.\N» es un ejemplo de una cadena de caracteres constante. Las expresiones que consisten completamente en valores constantes se llaman expresiones constantes. Así, la expresión

128 + 7 - 17

es una expresión constante porque cada uno de los términos de la expresión es un valor constante. Pero si se declarara que i es una variable entera, la expresión

128 + 7 – i

no representaría una expresión constante porque su valor cambiaría en función del valor de i. Si i es 10, la expresión es igual a 125, pero si i es 200, la expresión es igual a -65.

El tipo entero int

En C, una constante entera consiste en una secuencia de uno o más dígitos. Un signo menos que precede a la secuencia indica que el valor es negativo. Los valores 158, -10 y 0 son ejemplos válidos de constantes enteras. No se permiten espacios entre los dígitos y los valores superiores a 999 no pueden expresarse con comas. (Así, el valor 12.000 no es una constante entera válida y debe escribirse como 12000.)

Dos formatos especiales en C permiten que las constantes enteras se expresen en una base distinta a la decimal (base 10). Si el primer dígito del valor entero es un 0, el entero se toma como expresado en notación octal, es decir, en base 8. En ese caso, los dígitos restantes del valor deben ser dígitos válidos de base 8 y, por tanto, deben ser de 0 a 7. Así, para expresar el valor 50 en base 8 en C, que equivale al valor 40 en decimal, se utiliza la notación 050. Del mismo modo, la constante octal 0177 representa el valor decimal 127 (1 × 64 + 7 × 8 + 7). Un valor entero puede mostrarse en el terminal en notación octal utilizando los caracteres de formato %o en la cadena de formato de una sentencia printf(). En este caso, el valor se muestra en octal sin un cero a la izquierda. El carácter de formato %#o hace que se muestre un cero a la izquierda antes de un valor octal.

Si una constante entera está precedida por un cero y la letra x (ya sea minúscula o mayúscula), el valor se toma como expresado en notación hexadecimal (base 16). Inmediatamente después de la letra x están los dígitos del valor hexadecimal, que pueden estar compuestos por los dígitos 0-9 y las letras a-f (o A-F). Las letras representan los valores 10-15, respectivamente. Así, para asignar el valor hexadecimal FFEF0D a una variable entera llamada rgbColor, se puede utilizar la sentencia

rgbColor = 0xFFEF0D;

. Los caracteres de formato %x muestran un valor en formato hexadecimal sin el 0x inicial, y utilizando letras minúsculas a-f para los dígitos hexadecimales. Para mostrar el valor con el 0x inicial, se utilizan los caracteres de formato %#x, como en lo siguiente:

printf ("Color is %#x\n", rgbColor);

Se puede utilizar una x mayúscula, como en %X o %#X, para mostrar la x inicial y los dígitos hexadecimales que le siguen utilizando letras mayúsculas.

Tamaños y rangos de almacenamiento

Cada valor, ya sea un carácter, un entero o un número de punto flotante, tiene un rango de valores asociado. Este rango tiene que ver con la cantidad de almacenamiento que se asigna para almacenar un tipo particular de datos. En general, esa cantidad no está definida en el lenguaje. Suele depender del ordenador con el que se trabaja y, por tanto, se denomina dependiente de la implementación o de la máquina. Por ejemplo, un número entero puede ocupar 32 bits en tu ordenador, o tal vez pueda almacenarse en 64. Nunca debes escribir programas que hagan suposiciones sobre el tamaño de tus tipos de datos. Sin embargo, está garantizado que se reservará una cantidad mínima de almacenamiento para cada tipo de datos básico. Por ejemplo, se garantiza que un valor entero se almacenará en un mínimo de 32 bits de almacenamiento, que es el tamaño de una «palabra» en muchos ordenadores.

El tipo de número flotante float

Una variable declarada de tipo float puede utilizarse para almacenar valores que contengan decimales. Una constante de punto flotante se distingue por la presencia de un punto decimal. Se pueden omitir dígitos antes del punto decimal o dígitos después del punto decimal, pero obviamente no se pueden omitir ambos. Los valores 3., 125.8, y -.0001 son todos ejemplos válidos de constantes de punto flotante. Para mostrar un valor de punto flotante en el terminal, se utilizan los caracteres de conversión printf %f.

Las constantes de punto flotante también pueden expresarse en notación científica. El valor 1,7e4 es un valor de punto flotante expresado en esta notación y representa el valor 1,7 × 104. El valor que precede a la letra e se conoce como mantisa, mientras que el valor que le sigue se llama exponente. Este exponente, que puede ir precedido por un signo opcional de más o menos, representa la potencia de 10 por la que se va a multiplicar la mantisa. Así, en la constante 2,25e-3, el 2,25 es el valor de la mantisa y -3 es el valor del exponente. Esta constante representa el valor 2,25 × 10-3, es decir, 0,00225. Por cierto, la letra e, que separa la mantisa del exponente, puede escribirse en minúsculas o en mayúsculas.

Para mostrar un valor en notación científica, deben especificarse los caracteres de formato %e en la cadena de formato de printf(). Los caracteres de formato de printf() %g pueden utilizarse para que printf() decida si mostrar el valor de punto flotante en notación normal de punto flotante o en notación científica. Esta decisión se basa en el valor del exponente: Si es menor que -4 o mayor que 5, se utiliza el formato %e (notación científica); en caso contrario, se utiliza el formato %f.

Utilice los caracteres del formato %g para mostrar números de punto flotante-produce la salida más agradable estéticamente.

Una constante flotante hexadecimal consiste en un 0x o 0X inicial, seguido de uno o más dígitos decimales o hexadecimales, seguido de una p o P, seguido de un exponente binario con signo opcional. Por ejemplo, 0x0.3p10 representa el valor 3/16 × 210 = 0.5.

El tipo de precisión extendida double

El tipo double es muy similar al tipo float, pero se utiliza cuando el rango proporcionado por una variable float no es suficiente. Las variables declaradas de tipo double pueden almacenar aproximadamente el doble de dígitos significativos que una variable de tipo float. La mayoría de los ordenadores representan valores dobles usando 64 bits.

A menos que se diga lo contrario, todas las constantes de punto flotante son tomadas como valores dobles por el compilador de C. Para expresar explícitamente una constante float, añada una f o una F al final del número, como se indica a continuación:

12.5f

Para mostrar un valor doble, se pueden utilizar los caracteres de formato %f, %e o %g, que son los mismos que se utilizan para mostrar un valor float.

El tipo de carácter único char

Se puede utilizar una variable char para almacenar un carácter único.1 Una constante de carácter se forma encerrando el carácter dentro de un par de comillas simples. Así, ‘a’, ‘;’ y ‘0’ son ejemplos válidos de constantes de carácter. La primera constante representa la letra a, la segunda es un punto y coma y la tercera es el carácter cero, que no es lo mismo que el número cero. No confunda una constante de carácter, que es un solo carácter encerrado entre comillas simples, con una cadena de caracteres, que es cualquier número de caracteres encerrados entre comillas dobles.

La constante de carácter ‘\n’-el carácter de la barra invertida- es una constante de carácter válida aunque parezca contradecir la regla citada anteriormente. Esto se debe a que el carácter de la barra invertida es un carácter especial en el sistema C y no cuenta realmente como un carácter. En otras palabras, el compilador de C trata el carácter ‘\n’ como un solo carácter, aunque en realidad está formado por dos caracteres. Hay otros caracteres especiales que se inician con el carácter barra invertida. Consulte el Apéndice A, «Resumen del Lenguaje C», para obtener una lista completa.

Los caracteres de formato %c pueden utilizarse en una llamada a printf() para mostrar el valor de una variable char en el terminal.

El tipo de datos booleanos _Bool

Una variable _Bool se define en el lenguaje para que sea lo suficientemente grande como para almacenar sólo los valores 0 y 1. La cantidad exacta de memoria que se utiliza no está especificada. Las variables _Bool se utilizan en programas que necesitan indicar una condición booleana. Por ejemplo, una variable de este tipo podría utilizarse para indicar si se han leído todos los datos de un archivo.

Por convención, 0 se utiliza para indicar un valor falso, y 1 indica un valor verdadero. Al asignar un valor a una variable _Bool, un valor de 0 se almacena como 0 dentro de la variable, mientras que cualquier valor distinto de cero se almacena como 1.

Para facilitar el trabajo con variables _Bool en su programa, el archivo de cabecera estándar <stdbool.h> define los valores bool, true y false. Un ejemplo de esto se muestra en el programa 5.10A del capítulo 5, «Toma de decisiones».

En el programa 3.1 se utilizan los tipos de datos básicos de C.

Programa 3.1 Uso de los tipos de datos básicos

Programa 3.1 Salida

integerVar = 100floatingVar = 331.790009doubleVar = 8.440000e+11doubleVar = 8.44e+11charVar = WboolVar = 0;

La primera sentencia del programa 3.1 declara que la variable integerVar es una variable entera y también le asigna un valor inicial de 100, como si se hubieran utilizado las dos sentencias siguientes en su lugar:

int integerVar;integerVar = 100;

En la segunda línea de la salida del programa, observe que el valor de 331,79, que se asigna a floatingVar, se muestra en realidad como 331,790009. De hecho, el valor real que se muestra depende del sistema informático que se esté utilizando. La razón de esta inexactitud es la forma particular en que los números se representan internamente dentro del ordenador. Probablemente te hayas encontrado con el mismo tipo de inexactitud cuando tratas con números en tu calculadora de bolsillo. Si divides 1 entre 3 en tu calculadora, obtienes el resultado 0,33333333, con algunos 3 adicionales al final. La cadena de 3s es la aproximación de la calculadora a un tercio. En teoría, debería haber un número infinito de 3s. Pero la calculadora sólo puede contener un número determinado de dígitos, de ahí la inexactitud inherente a la máquina. El mismo tipo de imprecisión se aplica aquí: Ciertos valores de punto flotante no pueden ser representados exactamente dentro de la memoria de la computadora.

Cuando se muestran los valores de variables flotantes o dobles, se puede elegir entre tres formatos diferentes. Los caracteres %f se utilizan para mostrar los valores de forma estándar. A menos que se indique lo contrario, printf() siempre muestra un valor flotante o doble con seis decimales redondeados. Más adelante verá cómo seleccionar el número de decimales que se muestran.

Los caracteres %e se utilizan para mostrar el valor de una variable flotante o doble en notación científica. Una vez más, el sistema muestra automáticamente seis posiciones decimales.

Con los caracteres %g, printf() elige entre %f y %e y también elimina automáticamente de la pantalla cualquier cero final. Si no hay dígitos después del punto decimal, tampoco lo muestra.

En la penúltima sentencia printf(), los caracteres %c se utilizan para mostrar el único carácter ‘W’ que asignó a charVar cuando se declaró la variable. Recuerde que mientras que una cadena de caracteres (como el primer argumento de printf()) se encierra dentro de un par de comillas dobles, una constante de caracteres siempre debe estar encerrada dentro de un par de comillas simples.

La última sentencia printf() muestra que una variable _Bool puede tener su valor mostrado utilizando los caracteres de formato entero %i.

Especificadores de tipo: long, long long, short, unsigned y signed

Si el especificador long se coloca directamente antes de la declaración int, la variable entera declarada es de rango extendido en algunos sistemas informáticos. Un ejemplo de declaración de int largo podría ser

long int factorial;

Esto declara que la variable factorial es una variable entera larga. Al igual que con los flotadores y los dobles, la precisión particular de una variable larga depende de su sistema informático particular. En muchos sistemas, un int y un long int tienen el mismo rango y cualquiera de ellos puede ser utilizado para almacenar valores enteros de hasta 32 bits de ancho (231 – 1, o 2.147.483.647).

Un valor constante de tipo long int se forma añadiendo opcionalmente la letra L (mayúscula o minúscula) al final de una constante entera. No se permiten espacios entre el número y la L. Así, la declaración

long int numberOfPoints = 131071100L;

declara que la variable númeroDePuntos es de tipo long int con un valor inicial de 131,071,100.

Para mostrar el valor de un long int utilizando printf(), se utiliza la letra l como modificador antes de los caracteres de formato entero i, o y x. Esto significa que los caracteres de formato %li pueden utilizarse para mostrar el valor de un int largo en formato decimal, los caracteres %lo pueden mostrar el valor en formato octal, y los caracteres %lx pueden mostrar el valor en formato hexadecimal.

También existe un tipo de datos entero largo, por lo que

long long int maxAllowedStorage;

declara que la variable indicada tiene la precisión extendida especificada, que se garantiza que tiene al menos 64 bits de ancho. En lugar de una sola letra l, se utilizan dos ls en la cadena printf para mostrar enteros largos, como en «%lli».

El especificador long también se permite delante de una declaración de doble, como sigue:

long double US_deficit_2004;

Una constante doble larga se escribe como una constante flotante con la letra l o L inmediatamente después, como

1.234e+7L

Para mostrar un doble largo, se utiliza el modificador L. Así, %Lf muestra un valor doble largo en notación de punto flotante, %Le muestra el mismo valor en notación científica, y %Lg le dice a printf() que elija entre %Lf y %Le.

El especificador short, cuando se coloca delante de la declaración int, le dice al compilador de C que la variable particular que se está declarando se utiliza para almacenar valores enteros bastante pequeños. La motivación para utilizar variables cortas es principalmente la de conservar el espacio de memoria, lo que puede ser un problema en situaciones en las que el programa necesita mucha memoria y la cantidad de memoria disponible es limitada.

En algunas máquinas, un int corto ocupa la mitad de la cantidad de almacenamiento que una variable int normal. En cualquier caso, tiene garantizado que la cantidad de espacio asignado a un short int no será inferior a 16 bits.

No hay forma de escribir explícitamente una constante de tipo short int en C. Para mostrar una variable short int, coloque la letra h delante de cualquiera de los caracteres normales de conversión de enteros: %hi, %ho o %hx. Alternativamente, también se puede utilizar cualquiera de los caracteres de conversión de enteros para mostrar ints cortos, debido a la forma en que se pueden convertir en enteros cuando se pasan como argumentos a la rutina printf().

El último especificador que se puede colocar delante de una variable int se utiliza cuando una variable entera se utilizará para almacenar sólo números positivos. La declaración

unsigned int counter;

declara al compilador que el contador de la variable se utiliza para contener sólo valores positivos. Al restringir el uso de una variable entera al almacenamiento exclusivo de enteros positivos, se amplía la precisión de la variable entera.

Una constante int sin signo se forma colocando la letra u (o U) después de la constante, como se indica a continuación:

0x00ffU

Se pueden combinar las letras u (o U) y l (o L) al escribir una constante entera, por lo que

20000UL

indica al compilador que trate la constante 20000 como un long sin signo.

Una constante entera que no va seguida de ninguna de las letras u, U, l o L y que es demasiado grande para caber en un int de tamaño normal es tratada como un int sin signo por el compilador. Si es demasiado pequeño para caber en un int sin signo, el compilador lo trata como un int largo. Si todavía no cabe dentro de un long int, el compilador lo convierte en un unsigned long int. Si no cabe ahí, el compilador lo trata como un long int si cabe, y como un long int sin signo en caso contrario.

Cuando se declaran variables de tipo long long int, long int, short int o unsigned int, se puede omitir la palabra clave int. Por lo tanto, el contador de la variable sin signo podría haberse declarado de forma equivalente como sigue:

unsigned counter;

También puede declarar las variables char como sin signo.

El calificador con signo puede utilizarse para indicar explícitamente al compilador que una determinada variable es una cantidad con signo. Su uso es principalmente delante de la declaración de char, y su discusión se pospone hasta el capítulo 13, «Más sobre los tipos de datos».

No se preocupe si las discusiones de estos especificadores le parecen un poco esotéricas en este momento. En secciones posteriores de este libro, muchos de estos tipos diferentes se ilustran con ejemplos de programas reales. El capítulo 13 entra en más detalle sobre los tipos de datos y las conversiones.

La tabla 3.1 resume los tipos de datos básicos y los calificadores.

Tabla 3.1 Tipos de datos básicos