Sie sind auf Seite 1von 60

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

CONTENIDO
1. FUNCIONES .............................................................................................................. 3 Funcin principal C visual............................................................................................... 3 Declaracin de una funcin. ........................................................................................... 6 Elementos que conforman una funcin .......................................................................... 6 Variables locales y globales ........................................................................................... 8 Argumentos .................................................................................................................... 9 Paso de parmetro por valor y por referencia............................................................... 11 Llamadas de funciones ................................................................................................ 14 Funciones de biblioteca C visual .................................................................................. 16 2. ARREGLOS.............................................................................................................. 24 Definicin del arreglo.................................................................................................... 25 Direccin de memoria .................................................................................................. 26 Arreglos unidimensionales ........................................................................................... 26 Arreglos bidimensionales ............................................................................................. 28 Arreglos Tridimensionales ............................................................................................ 29 Arreglos multidimensionales ......................................................................................... 29 Arreglo de caracteres ................................................................................................... 30 3. PUNTEROS.............................................................................................................. 34 Definicin de punteros. ................................................................................................. 34 Punteros a arrays. ........................................................................................................ 35 Puntero a cadenas. ...................................................................................................... 36 Puntero a estructuras ................................................................................................... 37 Puntero a puntero......................................................................................................... 38 4. ESTRUCTURA Y UNIONES ..................................................................................... 39 Definicin de estructura. ............................................................................................... 39 Miembros. .................................................................................................................... 39 Instancia....................................................................................................................... 39 Arrays de estructura. .................................................................................................... 40 Estructura anidada. ...................................................................................................... 41

M.C. JORGE ENRIQUE ESTRADA MUOZ

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

Paso de estructura a funciones. ................................................................................... 42 Enumeraciones. ........................................................................................................... 44 Que es una unin. ........................................................................................................ 48 Campo de bits. ............................................................................................................. 51 Typedef. ....................................................................................................................... 55

M.C. JORGE ENRIQUE ESTRADA MUOZ

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

1. FUNCIONES
Funcin principal C visual
Durante la fase de enlazado de la compilacin, el "linker" aade a cualquier programa C++ un mdulo especial, de inicio, que es realmente el punto de entrada a la ejecucin del programa. Este mdulo realiza diversas tareas preparatorias a la ejecucin propiamente dicha. Por ejemplo, iniciar todas las variables estticas o globales y realizar determinadas verificaciones del hardware. Finalmente pasa el control a una funcin que debe responder al nombre de main y le pasa algunos argumentos en base a datos que ha recibido a su vez del Sistema Operativo; esta es la razn por la que todos los programas C++ deben contener una funcin con este nombre. As pues, main representa el punto de la ejecucin a partir del cual el programador toma el control de la ejecucin, antes de esto ya han sucedido muchas cosas en el programa. A su vez el punto de finalizacin de esta funcin, su punto de retorno (return) significa el fin del programa, aunque tambin existe otra forma de terminar el programa, que puede ser utilizada desde cualquier punto (sin necesidad de volver a la funcin main), consiste en utilizar la funcin exit de la Librera estndar. Argumentos La funcin main es imprescindible en cualquier programa C/C++ representa el punto de inicio de su ejecucin. Por lo general, su declaracin adopta la forma: int main() Aunque en realidad, el mdulo de inicio la invoca con dos parmetros (recibidos a su vez del SO), denominados tradicionalmente argc y argv, contracciones de "argument count" y "argument vector" respectivamente. El primero es un entero que representa el nmero de comandos que se pasan; el segundo es un puntero a una matriz de cadenas literales de distintas longitudes (es decir: puntero a matriz de punteros); cada una de estas cadenas representa en ltimo extremo los comandos iniciales que se quieren pasar al programa, generalmente para controlar aspectos de su comportamiento. As pues, la declaracin ms genrica de main es del tipo: int main(int argc, char* argv[]) El estndar establece que el compilador debe aceptar para main cualquiera de las dos formas anteriores. Por convencin, argv[0] es el nombre con que se ha llamado al programa (normalmente ser el nombre del fichero ejecutable incluyendo su direccin completa -path-). Este dato es proporcionado automticamente por el SO; as pues, el valor mnimo para argc es 1. Despus seguirn los que introduzcamos en la lnea de comandos, separados por espacios. Como ejemplo, puede usarse el siguiente programa, al que llamaremos prueba.exe: #include <stdio.h> // Prueba de parmetros para funcin main int main(int argc, char* argv[]) { int i; printf("Se han pasado %3d argumentos:\n", argc); for(i=0; i<argc; i++) printf("%5d- %s\n", i, argv[i]); return 0; }

M.C. JORGE ENRIQUE ESTRADA MUOZ

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

Si introducimos en la lnea de comandos: prueba se pasan seis, parmetros, se obtiene la siguiente salida: Se han pasado 6 argumentos: 1- D:\ZF\LEARNC\PRUEBA.EXE 2- prueba 3- se 4- pasan 5- seis, 6- parmetros

Se ha dicho que argv es un puntero a matriz de punteros, y en el ejemplo hemos utilizado la expresin argv[i], algo que a primera vista puede chocar, ya que argv no es una matriz. En realidad la declaracin completa: char* argv[] significa puntero-a-matriz-de-caracteres, para distinguirlo de char* argv que sera simplemente puntero-a-carcter. Los argumentos anteriores son recogidos por el sistema en forma de sendas variables globales _argc y _argv definidas en la cabecera <dos.h>. A continuacin se expone una variacin del programa anterior que utiliza estas variables: #include <iostream> using namespace std; #include <dos.h> // necesario para _argc y argv int main (int argc, char* argv[]) { // ============== cout << "Se han pasado " << _argc << " argumentos:" << endl; for (int i = 0; i < _argc; ++i) cout << " " << i << "- " << _argv[i] << endl; return 0; }

La salida es la misma que en el caso anterior. Restricciones La funcin main adolece de ciertas limitaciones que la diferencian del resto de funciones C++: No puede ser invocada explcitamente a lo largo del programa, es invocada de forma automtica por el mdulo de inicio. No puede obtenerse su direccin, por lo tanto no pueden declararse punteros a ella: int (* pmain)() = &main; // Error!! No puede ser sobrecargada. No puede ser declarada como inline. main debe estar en el espacio global de una de las unidades de compilacin del programa, lo que significa que no puede pertenecer a una clase. Valor devuelto por main En muchos sistemas operativos el valor devuelto por la funcin main es utilizado como control de estado para el entorno desde el que se ha ejecutado el programa (este valor es considerado el estado de retorno del programa). En UNIX, MS-DOS y MS Windows, los 8 bits ms bajos del valor

M.C. JORGE ENRIQUE ESTRADA MUOZ

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

devuelto son pasados al programa invocante o al intrprete de comandos. Este "estado de retorno" se utiliza en ocasiones para cambiar el curso de un programa, un proceso por lotes o un guin para el ejecutor de comandos. Algunos compiladores pueden generar un aviso de error si se intenta compilar un programa cuya funcin main no devuelva un int. Por contra, algunas plataformas pueden provocar fallos cuando estos programas arrancan o a su terminacin, ya que esperan un int de retorno. En los programas C++ no es necesario devolver nada desde la funcin main, aunque en realidad la definicin de esta sea int main(). La razn es que el estndar garantiza que si main llega a su final alcanzando el corchete de cierre "}" sin haber encontrado una sentencia return, el compilador debe devolver automticamente un 0 indicando un final correcto, de forma que en ausencia de ningn retorno el compilador proporciona automticamente un return 0. Nota: no obstante lo anterior, el comportamiento concreto vara de un compilador a otro. Por ejemplo, un programa en el que se alcanza el corchete de cierre de la funcin main sin ninguna sentencia de retorno compila sin dificultad ni aviso de ningn tipo en Borland C++ 5.5, mientras que MS Visual C++ 6.0 avisa: warning C4508: 'main' : function should return a value; 'void' return type assumed. En cualquier caso, es prctica de buena programacin incluir un valor de retorno para la funcin main. Tradicionalmente 0 significa una terminacin correcta del programa, cualquier otro valor es seal de terminacin anormal (error o excepcin). Si el programa termina por una invocacin a la funcin exit, el valor devuelto por main es el argumento pasado a exit. Por ejemplo, si el programa contiene la llamada exit(1), el valor devuelto es 1. Existen solamente tres valores completamente estndar y portables que puedan utilizarse como retorno para la funcin main o como argumento para la funcin exit: El clsico entero de valor 0. La constante simblica EXIT_SUCCESS definida en <stdlib.h> La constante EXIT_FAILURE definida en <stdlib.h> Si se utiliza cualquiera de los dos valores 0 o EXIT_SUCCESS se garantiza que el compilador los trasladar a un cdigo que sea considerado terminacin correcta por el Sistema Operativo. Si se utiliza EXIT_FAILURE el compilador lo trasladar a un cdigo que ser considerado como terminacin errnea por el Sistema Operativo. Algunos sistemas, como Unix, MS-DOS y Windows, truncan el entero pasado a exit o devuelto por main, a un unsigned char, con objeto de utilizarlos en el archivo de rdenes del intrprete de comandos, en un archivo de ejecucin por lotes, o en el proceso que invoc el programa. Algunos programadores utilizan valores positivos para indicar diferentes razones de fallo, excepcin o finalizacin del programa, pero estos usos no son necesariamente portables ni funcionan en todas las implementaciones. Sin embargo C++ proporciona la posibilidad de devolver valores que son totalmente portables mediante la funcin atexit.

M.C. JORGE ENRIQUE ESTRADA MUOZ

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

Declaracin de una funcin.


Al igual que turbo C++, las funciones se declaran en la cabecera, si devuelven algo son int, float o char segn lo que devuelvan, si no devuelven nada son de tipo void. Si se pasan valores, tambin va declarado: int suma(int sum1, int sum2); lo mismo si son caracteres u otro tipo de valores. Una vez declarada la funcin, se desarrolla despus del cdigo: int suma(int sum1, int sum2) { /*En este espacio va todo el procedimiento de la funcin, en este caso se coloca en el mismo return, ya que es una simple suma*/ return(sum1 + sum2); }

Para llamarlo desde el main, void main() { int a=12, b=15; printf("%d", (suma(a, b))); }

Al invocar la funcin devuelve un entero, suma de los dos valores que se le paso. No es necesario que la funcin devuelva un valor, ni que se tenga que pasar parmetros, si se usan variables declaradas en la cabecera (globales) puede tomar los valores cargados en ellas y cargar los resultados del procedimiento en otras.

Elementos que conforman una funcin


Una funcin es un modulo de un programa separado del cuerpo principal, que realiza una tarea especfica y que puede regresar un valor a la parte principal del programa u otra funcin o procedimiento que la invoque. La forma general de una funcin es: Tipodato Nomfun(parametros) { cuerpo de instrucciones; return [dato,var,expresion]; }

Donde tipodato especifica el tipo de dato que regresara la funcin. La instruccin RETURN es quien regresa uno y solo un dato a la parte del programa que le esta invocando, sin embargo es de considerar que return puede regresar un dato, una variable o una expresin algebraica (no ecuacin o frmula) como lo muestran los siguientes ejemplos;

M.C. JORGE ENRIQUE ESTRADA MUOZ

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

return 3.1416; return area; return x+15/2; La lista de parmetros formales es una lista de variables separadas por comas (,) que almacenaran los valores que reciba la funcin, estas variables actan como locales dentro del cuerpo de la funcin. Aunque no se ocupen parmetros los parntesis son requeridos. Instruccin return Dentro del cuerpo de la funcin deber haber una instruccin return cuando menos para regresar el valor, esta instruccin permite regresar datos. Recordar adems que cuando se llame una funcin deber haber una variable que reciba el valor que regresara la funcin, es decir generalmente se llama una funcin mediante una sentencia de asignacin, por ejemplo resultado=funcion(5, 3.1416); #using <mscorlib.dll> #using <System.dll> #using <lcnet.dll> using namespace System; //declarando funcion double triangulo(int base1, int altura); void main(){ //declarando y capturando int base1, altura; double area; // capturando,cargando y convirtiendo //los datos de la forma a las variables base1 = Int32::Parse(lcnet::getparametro("BASE1")); altura = Int32::Parse(lcnet::getparametro("ALTURA")); // ahora se llama a la funcion // esto debe ser por igualdad area=triangulo(base1,altura); //construyendo y desplegando la pagina de salida Console::WriteLine("Content-Type:text/html\n"); Console::WriteLine(String::Concat(S"area=",area.ToString("#.##")) ); }; // fin main // construyendo funcion double triangulo(int base1, int altura){ return base1 * altura / 2.0; }; Corrida prog16.html {{:visual_cpp:Image307.jpg}} corrida prog16.cpp {{:visual_cpp:Image308.jpg}}

M.C. JORGE ENRIQUE ESTRADA MUOZ

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

Usar de preferencia solo ints y doubles como parmetros. Es permitido poner ms de un return en el cuerpo de instrucciones sobre todo en condiciones, pero solo un return se ejecutara, ejemplo; if (suma >= 10) { return 10; } else { return 20; }

Existen 3 clases de funciones, las primeras son de tipo computacional que son diseadas para realizar operaciones con los argumentos y regresar un valor basado en el resultado de esa operacin, las segundas funciones son aquellas que manipulan informacin y regresan un valor que indican la terminacin o la falla de esa manipulacin y finalmente, las terceras son aquellas que no regresan ningn valor, es decir son estrictamente procedurales. Lo anterior significa que en general, toda operacin o clculo en un programa debe convertirse en una o varias funciones y el resto deben ser procedimientos.

Variables locales y globales


El lugar donde sea declarada una variable afectara el uso que el programa haga de esa variable. Las reglas bsicas que determinan como una variable puede ser usada dependen de 3 lugares donde se puede declarar una variable. 1. Dentro de cualquier funcin o procedimiento, a estas se les llama variables locales y solo pueden ser usadas por instrucciones que estn dentro de esa funcin o procedimiento. 2. Como parmetro de una funcin, donde despus de haber recibido el valor podr actuar como variable local en esa funcin o procedimiento. En esencia una variable local solo es conocida por el cdigo de esa funcin o procedimiento y es desconocida por otras funciones o procedimientos. 3. Fuera de los procedimiento o funciones, a este tipo de variables se les llama variables globales y podrn ser usadas por cualquier funcin o procedimiento del programa, sin embargo hay que agregarle la palabra reservada STATIC y a partir del momento en que se declara, se considera y puede usarse como variable global. No se acostumbra a usar muchas variables globales por varias razones, una de ellas es que las variables globales estn vivas todo el tiempo de ejecucin del programa y si una variable global solo es ocupada por unos cuantos procedimientos no tiene caso que este viva para todo el resto del programa. Otra razn es lo peligroso de tener variables globales porque todo el conjunto de procedimiento y funciones que componen un programa tienen acceso o comparten su valor y se corre el riesgo de que inadvertidamente alguno de ellos modifique su valor. #using <mscorlib.dll> #using <System.dll> #using <lcnet.dll> using namespace System; //declarando procedimientos void proc1(); void proc2(double area);

M.C. JORGE ENRIQUE ESTRADA MUOZ

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

//declarando variables globales static int base1, altura; void main(){ //llamando o activando proc1 proc1(); }; // main lleva ahora ; void proc1(){ //declarando variables double area; // capturando, cargando y convirtiendo //los datos de la forma a las variables base1=Int32::Parse(lcnet::getparametro("BASE1")); altura=Int32::Parse(lcnet::getparametro("ALTURA")); // operaciones area=base1*altura/2.0; //llamando proc2 y pasando un solo parmetro proc2(area); }; //fin proc1 void proc2(double area){ //construyendo y desplegando la pagina de salida Console::WriteLine("Content-Type:text/html\n"); Console::WriteLine(String::Concat(S"base = ",base1.ToString()) ); Console::WriteLine("<br>"); Console::WriteLine(String::Concat(S"altura = ",altura.ToString()) ); Console::WriteLine("<br>"); Console::WriteLine(String::Concat(S"area= ",area.ToString("0.00")) ); }; // fin proc2

Argumentos
Un parmetro es una variable que puede pasar su valor a un procedimiento desde el principal o desde otro procedimiento. Existen ocasiones en que es necesario mandar al procedimiento ciertos valores para que los use en algn proceso, estos valores que se pasan del cuerpo principal del programa o de un procedimiento a otros procedimientos se llaman parmetros o argumentos. Entonces la declaracin completa de un procedimiento es: [Static] Void Nom_Proc(lista de parametros) { cuerpo de instrucciones;}; Donde lista de parmetros es una o ms variables separadas por coma, como se muestra en el programa ejemplo. #using <mscorlib.dll> #using <System.dll> #using <lcnet.dll>

M.C. JORGE ENRIQUE ESTRADA MUOZ

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

using namespace System; void proc1(String *nom, int suma); void main(){ //llamando o activando procedimiento // y pasando dos parametros proc1("juan", 3+4); }; // main lleva ahora ; void proc1(String *nom, int suma) { //declarando variables int edad; // capturando,cargando y convirtiendo //los datos de la forma a las variables edad=Int32::Parse(lcnet::getparametro("EDAD")); // operaciones sumando parametro edad=edad+suma; //construyendo y desplegando la pagina de salida Console::WriteLine("Content-Type:text/html\n"); Console::WriteLine(String::Concat(nom, edad.ToString()) ); }; // fin proc

No olvidar declarar el procedimiento antes del main(), incluyendo sus parmetros como lo muestra el ejemplo, recordar tambin que se pueden mandar como parmetros, datos, variables y expresiones algebraicas (no frmulas o ecuaciones algebraicas). Observar que en el procedimiento los parmetros son dos variables de locales es decir variables que solo pueden usar dentro del procedimiento estas variables son quienes reciben los datos o valores. Reglas para el uso de parmetros. 1. Cuando se usan variables como parmetros, la variable que se manda debe ser declarada dentro del principal o del procedimiento de donde se est enviando. 2. La variable que se manda tiene un nombre, la que recibe puede tener otro nombre o el mismo nombre por claridad de programa, pero recordar que internamente en la memoria del computador existirn dos variables diferentes. 3. La cantidad de variables que se envan debe ser igual en cantidad, orden y tipo a las variables que se reciben. 4. La variable que se recibe tiene un mbito local dentro del procedimiento, es decir solo la puede usar ese procedimiento. 5. Se puede mandar a un procedimiento un dato, una variable o una expresin algebraica (no ecuacin o frmula), pero siempre se debern recibir en una variable.

M.C. JORGE ENRIQUE ESTRADA MUOZ

10

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

Paso de parmetro por valor y por referencia


La forma en que usualmente se declaran y pasan los parmetros de las funciones es la que normalmente se conoce como "por valor". Esto quiere decir que cuando el control pasa a la funcin, los valores de los parmetros en la llamada se copian a "objetos" locales de la funcin, estos "objetos" son de hecho los propios parmetros, ejemplo: #include <iostream> using namespace std; int funcion(int n, int m); int main() { int a, b; a=10; b=20; cout << "a,b ->" << a << ", " << b << endl; cout << "funcion(a,b) ->" << funcion(a, b) << endl; cout << "a,b ->" << a << ", " << b << endl; cout << "funcion(10,20) ->" << funcion(10, 20) << endl; return 0; } int funcion(int n, int m) { n=n+2; m=m-5; return n+m; }

Empezamos haciendo a=10 y b=20, despus llamamos a la funcin "funcion" con las objetos a y b como parmetros. Dentro de "funcion" esos parmetros se llaman n y m, y sus valores son modificados. Sin embargo al retornar a main, a y b conservan sus valores originales. Por qu? La respuesta es que lo que pasamos no son los objetos a y b, sino que copiamos sus valores a los objetos n y m. Piensa, por ejemplo, en lo que pasa cuando llamamos a la funcin con parmetros constantes, es lo que pasa en la segunda llamada a "funcion". Los valores de los parmetros no pueden cambiar al retornar de "funcion", ya que esos valores son constantes. Si los parmetros por valor no funcionasen as, no sera posible llamar a una funcin con valores constantes o literales. Referencias a objetos Las referencias sirven para definir "alias" o nombres alternativos para un mismo objeto. Para ello se usa el operador de referencia (&). Sintaxis:

M.C. JORGE ENRIQUE ESTRADA MUOZ

11

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

<tipo> &<alias>=<objeto de referencia> <tipo> &<alias> La primera forma es la que se usa para declarar objetos que son referencias, la asignacin es obligatoria ya que no pueden definirse referencias indeterminadas. La segunda forma es la que se usa para definir parmetros por referencia en funciones, en estos casos, las asignaciones son implcitas. Ejemplo: #include <iostream> using namespace std; int main() { int a; int &r=a; a=10; cout << r << endl; return 0; }

En este ejemplo los identificadores a y r se refieren al mismo objeto, cualquier cambio en una de ellos se produce en el otro, ya que son, de hecho, el mismo objeto. El compilador mantiene una tabla en la que se hace corresponder una direccin de memoria para cada identificador de objeto. A cada nuevo objeto declarado se le reserva un espacio de memoria y se almacena su direccin. En el caso de las referencias, se omite ese paso, y se asigna la direccin de otro objeto que ya exista previamente. De ese modo, podemos tener varios identificadores que hacen referencia al mismo objeto, pero sin usar punteros. Pasando parmetros por referencia Si queremos que los cambios realizados en los parmetros dentro de la funcin se conserven al retornar de la llamada, deberemos pasarlos por referencia. Esto se hace declarando los parmetros de la funcin como referencias a objetos. Por ejemplo: #include <iostream> using namespace std; int funcion(int &n, int &m); int main() { int a, b; a=10; b=20; cout << "a,b ->" << a << ", " << b << endl; cout << "funcion(a,b) ->" << funcion(a, b) << endl;

M.C. JORGE ENRIQUE ESTRADA MUOZ

12

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

cout << "a,b ->" << a << ", " << b << endl; /* cout << "funcion(10,20) ->" << funcion(10, 20) << endl; // (1) es ilegal pasar constantes como parmetros cuando estos son referencias */ return 0; } int funcion(int &n, int &m) { n = n + 2; m = m - 5; return n+m; }

En este caso, los objetos "a" y "b" tendrn valores distintos despus de llamar a la funcin. Cualquier cambio de valor que realicemos en los parmetros dentro de la funcin, se har tambin en los objetos referenciados. Esto quiere decir que no podremos llamar a la funcin con parmetros constantes, como se indica en (1), ya que aunque es posible definir referencias a constantes, en este ejemplo, la funcin tiene como parmetros referencias a objetos variables. Y si bien es posible hacer un casting implcito de un objeto variable a uno constante, no es posible hacerlo en el sentido inverso. Un objeto constante no puede tratarse como objeto variable. En C#, los argumentos tambin se pueden pasar a parmetros por valor o por referencia. El paso de parmetros por referencia permite a los miembros de funciones, mtodos, propiedades, indizadores, operadores y constructores cambiar el valor de los parmetros y hacer que ese cambio persista en el entorno que procede de la llamada. Para pasar un parmetro por referencia, utilice una de las palabras clave ref u out. En los ejemplos de este tema, para simplificar, slo se utiliza la palabra clave ref. class Program { static void Main(string[] args) { int arg; // Pase por valor. // El valor de arg en Main no se cambia. arg=4; squareVal(arg); Console.WriteLine(arg); // Output: 4 // Pase por referencia. // El valor de arg en Main se cambia. arg=4; squareRef(ref arg); Console.WriteLine(arg); // Output: 16 }

M.C. JORGE ENRIQUE ESTRADA MUOZ

13

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

static void squareVal(int valParameter) { valParameter *= valParameter; } // Pase por referencia static void squareRef(ref int refParameter) { refParameter *= refParameter; } }

Llamadas de funciones
El compilador de Visual C/C++ provee varias convenciones diferentes para llamadas de funciones internas y externas. La comprensin de estos distintos enfoques nos puede ayudar a depurar los programas y a enlazar nuestro cdigo con las rutinas en lenguaje ensamblador. Existen diferencias entre las convenciones de las llamadas, como se pasan los argumentos y como son devueltos los valores por las funciones. Convenciones del pase de argumentos y nomenclatura. Cuando se pasan, todos los argumentos se amplan a 32 bits. Los valores devueltos son tambin ampliados a 32 bits y se retornan en el registro EAX, excepto por las estructuras de 8 bytes, las cuales son devueltas en el par de registros EDX:EAX. Las estructuras ms grandes se devuelven en el registro EAX como punteros a estructuras de retorno ocultas. Los parmetros se insertan en la pila, de derecha a izquierda. Las estructuras que no son PODs, no sern devueltas en los registros. El compilador genera un cdigo prlogo y eplogo para guardar y restaurar los registros ESI, EDI, EBX y EBP, si son utilizados en la funcin. Cuando una estructura, unin o clase es devuelta de una funcin por valor, todas las definiciones de tipo necesitan ser iguales, de otra manera, el programa puede fallar durante su ejecucin. Las siguientes concenciones de llamadas estn admitidas por el compilador de Visual C/C++.
Palabra clave __cdecl _clrcall _stdcall _fastcall _thiscall Limpieza de pila Remitente n/d Destinatario Destinatario Destinatario Pase de parmetros Inserta los parmetros en la pila, en orden inverso (derecha a izquierda) Carga los parmetros en la pila de expresiones CLR en orden (izquierda a derecha) Inserta los parmetros en la pila, en orden inverso (derecha a izquierda) Almacenado en registros, entonces se inserta en la pila Insertado en la pila, puntero this almacenado en ECX

Ejemplo de llamada El siguiente ejemplo muestra los resultados de hacer una llamada a funcin usando varias convenciones de llamadas. El ejemplo est basado en la siguiente estructura de funcin. Reemplazar calltype con la convencin adecuada de llamada.

M.C. JORGE ENRIQUE ESTRADA MUOZ

14

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

void calltype MyFunc( char c, short s, int i, double f ); . . . void MyFunc( char c, short s, int i, double f ) { . . . } . . . MyFunc ('x', 12, 8192, 2.7183);

Convencin de la llamada _cdecl

Convenciones de las llamadas _stdcall y thiscall

Convencin de la llamada _fastcall

Usando llamadas a funciones naked para escribir cdigo de prlogo y eplogo personalizado.

M.C. JORGE ENRIQUE ESTRADA MUOZ

15

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

Las funciones declaradas con el atributo naked son emitidas sin cdigo de prlogo o eplogo, permitiendo escribir nuestra propia secuencia de prlogo/eplogo usando lneas en ensamblador. Las funciones naked se proveen como una caracterstica avanzada. Ello nos permite declarar una funcin que est siendo llamada desde un contexto distinto a C/C++, y de esta manera hacer distintas suposiciones acerca de donde estn los parmetros o cuales registros se conservan. Los ejemplos incluyen las rutinas tales como controladores de interrupcin. Esta caracterstica es particularmente til para los desarrolladores de drivers de dispositivos virtuales (VxDs). Coprocesador de punto flotante y convenciones de llamada. Si se escribe rutinas de ensamblado para el coprocesador de punto flotante, se debe conservar la palabra control del punto flotante y limpiar la pila del coprocesador a menos que se est regresando un valor float o double (por lo cual la funcin debe retornar ST(0)). Convenciones de llamadas obsoletas. Las convenciones de llamadas de _pascal, _fortran y _syscall ya no son soportadas. Se puede emular su funcionalidad usando una de las convenciones de llamadas admitidas y las opciones de vinculacin apropiadas. WINDOWS.H ahora soporta la macro WINAPI, la cual traduce a la convencin de llamada apropiada por el destino. Usar WINAPI donde previamente se usaba PASCAL o _pascal _far.

Funciones de biblioteca C visual


Librera estndar. C++ no llega al nivel de simplicidad de su antecesor C, pero al igual que aqul, tampoco dispone de utilidades o funciones para entrada o salida implementadas en el propio lenguaje, de modo que estas y otras muchas, como manejo de cadenas de caracteres (strings), manejo de ficheros, funciones matemticas, y ms son implementadas en forma de libreras externas. Una librera es un conjunto de recursos (algoritmos) prefabricados, que pueden ser utilizados por el programador para realizar determinadas operaciones. Las declaraciones de las funciones (prototipos) utilizadas en estas libreras, junto con algunas macros y constantes predefinidas que facilitan su utilizacin, se agrupan en ficheros de nombres conocidos que suelen encontrarse en sitios predefinidos. Por ejemplo, en los sistemas UNIX, en /usr/include. Estos ficheros se suelen llamar "de cabecera", porque es tradicin utilizar las primeras lneas del programa para poner las directivas #include que los incluir en el fuente durante la fase de preprocesado. Clases de libreras Los compiladores C++ incluyen un amplio repertorio de clases, funciones y macros que permiten realizar una amplia variedad de tareas, incluyendo entradas/salidas de bajo y alto nivel; manipulacin de cadenas alfanumricas y ficheros; control de procesos (incluyendo multiproceso); manejo de memoria; clculos matemticos y ms. Este repertorio de recursos es denominado colectivamente como "librera de rutinas", "libreras de ejecucin" RTL ("Runtime Librarys") o simplemente "Libreras". Puede decirse que el lenguaje aislado (tal cual) no tiene prcticamente ninguna utilidad sin la concurrencia de estas utilidades. El Estndar C++ las clasifica segn su utilidad:

M.C. JORGE ENRIQUE ESTRADA MUOZ

16

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

Soporte del lenguaje Diagnstico Utilidades generales Cadenas alfanumricas ("Strings") Localizacin Contenedores Iteradores Algoritmos Clculo numrico Entrada/Salida Librera Estndar C++ Para poner un poco de orden, el estndar C++ define la denominada librera estndar que debe acompaar a cada implementacin del compilador que se adhiera al estndar. Es decir: la norma determina cuales son, como se llaman y como se utiliza este conjunto de algoritmos que deben acompaar (como mnimo) a cada implementacin del compilador que quiera llamarse "Estndar". La ltima versin, ISO/IEC 14882 del ao 1998, especifica que se compone de 32 ficheros de cabecera de nombres fijos y conocidos agrupados segn la funcionalidad de los algoritmos. Son los siguientes:

Ficheros <algorithm> <bitset> <complex> <deque> <exception> <fstream> <functional> <iomanip> <ios> <iosfwd> <iostream> <istream> <iterator> <limits> <list> <locale> <map> <memory> <new> <numeric> <ostream> <queue> <set> <sstream> <stack> <stdexcept>

<streambuf>

Funcionalidad/funciones Parte de la STL que describe los algoritmos Parte de la STL relativa a contenedores tipo bitset . Set de valores booleanos Parte de la librera numrica de la STL relativa a los complejos Parte de la STL relativa a contenedores tipo deque; un tipo de colas: "Double-ended-queue" Parte de la librera de diagnstico relativa al manejo de excepciones Flujos hacia/desde ficheros Parte de la STL relativa a Objetos-funcin Manipuladores Supreclases para manejo de flujos de E/S Contiene declaraciones adelantadas de todas las plantillas de flujos y sus typedefs estndar Parte del a STL que contiene los algoritmos estndar de E/S Algoritmos estndar de flujos de entrada Parte de la STL relacionada con iteradores, un tipo de puntero que permite utilizar los algoritmos de la librera con las estructuras de datos representadas por los contenedores. Descripcin de propiedades dependientes de la implementacin que afectan a los tipos fundamentales Parte de la STL relativa a contenedores tipo list; listas doblemente enlazadas Parte de la STL relativa a la internacionalizacin Parte de la STL relativa a contenedores tipo map Utilidades relativas a la gestin de memoria, incluyendo asignadores y punteros inteligentes (auto_ptr) Manejo de memoria dinmica Parte de la librera numrica de la STL relativa a operaciones numricas Algoritmos estndar para los flujos de salida Parte de la STL relativa a contenedores tipo queue; colas de objetos Parte de la STL relativa a contenedores tipo set Flujos hacia/desde cadenas alfanumricas. Parte de la STL relativa a contenedores tipo stack; pilas de objetos Parte de la STL relativa a las clases de las que derivan los objetos lanzados por las excepciones ocasionadas en los algoritmos de la propia STL y otras expresiones. Estas clases son utilizadas para reportar errores detectados durante la ejecucin. Los usuarios tambin pueden utilizar excepciones para reportar errores en sus propios programas Parte de la STL relativa al almacenamiento de flujos de E/S ("Stream buffers"). Define los tipos que

M.C. JORGE ENRIQUE ESTRADA MUOZ

17

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

<string> <typeinfo> <utility> <valarray> <vector>

controlan la capa de transporte Parte de la STL relativa a contenedores tipo string; una generalizacin de las cadenas alfanumricas para albergar cadenas de objetos Mecanismo de identificacin de tipos en tiempo de ejecucin Parte de la STL que contiene elementos auxiliares como operadores y pares (pairs). Parte de la librera numrica de la STL relativa a manejo de matrices numricas () Parte de la STL relativa a los contenedores tipo vector; una generalizacin de las matrices unidimensionales C/C++

Es digno de mencin que aunque generalmente las libreras no aportan ninguna caracterstica al lenguaje (se supone que son utilidades auxiliares que no forman parte del lenguaje propiamente dicho), una pequea porcin de la librera estndar C++ s aporta caractersticas que se consideran pertenecientes a este, de forma que deben estar presentes los archivos de cabecera correspondientes si se desea usarlas. En concreto se refieren a los siguientes elementos: Operadores new, new[], delete y delete[] Clase type_info que corresponde al mecanismo RTTI de identificacin de tipos en tiempo de ejecucin representado por el operador typeid Rutinas de inicio y terminacin Las excepciones estndar lanzadas por los algoritmos anteriores Librera C Adems de otras nuevas, cuyo diseo e importancia cambian drsticamente la filosofa del lenguaje, C++ incluye prcticamente la totalidad de funciones de la primitiva librera estndar C. A esta librera, mantenida por compatibilidad, se le denomina librera clsica. Componentes Al referirnos a las libreras C++ utilizamos la terminologa siguiente: RTL Conjunto de libreras que acompaan a un compilador ("Runtime Library"), sean o no estndar. Librera Estndar. Conjunto de libreras cuyo contenido est definido por el Estndar C++ (abreviadamente LE) Libera clsica. Parte de la Librera Estndar correspondiente al C clsico. STL ("Standard Templete Library"). Parte de la LE genuina de C++ (que no es heredada de C) y que responde a la forma "++" de hacer las cosas. La calidad de un compilador C++ viene determinada en gran medida por la calidad y cantidad de su RTL; por su grado de adherencia al Estndar y por el grado de soporte que proporciona para la plataforma concreta a que se destina. En lo que concierne a la programacin para MS Windows (las referencias a la plataforma Wintel surgen de forma constante e inevitable), los compiladores Borland C++ y MS Visual C++ son quizs los ms conocidos y utilizados. El primero incluye una completa librera denominada VCL (Visual Component Library). La del segundo es conocida como MFC (Microsoft Foundation Classes). Linux dispone de su propio compilador: GNU Cpp, que comenz siendo un compilador C y ha evolucionado a un producto que es en realidad un superconjunto de compiladores. No solo puede

M.C. JORGE ENRIQUE ESTRADA MUOZ

18

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

compilar cdigo C y C++; tambin otros lenguajes como Ada o Fortran; de forma que es comn referirse a ellos como GCC ("GNU Compiler Collection"). La buena noticia es que existen versiones de este compilador para plataformas Windows, de forma que incluso en este ambiente "Propietario" pueden realizarse desarrollos utilizando herramientas "Open source". A grandes rasgos, la librera estndar C++ comprende los siguientes mdulos: La denominada Librera Estndar de Plantillas, abreviadamente STL ("Standard Templete Library"). o Librera numrica. Parte de la STL que contiene algoritmos especialmente concebidos para computacin numrica. Por ejemplo, una clase valarray optimizada para matrices numricas y una clase complex para manejo y representacin estandarizada de nmeros complejos (en realidad una plantilla con especializaciones para los tipos float, double y long double). o Utilidades. Parte de la STL dedicada a elementos auxiliares tales como adaptadores y la clase auto_ptr. Unas utilidades de entrada/salida de flujos, denominadas genricamente iostreams. Una utilidad locale para manejo de localismos. Una clase string para manejo estandarizado de cadenas de caracteres. En realidad es una instanciacin (especializacin) de la plantilla basic_string para cadenas de caracteres. Un esquema para describir de modo uniforme el entorno de ejecucin mediante la utilizacin de una clase estndar denominada numeric_limits y especializacin para cada uno de los tipos de datos fundamentales. Utilidades para manejo de memoria. Soporte para utilizacin de juegos de caracteres y signos de diversos idiomas. Utilidades de diagnstico y manejo de errores. Incluyen manejo de excepciones y la macro assert. Funcionalidad Si atendemos a su funcionalidad, agruparse en: las utilidades ofrecidas por la Librera Estndar pueden

Clasificacin: Clasifican caracteres ASCII, como letras, caracteres de control (no imprimibles), Maysculas/minsculas etc. Se definen en la cabecera <ctype.h>. Entradas/Salidas de Consola: Estas son las denominadas entrada/salida estndar. Por defecto se refieren al teclado y a la pantalla (no pueden utilizarse directamente en aplicaciones de interfaz grfica). Conversin: Convierten caracteres y cadenas de caracteres desde formato alfabtico a numrico de diversos tipos (float, int, long). Tambin realizan la conversin inversa: de formatos numricos a representaciones alfabticas y de maysculas a minsculas y viceversa. Diagnstico: Son rutinas destinadas a comprobaciones; a descubrir y corregir posibles errores. Directorio: Rutinas para manejo de directorios y sus direcciones (path names). En linea (Inline): Rutinas para versiones inline de funciones. El compilador genera el cdigo correspondiente para las versiones inline cuando se utiliza #pragma intrinsic o si se solicita optimizacin al compilador (optimizacin de tiempo de ejecucin).

M.C. JORGE ENRIQUE ESTRADA MUOZ

19

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

Entrada/Salida. Son rutinas que proporcionan manejo de flujos y operaciones de Entrada/Salida a bajo nivel (de Sistema Operativo). Manipulacin. Manejo de cadenas y bloques de memoria: copiar, comparar, convertir y buscar. Matemticas: Para realizar clculos matemticos. De Memoria: Proporcionan asignacin de memoria dinmica. Miscelnea. Se agrupan aqu rutinas varias, como las que posibilitan saltos (goto) no locales y las que manejan diferencias de tipo cultural o de lenguaje. Por ejemplo representacin de nmeros, de moneda, formatos de fecha y hora, clasificacin de tipo alfabtico, etc. Control de proceso. Rutinas que permiten invocar y terminar nuevos procesos desde otra rutina. Fecha y hora. Incluyen rutinas para conversin y manipulacin de variables de medida del tiempo (fecha y hora). Argumentos variables. Rutinas utilizadas cuando se usan listas variables de argumentos, como en los casos de printf(), vscanf(), etc. Utilizacin La utilizacin de la Librera Estndar C++ requiere de dos tipos de condiciones que podramos describir como formales y conceptuales. En cuanto a las primeras (condiciones formales) y habida cuenta que las utilidades aparecen en forma de funciones, resulta evidente que su utilizacin exige incluirlas en nuestro programa. Para ello se necesitan tres pasos (en realidad las exigencias son las mismas que con cualquier otra funcin, la diferencia estriba en la forma en que se realizan los pasos b y c): a) Incluir en el cdigo fuente las invocaciones a las funciones que estamos utilizando. Ejemplo: printf("Esto es una llamada a la funcin \"printf\" de librera\n"); b) Incluir en el cdigo fuente los prototipos de dichas funciones. Puesto que los prototipos ya estn incluidos en los archivos estndar de cabecera, hay que indicar al compilador que los incluya. Esto se realiza poniendo en nuestro fuente (normalmente al principio) una directiva de preprocesado #include que seala el fichero de cabecera que se debe aadir. Por ejemplo, si el manual indica que la funcin printf est definida en el fichero de cabecera stdio.h ponemos en nuestro cdigo: #include <stdio.h> c) Incluir en el cdigo fuente las definiciones de las funciones utilizadas. Como alternativa se puede indicar al compilador que tales definiciones estn en archivos compilados previamente. En este ltimo caso se dice que las definiciones de las funciones estn en libreras de las que existen dos tipos: estticas (.LIB, .OBJ y .BPI) y dinmicas (.DLL). Toda la informacin que necesita el compilador est contenida en los ficheros de cabecera, por lo que las operaciones correspondientes son realizadas de forma automtica; con la sola condicin de que los ficheros y libreras correspondientes sean accesibles al enlazador. No olvidar que la entidades de la Librera Estndar C++ (que no estn en archivos de cabecera .h), se han definido en un espacio de nombres denominado std, por lo que es preciso referirse a l especficamente cuando se quieran utilizar estos recursos.

M.C. JORGE ENRIQUE ESTRADA MUOZ

20

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

Respecto a las que hemos denominado "condiciones conceptuales", damos por sentado que la utilizacin de algoritmos de la librera exige conocerlos. Pero debemos advertir que existe una gran diferencia entre las rutinas de la que hemos denominado librera clsica y los recursos de la nueva Librera Estndar de Plantillas STL. En general los algoritmos contenidos en la librera clsica realizan tareas muy sencillas bajo la forma de funciones que, con un cierto nmero de argumentos, realizan la tarea encomendada. A veces devolviendo un objeto (que puede ser una estructura). Su utilizacin exige poco ms que repasar esta coleccin de funciones (209 en la ltima versin del Estndar) hasta encontrar la que mejor se ajusta a nuestras necesidades. Para esto lo mejor es recurrir a la clasificacin temtica ofrecida en la documentacin que acompaa a los compiladores antes que a la lista alfabtica de las mismas. El archivo BCB5RTL.HLP, que contiene la "C Runtime Library reference" (nombre con que aparece la Librera Clsica en la documentacin de Borland), contiene dos secciones; la primera, denominada "Categorical Routines and Types Listing", contiene la clasificacin temtica; la segunda, denominada "Alphabetical Routines and Types Listing", contiene la relacin alfabtica. Nota: La funcin max(), que aparece en primer lugar en la clasificacin temtica de la documentacin Borland C (Runtime Library reference: "Categorical Routines and Types Listing"), es una funcin ofrecida por este compilador para el entorno Windows-32 pero no es portable a UNIX ni tampoco pertenece a los estndares C o C++. La utilizacin de la nueva Librera de Plantillas (STL) exige la asimilacin de un nuevo paradigma; una nueva forma de pensar que, si se tiene experiencia en programacin tradicional, exige incluso un "cambio de chip", ya que estas herramientas conforman un mundo enteramente nuevo y singular. STL ofrece un conjunto de recursos flexible, potente y altamente optimizado para resolver una gran variedad de situaciones de programacin. Pero esta versatilidad y potencia tributan un precio: su alto grado de parametrizacin supone algo ms que utilizar herramientas aisladas. Es necesario saber ensamblar entre s los recursos disponibles, que no trabajan aisladamente y que son bsicamente de tres tipos: contenedores, iteradores y algoritmos. El resultado es que el proceso de utilizar la STL es algo ms complicado que la simple bsqueda de una funcin que resuelva nuestras necesidades; que la curva de aprendizaje es ciertamente ms ardua que en el caso de la librera clsica, y que los conceptos involucrados son ms abstractos y requieren un conocimiento ms extenso de sus fundamentos para utilizarlos. Desde luego, la descripcin detallada de todos sus elementos exige un libro completo, y de hecho son muchos los que se han publicado con el objeto exclusivo de describir la STL y/o sus tcnicas de uso. En compensacin, las contrapartidas obtenidas justifican sin duda el esfuerzo. El programador puede concentrarse ms en el problema que en los detalles de su implementacin en el cdigo fuente, se incremente la productividad y se gana en claridad conceptual. Funciones y macros Hay que sealar que algunas funciones pueden venir implementadas de dos formas: como macro y como funcin. Por ejemplo, la funcin isalnum, contenida en <ctype.h>. Esto significa que adems de estar implementada como una funcin en la correspondiente librera (que se utiliza con los argumentos sealados en el manual), est definida como una macro de preprocesado en <ctype.h>, de forma que salvo indicacin contraria al compilador, el preprocesador transforma la llamada del programador en otra serie de sentencias equivalentes que utilizan los mismos

M.C. JORGE ENRIQUE ESTRADA MUOZ

21

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

argumentos. El resultado es que en el cdigo resultante, que luego pasa al compilador y al enlazador, no existe nada parecido a una llamada a una funcin isalnum (tcnicamente el proceso es una sustitucin inline de la funcin de librera. Para evitar que esto ocurra y por consiguiente que la llamada a islanum nunca llegue a producirse, basta con indefinir la correspondiente directiva. Esto se hace incluyendo al principio del cdigo, y debajo de la lnea #include <ctype.h>, una lnea de preprocesado adecuada, en este caso: #undef isalnum, con lo que el #define del preprocesador quedar sin efecto, con el resultado de que todas las invocaciones a isalnum de nuestro cdigo sern respetadas por el preprocesador. Ms tarde el enlazador cargar el cdigo de isalnum (que extrae de la librera) con el resto de nuestro programa, y colocar en cada punto de nuestro cdigo donde aparezca una invocacin a isalnum, un salto a la direccin adecuada. En estos casos, el resultado es el mismo en ambas modalidades: como macro (por defecto) o como funcin de librera. La eleccin de una u otra es cuestin de optimizacin. Para tomar una decisin es necesario comprobar y valorar dos aspectos: El tamao del ejecutable que resulta en uno y otro caso. Posiblemente mayor si se utiliza la funcin muchas veces y se adopta la macro. La velocidad de ejecucin. Posiblemente mayor si se utiliza la funcin muchas veces (en bucles muy largos) y se utiliza la macro. El poderoso y flexible lenguaje de Visual C++y las herramientas en Visual Studio permiten el desarrollo de aplicaciones nativas para la tienda de Windows, aplicaciones nativas del escritorio y aplicaciones administrativas que ejecutan en .NET Framework. Visual C++ incluye los siguientes componentes: Entorno de desarrollo de Visual Studio. El entorno de desarrollo soporta el completo desarrollo del flujo de trabajo, desde crear y administrar proyectos a travs de la escritura del cdigo, depuracin, perfilando e implementando a los usuarios finales. Herramientas del compilador de Visual C++. El compilador soporta el cdigo de desarrollo nativo y el desarrollo orientado al lenguaje comn en tiempo de ejecucin .NET (CLR). Visual C++ soporta la compilacin de computadoras x86, y tambin compiladores destinados a x64 y ARM. Esto optimiza el rendimiento para todas las plataformas. Bibliotecas. Biblioteca en tiempo de ejecucin de C (CRT) Incluye alternativas de seguridad mejoradas a funciones que se sabe plantean problemas de seguridad. Biblioteca estndar de C++ Contiene la biblioteca iostream y la Standard Template Library (STL).

M.C. JORGE ENRIQUE ESTRADA MUOZ

22

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

Active Template Library (ATL) Para la creacin de componentes COM y aplicaciones. Bibliotecas Microsoft Foundation Class (MFC) Para la creacin de aplicaciones de escritorio que tienen interfaces de usuario tradicionales o estilo Office. Parallel Patterns Library (PPL) Para los algoritmos asincrnicos y paralelos que se ejecutan en la CPU. AMP de C++ (paralelismo masivo acelerado) Para los algoritmos paralelos masivos que se ejecutan en el GPU. Biblioteca de plantillas de Windows Runtime C++ (WRL), Para el desarrollo de aplicaciones del Windows Store estilo COM y componentes. Las bibliotecas de clases de .NET Framework (mediante C++/CLI), STL/CLR, y la biblioteca de compatibilidad de C++ Para el desarrollo de aplicaciones administradas. Adems, cuando se usa Visual C++ tambin puede tener acceso a las API de Windows para las aplicaciones del Windows Store y las aplicaciones de escritorio. Los archivos de encabezado y archivos de .winmd para estos API se incluyen en Visual Studio, en el kit de desarrollo de software de Windows (SDK) para Windows 8.

M.C. JORGE ENRIQUE ESTRADA MUOZ

23

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

2. ARREGLOS
Una estructura de datos es una coleccin de datos que pueden ser caracterizados por su organizacin y las operaciones que se definen en ella. Las estructuras de datos son muy importantes en los sistemas de cmputo. Los tipos de datos ms frecuentes utilizados en los diferentes lenguajes de programacin son:
Entero (integer) Real (real) Carcter (char) Lgico (boolean)

Estndar Datos simples Definido por el programador (no estndar)

Subrango (subrange) Enumerativo (enumerated)

Estticos Datos estructurados

Array (vector/matriz) Registro Archivo Conjunto Cadena (string)

Dinmicos

Lista (pila/cola) Lista enlazada rbol Grafo

Los tipos de datos simples o primitivos significan que no estn compuestos de otras estructuras de datos; los ms frecuentes y utilizados por casi todos los lenguajes son: enteros, reales y carcter (char), siendo los tipos lgicos, subrango y enumerativos propios del lenguajes estructurados como Pascal. Los tipos de datos compuestos estn construidos basados en tipos de datos primitivos; el ejemplo ms representativo es la cadena de caracteres (string). Los tipos de datos simples pueden ser organizados en diferentes estructuras de datos: estticas y dinmicas. Las estructuras de datos estticas son aquellas en las que el tamao ocupado en memoria se define antes de que el programa se ejecute y no puede modificarse dicho tamao durante la ejecucin del programa. Estas estructuras estn implementadas en casi todos los lenguajes: array (vectores/tablas-matrices), registros, archivos (los conjuntos son especficos del lenguaje Pascal). Las estructuras de datos dinmicas no tienen las limitaciones o restricciones en el tamao de memoria ocupada que son propias de las estructuras estticas. Mediante el uso de un tipo de datos especfico, denominado puntero, es posible construir estructuras de datos dinmicas que son soportadas por la mayora de los lenguajes, y en aquellos que s tienen estas caractersticas ofrecen soluciones eficaces y efectivas en la solucin de problemas complejos Pascal es el lenguaje tipo por excelencia con posibilidades de estructuras de datos dinmicos . Las estructuras dinmicas por excelencia son listas enlazadas, pilas, colas , rboles binarios, rbol-b, de bsqueda binaria y grafos. La leccin del tipo de estructura de datos idnea a cada aplicacin depender esencialmente del tipo de aplicacin y, en menor medida, del lenguaje, ya que en aquellos en que no est

M.C. JORGE ENRIQUE ESTRADA MUOZ

24

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

implementada una estructura por ejemplo, las listas y rboles no los soporta BASIC deber ser simulada con el algoritmo adecuado, dependiendo del propio algoritmo y las caractersticas del lenguaje su fcil o difcil solucin. Una caracterstica importante que diferencia a los tipos de datos es la siguiente: los tipos de datos simples tienen como caracterstica comn que cada variable representa a un elemento; los tipos de datos estructurados tienen como caracterstica comn que un identificador (nombre) puede representar mltiples datos individuales, pudiendo cada uno de estos ser referenciado independientemente.

Definicin del arreglo


Uno de los problemas ms comunes en los diversos sistemas de informacin es el tratamiento o procesamiento de un gran volumen de datos o de informacin. Las variables usadas hasta ahora reciben propiamente el nombre de variables escalares, porque solo permiten almacenar o procesar un dato a la vez. Por ejemplo si se quiere almacenar nombre y edad de 15 personas con el mtodo tradicional se ocuparan 30 variables y solo es nombre y edad de 15 personas, agreguen ms datos y ms personas y ya es tiempo de empezar a analizar otro tipo de variables. Es decir, en problemas que exigen manejar mucha informacin o datos a la vez, variables escalares no son suficientes ya que su principal problema es que solo permiten almacenar y procesar un dato a la vez. Se ocupan entonces variables que sean capaces de almacenar y manipular conjuntos de datos a la vez. Variables de tipo arreglo si permiten almacenar y procesar conjuntos de datos del mismo tipo a la vez. Cada dato dentro del arreglo se le conoce como elemento del arreglo y se simboliza y procesa (captura, operacin, despliegue ) usando el nombre del arreglo respectivo y un subndice indicando la posicin relativa del elemento con respecto a los dems elementos del arreglo, solo recordar que en Visual C++ la primera posicin, elemento o rengln es el 0 (cero), ej.
NOMBRES JUAN->nombres(0) MARIA->nombres(1) PEDRO->nombres(2) LAURA->nombres(3)

Sin embargo sus problemas son similares a los de variables normales es decir hay que declararlos, capturarlos, hacer operaciones con ellos, desplegarlos, compararlos, etc. En programacin tradicional siempre se manejan dos tipos de arreglos los arreglos tipo listas, vectores o unidimensionales y los arreglos tipo tablas, cuadros, concentrados, matrices o bidimensionales en ambos casos son variables que permiten almacenar un conjunto de datos del mismo tipo a la vez, su diferencia es en la cantidad de columnas que cada uno de estos tipos contiene, como en los siguientes ejemplos;

M.C. JORGE ENRIQUE ESTRADA MUOZ

25

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

a) Listas
NOMBRE Caldern, Jos Daz, Mara Durante, Luis Gonzlez, Ana Zrate, Carlos

b) Tablas Ingresos Mensuales 1er Semestre 2013 (en miles de pesos)


SUCURSAL CENTRO ORIENTE PONIENTE ENERO 350 211 300 FEBRERO 455 231 238 MARZO 600 322 292 ABRIL 452 231 302 MAYO 455 295 352 JUNIO 410 300 211

Como se puede observar la diferencia principal entre un arreglo tipo lista y un arreglo tipo tabla son las cantidades de columnas que contienen.

Direccin de memoria
Una direccin de memoria es un identificador para una localizacin de memoria con la cual un programa informtico o un dispositivo de hardware pueden almacenar un dato para su posterior reutilizacin. Una forma comn de describir la memoria principal de una computadora es como una coleccin de celdas que almacenan datos e instrucciones. Cada celda est identificada unvocamente por un nmero o direccin de memoria. Para poder acceder a una ubicacin especfica de la memoria, la CPU genera seales en el bus de direccin, que habitualmente tiene un tamao de 32 bits en la mayora de mquinas actuales. Un 32 bus de direccin de 32 bits permite especificar a la CPU 2 = 4,294967,296 direcciones de memoria distintas. Debido a la estructura de 32 bits de un procesador comn como los de Intel, las direcciones de memoria se expresan a menudo en hexadecimal. Por ejemplo, para no tener que escribir 111111010100000000000010101100 podemos escribir 3F5000AC en hexadecimal.

Arreglos unidimensionales
Un array (matriz o vector) es un conjunto finito y ordenado de elementos homogneos. La propiedad ordenado significa que el elemento primero, segundo, tercero,, ensimo de un array puedeser identificado. Los elementos de un array son homogneos, es decir, del mismo tipo de datos. Un array puede estar compuesto de todos sus elementos de tipo cadena, otro puede tener todos sus elementos de tipo entero, etctera. Los arrays se conocen tambin como matrices en matemticas y tablas en clculos financieros. El tipo ms simple de array es el array unidimensional o vector (matriz de una dimensin). Un vector de una dimensin denominado CALIFICACION que consta de n elementos se puede representar de la siguiente forma:

M.C. JORGE ENRIQUE ESTRADA MUOZ

26

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

CALIFICACION(1)

CALIFICACION(2)

CALIFICACION(i)

CALIFICACION(n)

El subndice o ndice de un elemento [1, 2, , i, , n] designa su posicin en la ordenacin del vector. Solo el vector global tiene nombre (CALIFICACION). Los elementos del vector se referencian por su subndice o ndice (subscript), es decir, su posicin relativa en el vector. En algunos libros y tratados de programacin, adems de las notaciones anteriores se suele utilizar esta otra: A[L:U]={A[I]} Para I=L, L+1, , U-1, U donde cada elemento A[I] es de tipo de datos T Que significa: A, vector unidimensional con elementos de datos tipo T, cuyos subndices varan en el rango de L a U, lo cual significa que el ndice no tiene porque comenzar necesariamente en 0 o en 1. Los vectores se almacenan en memoria central de la computadora en un orden adyacente. Cada elemento de un vector se puede procesar como si fuese una variable simple al ocupar una posicin de memoria. CALIFICACION[25] <- 72 Almacena el valor entero o real 72 en la posicin 25 del vector CALIFICACION y la instruccin de salida escribir (CALIFICACION[72]) visualiza el valor almacenado en la posicin 25, en este caso 72. Esta propiedad significa que cada elemento de un vector y posteriormente una tabla o matriz es accesible directamente. Esta ser una de las ventajas ms importantes de usar un vector: almacenar un conjunto de datos. Algunas de las instrucciones que manipulan un vector sern las que siguen si tomamos como ejemplo el siguiente vector:
X[1] 14.0 Elemento 1 X[2] 12.0 Elemento 2 X[3] 8.0 Elemento 3 X[4] 7.0 Elemento 4 X[5] 6.41 Elemento 5 X[6] 5.23 Elemento 6 X[7] 6.15 Elemento 7 X[8] 7.25 Elemento 8

Acciones Escribir (X[1]) X[4] <- 45 SUMA <- X[1]+X[3] SUMA <- SUMA+X[4] X(5) <- X[5]+3.5 X(6) <- X[1]+X[2]

Resultados Visualiza el valor de X[1] o 14.0 Almacena el valor 45 en X[4] Almacena la suma de X[1] y X[3] o bien 22.0 en la variable SUMA Aade en la variable SUMA el valor de X[4], es decir. SUMA=67.0 Suma 3.5 a X[5]; el nuevo valor de X[5] ser 9.91 Almacena la suma de X[1] y X[2] en X[6]; el nuevo valor de X[6] ser 26.0

Los subndices de un vector pueden ser enteros, variables o expresiones enteras. Veamos el siguiente ejemplo:
I <- 4

M.C. JORGE ENRIQUE ESTRADA MUOZ

27

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

X[I+1] X[I+2] X[I-2] X[I+3]

Representa el elemento X[5] de valor 6.41 Representa el elemento X[6] de valor 5.23 Representa el elemento X[2] de valor 12.0 Representa el elemento X[7] de valor 6.15

Los arrays unidimensionales y multidimensionales necesitan ser dimensionados previamente a su uso dentro de un programa. Las operaciones que se pueden realizar con vectores durante el proceso de resolucin de un problema son: Asignacin Lectura/escritura Recorrido (acceso secuencial) Actualizar (aadir, borrar, insertar) Ordenacin Bsqueda En general, las operaciones con vectores implican el procesamiento o tratamiento de los elementos individuales del vector.

Arreglos bidimensionales
Existen grupos de datos que son representados mejor en forma de tabla o matriz con dos o mas subndices, por ejemplo las tablas de distancias en kilmetros entre ciudades, cuadros horarios de aviones, informes de ventas peridicas, por mencionar solo algunos. Se pueden definir tablas o matrices como arrays muiltidimensionales, cuyos elementos se pueden referenciar por dos, tres o mas subndices. El array bidimensional se puede considerar como un vector de vectores. Es, por consiguiente, un conjunto de elementos, todos del mismo tipo, en el cual el orden de los componentes es significativo y en el que se necesita especificar dos subndices para poder identificar cada elemento del array. Si se visualiza un array unidimensional, se puede considerar como una columna de datos; un array bidimensional es un grupo de columnas como se aprecia a continuacin: 1 2 I M 1 2 j COLUMNAS n

El diagrama representa una tabla o matriz de mxn elementos con m filas y n columnas. Como en un vector de mxn elementos, cada uno de ellos tiene el mismo nombre, sin embargo, un subndice no es suficiente para especificar un elemento de un array bidimensional; por ejemplo, si el nombre del array es M, no se puede indicar M[3], ya que no sabemos si es el tercer elemento de la primera fila o el tercer elemento de la primera columna. Para evitar la ambigedad, los elementos de un

M.C. JORGE ENRIQUE ESTRADA MUOZ

FILAS

28

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

array bidimensional se referencian con dos subndices se refiere a la fila y el segundo subndice se refiere a la columna. Por consiguiente, M[2,3] se refiere al elemento de la segunda fila, tercera columna.

Arreglos Tridimensionales
Un array puede ser definido de tres dimensiones, cuatro dimensiones, hasta de n-dimensiones. Los conceptos de rango de subndices y nmero de elementos se pueden ampliar directamente desde arrays de una o dos dimensiones a estos arrays de un orden ms alto. En general, un array de ndimensiones requiere que los valores de los n subndices puedan ser especificados a fin de identificar un elemento individual del array. Si cada componente de un array tiene n subndices, el array se dice que es slo de n-dimensiones. El array A de n-dimensiones se puede identificar como A[L1:U1, L2:U2, , Ln:Un] Y un elemento individual del array se puede especificar por A[I1, I2,, In] Donde cada subndice Ik est dentro de los lmites adecuados Lk <= Ik <= Uk Donde K=1, 2, , n El nmero total de elementos de un array A es: (Uk Lk +1) (smbolo del producto) Que se puede escribir alternativamente como (U1-L1+1)*(U2-L2+1)**(UN-LN+1) Si los lmites inferiores comenzasen en 1, el array se representara por A[S1, S2, , Sn] y un elemento individual Ak1, k2,,kn Donde 1 <= k1 <= s1 1 <= k2 <= s2 . . 1 <= kn <= sn

Arreglos multidimensionales
Vase el tema anterior.

M.C. JORGE ENRIQUE ESTRADA MUOZ

29

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

Arreglo de caracteres
Hasta el momento vimos ejemplos de arreglos enteros. De la misma manera podramos crear un arreglo de caracteres, lo que nos permite manipular cadenas. Ejemplo de declaracin: char arregloCadena[] = "buenas"; Notemos que no hemos especificado ndice alguno, el compilador contar la cantidad de letras que tiene la cadena "buenas" (son 6) y agregar uno para inclur el carcter nulo ( '\0' ). El carcter nulo indica la terminacin de la cadena, es importante siempre tenerlo en cuenta. Ejemplo de declaracin: char arregloCadena2[7] = {'b','u','e','n','a','s','\0'}; En esta declaracin inicializamos cada uno de los elementos del arreglo de manera individual. Notar que inicializamos explcitamente en el elemento 7 del arreglo al carcter nulo '\0'. Ejemplo de declaracin: char arregloCadena3[] = "otra cadena"; El arregloCadena3, reservar 12 lugares en memoria, ya que adems de los 10 que suman las palabras, hay un espacio y el carcter nulo. Arreglos y "cin >>" Podemos utilizar cin >> arregloCadena para asignar a un arreglo (desde el teclado o entrada estandar), pero debemos tener en cuenta que cin >> leer y asignar hasta detectar el primer carcter en blanco (espacio). Ejemplo de "cin >>" char arregloCadena4[25]; cin >> arregloCadena4; Si aqu el usuario introdujera "hace calor" por teclado, el arregloCadena4 almacenara solamente la cadena "hace" y " calor" se ignorara por completo. Tambin podra suceder que el usuario ingrese ms de 24 carcteres (el ltimo es el nulo) lo que ocasionara una "Violacin de segmento" al tratar de asignar valores por fuera del arreglo, as que el programador debera estar atento al uso de cin >> con arreglos. Ejemplo En el ejemplo que sigue, utilizamos una funcin llamada cuentaCaracteres definida despus del cuerpo de main(). Esta funcin cuenta los elementos del los arreglos de tipo char, que le llegan como parmetros. Para esto utiliza un ciclo for, que incrementa su variable de control i hasta que cadena[i] sea igual al carcter nulo ('\0'). Cuando esto sucede la funcin devuelve el valor de i. Luego dentro de main() tambin se utiliza un ciclo exacto for, para mostrar los elementos individuales de cuentaCadena.

M.C. JORGE ENRIQUE ESTRADA MUOZ

30

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

//Uso de arreglos de caracteres en C++ #include <iostream> using std::cout; using std::cin; using std::endl; //prototipo de funcion que recibe un arreglo de char y devuelve int int cuentaCaracteres(char []); int main() { //Arreglo char de 10 elementos, inicializados con el caracter nulo char arregloCadena[10] = {'\0'}; char arregloCadena1[] = "soy el arregloCadena1 de 36 elementos"; cout << "arregloCadena tiene " << cuentaCaracteres(arregloCadena) << " caracteres." << endl; cout << "arregloCadena1 tiene " <<cuentaCaracteres(arregloCadena1) << " caracteres."<< endl; cout << "Introduzca para arregloCadena \"hace calor\""<< endl; cin >> arregloCadena; cout << "Elementos individuales del arregloCadenason: " << endl; for (int i = 0 ; i < 10 ; i++) //Notar el menor estricto(<) para ir desde 0 hasta 9 cout <<"arregloCadena["<<i<<"]="<<arregloCadena[i] << endl; cout << "Ahora la cantidad de caracteres de arregloCadena son: " << cuentaCaracteres(arregloCadena)<< " caracteres" << endl; return 0; }//fin de main //funcion que recibe un arreglo char, para contar sus caracteres. int cuentaCaracteres(char cadena[]) { int i; for (i = 0; cadena[i] != '\0';i++) {/*for vacio*/} return i; }

Comparacin. La comparacin de cadenas es una operacin muy importante, sobre todo en la clasificacin de datos de tipo carcter, que se utiliza con frecuencia en aplicaciones de procesos de datos. Los criterios de comparacin se basan en el orden numrico del cdigo o juego de caracteres que admite la computadora o el propio lenguaje de programacin. En nuestros algoritmos utilizaremos el cdigo ASCII como cdigo numrico de referencia, por ejemplo: El carcter A ser < el carcter C; el carcter 8 ser < el carcter i El carcter (cdigo 65) es menor a (cdigo 67) y el carcter (cdigo 56) es menor a (cdigo 105) En la comparacin de cadenas se pueden considerar dos operaciones ms elementales: igualdad y desigualdad. Igualdad. Dos cadenas A y B de longitud m y n son iguales si: El nmero de caracteres de A y B son los mismos (m=n) Cada carcter de A es igual a su correspondiente de B; si A=A1, A2, , An y B=B1, B2, , Bn se debe verificar que A1 = B1 para todo i en el rango 1<=i<=n. Desigualdad.

M.C. JORGE ENRIQUE ESTRADA MUOZ

31

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

Los criterios para comprobar la desigualdad de cadena utilizan normalmente los operadores de relacin <, <=, >=, <>, o ><, y se ajustan a una comparacin sucesiva de caracteres correspondiente en ambas cadenas hasta conseguir dos caracteres diferentes. De este modo, se pueden conseguir clasificaciones alfanumricas GARCIA < GOMEZ Ya que las comparaciones sucesivas son: GARCIA GOMEZ; G=G, A<O Una vez que se encuentra una desigualdad no es preciso continuar; como puede observarse, las cadenas no necesitan tener la misma longitud para compararse. Concatenacin. La concatenacin es la operacin de reunir varias cadenas de caracteres en una sola, pero conservando el orden de los caracteres de cada una de ellas. Para realizar los algoritmos usaremos los smbolos + y & indistintamente. As entonces tenemos que: ESTRUCTURA + DE + DATOS = ESTRUCTURADEDATOS Podemos comprobar que las cadenas en realidad se pegan unas a lado de otras; por ello si al concatenar frases se desea dejar espacios en blanco entre ellas, se debe indicar expresamente en alguna de las cadenas, as pues tenemos ESTRUCTURA + DE + DATOS = ESTRUCTURA DE DATOS ESTRUCTURA + DE + DATOS = ESTRUCTURA DE DATOS Producen el mismo resultado. Es posible concatenar variables de cadena. var cadena: A, B, C A&B&C equivale a A&(B&C) La asignacin de constantes tipo cadena a variables tipo cadena puede tambin realizarse con expresiones concatenadas. Subcadenas. Otra operacin funcin es importante de las cadenas es aquella que permite la extraccin de una parte especfica de una cadena: subcadena. La operacin subcadena se representa en dos formatos por: Subcadena (cadena_fuente,p,longsub) cadena_fuente es la cadena de la que debe extraerse una subcadena. p es un nmero o expresin nemrica entero que corresponde a la posicin inicial de la subcadena longsub es la longitud de la subcadena

M.C. JORGE ENRIQUE ESTRADA MUOZ

32

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

Subcadena (cadena_fuente, p) En este caso la subcadena empieza en p y termina en el final de la cadena. Es posible realizar operaciones de concatenacin con subcadenas. subcadena (ESTRUCTURA DE DATOS,1,4)&subcadena(UNIVERSIDAD DEL SUR,5,4) Equivale a la cadena ESTRERSI. La aplicacin de la funcin a una subcadena, Subcadena (cadena_fuente,p,longsub) Puede producir los siguientes resultados: Si longsub no existe, entonces la subcadena comienza en el mismo carcter posicin y termina con el ltimo carcter. Si longsub <= 0, el resultado es una cadena vaca. Si p > longitud(cadena_fuente), la subcadena resultante ser vaca. Si p <= 0, el resultado tambin es una cadena vaca. Bsqueda. Una operacin frecuente para realizar con cadenas es localizar si una determinada cadena forma parte de otra cadena ms grande o busca la posicin en que aparece un determinado carcter o secuencia de caracteres de un texto.

M.C. JORGE ENRIQUE ESTRADA MUOZ

33

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

3. PUNTEROS
Definicin de punteros.
Hasta ahora hemos venido trabajando con variables, dimensionadas o no, que son direcciones simblicas de posiciones de memoria, de forma que existe una relacin bien determinada entre nombres de variables y posiciones de memoria durante toda la ejecucin del programa. Aunque el contenido de una posicin de memoria asociada con una variable puede cambiar durante la ejecucin, es decir el valor asignado a la variable puede variar, las variables por si mismas no pueden crecer ni disminuir durante la ejecucin. Sin embargo, en muchas ocasiones es conveniente disponer de un mtodo por el cual, podamos adquirir posiciones de memoria adicionales, a medida que las vayamos necesitando durante la ejecucin y al contrario, liberarlas cuando no se necesiten. Las variables y estructuras de datos que renen estas condiciones se llaman dinmicas y se representan con la ayuda de un nuevo tipo de dato llamado puntero. Un puntero o apuntador es una variable cuyo valor es la direccin o posicin de otra variable. Puede concebirse como una flecha que apunta al dato en cuestin.

Figura 3.1 Representacin de un puntero

Los punteros proporcionan los enlaces de unin entre los elementos, permitiendo que durante la ejecucin del programa las estructuras dinmicas puedan cambiar sus tamaos. En las estructuras dinmicas, estos elementos llamados nodos, son normalmente registros de al menos dos campos, donde por lo menos uno de ellos es un puntero.

Figura 3.2 Representacin de un nodo

La utilizacin de punteros permite que sea relativamente fcil aadir indeterminadamente nuevos datos, insertar nuevos nodos en otros ya existentes y en general modificar estas estructuras. Dependiendo de las relaciones entre los nodos de la estructura hablaremos de estructuras lineales y no lineales: si partiendo del nodo inicial es posible dirigirse sucesivamente a todos los nodos visitando cada uno una nica vez diremos que es una estructura lineal; en caso de no ser posible el recorrido en estas condiciones se habla de estructura no lineal. Los punteros permiten simular el paso por referencia, crear y manipular estructuras dinmicas de datos, tales como listas encadenadas, pilas, colas y rboles. Generalmente las variables contienen valores especficos. Los punteros son variables pero en vez de contener un valor especifico, contienen las direcciones de las variables a las que apuntan. Para obtener o modificar el valor de la variable a la que apuntan se utiliza el operador de indireccin. Los punteros, al ser variables deben ser declaradas como punteros antes de ser utilizadas.

M.C. JORGE ENRIQUE ESTRADA MUOZ

34

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

Sintaxis int *ptrID, ID; ID = 8; ptrID = &ID; // puntero a ID ptrID es un puntero a una localidad de memoria de tipo int, mientras que la variable ID es solo una variable del tipo int. Todo puntero debe ser precedido por un asterisco (*) en la declaracin. Se puede declarar ms de un puntero en la misma sentencia. En el ejemplo que sigue se ve la declaracin de dos punteros a int. int *ptrY, *ptrX; Operadores Existen dos operadores a tener en cuenta cuando trabajamos con punteros. El operador de direccin (&) que devuelve la direccin de memoria de su operando y el operador de indireccin (*) que devuelve un alias para el objeto al cual apunta el operando del puntero. En el siguiente ejemplo vemos como se inicializa una variable X con el valor 15. Luego se crea un puntero a int y por ltimo el puntero pasa a apuntar a la variable X. Esto es, ptrX es un puntero a X. int X = 15; int *ptrX; ptrX = &X;

Punteros a arrays.
Las matrices o arrays son punteros constantes. Una matriz sin subindice es un puntero al primer elemento de la matriz. int X[15]; int *ptrX; ptrX = X; // ptrX recibe la direccin del primer elemento ( 0 ) de X As como tambin podra escribirse int X[15]; int *ptrX; ptrX = &X[0]; // ptrX es igual a la direccin del primer elemento de X Se pueden utilizar distintos elementos de la matriz teniendo en cuenta la sintaxis de punteros. int X[15], Y, *ptrX; ptrX = X; Y = *( ptrX + 7 ); En este caso puede verse que Y toma el valor del elemento 7 de la matriz X, siendo 7 el desplazamiento dentro de la matriz. El operador de indireccin queda fuera del parntesis porque tiene una prioridad superior a la del operador +. De no existir los parntesis, se sumara 7 al

M.C. JORGE ENRIQUE ESTRADA MUOZ

35

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

elemento X[0]. Teniendo en cuenta que las matrices son punteros constantes, el nombre de la matriz puede tratarse como un puntero: Y = *( X + 7 ); Aritmtica de Punteros Al usar punteros a matrices, hay que tener en cuenta que la aritmtica cambia sensiblemente. #include <iostream> using std::cout; using std::endl; void main() { int X[6] = { 1, 2, 3, 4, 5, 6 }; //Se declara un arreglo de tipo entero de seis elementos, cada elemento tiene un valor definido int *prtX; //Se declara un puntero de tipo entero prtX = X; // incializo el valor del puntero al primer elemento del arreglo X[0] cout << endl << *prtX; //Imprime el valor de X[0]=1 prtX += 2; //Se desplaza dos elementos cout << endl << *prtX; //Imprime el valor de X[2]=3 prtX -= 2; //Se desplaza dos elementos a la inversa cout << endl << *prtX; //Imprime el valor de X[0]=1 prtX++; //Se desplaza una localidad de memoria cout << endl << *prtX; //Imprime el valor de X[1]=2 } Si tenemos en cuenta que el ejemplo se ejecuta en una computadora con enteros de 4 bytes, el segundo elemento de la matriz tendr en memoria un desplazamiento de 4 bytes, el 2 de ocho y asi sucesivamente. La operacin prtX += 2; produce un desplazamiento llevndolo al 3 elemento dentro del arreglo. Debe entenderse que prtX ahora apunta a una direccin de memoria y la instruccin cambia esta direccin de memoria sumndole 2 multiplicado por el tamao del tipo de dato del arreglo que en este supuesto sera de 4. (dir = ( dir + 2 * 4 )), dando por resultado un desplazamiento de 8 bytes. Sera igual que ejecutar la operacin prtX = &X[2];. La operacin prtX = 2 obedece a la misma lgica estableciendo el puntero al primer elemento del array X[0] y el operador ++ modifica el puntero desplazndolo 4 bytes y asignndole el segundo elemento de la matriz.

Puntero a cadenas.
Matrices de punteros Para realizar una estructura de datos dinmica, se puede utilizar una matriz donde sus elementos sean punteros. Suponiendo que queramos hacer un calendario y lo dividamos por semanas. Podramos utilizar una matriz con los das de la semana. const char *dias[7] = { "Domingo", "Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado" } Cada da de la semana, no es un elemento de la matriz, sino que la expresin dias[7] crea una matriz de siete elementos como punteros a char.

M.C. JORGE ENRIQUE ESTRADA MUOZ

36

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

Ya hemos visto el uso que se le puede dar a un puntero como si de un array se tratase, entonces usando esta misma lgica podemos hacer un arreglo de caracteres usando punteros. char *nombre="Juan Pedro";//Es como un arreglo de 10 caracteres printf("%s",nombre); Sin embargo al tratarse de una constante de caracteres no podemos modificarla luego de definir sus valores. Como por ejemplo no podemos remplazar un carcter, o leer un nuevo valor. gets(nombre); //ERROR en ejecucin Para poder modificar el valor de este puntero, este tendra que apuntar a una direccin que no sea una constante, como un array. char nombre[]="Juan Pedro"; //declaramos un arreglo de caracteres char *puntero=nombre;//Asignamos al puntero el comienzo del array printf("%s \nIngrese otro nombre: ",puntero);//Escribimos en pantalla nombre gets(puntero); //leemos otro nombre printf("%s",puntero); //escribimos el nuevo nombre Esta vez pudiste notar que si se pudo remplazar el valor del nombre, pero aun la cantidad de caracteres est limitada por el arreglo original, mas adelante veremos cmo solucionar esto con memoria dinmica.

Puntero a estructuras
Del mismo modo que ocurre con las funciones, las estructuras tienen una direccin, asumiendo que esta es el comienzo de su almacenamiento. Esto es especialmente cierto en C, donde las estructuras representan exclusivamente conjuntos de datos. En C++ las estructuras son cierto tipo de clases que pueden contener cdigo (funciones), pero incluso entonces, lo que realmente se almacena en el cuerpo de la estructura son punteros (datos) a las funciones correspondientes. Veremos que los punteros a estructuras son de uso muy frecuente para el manejo de estas; en especial cuando se pasan como argumentos a funciones, o son devueltas por estas. Por ejemplo, la sentencia: struct punto {int x; int y;} pto = {3,4}, *ptr = &pto, arsp[10]; Define un tipo de estructura denominado punto; una estructura (instancia) pto, y un puntero ptr a dicha instancia. Finalmente declara una matriz arsp de 10 estructuras tipo punto. En general la sintaxis para declaracin de punteros a estructuras sigue la sintaxis general. <tipo_objeto> * <etiqueta_puntero> [ = <iniciador> ] En este caso, tipo_objeto es de la forma struct punto, con lo que la declaracin es: struct punto * ptr; Opcionalmente puede incluirse un iniciador como en el ejemplo anterior: struct punto * ptr = &pto;

M.C. JORGE ENRIQUE ESTRADA MUOZ

37

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

En este caso, ptr es un puntero, y su indireccin *ptr, representa la estructura pto. Los miembros de la estructura pueden referenciarse mediante el operador de acceso: (*ptr).x == 3; (*ptr).y == 4; Los parntesis son necesarios, ya que el operador de acceso (.) tiene mayor precedencia que el de indireccin. Por esta razn, *ptr.x es interpretada como *(ptr.x), lo que es errneo, ya que ptr.x no es un puntero (en este caso es un entero). La expresin struct { int x1; char * str; long *arr[10]; } *ptr; Declara un puntero ptr a un tipo de estructura annima de tres componentes. Aunque sintcticamente correcta y aceptable por el compilador, una declaracin como la anterior es prcticamente intil y muy peligrosa. Por ejemplo, la sentencia (*ptr).int = 30; puede producir una catstrofe. Los punteros son muy importantes para el manejo de matrices y estructuras, por lo que en este caso se ha previsto una notacin alternativa ms corta: ptr->x == 3; ptr->y == 3;

Puntero a puntero.
Es una variable que contiene la direccin de memoria de un puntero, el cual a su vez contiene la direccin de memoria de un tipo de dato. Recuerden que un puntero sigue siendo un espacio en memoria, pero en vez de almacenar un valor almacena una direccin. Si decimos que: int a=0; //Supongamos que es una variable cuya direccion es 0x1601 int *puntero1=&a; //El puntero tiene guardada la direccion de a, //pero este tiene como direccion 0x1890 int **puntero2=&puntero1; //**puntero 2 guarda la direccion 0x1890 Ahora se entiende mejor. Al uso de punteros se le llama variables con niveles de indireccion, ya que no apuntan directamente a un valor, sino que apuntan a alguien que lo tiene. Basndonos en esto podemos decir que *puntero1 es un puntero con un nivel de indireccion y *puntero2 es un puntero con dos niveles de indireccion. En general estos tipos de datos son usados con matrices multidimensionales.

M.C. JORGE ENRIQUE ESTRADA MUOZ

38

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

4. ESTRUCTURA Y UNIONES
Definicin de estructura.
Supongamos que queremos hacer una agenda con los nmeros de telfono de nuestros amigos. Necesitaramos un array de Cadenas para almacenar sus nombres, otro para sus apellidos y otro para sus nmeros de telfono. Esto puede hacer que el programa quede desordenado y difcil de seguir. Y aqu es donde vienen en nuestro auxilio las estructuras. Para definir una estructura usamos el siguiente formato: struct nombre_de_la_estructura { campos de estructura; }; Es importante no olvidar el ';' del final, si no a veces se obtienen errores extraos.

Miembros.
Para nuestro ejemplo podemos crear una estructura en la que almacenaremos los datos de cada persona. Vamos a crear una declaracin de estructura llamada amigo: struct estructura_amigo { char nombre[30]; char apellido[40]; char telefono[10]; char edad; }; A cada elemento de esta estructura (nombre, apellido, telfono) se le llama campo o miembro.

Instancia.
Ahora ya tenemos definida la estructura, pero aun no podemos usarla. Necesitamos declarar una variable con esa estructura. struct estructura_amigo amigo; Ahora la variable amigo es de tipo estructura_amigo. Para acceder al nombre de amigo usamos: amigo.nombre. Vamos a ver un ejemplo de aplicacin de esta estructura. (En el siguiente ejemplo los datos no se guardan en disco as que cuanda acaba la ejecucin del programa se pierden). #include <stdio.h> struct estructura_amigo { /* Definimos la estructura estructura_amigo */ char apellido[40]; char telefono[10]; char edad; }; struct estructura_amigo amigo; void main() { printf( "Escribe el nombre del amigo: " ); fflush( stdout );

char nombre[30];

M.C. JORGE ENRIQUE ESTRADA MUOZ

39

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

scanf( "%s", &amigo.nombre ); printf( "Escribe el apellido del amigo: " ); fflush( stdout ); scanf( "%s", &amigo.apellido ); printf( "Escribe el nmero de telfono del amigo: " ); fflush( stdout ); scanf( "%s", &amigo.telefono ); printf( "El amigo %s %s tiene el nmero: %s.\n", amigo.nombre, amigo.apellido, amigo.telefono ); } Este ejemplo estara mejor usando gets que scanf, ya que puede haber nombres compuestos que scanf no tomara por los espacios. Se podra haber declarado directamente la variable amigo: struct estructura_amigo { char nombre[30]; char apellido[40]; char telefono[10]; } amigo;

Arrays de estructura.
Supongamos ahora que queremos guardar la informacin de varios amigos. Con una variable de estructura slo podemos guardar los datos de uno. Para manejar los datos de ms gente (al conjunto de todos los datos de cada persona se les llama REGISTRO) necesitamos declarar arrays de estructuras. Cmo se hace esto? Siguiendo nuestro ejemplo vamos a crear un array de ELEMENTOS elementos: struct estructura_amigo amigo[ELEMENTOS]; Ahora necesitamos saber cmo acceder a cada elemento del array. La variable definida es amigo, por lo tanto para acceder al primer elemento usaremos amigo[0] y a su miembro nombre: amigo[0].nombre. Vemoslo en un ejemplo en el que se supone que tenemos que meter los datos de tres amigos: #include <stdio.h> #define ELEMENTOS 3 struct estructura_amigo { char nombre[30]; char apellido[40]; char telefono[10]; int edad; }; struct estructura_amigo amigo[ELEMENTOS]; void main() { int num_amigo; for( num_amigo=0; num_amigo<ELEMENTOS; num_amigo++ )

M.C. JORGE ENRIQUE ESTRADA MUOZ

40

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

{ printf( "\nDatos del amigo nmero %i:\n", num_amigo+1 ); printf( "Nombre: " ); fflush( stdout ); gets(amigo[num_amigo].nombre); printf( "Apellido: " ); fflush( stdout ); gets(amigo[num_amigo].apellido); printf( "Telfono: " ); fflush( stdout ); gets(amigo[num_amigo].telefono); printf( "Edad: " ); fflush( stdout ); scanf( "%i", &amigo[num_amigo].edad ); while(getchar()!='\n'); } /* Ahora imprimimos sus datos */ for( num_amigo=0; num_amigo<ELEMENTOS; num_amigo++ ) { printf( "El amigo %s ", amigo[num_amigo].nombre ); printf( "%s tiene ", amigo[num_amigo].apellido ); printf( "%i aos ", amigo[num_amigo].edad ); printf( "y su telfono es el %s.\n" , amigo[num_amigo].telefono ); } }

Estructura anidada.
Es posible crear estructuras que tengan como miembros otras estructuras. Esto tiene diversas utilidades, por ejemplo tener la estructura de datos ms ordenada. Imaginemos la siguiente situacin: una tienda de msica quiere hacer un programa para el inventario de los discos, cintas y cd's que tienen. Para cada ttulo quiere conocer las existencias en cada soporte (cinta, disco, cd), y los datos del proveedor (el que le vende ese disco). Podra pensar en una estructura as: struct inventario { char titulo[30]; char autor[40]; int existencias_discos; int existencias_cintas; int existencias_cd; char nombre_proveedor[40]; char telefono_proveedor[10]; char direccion_proveedor[100]; }; Sin embargo utilizando estructuras anidadas se podra hacer de esta otra forma ms ordenada: struct estruc_existencias { int discos; int cintas; int cd; }; struct estruc_proveedor { char proveedor[40]; char proveedor[10]; char proveedor[100]; };

M.C. JORGE ENRIQUE ESTRADA MUOZ

41

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

struct estruc_inventario { char titulo[30]; char autor[40]; struct estruc_existencias existencias; struct estruc_proveedor proveedor; } inventario; Ahora para acceder al nmero de cd de cierto ttulo usaramos lo siguiente: inventario.existencias.cd y para acceder al nombre del proveedor: inventario.proveedor.nombre Veamos las dos opciones de notacin para acceso de miembros en un ejemplo con estructuras anidadas: struct punto { int x; int y; }; struct line { struct punto p1; struct punto p2; } lin, *liptr = &lin; En las sentencias anteriores hemos definido dos tipos de estructuras; una instancia y un puntero a dicha instancia. En estas condiciones, las expresiones que siguen son equivalentes (1 y 6 son preferibles por legibilidad): lin.p1.x // L1. (lin.p1).x (*liptr).p1.x ((*liptr).p1).x liptr->p1.x // L6. (liptr->p1).x

Paso de estructura a funciones.


Las estructuras se pueden pasar directamente a una funcin igual que hacamos con las variables. Por supuesto en la definicin de la funcin debemos indicar el tipo de argumento que usamos: int nombre_funcin ( struct nombre_de_la_estructura nombre_de_la variable_estructura ) En el ejemplo siguiente se usa una funcin llamada suma que calcula cual ser la edad 20 aos ms tarde (simplemente suma 20 a la edad). Esta funcin toma como argumento la variable estructura arg_amigo. Cuando se ejecuta el programa llamamos a suma desde main y en esta variable se copia el contenido de la variable amigo. Esta funcin devuelve un valor entero (porque est declarada como int) y el valor que devuelve (mediante return) es la suma.

M.C. JORGE ENRIQUE ESTRADA MUOZ

42

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

#include <stdio.h> struct estructura_amigo { char nombre[30]; char apellido[40]; char telefono[10]; int edad; }; struct estructura_amigo amigo = { "Juanjo", "Lopez", "592-0483", 30 }; int suma( struct estructura_amigo arg_amigo ) { return arg_amigo.edad+20; } int main() { printf( "%s tiene ", amigo.apellido ); printf( "%i aos ", amigo.edad ); printf( "y dentro de 20 aos tendr %i.\n", suma(amigo) ); } Si dentro de la funcin suma hubisemos cambiado algn valor de la estructura, dado que es una copia no hubiera afectado a la variable amigo de main. Es decir, si dentro de 'suma' hacemos arg_amigo.edad = 20; el valor de arg_amigo cambiar, pero el de amigo seguir siendo 30. Tambin se pueden pasar estructuras mediante punteros o se puede pasar simplemente un miembro (o campo) de la estructura. Si usamos punteros para pasar estructuras como argumentos habr que hacer unos cambios al cdigo anterior (en negrita y subrayado): int suma( struct estructura_amigo *arg_amigo ) { return arg_amigo->edad+20; } int main() { printf( "%s tiene ", amigo.apellido ); printf( "%i aos ", amigo.edad ); printf( "y dentro de 20 aos tendr %i.\n", suma(&amigo) ); } Lo primero ser indicar a la funcin suma que lo que va a recibir es un puntero, para eso ponemos el * (asterisco). Segundo, como dentro de la funcin suma usamos un puntero a estructura y no una variable estructura debemos cambiar el '.' (punto) por el '->'. Tercero, dentro de main cuando llamamos a suma debemos pasar la direccin de amigo, no su valor, por lo tanto debemos poner '&' delante de amigo. Si usamos punteros a estructuras corremos el riesgo (o tenemos la ventaja, segn cmo se mire) de poder cambiar los datos de la estructura de la variable amigo de main.

M.C. JORGE ENRIQUE ESTRADA MUOZ

43

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

Pasar slo miembros de la estructura Otra posibilidad es no pasar toda la estructura a la funcin sino tan slo los miembros que sean necesarios. Los ejemplos anteriores seran ms correctos usando esta tercera opcin, ya que slo usamos el miembro 'edad': int suma( char edad ) { return edad+20; } int main() { printf( "%s tiene ", amigo.apellido ); printf( "%i aos ", amigo.edad ); printf( "y dentro de 20 aos tendr %i.\n", suma(amigo.edad) ); } Por supuesto a la funcin suma hay que indicarle que va a recibir una variable tipo char (amigo>edad es de tipo char).

Enumeraciones.
Las variables enumeradas, enumeraciones o ms abreviadamente enum (palabra reservada), son un tipo especial de variables que tienen la propiedad de que su rango de valores es un conjunto de constantes enteras denominadas constantes de enumeracin, a cada una de las cuales se le asigna un valor. Para mayor legibilidad del cdigo estos valores del rango se identifican por nemnicos. Por ejemplo, la declaracin: enum dia { DOM, LUN, MART, MIER, JUEV, VIER, SAB } diaX; Establece un tipo enum al que se identifica por dia. Las variables de este tipo pueden adoptar un conjunto de seis valores enteros 0, 1, 2, 3, 4, 5, 6 (enumeradores) representados por los nemnicos DOM, LUN, MART, MIER, JUEV, VIER, SAB. Adems se define una variable diaX de este tipo (variable enumerada). En el ejemplo anterior, la variable diaX puede adoptar siete valores enteros (del 0 al 6). El programa los identifica con los nemnicos ya sealados. Cada enumeracin distinta constituye un tipo de enumerando diferente. Ejemplo: enum Calificacion {APTO, NO-APTO} c1; enum Evolucion {SUBE, BAJA, IGUAL} c2; c1 y c2 son objetos de tipo distinto. Puede omitirse la palabra clave enum si dia no es identificador de nada ms en el mismo mbito. El compilador sabe que se trata de una variable tipo enum por la sintaxis de la propia declaracin. Por ejemplo, es correcto: Dia { DOM, LUN, MART, MIER, JUEV, VIER, SAB } diaX; El identificador Dia es la etiqueta opcional del tipo, y puede ser usada en subsecuentes declaraciones de variables del mismo tipo:

M.C. JORGE ENRIQUE ESTRADA MUOZ

44

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

enum Dia laborable, festivo;

// declara dos nuevas variables

Aunque tambin se podra omitir el especificador enum (el compilador ya sabe que Dia es de tipo enum): Dia laborable, festivo; // equivalente al anterior

Como ocurre con las declaraciones de estructuras y uniones, si no existen otras variables del mismo tipo, puede omitirse la etiqueta con lo que tenemos un tipo annimo: enum { DOM, LUN, MART, MIER, JUEV, VIER, SAB } diaX; Tambin aqu (como ocurre con las estructuras y uniones), el inconveniente de declarar un tipo annimo es que despus no podemos volver a declarar otra variable del mismo tipo. enum diaX { DOM, LUN, MART, MIER, JUEV, VIER, SAB }; enum { DOM, LUN, MART, MIER, JUEV, VIER, SAB } diaX; En C, una variable enumerada puede recibir cualquier valor de tipo int sin que se realice ninguna otra comprobacin; en cambio C++ est fuertemente tipeado en este sentido, y a una variable enumerada solo se le puede asignar uno de sus enumeradores. Ejemplo: diaX = LUN; diaX = 1; // Ok. // Ilegal, a pesar que LUN == 1

Hay que recordar que, al ser mostradas por el dispositivo de salida, estas variables son promovidas a enteros y este es el valor mostrado. En el ejemplo anterior MART es mostrado como 2. En C++ se puede conseguir escribir el tipo enum sobrecargando adecuadamente el operador <<. La opcin por defecto es que el tipo enum es promovido a entero y se imprime el valor resultante. Como puede verse, las enumeraciones proporcionan un modo muy flexible de asociar nombres con valores, algo que tambin puede hacerse con los #define, sin embargo, las enumeraciones (an de un solo elemento) presentan ventajas entre las que podemos sealar: Los valores pueden ser auto-generados Las variables de enumeradas ofrecen la posibilidad de comprobacin. El depurador puede ser capaz de imprimir los valores de los enumeradores en su forma simblica (lo que facilita grandemente las comprobaciones). En la prctica, las enumeraciones proporcionan un lugar muy conveniente para almacenar constantes enteras como cdigos de error o de cualquier otro tipo que podamos manejar en nuestras aplicaciones. Por ejemplo: en lugar de utilizar #define ERROR_NO_ERROR 0 #define ERROR_NOT_FOUND 1 #define ERROR_BUSY 2 #define ERROR_FULL 3 ... Es ms conveniente utilizar un enumerador: enum ERRORS { NO_ERROR, NOT_FOUND, BUSY, FULL, ... } err;

M.C. JORGE ENRIQUE ESTRADA MUOZ

45

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

Los tipos enum pueden aparecer en cualquier sitio donde sea permitido un entero. Ejemplo: enum dias { LUN, MAR, MIER, JUEV, VIER, SAB, DOM } diaX; enum dias diapago; typedef enum dias DIAS; DIAS *diaptr; int i = MIER; diaX = LUN; // Ok. *diaptr = diaX; // Ok. LUN = MIER; // ILEGAL: LUN es una constante! Visibilidad Las etiquetas de los enum comparten el mismo espacio de nombres que los de estructuras y uniones. Los identificadores de los enumeradores comparten el mismo espacio que los identificadores de las variables ordinarias; de aqu se deduce que los nombres de los enumeradores de las distintas enumeraciones, tienen que ser diferentes (los valores no tienen porqu serlo ni an en la misma enumeracin). Ejemplo int dom = 11; { enum dias { dom, lun, mar, mier, juev, vier, sab } diaX; /* el enumerador dom oculta otra declaracion de int dom */ struct dias { int i, j;}; // ILEGAL: identificador dias ya usado double mar; // ILEGAL: redefinicion de mar } dom = 12; // int dom vuelve a ser visible Los enumeradores declarados dentro de una clase tienen la visibilidad de la clase. Ejemplo class Date { public: std::string day; std::string month; std::string year; enum fomrat { US, SP, UK, FR, DE }; int fm; }; ... void foo() { Date d1; d1.fm = Date::US; ... } Es pertinente recordar que, junto con las constantes estticas enteras, los enumeradores son las nicas propiedades que pueden inicializarse dentro de la definicin de la clase. Asignaciones a tipo enum

M.C. JORGE ENRIQUE ESTRADA MUOZ

46

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

En el compilador Borland C++ 5.5, las reglas para expresiones que contengan tipos enum pueden forzarse a ser ms estrictas activando el conmutador -A (que significa ANSI C++ estricto), con lo que el compilador refuerza las reglas con mensajes de error. As, al asignar un entero a una variable enum (como en el ejemplo) producira un error. enum color { Rojo, Verde, Azul }; int f() { color c; c = 0; // Incorrecto: a 'c' solo se le puede asignar Rojo, Verde o Azul return c; } En estos casos de compilacin estricta, se obtiene tambin un error cuando se pasa un entero como parmetro a una funcin que espera un enum o viceversa. Estudie el ejemplo propuesto teniendo en cuenta que el resultado de la expresin flag1|flag2 (OR inclusivo entre bits) es un entero. #include <iostream.h> enum En { flag1 = 0x01, flag2 = 0x02 }; int f1(En) { // L.3: return (flag1 + 1); } void f2() { int x = f1(flag1|flag2); // L.7: cout << "El valor es: " << x << endl; } int main () { f2(); return 0; } Aqu En es un tipo enum; los enumeradores flag1 y flag2 son constantes de enumeracin de valores 1 y 2 respectivamente, que han definidas en formato hexadecimal. Al intentar compilar se produce un error: Cannot convert 'int' to 'En' in function f2() ya que la invocacin a f1 en L7 espera un enum tipo En (como indica el prototipo de L3), pero se le pasa un int, ya que como se ha apuntado, la expresin flag1|flag2 produce un entero. Para arreglarlo, aplicamos un modelado de tipo al argumento pasado a la invocacin en L.7, que lo transforma en el tipo exigido, con lo que la compilacin se realiza sin novedad. #include <iostream.h> enum En { flag1 = 0x01, flag2 = 0x02 }; int f1(En) { // L.3: return (flag1 + 1); } void f2() { int x = f1(En (flag1|flag2) ); // L.7bis: cout << "El valor es: " << x << endl; }

M.C. JORGE ENRIQUE ESTRADA MUOZ

47

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

int main () { f2(); } Salida: El valor es: 2

Que es una unin.


Las uniones C++ son un tipo especial de clase; un tipo de variable con cierta similitud con las estructuras. Pueden albergar diferentes tipos de datos, pero solo uno, de entre todos los posibles, al mismo tiempo. Se dice que solo uno puede estar "activo" en cada momento, y se corresponden con los registros de tipo variable de Pascal y Modula-2. El tamao de una unin es el del mayor elemento que puede albergar. El valor exacto depende de la implementacin y de las alineaciones internas. Desde el punto de vista de su organizacin interna son como estructuras en las que todos sus miembros tuviesen el mismo desplazamiento respecto al origen. Desde un punto de vista funcional pueden ser considerados almacenamientos u objetos multiuso. En realidad las uniones son un recurso de programacin que permite alojar distintos tipos de objetos en un mismo espacio cuando estos objetos no coexisten en el tiempo y no hay suficiente memoria disponible para asignarles espacios distintos. Se trata por tanto de objetos muy especializados en cuanto a su uso, propio de aplicaciones muy "afinadas", de tiempos en que la memoria era un bien escaso, pero cuya utilizacin real es bastante raro y no se aconseja. Declaracin La sintaxis de declaracin es similar a las estructuras con las siguientes diferencias: a) Las uniones pueden contener campos de bits, pero solo uno puede estar activo. Todos comienzan en el principio de la unin y como consecuencia, dado que los campos de bits son dependientes de la implementacin, pueden presentar problemas para escribir cdigo portable. b) Un objeto que tenga constructor o destructor no puede ser utilizado como miembro de una unin. c) A diferencia de las estructuras, en las uniones C++ no se permiten los especificadores de acceso public, private y protected de las clases. Todos sus campos son pblicos. d) Las uniones solo pueden ser inicializadas en su declaracin mediante su primer miembro. Ejemplo: union local87 { int i; double d; } a = { 20 }; Ejemplo union miUnion { int i; double d; // definicin de unin de nombre miUnion

M.C. JORGE ENRIQUE ESTRADA MUOZ

48

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

char ch; char *ptr; } mu, *muptr=&mu;

// declara un objeto y un puntero al objeto

Aqu se ha definido un tipo nuevo de la clase unin, identificado como miUnion; se ha instanciado un objeto de dicha clase, denominado mu, que puede utilizarse para almacenar un int, (4 bytes), un double (8 bytes), o un char (1 byte), pero solo uno cada vez. El uso debe ser consistente con los valores almacenados en cada caso, cuestin que queda bajo responsabilidad del programador (esta es la razn principal para que se desaconseje su uso salvo caso de necesidad insoslayable). Si se lee un dato de tipo distinto al que se escribi, el resultado obtenido es dependiente de la implementacin. Una unin no puede participar en la jerarqua de clases; no puede ser derivada de ninguna clase, ni ser una clase base. Aunque s pueden tener un constructor y ser miembros de clases. Acceso a miembros Como en el caso de las estructuras, se dispone de dos operadores para referenciar los miembros de las uniones: . Selector directo (Selector directo de miembro) Una expresin del tipo Un.obj representa el objeto obj de la unin Un. La expresin es un Lvalue siempre que Un no lo sea y obj no sea una matriz. -> Selector indirecto (Selector indirecto de miembro) Una expresin del tipo uPtr -> obj representa el objeto obj de la unin Un siempre que uPtr sea un puntero a dicha unin. La expresin es un Lvalue siempre que obj no sea una matriz. Esta expresin es equivalente, y preferible, a (*uPtr).obj. El uso de uno u otro selector es indiferente. Depende de que se tenga un identificador de la unin, en cuyo caso puede usarse el selector directo (expresin Un.obj), o un puntero, en cuyo caso puede usarse el indirecto (expresin uPtr->obj). En cualquier caso, es necesaria cierta atencin como se muestra en el ejemplo (referido al objeto mu declarado anteriormente): mu.d = 4.016; // Se inicia mu printf("mu.d = %f\n",mu.d); //Ok. Salida: mu.d = 4.016 printf("mu.i = %d\n",mu.i); //?? resultado particular mu.ch = 'A'; printf("mu.ch = %c\n",mu.ch); //Ok. Salida: mu.ch = A printf("mu.d = %f\n",mu.d); //?? resultado particular muptr->i = 3; printf("mu.i = %d\n",mu.i); //Ok. Salida: mu.i = 3 El segundo printf es legal, dado que mu.i es un entero. El problema es que el patrn de bits que correspondera a mu.i coincide con parte del double previamente asignado en la primera sentencia, y su valor no tiene ningn sentido considerado aisladamente. Como se ha sealado, las uniones comparten muchas caractersticas con las estructuras, incluyendo la notacin. Adems, con las uniones estn permitidas las mismas operaciones que con las estructuras: asignacin o copia como una unidad; obtener su direccin, y acceder a un miembro. Tamao y alineacin

M.C. JORGE ENRIQUE ESTRADA MUOZ

49

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

Como en el resto de los objetos, su tamao puede ser establecido en tiempo de ejecucin con el operador sizeof y como se ha sealado, corresponde con el mayor de los elementos que pueda almacenar. Lo mismo que en las estructuras, tambin aqu se producen alineaciones en las direcciones de memoria de los miembros. Por ejemplo, si nos referimos a la unin anterior, las sentencias sizeof(union miUnion) y sizeof(mu), ambas devuelven 8; este es el tamao en bytes de la unin, que corresponde a la opcin ms desfavorable, cuando se almacena un double, pero cuando mu almacena un int existen 4 bytes desaprovechados, y 7 cuando se almacena un char. Uniones annimas Uniones annimas son aquellas que no tienen etiqueta y tampoco se utilizan para declarar un objeto nominado (con nombre). Tienen la forma general: union { lista-de-miembros }; Sus miembros pueden ser accedidos directamente en el mbito de su declaracin sin necesidad de usar ninguno de los operadores de acceso x.y o p->y. Ejemplo: #include <iostream.h> void main () { union { int i; double d; }; i = 25; cout << "El valor de '?.i' es: " << i << endl; } Salida: El valor de '?.i' es: 25 Las uniones annimas pueden ser globales, y anidadas o sin anidar. Ejemplo: #include <iostream.h> static union { int i; double d; } ; void main () { i = 15; cout << "El valor de '?.i' es: " << i << endl; union { int i; double d; }; i = 25; cout << "El valor de '?.i' es: " << i << endl; cout << "El valor de '?.i' es: " << ::i << endl; } Salida: El valor de '?.i' es: 15 El valor de '?.i' es: 25 El valor de '?.i' es: 15

M.C. JORGE ENRIQUE ESTRADA MUOZ

50

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

Las uniones annimas no pueden tener funciones miembro ni miembros privados o protegidos (todos son pblicos). Si son globales deben ser declaradas estticas, y sin son locales pueden ser estticas o automticas. En otras palabras: las uniones annimas no pueden tener enlazado externo. Ejemplo: #include <iostream.h> union { int i; double d; } ; void main () { cout << "El valor '?.i' es: " << i << endl; } Resulado de la compilacin: Borland C++: Error E2020 pru1.c 2: Global anonymous union not static Compilador GNU C++ 3.3.1 namespace-scope anonymous aggregates must be static Uniones annimas anidadas La estructura, clase o unin exterior de una unin annima anidada debe tener un nombre. C++ permite uniones annimas anidadas. Por ejemplo: struct externa { // define estructura nominada externa int x; union { // unin annima anidada int y; char c; }; }; ... int main(void) { struct externa ex1; // ex1 es una instancia de externa return ex1.x + ex1.y; }

Campo de bits.
Los campos de bits, o simplemente campos, son grupos de un nmero determinado de bits, que pueden o no tener un identificador asociado. Representan un artificio que permite utilizar miembros de tamao arbitrario en estructuras, uniones y clases; independiente de la posibilidad que proporcionan los tipos bsicos cuyo tamao est predeterminado por el lenguaje. Por ejemplo, en ocasiones es necesario almacenar semforos (flags) con determinados estados del programa, para los que en realidad solo hace falta un bit, pero incluso una variable bool ocupa un octeto. Los campos de bits permiten utilizar cada bit de un octeto independientemente, aumentando as su capacidad de representacin. Esta tcnica, de manejo independiente de bits en una palabra, ha sido ampliamente utilizada desde siempre en la programacin, no solo de C/C++; casi todos los lenguajes ofrecen la posibilidad de operadores "bitwise", que permiten esto de forma ms o menos artesanal.

M.C. JORGE ENRIQUE ESTRADA MUOZ

51

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

Entre otros usos, los campos de bits se han utilizado histricamente para empaquetar variables en un espacio ms pequeo, pero obligan al compilador a generar cdigo adicional para manejarlos, lo que resulta costoso en trminos de tamao y velocidad del ejecutable. El resultado es que frecuentemente, el cdigo resulta mayor y ms lento si se usan estos tipos, por lo que generalmente se desaconseja su uso excepto para aplicaciones muy especficas de bajo nivel, en las que la alineacin exacta de los patrones de bits a utilizar es un aspecto primordial. Por ejemplo, transmisiones de datos Otra cuestin distinta, a veces decisiva para su utilizacin, es la significativa reduccin de espacio de almacenamiento externo (disco por ejemplo) que puede conseguirse cuando en determinados casos, se almacena gran nmero de registros que utilizan campos de bits en sustitucin de tipos bsicos. Declaracin La sintaxis para declaracin de campos es la siguiente: especificador-de-tipo <identificador> : ancho; Ejemplos: int Uno : 8; unsigned int Dos : 16; int : 2; El especificador-de-tipo puede ser alguno de los siguientes: bool; char; unsigned char; short; unsigned short; long; unsigned long; int; unsigned int; __int64 o unsigned __int64. Abreviadamente lo denominaremos tipo del campo. El especificador ancho (abreviadamente ancho del campo), debe ser una expresin que se evale a un entero constante de cualquier tamao. Un campo de ancho cero salta a la prxima unidad de almacenamiento. Si se omite el identificador (tercera lnea del ejemplo), se asigna el ancho correspondiente, pero el campo no es accesible. Esto permite ajustar patrones de bits a espacios determinados. Por ejemplo, registros hardware donde algunos bits no son utilizados. Los campos de bits solo pueden existir en estructuras, uniones y clases, y son accedidos utilizando los mismos operadores de acceso que al resto de los miembros; los selectores . y ->. Limitaciones de uso El uso de campos de bits requiere algunas consideraciones a ser tenidas en cuenta: El cdigo puede no resultar portable, dado que la organizacin de bits dentro de bytes, y de estos dentro de palabras, depende de la plataforma utilizada en cada caso. Esta organizacin puede variar incluso dentro de las sucesivas versiones de un mismo compilador. Los campos de bits no son direccionables, es decir, no se les puede aplicar el operador de referencia &. As pues, la expresin que sigue es ilegal si cbit es el nombre de un campo de bits: &miEstruct.cbit // Ilegal !!

M.C. JORGE ENRIQUE ESTRADA MUOZ

52

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

No se les puede aplicar el operador sizeof Una alternativa recomendada para disponer de variables de un bit (semforos), es el uso de define (#define). Por ejemplo, los "defines": #define Nada 0x00 #define bitUno 0x01 #define bitDos 0x02 #define bitTres 0x04 #define bitCuatro 0x08 #define bitCinco 0x10 #define bitSeis 0x20 #define bitSiete 0x40 #define bitOcho 0x80 Pueden ser utilizados para escribir el siguiente cdigo: if (flags & bitUno) {...} flags |= bitDos; flags &= ~bitTres; // si primer bit ON... // pone bit dos ON // pone bit tres OFF

Se pueden usar esquemas similares para campos de bits de cualquier tamao. Relleno de campos Si el ancho del campo es mayor que el del tipo correspondiente, el compilador puede insertar bits de ajuste hasta alcanzar el tamao del tipo. As pues, la declaracin: struct mystruct { int x : 40; int y : 8; }; Crear un espacio de 32 bits para x ms un aadido de 8 bits, y crear para y un almacenamiento de 8 bits. Para optimizar el acceso, el compilador puede considerar x una variable regular, no un campo de bits (el proceso ser transparente para el usuario, para el que seguir siendo un campo de bits). Diseo y alineacin Los campos de bits se componen de grupos consecutivos de campos de bit del mismo tipo sin preocupacin del signo. Cada grupo de campo se alinea segn el tipo de los miembros del grupo. El tipo de alineacin viene determinado por el tipo y por lo especificado para la alineacin general por la opcin -aN del compilador. Dentro de cada grupo, el compilador puede empaquetar los campos individuales dentro de reas tan grandes como las de los tipos, pero ningn campo puede estar a horcajadas entre dos de estas reas. A su vez, el tamao total de la estructura puede ser alineado segn la alineacin general. El ejemplo que sigue muestra el diseo de campos de bits y el resultado del relleno y alineacin. La estructura mystruct contiene 6 campos de bits de tres tipos diferentes: int, long y char: struct mystruct { int Uno : 8;

M.C. JORGE ENRIQUE ESTRADA MUOZ

53

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

unsigned int Dos : 16; unsigned long Tres : 8; long Cuatro : 16; long Cinco : 16; char Seis : 4; }; Los campos Uno y Dos deben ser empaquetados en un rea de 32 bits. A continuacin, en caso necesario, el compilador inserta un relleno en base a la alineacin general y la del siguiente tipo (dado que el tipo cambia entre los campos Dos y Tres). En este caso, la alineacin general es (doble palabra por defecto), -a4 = 32 bits, con lo que se inserta un relleno de 8 bits (si la alineacin por defecto hubiese sido -a1 no hubiese sido necesario). A continuacin se empaquetan las variables Tres, Cuatro y Cinco, que a efectos son del mismo tipo long, pero no caben juntas en un rea de 32 bits; necesitan (8 + 16 + 16) 40 bits como mnimo, que es ms que los 32 bits permitidos para el tipo long. Para empezar una nueva rea para el campo Cinco, el compilador debe insertar un relleno de 8 bits (que no hubiese sido necesario si la alineacin hubiese sido tipo byte - media palabra). Al llegar al campo Seis el tipo cambia de nuevo. Puesto que los tipo char son siempre de alineacin tipo byte, no se necesita relleno para alinearla despus del campo Cinco. Llegados al final, la totalidad de la estructura diseada debe ajustarse a la alineacin global (doble palabra), de forma que para ajustar a mltiplos de 32 bits se insertan 12 bits de relleno (el relleno hubiesen sido 4 si se hubiese utilizado una alineacin global de media palabra). Para obtener los mejores resultados utilizando campos de bits debe procurar: Agrupar los campos por tipo (juntos los del mismo tipo). Asegurarse que estn empaquetados dentro de sus reas, ordenndolos de forma que ningn campo tenga que saltar los lmites de un rea. Asegurarse que la estructura est tan rellena como sea posible. Forzar alineacin de media palabra (byte) mediante la directiva #pragma option -a1. Si se desea conocer el tamao de la estructura, puede utilizarse la directiva #pragma sizeof(mystruct), que proporciona el tamao. Usar campos de un bit con signo Los valores posibles para campos con signo (signed) de un bit son 0 o 1. Para tipo sin singo (unsigned) de un bit son 0 o 1. Observe que si asigna 1 a un campo signed de un bit, el valor puede ser evaluado como -1 (uno negativo). Por las razones expuestas, cuando se almacenan valores verdadero y falso en un campo signed de un bit, no es posible comprobar utilizando la igualdad con true, porque los valores almacenados (0 y -1) no son compatibles con las constantes predefinidas true y false; es mejor chequear la desigualdad con cero. Para los campos sin signo (unsigned) de todos los tipos, incluyendo los booleanos, la verificacin de igualdad con true funciona correctamente. Por consiguiente:

M.C. JORGE ENRIQUE ESTRADA MUOZ

54

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

struct mystruct { int flag : 1; } M; int prueba() { M.flag = true; if (M.flag == true) printf("- Cierto -"); } El ejemplo anterior no funcionara adecuadamente. Sin embargo: struct mystruct { int flag : 1; } M; int prueba() { M.flag = true; if (M.flag) printf("- Cierto -"); } S funcionara en la forma esperada. Recuerde que: "cualquier valor cero, puntero nulo o puntero a miembro de clase nulo, se convierte a false. Cualquier otro valor se convierte a true". Por consiguiente, la expresin (M.flag) se evala a false si es cero; cualquier otro valor resultar true.

Typedef.
La palabra reservada typedef se utiliza para asignar un alias a un tipo. No crea ningn nuevo tipo, solo define un nuevo identificador para un tipo que ya tiene su propio identificador (el identificador puede ser un nombre o una expresin compleja que contiene al nombre). Es importante recalcar que el nuevo nombre es un aadido, y no sustituye al identificador original. Ambos identificadores pueden ser intercambiados libremente en cualquier expresin. Formalmente typedef es un especificador de identificador (nombre). Su introduccin en el lenguaje se debe a que, como reconoce su propio creador, la sintaxis de declaraciones C++ es innecesariamente dura de leer y escribir. Esto se debe a la herencia del C y a que la notacin no es lineal, sino que mimetiza la sintaxis de las expresiones que est basada en precedencias. En este sentido, la utilizacin de typedef permite paliar en parte el problema, mejora la legibilidad y ayuda a la documentacin y mantenimiento del programa, ya que permite sustituir identificadores de tipo complejos por expresiones ms sencillas. Sintaxis: typedef <tipo> <alias>; Asigna un nombre <alias> con el tipo de dato de <tipo>. Para distinguir un identificador <alias> introducido con un typedef de un nombre de tipo normal <tipo>, al primero se le denomina nombre-typedef ("typedef-name") o alias-typedef ("typedefalias"). Los typedef pueden ser usados con tipos simples o abstractos, pero no con nombres de funciones. Ejemplos:

M.C. JORGE ENRIQUE ESTRADA MUOZ

55

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

typedef unsigned char BYTE; En lo sucesivo, cualquier referencia a BYTE (es una tradicin de C/C++ utilizar los alias-typedef en maysculas) equivale a colocar en su lugar unsigned char, incluso para crear nuevos tipos unsigned char: BYTE z, y // equivale a: unsigned char z, y ... typedef const float KF; typedef const float* KF_PTR; KF pi = 3.14; KF_PTR ppi = &pi; typedef long clock_t; // no sera muy C++, mejor CLOCK_T clock_t slice = clock(); En realidad el nuevo identificador introducido por typedef se comporta dentro de su mbito como una nueva palabra-clave con la que pueden declararse nuevos tipos: typedef int* Pint; ... Pint p1, p2; // Ok. p1 y p2 son punteros-a-int Tambin pueden encadenarse, de forma que pueden definirse nuevos alias en funcin de otros definidos previamente. Por ejemplo: typedef char CHAR; typedef CHAR * PCHAR, * LPCH, * PCH, * NPSTR, * LPSTR, * PSTR ; Como en otras declaraciones, es posible definir una serie de alias-typedef mediante expresiones unidas por comas. Por ejemplo: typedef const char * LPCCH, * PCCH, * LPCSTR, * PCSTR ; ... LPCCH ptr1 = "Hola Amrica"; PCSTR ptr2 = "Hola Amrica"; const char* ptr3 = "Hola Amrica"; Los punteros ptr1; ptr2 y ptr3 son equivalentes. Otros ejemplos (tomados de definiciones reales de MS VC++) typedef long INT_PTR, *PINT_PTR; typedef unsigned short UHALF_PTR, *PUHALF_PTR; typedef short HALF_PTR, *PHALF_PTR; Asignaciones complejas Es til utilizar typedef para asignaciones complejas; en particular en la declaracin y definicin de punteros a funciones. Por ejemplo: typedef long (*(*(*FPTR)())[5])(); // L.1 FPTR an; // L.2

M.C. JORGE ENRIQUE ESTRADA MUOZ

56

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

La sentencia L.1 define un identificador: FPTR como un puntero a funcin que no recibe argumentos y devuelve un puntero a array de 5 punteros a funcin, que no reciben ningn parmetro y devuelven long. Despus, L.2 declara que an es un elemento del tipo indicado. typedef void (new * new_handler)(); // L.3 new_handler set_new_handler(new_handler); // L.4 L:3 define new_handler como el identificador de un puntero a funcin que no recibe argumentos y devuelve void. Despus L.4 declara set_new_handler como el nombre de una funcin que devuelve el tipo new_handler recin definido y acepta un nico argumento de este mismo tipo. typedef void (X::*PMF)(int); PMF pf = &X::func; // L.5 // L.6

L.5 define el identificador PMF como puntero a funcin-miembro de la clase X que recibe un int y no devuelve nada. L.6 declara pf como tipo PMF (puntero a funcin...) que apunta al mtodo func de X. Cuando se trata de expresiones muy complejas, puede ser til proceder por fases, aprovechando la propiedad ya enunciada de que pueden definirse nuevos alias en funcin de otros definidos previamente. Por ejemplo, queremos definir un puntero p a matriz de 5 punteros a funcin que toman un entero como argumento y devuelven un puntero a carcter. En este caso, puede ser conveniente empezar por las funciones: char* foo(int); // foo es una funcin aceptando int y devolviendo char typedef char* F(int); // F es un alias de funcin aceptando int y devolviendo... A continuacin definimos la matriz: F* m[5]; // m es una matriz de 5 punteros a F typedef F* M[5]; // M es el alias de una matriz de 5 punteros a F Finalmente escribimos la declaracin del tipo solicitado: M* p; Cualquier manipulacin posterior del tipo mencionado resulta ahora mucho ms sencilla. Por ejemplo, la declaracin: int* foo(M*); Corresponde a una funcin aceptando un puntero a matriz... que devuelve un puntero a int. En ocasiones, la simplificacin mencionada en el prrafo anterior, permite solventar algn que otro problema con la compilacin de expresiones complejas. Por ejemplo, un miembro de cierta clase tiene la siguiente declaracin: class MYClass { ... MyNAMESPACE::Garray<MyNAMESPACE::MyString> arrQuer; ... }

M.C. JORGE ENRIQUE ESTRADA MUOZ

57

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

Como sugiere su nombre, Garray es una clase genrica, destinada a almacenar matrices de objetos de cualquier tipo, est definida en el espacio de nombres MyNAMESPACE. En este caso, el objeto arrQuer es una matriz de objetos tipo MyString, que es una clase para manejar cadenas de caracteres -similar a la conocida string de la librera estndar de plantillas STL- tambin definida en MyNAMESPACE. En resumen, arrQuer es una matriz de cadenas de caracteres. Ocurre que deseo incluir una invocacin explcita para la destruccin del objeto arrQuer en el destructor de MYClass, Algo como: class MYClass { ... MyNAMESPACE::Garray<MyNAMESPACE::MyString> arrQuer; ... ~MYClass() { arrQuer.~MyNAMESPACE::Garray<MyNAMESPACE::MyString>(); } }

// Compiler error

Sin embargo, el compilador muestra un mensaje de error porque no es capaz de interpretar correctamente la sentencia sealada. En este caso, la utilizacin de un typedef resuelve el problema y el compilador construye sin dificultad la aplicacin. class MYClass { ... typedef MyNAMESPACE::Garray<MyNAMESPACE::MyString> ZSTR; ZSTR arrQuer; ... ~MYClass() { arrQuer.~ZSTR(); // Compilacin Ok. } } Tambin es posible utilizar typedef al mismo tiempo que se declara una estructura u otro tipo de clase. Ejemplo: typedef { double re, im; } COMPLEX; ... COMPLEX c, *ptrc, Arrc[10]; La anterior corresponde a la definicin de una estructura annima que puede ser utilizada a travs de su typedef. Por supuesto, aunque no es usual necesitar el nombre y el alias simultneamente, tambin se puede poner nombre a la estructura al mismo tiempo que se declara el typedef. Por ejemplo: typedef struct C1 { double re, im; } COMPLEX; ... C1 c, *ptrc; COMPLEX Arrc[10];

M.C. JORGE ENRIQUE ESTRADA MUOZ

58

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

Otro uso de typedef puede consistir en localizar determinadas referencias concretas en un solo punto (donde se declara el typedef), de forma que los posibles cambios posteriores solo requieren cambiar una lnea de cdigo. Por ejemplo, supongamos que necesitamos una variable de 32 bits y estamos utilizando C++Builder, en el que int tiene justamente 32 bits; a pesar de ello utilizamos la expresin: typedef int INT32; En lo sucesivo, para todas las referencias utilizamos INT32 en vez de int. Por ejemplo: INT32 x, y, z; Si tuvisemos que portar el cdigo a una mquina o a un compilador en el que int fuese menor y, por ejemplo, los 32 bits exigieran un long int, solo tendramos que cambiar la lnea de cdigo del typedef: typedef long INT32; // Todas las dems referencias se mantienen ... INT32 x, y, z; // Ok. No est permitido usar typedef con clases de declaracin adelantada. Por ejemplo sera incorrecto: typedef struct COMPLEX; // Ilegal!! Tampoco est permitido utilizarlo en la definicin de funciones o utilizar dos veces el mismo identificador en el mismo espacio de nombres: typedef long INT32; ... typedef float INT32;

// Error!!

Cuando el alias-typedef se refiere a una clase, se constituye en un nombre de clase. Este alias no puede ser utilizado despus de los prefijos class, struct o union. Tampoco puede ser utilizado con los nombres de constructores o destructores dentro de la clase. Ejemplo: typedef struct S { ... S(); // constructor ~S(); // destructor } STR; ... S o1 = STR(); // Ok. STR o2 = STR(); // Ok. struct STR* sp; // Error!! Observe que: typedef struct { ... S(); // Error!! ~S(); // Error!! } STR; ...

M.C. JORGE ENRIQUE ESTRADA MUOZ

59

ESTRUCTURA DE DATOS

MEMORIA DEL CURSO

S() y ~S() seran tratadas como funciones normales, no como constructor y destructor de la estructura. Cuando se quiere utilizar un alias para el identificador de un espacio de nombres, el mecanismo es distinto; no es necesario utilizar typedef.

M.C. JORGE ENRIQUE ESTRADA MUOZ

60

Das könnte Ihnen auch gefallen