A la hora de desarrollar aplicaciones necesitamos almacenar una gran cantidad de información, necesitamos también
estructuras que recojan varios tipos de datos a la vez. C cuenta con varias
herramientas para poder desarrollar todas estas funcionalidades. En éste
capítulo veremos los Arrays simples y multidimensionales para poder almacenar
una cantidad determinada de datos de un mismo tipo, acceder a ellos en
cualquier momento y operar, también veremos los registros para poder trabajar
con conjuntos de variables.
Foto tomada de freedigitalphotos.net |
Arrays
Un array, vector, tabla o arreglo es una cantidad de valores de un
determinado tipo colocados de manera secuencial e indexados, cuya forma de
acceder a ellos es especificando la posición (o índice) donde se encuentre
dentro del array.
Declaración.
Para declarar un array hay que seguir la siguiente estructura:
Tipo_dato nombre_variable [longitud_array];
El tipo de datos puede ser cualquier de los vistos anteriormente, por
ejemplo, un array de 20 enteros sería así:
int num[20];
La declaración es exactamente igual que cuando declaramos variables
normales, salvo que hay que añadir la longitud del array en cuestión.
Una cosa importante que hay que tener en cuenta a la hora de trabajar con
arrays en C es que la primera celda del array tiene el índice 0, por lo que el
array anterior tendría las siguientes posiciones:
num[0], num[1], num[2], num[3],
num[4], num[5], num[6] … num[19].
En una misma fila de declaración se pueden declarar tanto varios arrays a
la vez como variables normales.
int
num1,num2,num3[10],num4,num5[5];
También es posible declarar arrays prescindiendo del uso de números para
definir su tamaño, aunque es necesario que tengamos en cuenta ciertos factores:
1 – Para declarar un array usando identificadores sólo se podrá usar
constantes definidas mediante #define.
#define TAM 50
int main(void)
{
int
a[TAM];
}
2 – No es correcto definir el tamaño de un array con variables.
int main(void)
{
int
tam=50;
int
a[tam];
}
3 – No es correcto definir el tamaño de un array con constantes declaradas
mediante const. Esto es debido a que, a efectos del compilador, una constante
declarada mediante const es una variable de sólo lectura.
int main(void)
{
const
int tam=50;
int
a[tam];
}
Asignación de valores e iniciación de un array.
Cuando se declara un array las celdas de éste contienen valores
completamente aleatorios, es necesario que le asignemos los valores con los que
necesitamos trabajar, para esto hay varias posibilidades.
Asignación directa de un valor mediante el operador de asignación =, hay
que especificar mediante su índice la celda concreta donde se va a almacenar.
En el array anterior sería tal que así:
a[2] = 1;
Por lo general cuando comenzamos un programa se debe inicializar los
valores de todo el array, es decir, tendremos que asignar valores en todos sus
índices, para ello lo mejor es recorrer el array completo mediante un bucle.
El bucle for es perfecto para trabajar con arrays puesto que al tener
controlados todos los elementos esenciales de un bucle podemos centrarnos en
trabajar con el array directamente.
Un ejemplo de inicialización de un array es el siguiente:
#include <stdio.h>
#define TAM 20
int main(void)
{
int x, a[TAM];
for (x = 0; x < TAM; x++)
{
a[x]=0;
}
return 0;
}
También es posible inicializar un array en su propia declaración, para ello
debemos seguir la siguiente estructura:
Tipo_dato nombre_variable [longitud_array] = {valor0, valor1...
valor_longitud_array};
Un ejemplo práctico sería el siguiente:
int num[10] = {0,0,0,0,0,0,0,0,0,0}:
así nos aseguramos de que tenemos el array con valores definidos por
nosotros desde el principio del programa.
Recorrer un array.
Como hemos podido comprobar en el anterior apartado, un array se recorre
mediante un bucle.
Se toma como primer valor el cero puesto que la primera celda tiene índice
cero, por lo tanto la condición para salir del bucle es el tamaño menos uno. Si
recorremos el array y nos pasamos, o bien hacemos referencia a una celda fuera
del rango del array el programa dará errores.
Veamos un ejemplo donde recorremos un array y mostramos su valor por
pantalla:
#include <stdio.h>
#define TAM 5
int main(void)
{
int x,
int a[TAM] = {0,0,0,0,0};
for (x = 0; x < TAM; x++)
{
printf(“%d”,a[x]);
}
return 0;
}
Cadenas de texto o array de caracteres.
El tipo de dato String o Cadena no existe en C como tal, en lugar de eso lo
que tenemos a nuestra disposición es el array de caracteres, la forma de
tratarlo es exactamente igual que con los arrays de otros tipos de datos a
excepción de muchas instrucciones, entre ellas printf y scanf.
Consideraciones del array de caracteres
Definir un array de caracteres es sencillo, exactamente igual que con los
otros tipos de datos, pero debemos tener en consideración el término de la
cadena.
En las variables de tipo entero todas las celdas del array se rellenan por
defecto con valores aleatorios, en los arrays de caracteres pasa igual. Al
introducir o rellenar un array con caracteres no es necesario que lo rellenos
al completo, no obstante hay que indicar cuando termina la cadena.
Para eso en C disponemos del carácter especial \0, con éste le diremos al
programa que tenga en cuenta dentro del array todos los caracteres hasta llegar
al carácter \0.
El \0 cuenta como un carácter más dentro del array y como tal ocupa una
celda, es por eso que si definimos un array de 50 caracteres en realidad sólo
podremos rellenar los primeros 49, ya que siempre el carácter final es el \0.
H
|
O
|
L
|
A
|
\0
|
H
|
A
|
Y
|
\0
|
El carácter \0 no tenemos por qué introducirlo nosotros, el programa puede
encargarse, con que sepamos qué significa y cómo utilizarlo y
controlarlo es suficiente.
Un truco para poder almacenar un número de caracteres en un array con el
tamaño de ese número es definir el array con un tamaño igual y sumar una
posición:
#define TAM 5
int main(void)
{
char a[TAM+1};
return 0;
}
Cadenas y printf
Para poder escribir un array de caracteres utilizamos la sentencia printf y
la marca de formato %s
#include <stdio.h>
#define TAM 50
int main(void)
{
char saludo[TAM +1] = "hola";
printf ("%s.\n", saludo);
return 0;
}
No es necesario utilizar los bucles y recorrer celda a celda, aunque se
puede, resulta trabajoso ya que a veces los arrays pueden ser bastante grandes.
Cadenas y scanf.
La instrucción scanf cumple con su cometido de leer una palabra, pero se
presenta un problema y es el que acabo de decir, sólo lee una palabra, no una
frase completa.
Pero a eso le daremos solución en el siguiente apartado, ahora veamos cómo
utilizar la instrucción scanf:
#include <stdio.h>
#define TAM 50
int main(void)
{
char saludo[TAM +1];
scanf(“%s”,saludo);
printf ("%s.\n", saludo);
return 0;
}
Como se puede observar no es necesario de nuevo recorrer el array, la
instrucción hace posible asignar los caracteres directamente en sus celdas.
También si se observa el código, en la instrucción scanf no he puesto un
“&” delante del array, esto es debido a que hasta ahora hemos usado el
scanf con “&” porque lo que scanf necesita es una dirección de memoria
donde alojar el valor, cosa que hacíamos con “&”, como los arrays son en si
mismos direcciones de memoria indexados no es necesario colocar el “&”.
Prueba el código introduciendo la siguiente cadena “Hola buenos días” y
observa el resultado.
Cadenas y gets.
Para solucionar el problema del scanf con el array de caracteres tenemos
dentro de la librería stdio.h la instrucción gets
Con gets no es necesario utilizar una marca de formato, tan sólo con especificar
el array es suficiente, veamos un ejemplo:
#include <stdio.h>
#define TAM 50
int main(void)
{
char saludo[TAM +1];
gets(saludo);
printf ("%s.\n", saludo);
return 0;
}
Prueba ahora el código introduciendo de nuevo la cadena “Hola buenos días”
y observa el resultado.
Copiar cadenas.
El caso de necesitar hacer una copia de cadenas es una cosa que nos podemos
encontrar perfectamente en un programa, hasta ahora todo parece que se puede
realizar perfectamente mediante sentencias, por lo que copiar cadenas no debe
ser muy distinto, veamos el siguiente ejemplo:
#include <stdio.h>
#define TAM 50
int main(void)
{
char saludo[TAM +1] = "hola";
char despedida[TAM +1];
despedida=saludo;
printf ("%s.\n", despedida);
return 0;
}
Esto es incorrecto, el compilador dará error y el programa no llegará ni a
ejecutarse, esto es debido a que, recordemos, las cadenas son arrays, y los
arrays son direcciones de memoria que una vez declarados no se pueden alterar,
por lo que en el programa anterior lo que estaríamos intentando hacer es
asignar la dirección de memoria de otra dirección de memoria.
La copia de cadenas debe realizarse carácter a carácter, asignando los
valores uno a uno en todas las posiciones implicadas, veamos el mismo ejemplo
pero correctamente:
#include <stdio.h>
#define TAM 50
int main(void)
{
char saludo[TAM +1] = "hola";
char despedida[TAM +1];
for (x=0;x<TAM;x++)
{
despedida[x]=saludo[x];
}
printf ("%s.\n", despedida);
return 0;
}
Esta es la forma correcta de copiar cadenas, no obstante se puede refinar
un poco dado que tenemos dos cadenas de 50 caracteres y realmente sólo tenemos
que copiar cuatro, para ello introduciremos un condicional if para detectar el
\0 y salir del bucle, veamos el resultado final:
#include <stdio.h>
#define TAM 50
int main(void)
{
char saludo[TAM +1] = "hola";
char despedida[TAM +1];
for (x=0;x<TAM;x++)
{
despedida[x]=saludo[x];
if (saludo[x]==’\0’)
{
break;
}
}
printf ("%s.\n", despedida);
return 0;
}
Esto se puede plantear de múltiples formas, podemos refinarlo de diferentes
maneras, controlando en algunos sitios o bien modificando las condiciones del
bucle.
Arrays Multidimensionales.
Hasta ahora lo que hemos visto como array es una tabla de una columna y un
número determinado de filas, es posible ampliar todo esto bastante más, para
ello se utilizan los arrays multidimensionales. De esta forma podemos trabajar
con una tabla de filas y columnas a determinar, pero eso no es todo, también
podemos darle más dimensiones al array.
Declaración
Los arrays multidimensionales se declaran de la misma forma que los arrays
normales, pero por cada dimensión que queramos añadir debemos especificar
igualmente su longitud.
int numeros [10][2];
int numeros [10][2][5];
Recorrer un array multidimensional.
Un array multidimensional se recorre de la misma forma que un array normal,
mediante el bucle for, pero al igual que en la declaración debemos agregar
tantos bucles como sean necesarios y anidaarlos entre ellos.
Para los arrays anteriores sería así:
for (x=0;x<10,x++)
{
for (y=0;y<2,y++)
{
}
}
De ésta forma recorremos de la siguiente forma: Primera fila, primera
columna, segunda columna, ... , segunda fila, primera columna, segunda columna,
... etc.
for (x=0;x<10,x++)
{
for (y=0;y<2,y++)
{
for (z=0;z<5,z++)
{
}
}
}
Aquí recorremos así: Primera fila, primera columna, primera celda, segunda
celda, ... , primera fila, segunda columna, primera celda, segunda celda, ...
etc.
Todo lo que hemos visto en el apartado de arrays es completamente válido
para los arrays multimensionales, no necesitan de mayores retoques.
Registros.
El último punto de éste capítulo es bastante interesante, imaginemos que
necesitamos gestionar los datos de una tienda de discos, sería necesario
conocer varios datos como por ejemplo el nombre del disco, el año en que se
puso a la venta o el género al que pertenece. Esto se puede realizar
perfectamente usando variables y arrays, pero hay ocasiones en las que es mejor
agrupar estos datos con el fin de poder acceder a todos ellos de una sola vez.
Imaginemos que queremos gestionar los datos de 100 discos de música, es
sencillo porque utilizaremos tres arrays, uno para el nombre del disco, otro
para el año de publicación y otro para el género. Todo perfecto.
Ahora imaginemos que necesitamos buscar un disco en concreto y mostrar la
información completa del disco, del que sólo sabemos el nombre. Buscamos en el
primer array y lo localizamos, tenemos el nombre, ahora busquemos en el segundo
array el año en que se publicó, deberemos saber en qué posición del array se
encuentra, después busquemos en el siguiente array el género al que pertenece
¿No es un poco engorroso esto?
Ahora un caso perfectamente posible, imaginemos que deseamos eliminar un
disco, nos vamos al array del nombre y lo eliminamos, después al array de año y
luego al array de género, nuevamente engorroso.
Ahora lo último, imaginemos que nos hemos equivocado al programar y resulta
que por un error al eliminar el nombre del disco no hemos podido eliminar el
año y el género. El caos está servido.
En C disponemos de la posibilidad de declarar registros, esto son
agrupaciones de datos de cualquier tipo, accesibles mediante identificadores.
Usando un registro podemos agrupar los tres arrays anteriores en uno sólo, y
si queremos realizar cualquier operación la estaremos haciendo con un solo
array, un array de registros.
La representación de los tres arrays podría ser así:
Disco1
|
2000
|
Pop
|
||
Disco2
|
1997
|
Rock
|
||
Disco3
|
1999
|
Pop
|
La representación de un array de registros podría ser así:
Disco1
2000
Pop
|
Disco2
1997
Rock
|
Disco3
1999
Pop
|
Así lo tenemos mucho mejor ¿verdad? La representación de los datos mediante
un array de registros nos facilita operar con los datos y evitar mantenimientos
incómodos y que de resultar erróneos podría ocasionar errores de datos muy
graves.
Para definir un registro usaremos el siguiente esquema:
struct NombreRegistro {
variable1;
variable2;
variable3;
...
variableN;
};
Una vez lo hemos definido procedemos a declarar las variables basándonos en
la estructura siguiendo el siguiente esquema:
Struct NombreRegistro nombre_variable;
El registro lo definimos antes del programa principal (main), concretamente
después del #define, y por consiguiente después del #include, la declaración de
variables basadas en el registro la podemos hacer en cualquier momento.
Tanto en las variables de la definición como en la declaración podemos usar
arrays de cualquier dimensión.
Veamos el caso del programa para gestionar discos:
#include <stdio.h>
#include <string.h>
#define TAM 100
#define TAMEST 50
struct Discos {
char nombre[TAMEST+1];
int anno;
char genero[TAMEST+1];
};
int main(void)
{
struct Discos misdiscos[TAM];
return 0;
}
Con esto habremos contemplado el caso que planteábamos, ahora tenemos un
array de 100 registros donde gestionaremos nuestra colección de discos.
Para poder hacer referencia a una variable del registro tan sólo debemos
indicar su nombre de la siguiente forma:
Discos.nombre
Discos.anno
Discos.genero
El tratamiento con respecto a los operadores es el mismo que con las
variables, podemos asignar valores, realizar operaciones, comparar, etc.
En el caso que nos ocupa, el de los discos, al tratarse de un array lo
recorremos como ya hemos visto y trabajaremos con las variables así:
Discos[x].nombre
Discos[x].anno
Discos[x].genero
Donde X es el índice del array.
Con esto hemos terminado el sexto capítulo del curso básico de C. En éste
capítulo hemos aprendido los conceptos de arrays simples y multidimensionales,
hemos visto como recorrerlos y como trabajar con sus datos, también hemos visto
las cadenas o arrays de caracteres y la nueva instrucción gets, por último
hemos definido los registros, hemos visto como construirlos y como operar con
ellos.
En el siguiente capítulo veremos dos conceptos importantes dentro de la
programación, los procedimientos y las funciones, así como el paso de
parámetros y formas de utilización.
¿A qué se os asemejan los registros? ¿Veis complicado el tratamientos de arrays?