Tabla de contenidos
Las estructuras de datos del lenguaje C son más simples que las que ofrece Java porque no existe el concepto de “clase” ni de “objeto”. C ofrece tipos de datos básicos y dos construcciones para crear datos más complejos. El control de acceso a datos que ofrece Java (métodos y campos privados, públicos y protegidos) no existe en C. Las variable son globales, locales a un fichero, o locales a un bloque de código.
C ofrece tres tipos de datos básicos:
Números enteros definidos con la palabra clave
int
Letras o caracteres definidos con la palabra clave
char
Números reales o en coma flotante definidos con las
palabras claves float
o double
Se definen con “int
” y admiten
de forma opcional dos prefijos modificadores:
“short
” y
“long
”: Modifica el tamaño en bits del
entero. Existen por tanto tres tipos de enteros:
“int
”, “short int
”
(que se puede abreviar como “short
”), y
“long int
” (que se puede abreviar
como “long
”).
El lenguaje C no define tamaños fijos para sus tipos
de datos básicos. Lo único que garantiza es que un short
int
tiene un tamaño menor o igual que un
int
y este a su vez un tamaño menor o igual a un
long int
. Esta característica del lenguaje ha complicado
la creación de programas que sean compatibles entre varias
plataformas.
“unsigned
”: define un número
natural (mayor o igual a cero).
En tu entorno de desarrollo crea un fichero de texto con la siguiente estructura (puedes simplemente copiar y pegar el texto del siguiente cuadro):
int main() { }
Inserta en la función main
varias
definiciones de enteros para probar todas las combinaciones posibles
(hasta diez). Para comprobar que la sintaxis utilizada es correcta abre
una ventana con el intérprete de comandos y, en la carpeta donde se
encuentra el fichero creado, ejecuta el comando gcc -Wall -o
programa fichero.c reemplazando fichero.c
por el nombre del fichero que has creado. Si el comando no imprime
mensaje alguno por pantalla, tu programa es correcto. Verás que el
compilador genera un fichero con extensión
“.o
”, puedes borrarlo.
Responde a las siguientes preguntas (comprueba tus respuestas también compilando el programa):
Las variables de tipo letra se declaran como
“char
”. Para referirse a una letra se rodea de
comillas simples: 'M'
. Como las letras se representan
internamente como números, el lenguaje C permite realizar operaciones
aritméticas como 'M' + 25
.
Las cadenas de texto o
strings son simplemente tablas de
“char
”. Las funciones de biblioteca para
manipular estas cadenas asumen que el último byte tiene valor cero. Las
cadenas de texto se escriben en el programa rodeadas de dobles comillas y
contienen el valor cero al final. A continuación se muestran dos
definiciones:
#define SIZE 6 char a = 'A'; char b[SIZE] = "hello";
¿Por qué la segunda definición es una tabla de seis elementos si la palabra tiene sólo cinco letras?
Reutiliza el programa de la sección anterior y añade definiciones de letras y cadenas. Para estas últimas prueba a poner diferentes tamaños de tabla (demasiado pequeños y demasiado grandes para la cadena). Escribe también expresiones aritméticas sobre las letras. Recuerda que si el compilador no emite mensaje alguno, el programa es correcto.
Considera la siguiente declaración:
#define SIZE 6 char m[SIZE] = 'strag';
Si te parece que las respuestas correctas están equivocadas, escribe esa declaración en un programa y compílalo.
Los números reales se definen con
“float
” o “double
”. La
diferencia entre ambas es la precisión que ofrece su representación
interna. Hay un número infinito de reales, pero se representan con un
número finito de bits. A mayor número de bits, mayor número de reales se
representan, y por tanto, mayor precisión. Los reales definidos con
“double
” tienen un tamaño doble a los definidos
con “float
”. Al igual que en el caso de los
enteros, el tamaño de estas representaciones varía de una plataforma a
otra.
Algunas plataformas ofrecen números reales con tamaño
mayor al “double
” que se definen como
“long double
”. Los tamaños típicos para los
tipos “float
”,
“double
” y “long
double
” son 4, 8 y 12 bytes respectivamente. A continuación
se muestran varias definiciones de números reales.
float a = 3.5; double b = -5.4e-12; long double c = 3.54e320;
Añade al programa de los apartados anteriores definiciones de números reales. Prueba a definir números muy grandes o pequeños para ver la capacidad de representación de los tres tipos. Compila para ver si las definiciones son correctas.
Las tablas en C son prácticamente idénticas a las de Java, con el tamaño entre corchetes a continuación del nombre. Al igual que en Java, los índices de la tabla comienzan por cero. A continuación se muestran algunos ejemplos:
#define SIZE_TABLE 100 #define SIZE_SHORT 5 #define SIZE_LONG 3 #define SIZE_NAME 10 int table[SIZE_TABLE]; short st[SIZE_SHORT] = { 1, 2, 3, 4, 5 }; long lt[SIZE_LONG] = { 20, 30, 40}; char name[SIZE_NAME];
Los elementos de la tabla se acceden con el nombre de la tabla seguido del índice entre corchetes.
Una de las diferencias entre C y Java es que el acceso a
una tabla en C no se verifica. Cuando se ejecuta un programa en Java si se
accede a una tabla con un índice incorrecto, se genera una excepción de
tipo “ArrayIndexOutOfBounds
”. Estas
comprobaciones no se hacen nunca en C (a no ser que
se escriban explícitamente en el programa). Si se accede a una tabla con
un índice incorrecto se manipulan datos en una zona de memoria incorrecta
y el programa continua su ejecución.
Tras este acceso incorrecto pueden suceder dos cosas. La primera es que la memoria a la que ha accedido por error esté fuera de los límites del programa. En este caso la ejecución termina de manera abrupta y en el intérprete de comandos se muestra el mensaje “segmentation fault”. La otra posibilidad es que se acceda a otro lugar dentro de los datos del programa. Esta situación seguramente producirá un error cuyos síntomas sean difíciles de relacionar con el acceso incorrecto.
C permite la definición de tablas de múltiples dimensiones escribiendo los diferentes tamaños rodeados de corchetes y concatenados. El acceso se realiza concatenando tantos índices como sea preciso rodeados de corchetes. Al igual que en el caso de las tablas unidimensionales, no se realiza ningún tipo de comprobación de los índices cuando se accede a un elemento. A continuación se muestra la definición de tablas de más de una dimensión.
#define MATRIX_A 100 #define MATRIX_B 30 #define COMMON_SIZE 10 int matrix[MATRIX_A][MATRIX_B]; long squarematrix[COMMON_SIZE][COMMON_SIZE]; char soup[COMMON_SIZE][COMMON_SIZE];
Añade al programa de los apartados anteriores definiciones y manipulación de tablas de los diferentes tipos de datos básicos. Comprueba que son correctos sintácticamente mediante el compilador.
En C, el tamaño de los tipos de datos básicos puede variar de una plataforma a otra. Esta característica está detrás de buena parte de las críticas que recibe este lenguaje, pues de ella se derivan problemas de compatibilidad (una aplicación se comporta de forma diferente cuando se ejecuta en plataformas diferentes).
A modo de ejemplo, en la siguiente tabla se incluyen los tamaños de los tipos de datos para las plataformas Linux/Intel i686.
Tabla 2.1. Tamaños de los tipos de datos en C en la plataforma Linux/Intel i686
Tipo | Tamaño (bytes) |
---|---|
char , unsigned char | 1 |
short int , unsigned short int
| 2 |
int , unsigned int , long
int , unsigned long int
| 4 |
float | 4 |
double | 8 |
long double | 12 |