Anuncios

Bienvenidos, en el post de hoy vamos a estudiar un tema visto por arriba, como son los arrays.

Anuncios

Hasta ahora hemos utilizado algunos en varios ejemplos pero sin dar una explicacion sobre los mismos, los arrays son una coleccion de ubicaciones para almacenar datos del mismo tipo (int, float, etc), cada ubicacion del array se llama elemento, la estructura de declaracion basica de un array es la siguiente:

tipoDeDato nombre[ cantidad ];
int ArrayEntero[ 5 ];
Anuncios

Primero definimos el tipo de dato a almacenar, despues definimos el nombre con el cual se va a identificar y por ultimo el subindice entre corchetes ([ ]) donde ira la cantidad de elementos que va a tener el array, en este caso cinco. Para acceder a la ubicacion se debe poner el numero del elemento, en este caso establecimos el valor de subindice en cinco por ende la cantidad de elementos va a ser de cinco y para contarlos se debe hacer desde 0 a 4, por ejemplo ArrayEntero[1], con este indicador devolvera el valor almacenado en el segundo elemento, pasemos al siguiente ejemplo:

array00.cpp

# include <iostream>

using namespace std;

int main()
{
 	int Arreglo[ 5 ];
 	int i;
 	int j=3;
 	for (i=0; i<5; i++)
 	{
 		cout << "Valor asignado a Arreglo[" << i;
		cout << "]: " << j << endl;
 		Arreglo[i]=j;
 		j=j+3;
 	}
 	for (i=0; i<5; i++)
 	{
 		cout << "Posicion " << i << ": " << Arreglo[i] << endl;
 	}
 	return 0;
}
Anuncios

Analicemos el codigo, primero creamos el array llamado Arreglo, este va a contener cinco elementos, como lo indica el subindice, despues declaramos un valor i para el contador del for, y finalmente una variable j iniciado con tres para la operacion del primer for. En el primer for, vamos a almacenar en los elementos de Arreglo el valor de j, que va a sumarse de a tres por cada vuelta del ciclo y tambien vamos a mostrar el valor asignado a cada elemento, en el proximo for vamos a recuperar esa informacion almacenada, compilemos y veamos la salida del programa:

tinchicus@dbn001dsk:~/lenguaje/c++$ ./array00
Valor asignado a Arreglo[0]: 3
Valor asignado a Arreglo[1]: 6
Valor asignado a Arreglo[2]: 9
Valor asignado a Arreglo[3]: 12
Valor asignado a Arreglo[4]: 15
Posicion 0: 3
Posicion 1: 6
Posicion 2: 9
Posicion 3: 12
Posicion 4: 15
tinchicus@dbn001dsk:~/lenguaje/c++$
Anuncios

Los elementos de este array son cinco pero van del cero a cuatro, en programacion en gral. el primer valor para contar se inicia desde cero. Algo muy importante sobre los arrays, traten de no excederse con los elementos asignados en un Array porque si bien en Linux esto puede generar un error o bien ocasionar que termine el programa en otros sistemas operativos no tan robustos (como MS-DOS) esto podria ocasionar escritura en la memoria del sistema operativo y ocasionar el congelamiento del mismo. Este tipo de error habitualmente se llama “Error tipo de poste de barda”, esto se lo relaciona habitualmente con el contexto de cuando a las personas se le pregunta cuantos postes necesitan para un barda de diez metros, todos responden que diez postes pero en realidad van a necesitar once, porque se va a necesitar el de origen (cero) y diez mas por cada metro. En programacion  ocurre algo parecido, por lo que recuerden al elemento cero se lo llama primer elemento y a la hora de enumerarlo recuerden relacionarlo con la posicion del elemento no con el numero de subindice. Pasemos a como inicializar un array, veamos el ejemplo:

int Arreglo[ 5 ] = { 3, 6, 9, 12, 15 };

Otra forma de inicializarlo es:

int Arreglo[] = { 3, 6, 9, 12, 15 };

En este caso, ocurre exactamente lo mismo, pero para este caso el compilador asigna el mayor valor posible para el array en el caso de necesitar guardar algo mas de informacion. Suponiendo la utilizacion del segundo caso y nosotros necesitamos averiguar el tamaño del mismo deberiamos utilizar una expresion como la siguiente:

unsigned short LongitudArregloEntero;
LongitudArregloEntero = sizeof(Arreglo) / sizeof(Arreglo[0]);
Anuncios

Para lograr este valor se debe utilizar sizeof, este nos devolvera el tamaño de la variable, primero averiguamos el tamaño del array (Arreglo) y luego lo dividimos por el tamaño de uno de los elementos del array (en este caso el primer registro), esto nos da como resultado la cantidad de elementos en el mismo. A la hora de iniciarlos tengan en cuenta que nunca excedan el valor del subindice, por ejemplo:

int Arreglo[ 5 ] = { 3, 6, 9, 12, 15, 18 };

Esta iniciacion nos devolvera un error pero si por ejemplo no llegan a completar todos los elementos, en ese caso no habria inconvenientes:

int Arreglo[ 5 ] = { 3, 6 };
Anuncios

El array se puede declarar como cualquier variable valida siempre y cuando no se repitan en el mismo bloque con otra variable, por ejemplo usted no podria tener un array llamado misDatos y otra variable llamada misDatos pero recuerde que si puede tener uno misDatos y otro misdatos, aunque esto realmente resultaria poco practico y confuso en el codigo, para evitar esto trate de usar nombres distintos, vamos a ver un ejemplo de como declarar un array y utilizarlo:

array01.cpp

# include <iostream>

using namespace std;

int main()
{
 	enum SemanaDias {
 		Dom, Lun, Mar, Mie, Jue, Vie, Sab, DiadelaSemana
 	};
 	int i;
 	string dia;
 	int valor;
 	int ArrayWeek[ DiadelaSemana ] = { 10, 20, 30, 40, 50, 60, 70 };
	for(i = 0; i < DiadelaSemana; i++)
 	{
 		switch(i)
 		{
 			case 0:
 				dia="Dom";
 				valor=ArrayWeek[ Dom ];
 				break;
 			case 1:
 				dia="Lun";
 				valor=ArrayWeek[ Lun ];
 				break;
 			case 2:
 				dia="Mar";
 				valor=ArrayWeek[ Mar ];
 				break;
 			case 3:
 				dia="Mie";
 				valor=ArrayWeek[ Mie ];
 				break;
 			case 4:
 				dia="Jue";
 				valor=ArrayWeek[ Jue ];
 				break;
 			case 5:
 				dia="Vie";
 				valor=ArrayWeek[ Vie ];
 				break;
 			default:
 				dia="Sab";
 				valor=ArrayWeek[ Sab ];
 				break;
 		}
 		cout << "El valor del dia " << dia; 
		cout << " es: " << valor << endl;
 	}
 	return 0;
}
Anuncios

En este ejemplo declaramos un enum, el cual va a contener todos los dias, desde Domingo a Sabado, este se va a encargar de asignarles un valor entre cero y seis, y despues del sabado vamos a agregar otro llamado DiasdelaSemana que va a tener el valor siete. Despues crearemos un array llamado ArrayWeek, este se encargara de guardar un valor para cada dia de la semana, el subindice estara suministrado por DiasdelaSemana, despues pasaremos al for que se encargara, mediante un switch, de asignar a valor el numero del array que esta asignado para el dia correspondiente y por otro lado el nombre del dia correspondiente a cada posicion del enum con respecto al ciclo del for, y por cada ciclo imprimira el nombre del dia con el valor correspondiente, lo compilamos y ejecuatamos nos devolvera la siguiente salida:

tinchicus@dbn001dsk:~/lenguaje/c++$ ./array01
El valor del dia Dom es: 10
El valor del dia Lun es: 20
El valor del dia Mar es: 30
El valor del dia Mie es: 40
El valor del dia Jue es: 50
El valor del dia Vie es: 60
El valor del dia Sab es: 70
tinchicus@dbn001dsk:~/lenguaje/c++$
Anuncios

Pasemos a hablar sobre otro tipo de array, el utilizado para los objetos. Para poder realizar el array de objetos se necesita crear en la clase un constructor predeterminado (sin parametros), veamos a traves de un ejemplo la declaracion y la creacion de objetos:

array02.cpp

# include <iostream>

using namespace std;

class Gato
{
public:
 	Gato(){ suEdad=1; suPeso=5; }
 	~Gato(){}
 	int ObtenerEdad() const { return suEdad; }
 	int ObtenerPeso() const { return suPeso; }
 	void AsignarEdad(int edad) { suEdad = edad; }
private:
 	int suEdad;
 	int suPeso;
};

int main()
{
 	Gato camada [ 5 ];
 	int i;
	for(i = 0; i < 5; i++ )
 	{
 		camada[ i ].AsignarEdad(2 * i + 1);
 	}
	for(i=0; i < 5; i++)
 	{
 		cout << "Gato #" << i << ": ";
 		cout << camada[ i ].ObtenerEdad() << endl;
 	}
 	return 0;
}
Anuncios

En este ejemplo, creamos una clase Gato con un constructor predeterminado y unos metodos (ObternerEdad, ObtenerPeso, AsignarEdad), hasta aca el mismo procedimiento como hicimos hasta ahora, en el cuerpo del main, creamos el objeto camada de la clase Gato pero le agregamos el subindice cinco:

 Gato camada[ 5 ];
Anuncios

Esto nos dara la posibilidad de crear cinco objetos dentro un array, despues llamamos a un for para generar las edades para los distintos Gatos, y observen la linea:.

camada[ i ].AsignarEdad(2 * i + 1);

Anuncios

En la llamada al objeto utilizamos como elementos al valor de i que genera el ciclo for, separada por un punto (.), como se debe llamar al metodo para asignar un nuevo valor a suEdad de cada gato en el array, una vez finalizado llamamos a traves de for para obtener la edad de cada uno:

tinchicus@dbn001dsk:~/lenguaje/c++$ ./array02
Gato #0: 1
Gato #1: 3
Gato #2: 5
Gato #3: 7
Gato #4: 9
tinchicus@dbn001dsk:~/lenguaje/c++$
Anuncios

Cual es la diferencia con lo que vimos hasta ahora, es a la hora de invocar al objeto creado tenemos que agregar los subindices del array, si no es una array lo declaramos como un objeto normal, ahora pasemos a describir los array multidimensionales.

Anuncios

Los array vistos hasta ahora fueron de una sola dimension, pero pueden tener n dimensiones, por ejemplo si tuviesemos un array de dos dimensiones a la hora de declararlo se crean dos subindices, en el caso de tres dimensiones, tres subindices y asi sucesivamente con la cantidad de dimensiones, un ejemplo:

int Arreglo[ 5 ][ 5 ]; // Seria un array de dos dimensiones sin iniciar.
Anuncios

Igualmente en la vida real es muy raro tener un array de mas de dos dimensiones, vamos a suponer un tablero de ajedrez, vamos a tener dos tipos de datos (filas y columnas) y para este ejemplo vamos a tener una clase CUADRO, a la cual le vamos a crear un objeto llamado Tablero, la creacion seria asi:

CUADRO Tablero [ 8 ][ 8 ];
Anuncios

y ahora vamos a ubicar a la segunda torre en este array, esta deberia ir en Tablero[ 0 ][ 7 ], suponiendo que el primer dato es la fila y el segundo es la columna, es la primera fila (0) en la octava columna (7), ahora para iniciar un array de mas de una dimension debemos hacerlo asi:

elArreglo[ 5 ][ 3 ] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };

El array los guardara en base al ultimo subindice declarado, por ejemplo en este caso van a ser guardarlos de a tres, para verlo un poco mejor lo voy a sepaarar entre llaves:

elArreglo[ 5 ][ 3 ] = {
	{1,2,3},
 	{4,5,6},
 	{7,8,9},
 	{10,11,12},
 	{13,14,15}
};
Anuncios

Esta es la forma en realidad como se guarda dentro del array, lo unico que deben recordar que todos los valores van separados por comas y en este caso el compilador ignora las llaves porque ya sabe como se debe almacenar la informacion y nosotros la utilizamos mas por un metodo de mejor visualizacion, pasemos a un ejemplo para entender mejor el concepto:

array03.cpp

# include <iostream>

using namespace std;

int main()
{
 	int elArreglo[ 5 ][ 2 ] =
 		{
 		{0,0},
 		{1,2},
 		{2,4},
 		{3,6},
 		{4,8}
 		};
	for(int i = 0; i < 5; i++)
 	{
 		for(int j = 0; j < 2; j++)
 		{
 		cout << "elArreglo[ " << i << " ][ " << j << " ]: ";
 		cout << elArreglo[ i ][ j ] << endl;
 		}
 	}
 	return 0;
}
Anuncios

En el array hacemos al segundo valor el doble del primero, como ven en el caso de aca hubiera sido lo mismo escribir la iniciacion del array de esta forma:

int elArreglo[ 5 ][ 2 ] = { 0,0,1,2,2,4,3,6,4,8 };
Anuncios

Hubieramos tenido el mismo resultado, para verificar la correcta inicializacion del array utilizamos dos for, uno con un ciclo de cinco para verificar el primer subindice, y el segundo para verificar el segundo subindice, compilemos y probemos nuestro programa:

tinchicus@dbn001dsk:~/lenguaje/c++$ ./array03
elArreglo[ 0 ][ 0 ]: 0
elArreglo[ 0 ][ 1 ]: 0
elArreglo[ 1 ][ 0 ]: 1
elArreglo[ 1 ][ 1 ]: 2
elArreglo[ 2 ][ 0 ]: 2
elArreglo[ 2 ][ 1 ]: 4
elArreglo[ 3 ][ 0 ]: 3
elArreglo[ 3 ][ 1 ]: 6
elArreglo[ 4 ][ 0 ]: 4
elArreglo[ 4 ][ 1 ]: 8
tinchicus@dbn001dsk:~/lenguaje/c++$
Anuncios

El resultado final son como unas coordenadas para usar tranquilamente en algun programa o juego, tipo damas o ajedrez, en realidad es un ejemplo bastante simple pero asi y todo tiene su alto nivel de complejidad. En este caso se toma como referencia el ultimo subindice para indicar la cantidad de datos a separar hasta volverlo a asignar al siguiente subindice, el uso de arrays como lo vimos hasta ahora es utilizado en la pila pero como sabemos esta es limitada, para evitar inconvenientes con la misma se debe trabajar con apuntadores, para crear los objetos en el heap y luego utiizarlos a traves de los mismos, del ejemplo utilizado para el array de objetos vamos a modificarlo para ser utilizado con apuntadores, veamos como se debe modificar el codigo:

array02.cpp

# include <iostream>

using namespace std;

class Gato
{
public:
        Gato(){ suEdad=1; suPeso=5; }
        ~Gato(){}
        int ObtenerEdad() const { return suEdad; }
        int ObtenerPeso() const { return suPeso; }
        void AsignarEdad(int edad) { suEdad = edad; }
private:
        int suEdad;
        int suPeso;
};

int main()
{
        Gato * Familia[ 500 ];
        int i;
	Gato * apGato;
        for(i = 0; i < 500; i++ )
        {
                apGato = new Gato;
		apGato -> AsignarEdad(2*i+1);
		Familia[i] = apGato;
        }
        for(i=0; i < 500; i++)
        {
                cout << "Gato #" << i << ": ";
                cout << Familia[ i ]->ObtenerEdad() << endl;
        }
        return 0;
}
Anuncios

En esta ocasion cambiamos el objeto camada por Familia, y en este caso creamos un array para quinientos elementos, luego creamos un apuntador (apGato), despues tenemos un for para crear los objetos en el heap y por ultimo le asignamos un valor con AsignarEdad, una vez terminado el ciclo, pasamos a otro ciclo donde obtendremos todos los valores almacenados, la salida es asi

Anuncios

En esta imagen podemos ver los 500 elementos cargados en el array y creados en el heap, cada uno con los valores asignados. En realidad vamos a tener todo lo que vayamos asignando con el metodo. En este ejemplo vamos a tener el Array Familia y todos sus apuntadores en la pila pero los quinientos objetos creados de tipo Gato quedan en el heap. Nosotros del caso anterior podriamos haber creado el array en el heap, esto se podria haber hecho con este ejemplo:

Gato * Familia = new Gato[ 500 ];
Anuncios

En este caso el tipo Gato va a tener un apuntador llamado Familia, y vamos a crear un aparcamiento de tipo Gato como un array de 500 objetos, en este caso en realidad el apuntador apGato apunta a Familia[0] y lo positivo es poder utilizar los operadores arimeticos para apuntadores, veamos este breve ejemplo:

Gato * Familia = new Gato[ 500 ];
Gato * apGato = Familia;        // apDato apunta a Familia[0]
apGato -> AsignarEdad(10);  // asignar el valor 10 a Familia[0]
apGato++;                                  // apDato avanza a Familia[1]
apGato -> AsignarEdad(20);  // asignar el valor 20 a Familia[1]
Anuncios

Como se ve asignamos el apuntador apGato a Familia y como dice el comentario vamos a tener Familia[0], despues le asignamos el valor 10 con el metodo AsignarEdad, luego utilizamos el operador arimetico ++ con el apuntador apGato para avanzar al siguiente elemento, es decir Familia[1] y por ultimo le asignamos a el valor 20 con AsignarEdad pero como lo movilizamos con el operador anterior se va a asignar al nuevo elemento y asi lo podemos hacer con el resto de los elementos. Como vimos hasta ahora, hay distintas formas de crear los apuntadores con los arrays, vamos a ver estos tres ejemplos:

Gato FamiliaUno[ 500 ];
Gato * FamiliaDos[ 500 ];
Gato * FamiliaTres = new Gato[ 500 ];
Anuncios

En FamiliaUno creamos un array de 500 elementos de tipo Gato, FamiliaDos es un array de 500 apuntadores a objetos tipo Gato y FamiliaTres es un apuntador a un array de 500 objetos de tipo Gato. La primera y tercer linea son basicamente lo mismo pero las diferencias mas importantes son que uno esta en la pila (FamiliaUno) y el otro en el Heap (FamiliaTres), el primero va a ser un array, el otro un apuntador, el tercer tiene la direccion de memoria del primer registro del array. Otra forma valida de obtener el acceso a un valor de array, es Familia + 4 lo cual es equivalente a decir a Familia[ 4 ], esto es debido a que en realidad un array es un apuntador a la direccion de memoria del primer elemento del array y el compilador sabra como interpretarlo. Como se libera la memoria del array creado? esto se hace con delete, veamos a traves de un ejemplo con algunas variaciones del caso anterior:

array04.cpp

# include <iostream>

using namespace std;

class Gato
{
public:
        Gato(){ suEdad=1; suPeso=5; }
        ~Gato(){ cout << "El destructor de Gato..." << endl; }
        int ObtenerEdad() const { return suEdad; }
        int ObtenerPeso() const { return suPeso; }
        void AsignarEdad(int edad) { suEdad = edad; }
private:
        int suEdad;
        int suPeso;
};

int main()
{
	Gato * Familia = new Gato[ 15 ];
	int i;
	for(i = 0; i < 15; i++)
	{
		Familia[i].AsignarEdad(2*i+1);
	}
	for(i = 0; i < 15; i++)
	{
		cout << "Gato #" << i << ":";
		cout << Familia[i].ObtenerEdad() << endl;
	}
	delete[] Familia;
	return 0;
}
Anuncios

En este nuevo ejemplo, hemos modificado la forma de crear el array para el objeto Gato, en este caso creamos un apuntador llamado Familia y le asignamos un nuevo tipo de Gato y a su vez que sea un array de 15 elementos. Tambien modificamos el destructor para notificarnos cuando es utilizado, y por ultimo ahora agregamos la instancia delete [] familia la cual es la encargada de eliminar el array que creamos en el heap, compilemos y probemos el programa para obtener la siguiente salida:

tinchicus@dbn001dsk:~/lenguaje/c++$ ./array04
Gato #0:1
Gato #1:3
Gato #2:5
Gato #3:7
Gato #4:9
Gato #5:11
Gato #6:13
Gato #7:15
Gato #8:17
Gato #9:19
Gato #10:21
Gato #11:23
Gato #12:25
Gato #13:27
Gato #14:29
El destructor de Gato…
El destructor de Gato…
El destructor de Gato…
El destructor de Gato…
El destructor de Gato…
El destructor de Gato…
El destructor de Gato…
El destructor de Gato…
El destructor de Gato…
El destructor de Gato…
El destructor de Gato…
El destructor de Gato…
El destructor de Gato…
El destructor de Gato…
El destructor de Gato…
tinchicus@dbn001dsk:~/lenguaje/c++$

En este caso vemos cada uno de los elementos del array y como son destruidos una vez finalizado el programa.

Anuncios

En resumen, hoy hemos visto la primera parte de arrays, hemos visto como crearlos, para que se usan, como utilizarlos como mas de una dimension, como usar referencia y apuntadores para usarlos en memoria y una serie de ejemplos para ponerlos en practica, espero les haya sido util sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios

Tengo un Patreon donde podes acceder de manera exclusiva a material para este blog antes de ser publicado, sigue los pasos del link para saber como.

Tambien podes donar

Es para mantenimiento del sitio, gracias!

$1.00