Está en la página 1de 38

Starmedia Haz starMedia tu pgina de inicio

Correo Chat Videos

header

w eb

Buscador
top bsquedas

Runas Luces Fontanera

Correo
usuario latinmail.com

Autos Cine Clima Deportes Economa Entretenimiento Estudiantes Humor Juegos Mujer Noticias Vdeos

Inicio Documentos Tests Aulas Chuletas Amor Foros Postales Enva tus apuntes

Correo Ayuda Blog

publicidad

ir a starMedia

Noticias inslitas
Chcate estas imgenes que te sorprendern!!!

Entretenimiento
Entrate de los mejores chismes de los famosos!!!

Apuntadores en lenguajes de programacin


Informtica. Lenguaje C y C++. Variables. Memoria. Valores. Operadores booleanos. Inicializacin de apuntadores. Lnea de comandos
Informtica

Apuntadores en lenguajes de programacin


Ficha resumen del documento Versin PDF

Apuntadores en lenguajes de programacin Apuntadores en lenguajes de programacin


Versin para descargar

REPUBLICA BOLIVARIANA DE VENEZUELA MINISTERIO DE EDUCACIN SUPERIOR INSTITUTO UNIVERSITARIO DE TECNOLOGA CUMAN INFORMTICA II DEPARTAMENTO DE ELECTRICIDAD - MENCIN ELECTRNICA NDICE INTRODUCCIN Los apuntadores son una parte fundamental de C. Si usted no puede usar los apuntadores apropiadamente entonces esta perdiendo la potencia y la flexibilidad que C ofrece bsicamente. El secreto para C esta en el uso de apuntadores. C, usa los apuntadores en forma extensiva. Por qu?

Es la nica forma de expresar algunos clculos. Se genera cdigo compacto y eficiente. Es una herramienta muy poderosa.

C, usa apuntadores explcitamente con:

Es la nica forma de expresar algunos clculos.

Se genera cdigo compacto y eficiente. Es una herramienta muy poderosa.

C, usa apuntadores explcitamente con:

Arreglos, Estructuras y Funciones

El uso de apuntadores en C y C++ es muy importante debido a que permite hacer los programas ms eficientes y ms flexibles. En este artculo se explica de una manera sencilla y breve todo lo referente a la utilizacin de apuntadores tanto en C como en C++. Todo lo explicado en este artculo aplica tanto para C como para C++, a menos que se especifique un lenguaje en particular. En algunos ejemplos de cdigo que son aplicables a C aparecen instrucciones de entrada y salida de las libreras estndar de C++. LOS APUNTADORES:

Los apuntadores son variables que almacenan direcciones de memoria. En general una variable contiene un valor especfico dependiendo de como fue declarada. Un apuntador contiene la direccin de una variable que contiene un valor especfico. Una variable se refiere directamente a un valor y un apuntador se refiere indirectamente a un valor. Apuntadores usados en C debido a que a veces son la nica manera de expresar un clculo. Se puede llegar a obtener un cdigo ms compacto y eficiente. Cuando se emplean sin cuidado pueden crear programas imposibles de entender. Cuentan con una declaracin propia. Los apuntadores disponen de dos operadores: El operador unario o mondico & devuelve la direccin de memoria de una variable; El operador de indireccin o desreferencia * devuelve el ``contenido de un objeto apuntado por un apuntador''.

Declaracin De Apuntadores: Cuando se declara una variable, el compilador reserva un espacio de memoria para ella y asocia el nombre de sta a la direccin de memoria desde donde comienzan los datos de esa variable. Las direcciones de memoria se suelen describir como nmeros en hexadecimal. Un apuntador es una variable cuyo valor es la direccin de memoria de otra variable. Se dice que un apuntador apunta a la variable cuyo valor se almacena a partir de la direccin de memoria que contiene el apuntador. Por ejemplo, si un apuntador p almacena la direccin de una variable x, se dice que p apunta a x.

Los apuntadores como cualquier otra variable deben de ser declarados antes de que puedan ser utilizados.

El tipo de un apuntador lo proporciona implcitamente el tipo de la variable a la que apunta. Los apuntadores pueden ser declarados para apuntar a objetos de cualquier clase. La sintaxis general de declaracin es: <tipo> * <variable>

Ejemplos de declaraciones: La variable contPtr es del tipo apuntador a entero, (int *) y se lee ``contPtr es un apuntador a int'' o ``contPtr apunta a una variable entera''.

NOTA: Un apuntador a cualquier tipo de variables es una direccin en memoria, la cual es una direccin entera, pero un apuntador NO es un entero. La razn por la cual se asocia un apuntador a un tipo de dato, es por que se debe conocer en cuantos bytes esta guardado el dato. De tal forma, que cuando se incrementa un apuntador, se incrementa el apuntador por un ``bloque'' de memoria, en donde el bloque esta en funcin del tamao del dato. Por lo tanto para un apuntador a un char, se agrega un byt a la direccin y para un apuntador a entero o a flotante se agregan 4 bytes. De esta forma si a un apuntador a flotante se le suman 2, el apuntador entonces se mueve dos posiciones float que equivalen a 8 bytes. Los Operadores De Los Apuntadores: Un operador de direccin &: Representa la direccin de memoria de la variable que le sigue; Operador unario que regresa la direccin de su operando, ejemplo: main() { int y; int *yPtr; y = 5; yPtr = &y; } 2. Un operador de indireccin o de desreferencia: *. El operador * aplicado al nombre de un apuntador indica el valor de la variable apuntada; Regresa el valor del objeto hacia el cual su operando apunta, es decir un apuntador, ejemplo: main() { int x,y; int *py; y = 5; *py = y; x = *py + 5;

printf(''%d %d nn'',*py,x); }

Veamos con un ejemplo en C la diferencia entre todos estos conceptos Es decir: int x = 25, *pint; pint = &x; La variable pint contiene la direccin de memoria de la variable x. La expresin: *pint representa el valor de la variable (x) apuntada, es decir 25. La variable pint tambin tiene su propia direccin: &pint Inicializacin de APUNTADORES: < Almacenamiento > < Tipo > * < Nombre > = < Expresin > Si <Almacenamiento> es extern o static, <Expresin> deber ser una expresin constante del tipo <Tipo> expresado. Si <Almacenamiento> es auto, entonces <Expresin> puede ser cualquier expresin del <Tipo> especificado. Ejemplos: La constante entera 0, NULL (cero) proporciona un apuntador nulo a cualquier tipo de dato: int *p; p = NULL; //actualizacin El nombre de un arreglo de almacenamiento static o extern se transforma segn la expresin: a) float mat[12]; float *punt = mat; b) float mat[12]; float *punt = &mat[0]; Un cast apuntador a apuntador: int *punt = (int *) 123.456; Inicializa el apuntador con el entero. Esto es, en la direccin a la que apunta la variable punt se almacena el valor 123. Un apuntador a carcter puede inicializarse en la forma: char *cadena = Esto es una cadena; Se pueden sumar o restar valores enteros a las direcciones de memoria en la forma: (aritmtica de APUNTADORES)

static int x; int *punt = &x+2, *p = &x-1; Equivalencia: Dos tipos definidos como APUNTADORES a objeto P y apuntador a objeto son equivalentes slo si P y Q son del mismo tipo. Aplicado a matrices: nombre_apuntador = nombre_matriz; Apuntadores y Funciones: Cuando C pasa argumentos a funciones, los pasa por valor, es decir, si el parmetro es modificado dentro de la funcin, una vez que termina la funcin el valor pasado de la variable permanece inalterado. Hay muchos casos que se quiere alterar el argumento pasado a la funcin y recibir el nuevo valor una vez que la funcin ha terminado. Para hacer lo anterior se debe usar una llamada por referencia, en C se puede simular pasando un puntero al argumento. Con esto se provoca que la computadora pase la direccin del argumento a la funcin. Para entender mejor lo anterior consideremos la funcin swap() que intercambia el valor de dos argumentos enteros: void swap(int *px, int *py); main() { int x, y; x = 10; y = 20; printf("x=%d\ty=%d\n",x,y); swap(&x, &y); printf("x=%d\ty=%d\n",x,y); } void swap(int *px, int *py) { int temp; temp = *px; /* guarda el valor de la direccion x */ *px = *py; /* pone y en x */ *py = temp; /* pone x en y */

APUNTADORES Y ARREGLOS:

Existe una estrecha relacin entre apuntadores y arreglos, tanto que pueden ser usados en forma casi indistinta. En C, un nombre de un arreglo es un ndice a la direccin de comienzo del arreglo. En esencia, el nombre de un arreglo es un puntero al arreglo. Una variable de tipo arreglo puede considerarse como un apuntadora tipo del arreglo. Los apuntadores pueden ser utilizados en cualquier operacin que involucre subndices de arreglos.


Ejemplo: main() {

int tabla[10],i,x,*pt,*ptr; pt = &tabla[0]; x = *pt; for (i=0; i!10; i++) *(pt+i) = random(); ptr = tabla; for (i=0; i!10; i++) printf(''%d nn'',*(ptr+i),tabla[i]); }

Cuando se suma 1 a un apuntador el incremento se adecua al tamao en memoria del objeto apuntado. Un apuntador es una variable, por lo que operaciones como pa = a y pa++ son permitidas.

Un nombre de un arreglo es una constante, no una variable, de ah que a = pa o a++ o p = a. Arreglos de apuntadores:

Los arreglos pueden contener apuntadores. El uso ms comn es el de formar arreglos de cadenas de caracteres. Cada entrada en el arreglo es un apuntador al primer carcter de la cadena. Sea la declaracin: char * mensaje[4] = {''Hola'',''Adios'',''Bye'',''Salut''}

Cada cadena est almacenada en memoria como una cadena de caracteres terminada en NULL n0. En el arreglo no estn colocadas las cadenas, tan solo estn almacenados los apuntadores.

Aunque el arreglo es de tamao fijo, permite el acceso a cadenas de caracteres de cualquier longitud.

En C se pueden tener arreglos de apuntadores ya que los apuntadores son variables. A continuacin se muestra un ejemplo de su uso: ordenar las lneas de un texto de diferente longitud. Los arreglos de apuntadores son una representacin de datos que manejan de una forma eficiente y conveniente lneas de texto de longitud variable. Cmo se puede hacer lo anterior? Guardar todas las lneas en un arreglo de tipo char grande. Observando que \n marca el fin de cada lnea. Ver figura 1.1. Guardar los apuntadores en un arreglo diferente donde cada apuntador apunta al primer caracter de cada lnea. Comparar dos lneas usando la funcin de la biblioteca estndar strcmp(). Si dos lneas estn desacomodadas -- intercambiar (swap) los apuntadores (no el texto).

Figura 1.1: Arreglos de apuntadores (Ejemplo de ordenamiento de cadenas). Con lo anterior se elimina:

El manejo complicado del almacenamiento. Alta sobrecarga por el movimiento de lneas.

Apuntadores y arreglos multidimensionales:

Puede provocar confusin el uso de arreglos de dos dimensiones y un arreglo de apuntadores. Considerar:

int a[10][10]; int *b[10];

El uso de a y b puede ser parecido, desde el momento en que a[5][5] y b[5][5] son referencias validas a un int El arreglo a es un arreglo verdadero, existen 100 celdas de memoria asignadas y se efecta el clculo de subndices rectangulares convencional para localizar un elemento dado Sin embargo, a b la declaracin solo le asigna 10 apuntadores, cada uno de los cuales deber de apuntar a un arreglo de enteros La desventajas de b son: Ocupa ms espacio, suponiendo que cada uno apunta a un arreglo de 10 elementos, el tamao ser de 10 apuntadores ms 100 elementos. Se debe de crear el espacio de los arreglos antes de asignarlos.

o o o

La declaracin b tiene dos ventajas: El acceso se hace ms rpido, una indereccin es ms rapida que el hacer una multiplicacin seguida de una suma. El tamao de los arreglos apuntados por cada una de las diez localidades pueden ser diferentes.

Un arreglo multidimensional puede ser visto en varias formas en C, por ejemplo: Un arreglo de dos dimensiones es un arreglo de una dimensin, donde cada uno de los elementos es en s mismo un arreglo. Por lo tanto, la notacin a[n][m] nos indica que los elementos del arreglo estn guardados rengln por rengln. Cuando se pasa una arreglo bidimensional a una funcin se debe especificar el nmero de columnas -- el nmero de renglones es irrelevante. La razn de lo anterior, es nuevamente los apuntadores. C requiere conocer cuantas son las columnas para que pueda brincar de rengln en rengln en la memoria. Considerando que una funcin deba recibir int a[5][35], se puede declarar el argumento de la funcin como: f( int a[][35] ) { ..... } o an f( int (*a)[35] ) { ..... }

En el ltimo ejemplo se requieren los parnteis (*a) ya que [ ] tiene una precedencia ms alta que *. Por lo tanto: int (*a)[35]; declara un apuntador a un arreglo de 35 enteros, y por ejemplo si hacemos la siguiente referencia a+2, nos estaremos refiriendo a la direccin del primer elemento que se encuentran en el tercer rengln de la matriz supuesta, mientras que int *a[35]; declara un arreglo de 35 apuntadores a enteros. Ahora veamos la diferencia (sutil) entre apuntadores y arreglos. El manejo de cadenas es una aplicacin comn de esto. Considera: char *nomb[10]; char anomb[10][20]; En donde es vlido hacer nomb[3][4] y anomb[3][4] en C. Sin embargo:

anomb es un arreglo verdadero de 200 elementos de dos dimensiones tipo char. El acceso de los elementos anomb en memoria se hace bajo la siguiente frmula 20*renglon + columna + direccin_base En cambio nomb tiene 10 apuntadores a elementos.

NOTA: si cada apuntador en nomb indica un arreglo de 20 elementos entonces y solamente entonces 200 chars estarn disponibles (10 elementos). Con el primer tipo de declaracin se tiene la ventaja de que cada apuntador puede apuntar a arreglos de diferente longitud. Considerar: char *nomb[] = { "No mes", "Ene", "Feb", "Mar", .... }; char anomb[][15] = { "No mes", "Ene", "Feb", "Mar", ... }; Lo cual grficamente se muestra en la figura 1.2. Se puede indicar que se hace un manejo ms eficiente del espacio haciendo uso de un arreglo de apuntadores y usando un arreglo bidimensional.

Figura 1.2: Arreglo de 2 dimensiones VS. arreglo de apuntadores. Diferentes formas de declarar a[i][j]: Cuando se ve la referencia a un arreglo de dos dimensiones, a[i][j] , no se puede deducir inmediatamente como fue declarado a :

Como un arreglo de 10 arreglos de tamao 20 int a[10][20];

Como un arreglo de tamao 20 de vectores de longitud variable int *a[10];

Como un apuntador de apuntadores a enteros int **a;

Como un apuntador a un arreglo de enteros de tama~no 20 int (* a)[20];

Para poder direccionar un elemento de un apuntador de apuntadores se sigue la regla: tab[i][j] * ( *(tab + i) + j)

ARGUMENTOS EN LA LNEA DE COMANDOS:

Existe una forma de transmitr al programa los argumentos de la lnea de comando, o parmetros, cuando comienza la ejecucin Cuando se invoca el main() se le puede pasar dos argumentos, (los nombres son por convencin): argc es el nmero de argumentos en la lnea de comandos. argv[] es un apuntador a un arreglo de cadena de caracteres que contienen los argumentos, uno por cadena Ejemplo de uso: main( int argc, char *argv[]) { int i; for (i=0; i!argc; i++) printf(''Argumento %d :'' %s'',); }

Ya que el primer elemento del arreglo, ( *argv[] ) apunta a la cadena que contiene el nombre del comando, argc es al menos igual a 1. Esta estructura de datos es creada por el sistema operativo, (Unix u otro), por lo que la nica preocupacin del programador es usarla, no generarla.

Fallas comunes con apuntadores: A continuacin se muestran dos errores comunes que se hacen con los apuntadores:

int *x *x = 100;

No asignar un apuntador a una direccin de memoria antes de usarlo:

lo adecuado ser, tener primeramente una localidad fsica de memoria, digamos int y; int *x, y; x = &y; *x = 100;

Indireccin no vlida:

Supongamos que se tiene una funcin llamada malloc() la cual trata de asignar memoria dinmicamente (en tiempo de ejecucin), la cual regresa un apuntador al bloque de memoria requerida si se pudo o un apuntador a nulo en otro caso.

char *malloc() -- una funcin de la biblioteca estndar que se ver ms adelante. Supongamos que se tiene un apuntador char *p Considerar: *p = (char *) malloc(100): /* pide 100 bytes de la memoria */ *p = 'y'; Existe un error en el cdigo anterior. Cul es? El * en la primera lnea ya que malloc regresa un apuntador y *p no apunta a ninguna direccin. El cdigo correcto deber ser: p = (char *) malloc(100); Ahora si malloc no puede regresar un bloque de memoria, entonces p es nulo, y por lo tanto no se podr hacer: *p = 'y'; Un buen programa en C debe revisar lo anterior, por lo que el cdigo anterior puede ser reescrito como: p = (char *) malloc(100): /* pide 100 bytes de la memoria */ if ( p == NULL ) { printf("Error: fuera de memoria\n"); exit(1); } *p = 'y'; Apuntadores de mayor complejidad: int *p; int *p[10]; int (*p)[10]; int *p(void); int p(char *a); int *p(char *a); int (*p)(char *a); p es un apuntador a un entero p es un arreglo de 10 apuntadores a enteros p es un apuntador a un arreglo de 10 enteros p es una funcin que devuelve un apuntador a entero

p es una funcin que acepta un argumento que es un apuntador a carcter, dev un entero

p es una funcin que acepta un argumento que es un apuntador a carcter, dev un apuntador a entero p es un apuntador a funcin que acepta un argumento que es un apuntador

carcter, devuelve un apuntador a entero int (*p(char *a))[10]; int p(char (*a)[]); int p(char *a[]); int *p(char a[]); int *p(char (*a)[]); int *p(char *a[]); int (*p)(char (*a)[]); int *(*p)(char (*a)[]); int *(*p)(char *a[]); int(*p[10])(void); int (*p[10])(char * a); int *(*p[10])(char a); char *(*p[10])(char * a);

p es una funcin que acepta un argumento que es un apuntador a carcter, dev un apuntador a un arreglo de 10 enteros

p es un apuntador a funcin que acepta un argumento que es un apuntador a arreglo de caracteres, devuelve un apuntador a entero

p es un apuntador a funcin que acepta un argumento que es un arreglo de apuntadores a caracteres, devuelve un apuntador a entero

p es una funcin que acepta un argumento que es un arreglo de caracteres, dev un apuntador a entero p es una funcin que acepta un argumento que es un apuntador a un arreglo caracteres, devuelve un apuntador a entero p es una funcin que acepta un argumento que es un apuntador a un arreglo apuntadores a caracteres, devuelve un apuntador a entero p es una funcin que acepta un argumento que es un apuntador a un arreglo caracteres, devuelve un apuntador a entero

p es un apuntador a una funcin que acepta un argumento que es un apuntador arreglo de apuntadores a caracteres, devuelve un apuntador a entero p es un apuntador a una funcin que acepta un argumento que es un arreglo apuntadores a caracteres, devuelve un apuntador a entero

p es una arreglo de 10 apuntadores a funcin, cada funcin devuelve un ente

p es un arreglo de 10 apuntadores a funcin; cada funcin acepta un argumento es un apuntador a carcter y devuelve un entero

p es un arreglo de 10 apuntadores a funcin; cada funcin acepta un argumento es un carcter, y devuelve un apuntador a entero

p es un arreglo de 10 apuntadores a funcin; cada funcin acepta un argumento es un carcter, y devuelve un apuntador a carcter. BIBLIOGRAFA

El presente articulo fue realizado con la ayuda de:

El libro Programacin en C++, del autor Lus Joyanes Aguilar, editorial Mc Graw Hill. Y las siguientes paginas de Internet:

http://webdia.cem.itesm.mx/ac/rogomez/Tutorial-LengC/apuntadores.html http://www.ldc.usb.ve/~gabro/teaching/CI2126/Clase1_Apuntadores.htm http://www.itq.edu.mx/vidatec/maestros/sis/mlopez/Tutorial/apunt.htm http://garota.fismat.umich.mx/mn1/manual/node9.html http://www.geocities.com/eztigma/apuntadores.html 18 INTEGRANTE:

Eduardo R., Aranguren P.; 15.743.681

GRUPO: 02 FECHA DE ENTREGA: 28/05/2007 int *contPtr, cont; float *res; unsugned int *nosigno; char *mensaje;

El Rincn del Vago, en Salamanca desde 1998 - Condiciones de Uso - Contacto

footer

w eb

Buscador
Copyright 2011 Orange

Publicidad Contctanos Mapa web Acerca de Orange

Mexico USA Colombia Argentina Chile Per Espaa Venezuela Ecuador Brasil Puerto Rico Panam Rep.Dominicana Costa Rica Guatemala Bolivia Uruguay El Salvador

Paraguay Nicaragua Honduras Cuba

C++ Estndar
Programacin con el Estndar ISO y la Biblioteca de Plantillas (STL) Paraninfo Thomson Learning 2001

Ejercicios resueltos por captulos.


Aqu encontrar los ejercicios resueltos por captulos (Tambin puede descargarse un fichero comprimido con todos los fuentes de los ejercicios)

PARTE I 1. Introduccin
No tiene ejercicios.

2. Conceptos bsicos
2.1) Quedara del siguiente modo: , hay otros tipos de comentarios como los de C++: empezar un comentario tipo C y ahora lo acabo. */ / * Que comentario ms precioso * / / / Este es ms precioso todava. 2.2) Si en un programa no ponemos la funcin main(), el programa no se podra enlazar. Si ponemos dos funciones main() ocurre lo mismo, el compilador da un error de redefinicin de una funcin. 2.3) El programa puede parecer a primera vista muy sencillo. En primer lugar vamos a leer y escribir una cadena. La primera solucin intuitiva:

#include <iostream> // USAMOS: cin, cout void main() { char s[20]; // Cadena de hasta 19 caracteres cin >> s; // Leer la primera palabra cout << endl << s // Escribir en nueva lnea la cadena << endl; // Y pasar a la lnea siguiente } El problema es que esto nicamente nos lee la primera palabra de una cadena (esto se explicar en el captulo de entrada/salida). Aunque no se comprenda de momento, la solucin se encuentra en el fichero EJ02_03.CPP 2.4) Aqu est el programa: #include <iostream> // USAMOS: cin, cout void main() { double d1, d2; out << "Introduce dos reales: "; cin >> d1 >> d2; cout << "La suma es: " << d1 + d2 << endl } 2.5) El programa correcto es ste: #include <iostream.h> // USAMOS: cout void main() { cout << "Hola mundo"; } 2.6) S es correcta. 2.7) Este comentario es errneo. Hemos dicho que los comentarios no se detectan en las cadenas. Pues no es completamente cierto. No se detecta su apertura pero s su clausura. Por ello, las sentencias se convertiran en: "; */ La solucin sera definir de nuevo las sentencias como: /* cout << "/* Me pillaste *""/"; // Concatenacin de cadenas */

3. Tipos de datos
3.1) La funcin es: int Convierte(char c) { return int(c - '0');

} // Usando int() en vez de (int) se ahorra un par de parntesis 3.2) S que es vlido ya que en C++ todos los tipos integrales son compatibles. Aunque sera mucho mejor explicitar las conversiones: b= (byte)w; w= (word)l; d= (dword)w; 3.3) Su longitud es 9 tomando

sizeof(int) == 2.

3.4) La primera dar error ya que 8 no es un dgito octal y por tanto 08 es un error. La segunda dar 24 porque 014 est en octal que es 12 en decimal.

4. Control de Flujo
4.1) El listado es funcionalmente correcto pero sintcticamente no. Faltan los puntos y comas de las cuatro sentencias de asignacin. if (a < b) if (a < c) min= a; else min= c; else if (b > c) min= c; else min= b; 4.2) Programa que cuenta el nmero de ocurrencias en una cadena de las 5 vocales en 5 variables diferentes: a, e, i, o, u. Usaremos la funcin Leer_Cadena() del ejercicio 2.3. El programa est en EJ04_02.CPP 4.3) Una funcin que calcule el M.C.D. de dos nmeros: int Mcd(int a, int b) { if (a <= 0 || b <= 0) return -1; // Cdigo de error while (a != b) if (a < b) b= b - a; // b-= a; // Igual que la anterior. Ya se ver else a= a - b; // a-= b; // Igual que la anterior return a; // Al final el mcd est en a y en b (a == b) } Un ejemplo de uso de la funcin est en EJ04_03.CPP 4.4) Funcin que compara dos cadenas:

int StrCmp(char *s1, char *s2) { int i= 0; while (s1[i] || s2[i]) { // Hasta terminar las dos if (s1[i] < s2[i]) return -1; // La cadena 1 es menor que la 2 else if (s1[i] > s2[i]) return 1; // La cadena 1 es mayor que la 2 i++; } return 0; // Las cadenas son iguales } Esta funcin es similar a strcmp() de la librera estndar <cstring> del C++. Un ejemplo de uso de la funcin est en EJ04_04.CPP 4.5) Slo la b) es correcta. Recordemos que la sentencia: for(a; b; c); se convierte en: { a; while(b) { d; c; } } Por tanto, las sentencias anteriores son: a) int i= 0, int j= 0; // Incorrecto // Dos declaraciones separadas por una coma while .. b) int i= 0, j= 0; // Correcto // Dos declaraciones de tipo entero while .. c) int i= 0, long j= 0; // Incorrecto while .. d) (int i = 0), (long j = 0) // Incorrecto // Lstima porque era una buena idea 4.6) La solucin se encuentra en el fichero EJ04_06.CPP 4.7) En este ejercicio se ha pretendido aumentar la atencin del lector en este error comn y sutil pero difcil de detectar. La condicin del bucle est formada por el operador de asignacin (=) y no el operador de comparacin (==), con lo que el resultado del programa es que slo muestra un 0, ya que el resultado de la asignacin i=10, adems de asignar 10 a la variable i, es que devuelve el valor 10, que es un valor cierto, al ser no nulo. Si despus lo negamos con el operador ! obtenemos falso, con lo que el bucle sale despus de la primera iteracin.

4.8) La solucin se encuentra en el fichero EJ04_08.CPP 4.9) La solucin se encuentra en el fichero EJ04_09.CPP 4.10) La solucin se encuentra en el fichero EJ04_10.CPP 4.11) La solucin se encuentra en el fichero EJ04_11.CPP

5. Operadores
5.1) Es simple: x & (x - 1) 5.3) Se supone que tenemos dos valores enteros almacenados en dos variables reales. Yo lo hara as: float Resto(float a, float b) { return float((long)a % (long)b); } 5.4) NO ES VLIDO PORQUE EL OPERADOR COMA NO SE PUEDE UTILIZAR EN ESE PARTE DEL FOR. Si cogemos uno de los dos incementos y lo ponemos al final del bucle s que funciona. En este caso invierte el vector de caracteres s (no es una cadena porque no acaba en '\0'). El resultado en s ser ACABATOR. 5.5) Con algo parecido a esto sera suficiente para que pareciera aleatorio. Si adems hacemos coincidir la llamada a Rand() con un factor externo (tiempo, preferiblemente), esta funcin es casi impredecible. El programa se encuentra en EJ05_05.CPP

6. Funciones
6.1) La solucin se encuentra en el fichero EJ06_01.CPP 6.2) La solucin se encuentra en el fichero EJ06_02.CPP 6.3) Es sintcticamente correcto. El compilador crea variables temporales para almacenar estas constantes y as ya puede tomar la direccin. De todas formas no es un buen estilo de programacin pasar constantes por referencia porque aunque la funcin modifique su valor no nos podemos dar cuenta. 6.4) La llamada f(25) es ambigua. El compilador no sabe si llamar a la funcin con un argumento o llamar a la segunda usando parmetros por defecto. La llamada f(17, 42) es completamente correcta ya que no hay ambigedad. 6.5) S que es correcto y sera equivalente a: void f(int a= 1, int b= 2, int c= 3) { // .. } 6.6) La solucin se encuentra en el fichero EJ06_06.CPP

7. Variables
7.1) Las variables estticas se inicializan a 0. Las variables automticas no. Por tanto a valdr 0 y b tendr un valor indefinido dependiendo del compilador. No se recomienda usar la declaracin de 'a' de ese modo. Es mejor explicitar: int a= 0; 7.2) Este sera un programa que volvera loco al propio Bjarne Stroustrup: void Funcion(float f); // Decl1. Campo prototipo float f; // Decl 2. Campo global. Se almacena en el seg. de datos. f vale 0 void Funcion(float f) { // Decl. 2. Campo local automtico. Se almacena en pila float f; // Error: parmetros y var. locales tienen el mismo campo auto float a; // Este auto es opcional // Decl.3.Campo local automtico. Se almacena en pila. a vale ? static float f; // Error: mismo campo. static float s; // Decl.4.Campo local esttico. Se almac. en el s. de datos. s vale 0 { float f; // Decl. 5. Campo de bloque. Se almacena en la pila f= 2; // Accedo a la 'f' de la decl. 5 ::f= 3; // Accedo a la 'f' de la decl. 1 s= 4; // Accedo a la 's' de la decl. 4 a= 5.5; // Accedo a la 'a' de la decl. 3 // No hay forma de acceder al parmetro 'f' de la funcin (Decl. 2) } } float f; // Error! Redefinimos la variable global. 7.3) Como hemos visto en el caso anterior, no es correcto ya que los dos tienen el mismo campo local automtico. 7.4) Dar un error en la definicin const int a ya que las constantes se deben inicializar en el momento de la definicin. Las otras dos tambin daran error. 7.5) No sera equivalente a: const char * Var;

sino a: char * const Var; porque

typedef no es una macro.

7.6) El programa A funciona correctamente. El programa B da error porque no sabemos cmo es la estructura, por tanto, no podemos definir una variable de ella. El programa C funcionara si no se tratara de una estructura. Ya se vio que extern slo es aplicable a variables de tipos no compuestos. 7.7) Este sera un programa que volvera loco al propio Bjarne Stroustrup: void Funcion(float f); // Decl1. Campo prototipo float f; // Decl 2. Campo global. Se almacena en el seg. de datos. f vale 0 void Funcion(float f) { // Decl. 2. Campo local automtico. Se almacena en pila float f; // Error: parmetros y var. locales tienen el mismo campo auto float a; // Este auto es opcional // Decl.3.Campo local automtico. Se almacena en pila. a vale ? static float f; // Error: mismo campo. static float s; // Decl.4.Campo local esttico.Se almac. en el s. de datos. s vale 0 { float f; // Decl. 5. Campo de bloque. Se almacena en la pila f= 2; // Accedo a la 'f' de la decl. 5 ::f= 3; // Accedo a la 'f' de la decl. 1 s= 4; // Accedo a la 's' de la decl. 4 a= 5.5; // Accedo a la 'a' de la decl. 3 // No hay forma de acceder al parmetro 'f' de la funcin (Decl. 2) } } float f; // Error! Redefinimos la variable global.

8. Sobrecarga y conversiones
8.1) En C++, las constantes tienen tipo por lo que el compilador asignar: - la primera es un

int . Coincidencia exacta con Print(int ).

- la segunda es un double. No hay coincidencia exacta ni trivial. No hay promocin. Hay conversin estndar. Pero las conversiones estndar de un tipo aritmtico puede ser a cualquier otro tipo aritmtico. Por tanto, fallar porque hay una ambigedad. Podramos haberlo solventado poniendo 2.2F. - la tercera es un char. No hay coincidencia exacta ni trivial. Pero hay promocin con int; por tanto, se llama a Print(int ). En general, las posibles soluciones a los problemas que aparecen (como el de la segunda llamada) son: a) Declarar variables auxiliares del tipo que se desee. b) Forzar que las constantes sean del tipo requerido. c) Utilizar conversiones explcitas (cast) 8.2) S, no hay coincidencia exacta o trivial, no hay promociones, pero hay conversin estndar aritmtica. Por tanto, se llama sin ningn problema. 8.3) No porque tomar f() como float y no como una funcin. Concretamente, dar un error de llamada a no-funcin ("call of non-function") ya que estamos intentando llamar a un float como si fuera una funcin. 8.4) La solucin se encuentra en el fichero EJ08_04.CPP 8.5) La solucin se encuentra en el fichero EJ08_05.CPP 8.6) Dara error al haber conversin trivial entre

const T y T.

8.7) Como no hay conversin trivial, se podra definir perfectamente. 8.8) Las dos primeras llamadas invocan a sus funciones correspondientes sin ningn problema. La tercera sigue estos pasos: Primero: no hay coincidencia exacta. Segundo: no hay promocin. Tercero: conversin estndar, pero la hay a los dos, no le damos preferencia a la que no tiene signo. Por tanto dara error de ambigedad. 8.9) La solucin se encuentra en el fichero EJ08_09.CPP 8.10) La solucin se encuentra en el fichero EJ08_10.CPP 8.11) Son correctas. Se trata de conversiones de lnea. 8.12) En C++,

typedef no crea tipos nuevos distintos, slo les da un nombre diferente.

8.13) Para las cinco llamadas, el proceso es bien diferente: 1.- El literal 0.0 es un double. Pasos: Primero: coincidencia exacta. Por tanto se llama a f(double ). 2.- El literal 0 es un int. Pasos: Primero: no hay coincidencia exacta. Segundo: no hay promocin posible. Tercero: hay conversin estndar de int a char y de int a

double. Adems, dijimos que la constante 0 tiene conversin estndar con cualquier
puntero. Por tanto habr error de ambigedad al no poder elegir ninguna de las tres funciones. 3.- El literal

0F da error de sintaxis, ya que F slo se puede aplicar a constantes reales.

4.- El literal 0.0F es un float. Pasos: Primero: no hay coincidencia exacta. Segundo: hay promocin de float a double. Por tanto se llama a f(double ). 5.- El literal cadena es un char *. Pasos: Primero: no hay coincidencia exacta. Segundo: no hay promocin. Tercero: hay conversin estndar entre char * y *. Por tanto se llama a f(void *).

void

8.14) Para la primera combinacin, la segunda llamda es correcta (mismo tipo), pero la primera no, porque no hay conversin estndar desde int a enum. Como si est permitido lo contrario, la combinacin dos es perfectamente correcta. La combinacin tercera tambin lo es, llamando cada una a su correspondiente funcin. 8.15) El compilador da un error de ambigedad, ya que no sabe si llamar a ff(fc) con signo. Qu complicados son los complicadores!

ff(fc) sin signo o

9. Punteros
9.1) El primero carga en p la direccin de la variable a se destruye con lo que el acceso posterior de (*p=

a (p= &a), pero al cerrarse el bloque la variable 10) puede ser catastrfico.

El segundo programa, en cambio, funciona correctamente ya que el carcter a tratar se almacena en el 'heap' y no en la pila, as al cerrar el bloque no destruimos ninguna variable ya que no hemos definido ninguna tampoco. El acceso (*p= 10) ser vlido hasta que pongamos (delete p;). Una mejor solucin sera: void main() { char *p; int a; { p= &a; } *p= 10; } 9.2) Invierte una cadena. La solucin se encuentra en el fichero EJ09_02.CPP 9.3) La solucin se encuentra en el fichero EJ09_03.CPP 9.4) La solucin se encuentra en el fichero EJ09_04.CPP

9.5) La solucin se encuentra en el fichero EJ09_05.CPP 9.6) Ese programa es muy peligroso. Leemos una cadena en s, pero s apunta a una direccin indefinida; por ello, podemos estar estropeando cdigo, datos de nuestro o de otro programa. Adems no se puede asegurar que la salida sea igual que la entrada. En fin, que este es uno de los errores ms graves y tpicos del C++. Adems, puede que en un primer momento funcione. Ms tarde el error aparecer inesperadamente de forma catastrfica. La solucin es reservar la memoria que vamos a usar: #include <iostream.h> void main() { char s[100]; // Suponemos que con 100 caracteres es suficiente cin >> s; cout << s; } Tambin podramos haber usado: #include <iostream.h> void main() { char *s; s= new int[100]; cin >> s; cout << s; delete []s; } 9.7) No ocurre nada, al final del programa el compilador se encarga de hacer todos los delete que falten. De todas formas, es muy recomendable no olvidarse de ponerlo porque si es en una funcin que se llama 1000 veces acabaremos con el 'heap' lleno!. Tampoco es muy recomendable hacer lo que se ha hecho en el ejercicio 1, pero a veces como en ese ejercicio, es necesario. 9.8) Para hacer lo que se nos pide en el ejercicio habra que hacer uso de punteros: float f; int *pi= (int *)&f; char *pc= (char *)&f; Y con f, *pi, *pc accederamos a lo mismo que con la unin: f, i, c. Claramente, usar una unin annima es ms limpio aunque con punteros se ve fsicamente que comparten la misma memoria. En este caso, trabajar con punteros puede ser peligroso, ya que si tenemos: char c; int *pi= (int *)&c; float *pf= (float *)&c; un acceso a (*pi) a (*pf) excedera del tamao del carcter, estropeando lo que hay despus en memoria, que en este caso es el puntero que accede. Aqu, se puede decir, que est casi asegurado que el sistema se quede bloqueado o lo que en el argot se conoce como "colgado".

9.9) El programa compara los punteros, no donde apuntan. Si lo sustituyramos por (*s == *t) tampoco ya que slo comparara el primer elemento. Queda como ejercicio hacer una funcin que compare cadenas. En el siguiente captulo tambin se vern algunas funciones de comparacin. 9.10) No es correcto porque hemos definido p como un puntero a enteros constantes sobre los cuales nos podemos hacer un delete. Adems, delete p slo borrara el primer elemento, en el caso de que no fuera const. 9.11) Los dos son, obviamente, equivalentes y ninguno de ellos da error. El puntero retornado en p es indefinido y la direccin a la que apunte no est reservada. No retorna NULL como podramos imaginar en un principio, del mismo modo que delete no modifica el puntero, sino simplemente libera la memoria. 9.12) Intentar borrar slo una parte del vector reservado es una barbaridad, no porque sea ilgico pensarlo, sino porque el C++ no lo detecta como error y dependiendo de la implementacin, puede ser que no ocurra nada o se convierta en un desastre. Lo nico que sabemos con seguridad es que si hacemos lo correcto, no tendremos ningn problema.

10. Eficiencia y Optimizacin


10.1) La solucin se encuentra en el fichero EJ10_01.CPP 10.2) La solucin se encuentra en el fichero EJ10_02.CPP 10.3) Tenemos un tipo

reloj y tres funciones:

reloj Start_Timer(); // Crea un reloj y lo pone en marcha double Get_Timer(reloj &); // Retorna el tiempo en segundos desde que se creo este reloj double Stop_Timer(reloj &); // Igual que Get_Timer() pero adems destruye el reloj Adems se ha implementado una funcin de retardo Delay(unsigned long ) que tarda tantos milisegundos como se le pasen en su parmetro. Adems tenemos una funcin Calibrar(int ) para calibrar durante unos segundos la funcin Delay(). El listado de la implementacin es EJ10_03.CPP 10.4) Usando las funciones necesarias del ejercicio anterior veamos EJ10_04.CPP. En muchas mquinas saldr Fact3() la ms rpida y Fact2() la ms lenta, completamente al contrario de lo que podramos pensar en un principio. Esto depende de cmo estn orientados los procesadores, si tienen antememorias (cachs), si son mquinas RISC o CISC, etc. 10.5) Se prueba en el siguiente ejercicio. 10.6) La solucin se encuentra en el fichero EJ10_06.CPP 10.7) La funcin al ser inline hara que cualquier aparicin de sentido y eficiencia a i. 10.8) La solucin se encuentra en el fichero EJ10_08.CPP

alias(i) fuera equivalente en

10.9) Una forma de implementar el algoritmo quicksort() est en EJ10_09.CPP 10.10) La multiplicacin por potencias de dos se puede realizar por medio de desplazamientos de bit. Ejemplos para 2, 4 y 8 seran: inline int Mult2(int a) { return a << 1; } inline int Mult4(int a) { return a << 2; } inline int Mult8(int a) { return a << 3 } que por las pruebas que se han realizado son ligeramente ms rpidas que la multiplicacin normal. Esto depende mucho de la mquina. Las funciones para la divisiones son similares pero utilizando el operador >>. 10.11) Se tratara de lo siguiente: inline int Mult3(int a) { return Mult2(a) + a; } inline int Mult5(int a) { return Mult4(a) + a; } inline int Mult6(int a) { return Mult4(a) + Mult2(a); } inline int Mult7(int a) { return Mult(6) + a; } inline int Mult9(int a) { return Mult8(a) + a; } Segn vamos aumentando iremos perdiendo en eficiencia. La reutilizacin de unas funciones en otras no ralentiza ya que son inline. En general:

int Mult(int a, int b) { int r= 0; while (b) { if ((b | 1) == b) // bit es 1 r+= a; b >>= 1; a <<= 1; } return r; } que ya no es eficiente. Esta solucin y medidas de tiempo se encuentran en el fichero EJ10_11.CPP 10.12) Es correcto ya que en los macros los comentarios no son expandidos. Esto se ver mejor cuando se vea preprocesamiento. 10.13) El algoritmo se encuentra en EJ10_13.CPP. 10.14) La solucin se encuentra en el fichero EJ10_14.CPP

PARTE II 11. Clases


11.1) Al hacer delete this estamos liberando la memoria que ocupa el objeto actual por lo que el siguiente this= Ultimo ya no es vlido porque el Ultimo puede haber perdido su valor. Para la gente que empieza puede quedar ms claro poniendo: delete this; this= this->Ultimo; que es lo mismo que antes pero ahora se ve que el puntero this al que hemos hecho un delete, lo utilizamos como fuente en la siguiente sentencia. Por ello, se suele utilizar el puntero this para acceder a los atributos de una clase cuando queda comprometida la claridad. En segundo lugar como this es un puntero constante ni se puede hacer un delete sobre l ni se puede poner como destino en una asignacin. 11.2) El programa es completamente correcto. El primer objeto Obj1 llama al Pon de la clase c1 con el parmetro 3. Por tanto Obj1.Valor se pone a 3. El segundo objeto Obj2 llama al Pon de la clase c2 sin parmetros por lo que se toma el parmetro 1 por defecto que es lo que se almacena en Obj2.Valor. Al hacer Obj3.Valor= 10 no modificamos ningn otro objeto ni de c1 y mucho menos de c2 que no tiene nada que ver. 11.3) Las dos son

inline.

11.5) La solucin se encuentra en el fichero EJ11_05.CPP

11.6) La solucin se encuentra en el fichero EJ11_06.CPP 11.7) La solucin se encuentra en el fichero EJ11_07.CPP 11.9) En primer lugar no funcionara porque hemos definido los mtodos privados. Solventando este problema no funcionara tampoco porque cuando se llama a una funcin inline debe tener su implementacin ya definida. En este caso la solucin sera cambiar de orden f1() y f2(). class clase { .. public: void f1(); void f2(); .. }; inline void clase::f2() { .. } void clase::f1() { .. f2(); .. } void main() { clase o; o.f1(); } Una curiosa solucin es poner las dos funciones inline, as las funciones no son evaluadas hasta que se expanden, que en este caso ocurrir cuando lleguemos a main(), pasadas ya las definiciones de f1() y f2(). Otra solucin, evidentemente, es no definir ninguna inline. 11.10) La solucin se encuentra en el fichero EJ11_10.CPP 11.11) Si hacemos la implementacin de los complejos en forma polar, no quita para que definamos exactamente los mismos mtodos, incluso los constructores. Por tanto, si slo visemos las declaraciones de los mtodos, no podemos saber si estn implementados en forma rectangular o en forma polar. 11.12) La primera sentencia modifica el parmetro c1. La segunda modifica el miembro c2. La tercera modifica la variable global c3. La cuarta sentencia, modifica el miembro c1 al usar this. La quinta sentencia tambin al utilizar el operador de campo de clase. 11.13) No se puede. Deberemos hacer: class clase { static int Estatuto; .. }; int clase::Estatuto= 23;

o definir un mtodo esttico para acceder a int clase::Estatuto; se debe seguir poniendo.

Estatuto. De todas formas la sentencia:

11.14) Perfectamente. Aunque no tiene mucho sentido. 11.15) No podemos acceder a a porque f() es una funcin esttica y por tanto no tenemos el parmetro implcito this para poder acceder a los miembros. 11.16) La solucin se encuentra en el fichero EJ11_16.CPP

12. Creacin de objetos


12.1) Los mtodos son: a) constructor normal b) constructor por defecto c) exactamente igual a lo anterior d) constructor copia e) constructor por defecto (todos los argumentos por defecto) y constructor de conversin de (int *) a c1 f) constructor de conversin de float a cl si se toma el ltimo argumento por defecto, si no, constructor normal g) operador suma h) operador de conversin de cl a int. No se pone retorno i) operador de asignacin j) destructor k) Error! Los destructores no tienen parmetros 12.2) No es correcta ya que punto(c.RE(), c.IM()) crea un objeto temporal en el cuerpo de la funcin punto(complejo c) y no modifica 'x' e 'y'. La solucin sera: class punto { private: double x, y; public: void Pon(double xx, double yy) { x= xx; y= yy; } punto(double xx, double yy) { Pon(xx, yy); } punto(const complejo & c) { Pon(c.RE(), c.IM()); } }; 12.3) Tiene dos problemas, el primero es que como no hemos puesto ningn modificador de acceso y se trata de 'class', el mtodo f() ser privado con lo que no lo podremos llamar. En segundo lugar, no

podemos llamar a funciones no constantes desde objetos constantes. En este caso, esta ltima restriccin es una garanta de seguridad de que el objeto si es constante no va a ser modificado. 12.4) Depender del orden en que estn definidos dentro de una clase. Lo nico que sabemos con seguridad es que x pasar a valer a antes de que y pase a valer b. Esto es debido a que los dos se construyen en la lista de inicializacin, como 'x' si que est en la lista se construye y toma su valor a la vez mientras que 'y' tiene que esperar a valer 'b' al cuerpo de la funcin. 12.5) Para la primera no, ya que al haber otro constructor, ya no est definido el constructor por defecto. En la segunda s ser posible (en la versin 2.0 no). Las dos ltimas son perfectamente vlidas. 12.6) Se crear un objeto temporal por lo que el objeto constante no puede ser modificado por mucha referencia de que se trate. 12.8) Ver EJ12_08.CPP 12.10) S se pueden definir miembros (atributos y mtodos) 12.11) El operador

volatile.

sizeof no puede sobrecargarse.

12.12) En primer lugar, falta el punto y coma final de la clase. En segundo lugar, nunca deberemos hacer una asignacin a this y mucho menos un delete. 12.13) Es correcto aunque es ms recomendable definir la unin dentro de una clase. 12.14) Genera ambigedad. No sabemos si llamar a f(A(Objeto)); o a:

f(Objeto.operator A ());
12.15) No funcionara porque en C++ no se buscan conversiones multinivel. Y no hay ninguna conversin en un solo paso para hacer coincidir los parmetros. 12.16) Al llamarse a la funcin Nada() que parece que no hace nada, se crea un objeto temporal usando el constructor copia. El constructor copia que tenemos definido slo copia los atributos. Al llegar al final del cuerpo de la funcin (en seguida porque no hace nada), se retornara llamando al destructor del objeto temporal, que de la forma que tenemos definida la cadena hara un delete s; liberando la memoria. Cuando hiciramos cout << c1; probablemente salga la cadena por pantalla, pero no se puede asegurar, ya que hemos liberado la memoria que ocupa y puede ser utilizada por cualquier otro. Lo peor no es esto, sino que al llegar al final de la funcin se destruira c1 volviendo a llamar a delete s que ya est borrado. Esto lo suele avisar el compilador por medio de un error al final del programa del tipo "Null pointer assignment" 12.17) La solucin se encuentra en el fichero EJ12_17.CPP

13. Herencia y Polimorfismo

13.1) La asignacin e) es incorrecta ya que no podemos asignar un clase derivada con una clase base. La asignacin f) nos muestra que esto es imposible incluso utilizando casts. La asignacin h) es incorrecta por el mismo motivo que la e). Pero la i) es correcta porque siempre podemos pasar de un puntero de un tipo a un puntero de otro tipo utilizando casts. 13.2) No, no tiene sentido heredar dos veces ya se virtual o no virtual. Si se quiere incluir dos veces una clase se hace precisamente eso, incluir (composicin). 13.3) La primera crea un objeto dinmico de la clase cuadrado y toma su direccin en c1 que es un puntero a cuadrilatero. La segunda sentencia es incorrecta ya que no se puede asignar un puntero a un cuadrilatero a un puntero a un cuadrado. En el segundo lugar podramos usar un cast pero si los mtodos no son virtuales puede ser peligroso. cuadrado *c2= (cuadrado *)new cuadrilatero; 13.4) La longitud es 4 + 4 + 4 = 12 suponiendo 4 la longitud de int, 4 la longitud de float y 4 la longitud del puntero a la tabla de mtodos virtuales (suponiendo punteros de 32 bits). 13.5) Las funciones f() darn error ya que tienen los mismos parmetros y distinto tipo de retorno. En cambio las funciones g() son funciones totalmente diferentes ya que tienen parmetros distintos. Por tanto B heredar g(int, double) y tendr adems g(double, int). 13.6) Son los dos virtuales ya que si definimos un destructor como virtual en una clase base, los destructores en las clases heredadas tambin sern virtuales. En estos casos se recomienda poner la palabra virtual para dejarlo ms claro. Se deja como ejercicio averiguar si teniendo dos clases A y B, una con destructor virtual y la otra normal, si heredamos las dos en una clase C, el destructor de C ser virtual? 13.7) La solucin se encuentra en el fichero EJ13_07.CPP

14. Plantillas
14.1) S que podemos compilar ese programa, pero en el momento que usemos la funcin La solucin es simplemente borrar la primera declaracin ya que la segunda la incluye.

f() dar error.

14.2) Porque el tipo A no est incluido en los parmetros de la funcin. Ya sabemos que el retorno no cuenta. 14.3) Ver EJ14_03.CPP. Se han definido algunos mtodos internos y otros externos para mostrar el acceso a vector. Sera preferible todos externos. 14.4) Que no se puede hacer coincidir (C int. 14.5) La solucin vale para cualquier tipo: template <class T> int SizeOf_EnBits(T v) { return sizeof(T) * 8; //return sizeof v * 8; // Tambin vlido }

*) con (int). Si hubiera sido (C) no habra problema, C valdra

12.6) No, pero la solucin es simple: typedef clase1<int> clase1_int; clase2 <clase1_int> a;

15. Errores y Excepciones 16. Modularidad


16.1) Porque ya vienen provistas del mtodo de proteccin contra redefiniciones que hemos explicado. 16.2) Funcionara muy mal ya que no hemos definido el constructor copia y el operador de asignacin. Al tratarse de una estructura dinmica, cada vez que llamemos implcitamente al constructor copia (por ejemplo con objetos temporales), deberamos copiar toda la estructura y slo copiamos la direccin. Pero cuando destruimos los objetos temporales, s que destruimos toda la estructura. En resumidas cuentas, que vamos a destruir ms veces que a construir. 16.3) Aqu viene la solucin al ejercicio anterior. Se compone de tres ficheros EJ16_03.H, EJ16_03.H1, EJ16_03.H2. Adems tenemos un fichero EJ16_03.CPP que nos lo prueba todo. El fichero EJ16_03.H como vemos, queda limpio de toda implementacin. En primer lugar incluye EJ16_03.H1 en la parte privada de la clase y despus incluye fuera a EJ16_03.H2. Como se observa lo nico que ve el usuario son los mtodos de la lista. No se puede saber si est implementada dinmica o estticamente, no se sabe nada de sus miembros privados, ni estticos, slo lo imprescindible que debe conocer el que usa esta clase. La parte privada de la clase (los atributos) est en el fichero EJ16_03.H1. Aqu se definen los miembros privados. Es de resaltar la presencia interna de nodo. Se podra haber definido como clase amiga de clista, pero como en este caso slo la utilizamos aqu, la incluimos dentro del campo de la funcin. Pasemos ahora a la implementacin de los mtodos. Estn en el fichero EJ16_03.H2. El ltimo mtodo (Alias) se suele incluir para hacer referencias. Esto sirve para que tengamos varias listas operando sobre los mismos datos. Esto suele ser peligroso por los objetos temporales y porque la destruccin de uno implica que se ha liberado el espacio al que apuntan todos. Por eso no lo vamos a usar. Por ltimo, hay un fichero que lo prueba todo; este fichero slo debe incluir la especificacin. Es el fichero EJ16_03.CPP. COMENTARIOS: Los operadores de postincremento y postdecremento retornan por valor. As, operaciones como la siguiente, estaran permitidas pero no funcionaran de manera correcta: ++l1++; Slo incrementara una vez l1, el otro operador actuara sobre un objeto temporal retornado por el primero. En resumen, este artificio de estructura modular es un poco largo de realizar y difcil de entender para el que lo desarrolla. Pero nadie puede dudar que el fichero EJ16_03.H est claro como el agua. 16.5) S que compilara y enlazara. Al tener los dos el atributo const tienen acceso privado al mdulo, por lo que no son visibles externamente y no habra conflicto entre ellas. De todas formas, sera mucho ms

conveniente, poner una sola declaracin en una cabecera e incluirla en los dos mdulos.

PARTE III 17. Introduccin a las Libreras Estndar


No tiene ejercicios.

18. Entrada y salida


18.1) La solucin se encuentra en el fichero EJ18_01.CPP 18.2) En cada caso saldra: a) 00103 b) 10 // Todava no haba hecho efecto c) a 18.3) El programa debe incluir algunos manipuladores y flags para que no se ignoren los caracteres blancos. #include <iostream.h> #include <iomanip.h> void main() { cin >> resetiosflags(ios::skipws); while (1) { char c; cin >> c; if (!cin) break; cout << c; } } Tambin se poda haber hecho as: while (1) { char c; cin.get(c); if (cin.eof()) break; // Fin copia cout.put(c); } que no utiliza manipuladores. 18.4) No ya que el setw(100) acta sobre un stream (cin) y el (cout). Adems, la salida sera:

setw(5) acta sobre otro

00069 18.5) No ya que ya est sobrecargado en

<iostream.h> en las clases istream y ostream.

18.6) Tenemos aqu un programa que produce un volcado hexadecimal de un fichero de entrada a otro de salida. Si se omiten estos ficheros se cogern por defecto la entrada y salida por pantalla estndar. Ver EJ18_06.CPP 18.7) La solucin es: int i= 42; const char *fn= "test.dat" const int Largo = 7; { fstream f(fn, ios::out | ios::binary); f.seekp(Largo, ios::beg); f.write((const char *)&i, 2); } // Al destruirse se cierra { fstream f(fn, ios::in | ios::binary); f.seekg(Largo, ios::beg); f.read((char *)&i, 2); } // Al destruirse se cierra Tambin podamos haber llamado a los destructores explcitamente. Ya que estamos con la programacin orientada a objetos, es ms lgico utilizar constructores y destructores. Principalmente, lo que no hay que hacer es mezclar los dos mtodos. 18.8) Simplemente hay que saber el cdigo del descriptor de la impresora (que suele ser 4). Utilizamos entonces el constructor ofstream(int fh): fstream Stream_de_la_impresora(4); Si queremos utilizar buffer: char *Buffer= new char [1024]; ofstream Str_de_la_impr(4, Buffer, 1024); 18.9) La funcin

Leer_Cadena() la definimos as:

#include <iomanip.h> // resetiosflags void Leer_Cadena(char *s) { cin >> resetiosflags(ios::skipws); // No pasar los caracteres blancos for(int i= 0; cin >> s[i]; i++) // Leer hasta '\0' if (s[i] == '\n') // Se ha pulsado INTRO break; s[i]= '\0'; // Poner caracter nulo de terminacin de cadena }

En primer lugar hacemos que no se quiten los caracteres blancos. Luego leemos hasta encontrar uno de estos dos caracteres '\0', '\n'. ste ltimo se producir cuando pulsemos la tecla de retorno. Al final deberemos poner el carcter nulo ya que el stream no lo inserta.

19. Cadenas y Numricos


19.1) La solucin se encuentra en el fichero EJ19_01.CPP 19.2) La solucin se encuentra en el fichero EJ19_02.CPP 19.4) La solucin se encuentra en el fichero EJ19_04.CPP 19.5) La solucin se encuentra en el fichero EJ19_05.CPP

20. Introduccin a la STL


20.1-2) La solucin se encuentra en el fichero EJ20_01.CPP 20.3) La solucin se encuentra en los ficheros EJ20_03a.CPP, EJ20_03b.CPP y EJ20_03c.CPP. 20.4) La solucin se encuentra en el fichero EJ20_04.CPP 20.5) La solucin se encuentra en el fichero EJ20_05.CPP

21. Contenedores y adaptadores


21.1) La solucin se encuentra en el fichero EJ21_01.CPP 21.2) La solucin se encuentra en el fichero EJ21_02.CPP 21.3) La solucin se encuentra en los ficheros EJ21_03a.CPP y EJ21_03b.CPP. 21.4) La solucin se encuentra en los ficheros EJ21_04a.CPP y EJ21_04b.CPP. 21.5) La solucin se encuentra en el fichero EJ21_05.CPP 21.6) La solucin se encuentra en el fichero EJ21_06.CPP 21.7) La solucin se encuentra en el fichero EJ21_07.CPP 21.8) La solucin se encuentra en el fichero EJ21_08.CPP 21.9) La solucin se encuentra en el fichero EJ21_09.CPP

22. Objetos-funciones y algoritmos


22.1) La solucin se encuentra en el fichero EJ22_01.CPP

22.2) La solucin se encuentra en el fichero EJ22_02.CPP 22.3) La solucin se encuentra en el fichero EJ22_03.CPP 22.4) La solucin se encuentra en el fichero EJ22_04.CPP 22.5) La solucin se encuentra en el fichero EJ22_05.CPP 22.6) La solucin se encuentra en el fichero EJ22_06.CPP 22.7) La solucin se encuentra en el fichero EJ22_07.CPP

23. El Proceso de Desarrollo con C++


23.1) Est en INTERPRETE.CPP

2001 Paraninfo Thomson Learning y los autores: ltima actualizacin: Ir a la pgina principal 12 de noviembre de 2001. Enrique Hernndez Orallo, Jos Hernndez Orallo y M Carmen Juan Lizandra

También podría gustarte