Está en la página 1de 38

Starmedia Haz starMedia tu página de inicio

    

Correo Chat Videos

header

w eb

Buscador
top búsquedas

  

Runas Luces Fontanería

Correo
usuario latinmail.com

Autos Cine Clima  Deportes  Economía  Entretenimiento  Estudiantes  Humor  Juegos  Mujer  Noticias  Vídeos  

        

Inicio Documentos Tests Aulas Chuletas Amor Foros Postales Envía tus apuntes

   

Correo Ayuda Blog

publicidad

ir a starMedia

Noticias insólitas
Chécate estas imágenes que te sorprenderán!!!

Entretenimiento
Entérate de los mejores chismes de los famosos!!!

Apuntadores en lenguajes de programación
Informática. Lenguaje C y C++. Variables. Memoria. Valores. Operadores booleanos. Inicialización de apuntadores. Línea de comandos
Informática

  

Apuntadores en lenguajes de programación
Ficha resumen del documento Versión PDF

Apuntadores en lenguajes de programación Apuntadores en lenguajes de programación
Versión para descargar

REPUBLICA BOLIVARIANA DE VENEZUELA MINISTERIO DE EDUCACIÓN SUPERIOR INSTITUTO UNIVERSITARIO DE TECNOLOGÍA “CUMANÁ” INFORMÁTICA II DEPARTAMENTO DE ELECTRICIDAD - MENCIÓN ELECTRÓNICA ÍNDICE INTRODUCCIÓN 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 básicamente. 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 cálculos. Se genera código compacto y eficiente. Es una herramienta muy poderosa.

C, usa apuntadores explícitamente con:

Es la única forma de expresar algunos cálculos.

Una variable se refiere directamente a un valor y un apuntador se refiere indirectamente a un valor. Es una herramienta muy poderosa. En algunos ejemplos de código que son aplicables a C aparecen instrucciones de entrada y salida de las librerías estándar de C++. Se puede llegar a obtener un código más compacto y eficiente. Un apuntador contiene la dirección de una variable que contiene un valor específico. . Un apuntador es una variable cuyo valor es la dirección de memoria de otra variable. En general una variable contiene un valor específico dependiendo de como fue declarada. El operador de indirección o desreferencia “*” devuelve el ``contenido de un objeto apuntado por un apuntador''. LOS APUNTADORES:          Los apuntadores son variables que almacenan direcciones de memoria. En este artículo se explica de una manera sencilla y breve todo lo referente a la utilización de apuntadores tanto en C como en C++. C. Apuntadores usados en C debido a que a veces son la única manera de expresar un cálculo. Se dice que un apuntador “apunta” a la variable cuyo valor se almacena a partir de la dirección de memoria que contiene el apuntador.  Se genera código compacto y eficiente. Todo lo explicado en este artículo aplica tanto para C como para C++. Por ejemplo. el compilador reserva un espacio de memoria para ella y asocia el nombre de ésta a la dirección de memoria desde donde comienzan los datos de esa variable. se dice que “p apunta a x”.  Los apuntadores como cualquier otra variable deben de ser declarados antes de que puedan ser utilizados. usa apuntadores explícitamente con:    Arreglos. Cuentan con una declaración propia. si un apuntador p almacena la dirección de una variable x. Las direcciones de memoria se suelen describir como números en hexadecimal. Estructuras y Funciones El uso de apuntadores en C y C++ es muy importante debido a que permite hacer los programas más eficientes y más flexibles. a menos que se especifique un lenguaje en particular. Cuando se emplean sin cuidado pueden crear programas imposibles de entender. Los apuntadores disponen de dos operadores: El operador unario o monádico “&” devuelve la dirección de memoria de una variable. Declaración De Apuntadores: Cuando se declara una variable.

es por que se debe conocer en cuantos bytes esta guardado el dato. *py = y. la cual es una dirección entera.   El tipo de un apuntador lo proporciona implícitamente el tipo de la variable a la que apunta. Un operador de indirección o de desreferencia: *.y. pero un apuntador NO es un entero. De esta forma si a un apuntador a flotante se le suman 2. Los apuntadores pueden ser declarados para apuntar a objetos de cualquier clase. y = 5. ejemplo: main() { int y. Operador unario que regresa la dirección de su operando. De tal forma. Por lo tanto para un apuntador a un char. La razón por la cual se asocia un apuntador a un tipo de dato. en donde el bloque esta en función del tamaño del dato. NOTA: Un apuntador a cualquier tipo de variables es una dirección en memoria. int *yPtr. que cuando se incrementa un apuntador. se agrega un byt a la dirección y para un apuntador a entero o a flotante se agregan 4 bytes. el apuntador entonces se mueve dos posiciones float que equivalen a 8 bytes. (int *) y se lee ``contPtr es un apuntador a int'' o ``contPtr apunta a una variable entera''. ejemplo: main() { int x. Regresa el valor del objeto hacia el cual su operando apunta. . Los Operadores De Los Apuntadores:  Un operador de dirección &: Representa la dirección de memoria de la variable que le sigue. y = 5. x = *py + 5. El operador * aplicado al nombre de un apuntador indica el valor de la variable apuntada. se incrementa el apuntador por un ``bloque'' de memoria. int *py. } 2. es decir un apuntador. yPtr = &y. La sintaxis general de declaración es: <tipo> * <variable>   Ejemplos de declaraciones: La variable contPtr es del tipo apuntador a entero.

x). <Expresión> deberá ser una expresión constante del tipo <Tipo> expresado.456.  Un apuntador a carácter puede inicializarse en la forma: char *cadena = Esto es una cadena”. NULL (cero) proporciona un apuntador nulo a cualquier tipo de dato: int *p.*py. es decir 25.  Se pueden sumar o restar valores enteros a las direcciones de memoria en la forma: (aritmética de APUNTADORES) . La variable pint también tiene su propia dirección: &pint Inicialización de APUNTADORES: < Almacenamiento > < Tipo > * < Nombre > = < Expresión > Si <Almacenamiento> es extern o static. Inicializa el apuntador con el entero. Esto es.printf(''%d %d nn''. //actualización  El nombre de un arreglo de almacenamiento static o extern se transforma según la expresión: a) float mat[12]. pint = &x. p = NULL. en la dirección a la que apunta la variable punt se almacena el valor 123. entonces <Expresión> puede ser cualquier expresión del <Tipo> especificado. } Veamos con un ejemplo en C la diferencia entre todos estos conceptos Es decir: int x = 25. Si <Almacenamiento> es auto. Ejemplos:  La constante entera 0. float *punt = mat.  Un “cast” apuntador a apuntador: int *punt = (int *) 123. *pint. b) float mat[12]. La variable pint contiene la dirección de memoria de la variable x. La expresión: *pint representa el valor de la variable (x) apuntada. float *punt = &mat[0].

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

Sea la declaración: char * mensaje[4] = {''Hola''. x = *pt.''Bye''.*pt. Un nombre de un arreglo es una constante.*(ptr+i). i++) *(pt+i) = random().   Ejemplo: main() { int tabla[10]. for (i=0.x. el nombre de un arreglo es un puntero al arreglo.APUNTADORES Y ARREGLOS:  Existe una estrecha relación entre apuntadores y arreglos. un nombre de un arreglo es un índice a la dirección de comienzo del arreglo. de ahí que a = pa o a++ o p = a. i++) printf(''%d nn''. no una variable. En esencia. for (i=0.''Salut''}   Cada cadena está almacenada en memoria como una cadena de caracteres terminada en NULL n0.i. Los apuntadores pueden ser utilizados en cualquier operación que involucre subíndices de arreglos. Un apuntador es una variable. Una variable de tipo arreglo puede considerarse como un apuntadora tipo del arreglo. tanto que pueden ser usados en forma casi indistinta. Cada entrada en el arreglo es un apuntador al primer carácter de la cadena. ptr = tabla.*ptr. . tan solo están almacenados los apuntadores. por lo que operaciones como pa = a y pa++ son permitidas. En el arreglo no están colocadas las cadenas. i!10. En C. }   Cuando se suma 1 a un apuntador el incremento se adecua al tamaño en memoria del objeto apuntado. Arreglos de apuntadores:     Los arreglos pueden contener apuntadores. El uso más común es el de formar arreglos de cadenas de caracteres. pt = &tabla[0].tabla[i]). i!10.''Adios''.

Alta sobrecarga por el movimiento de líneas. permite el acceso a cadenas de caracteres de cualquier longitud.  Si dos líneas están desacomodadas -.1: Arreglos de apuntadores (Ejemplo de ordenamiento de cadenas). A continuación se muestra un ejemplo de su uso: ordenar las líneas de un texto de diferente longitud. Ver figura 1.intercambiar (swap) los apuntadores (no el texto). Observando que \n marca el fin de cada línea.1. Considerar: . En C se pueden tener arreglos de apuntadores ya que los apuntadores son variables. Aunque el arreglo es de tamaño fijo.  Comparar dos líneas usando la función de la biblioteca estándar strcmp(). Apuntadores y arreglos multidimensionales:   Puede provocar confusión el uso de arreglos de dos dimensiones y un arreglo de apuntadores. Figura 1.  Guardar los apuntadores en un arreglo diferente donde cada apuntador apunta al primer caracter de cada línea. Con lo anterior se elimina:   El manejo complicado del almacenamiento. Los arreglos de apuntadores son una representación de datos que manejan de una forma eficiente y conveniente líneas de texto de longitud variable. ¿Cómo se puede hacer lo anterior?  Guardar todas las líneas en un arreglo de tipo char grande.

int a[10][10].       El uso de a y b puede ser parecido.. Por lo tanto.. Cuando se pasa una arreglo bidimensional a una función se debe especificar el número de columnas -. a b la declaración solo le asigna 10 apuntadores. El tamaño de los arreglos apuntados por cada una de las diez localidades pueden ser diferentes.el número de renglones es irrelevante.. una inderección es más rapida que el hacer una multiplicación seguida de una suma. la notación a[n][m] nos indica que los elementos del arreglo están guardados renglón por renglón. es nuevamente los apuntadores. int *b[10]. } . por ejemplo: Un arreglo de dos dimensiones es un arreglo de una dimensión. La razón de lo anterior. } o aún f( int (*a)[35] ) { . existen 100 celdas de memoria asignadas y se efectúa el cálculo de subíndices rectangulares convencional para localizar un elemento dado Sin embargo.. Un arreglo multidimensional puede ser visto en varias formas en C. C requiere conocer cuantas son las columnas para que pueda brincar de renglón en renglón en la memoria.. o o o La declaración b tiene dos ventajas: El acceso se hace más rápido. suponiendo que cada uno apunta a un arreglo de 10 elementos. Se debe de crear el espacio de los arreglos antes de asignarlos. se puede declarar el argumento de la función como: f( int a[][35] ) { . donde cada uno de los elementos es en sí mismo un arreglo. 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.. cada uno de los cuales deberá de apuntar a un arreglo de enteros La desventajas de b son: Ocupa más espacio.. Considerando que una función deba recibir int a[5][35].. el tamaño será de 10 apuntadores más 100 elementos.

El manejo de cadenas es una aplicación común de esto. mientras que int *a[35]. y por ejemplo si hacemos la siguiente referencia a+2. declara un arreglo de 35 apuntadores a enteros.En el último ejemplo se requieren los parénteis (*a) ya que [ ] tiene una precedencia más alta que *. Por lo tanto: int (*a)[35]. "Mar". }. .. Con el primer tipo de declaración se tiene la ventaja de que cada apuntador puede apuntar a arreglos de diferente longitud. NOTA: si cada apuntador en nomb indica un arreglo de 20 elementos entonces y solamente entonces 200 chars estarán disponibles (10 elementos). Considerar: char *nomb[] = { "No mes". Ahora veamos la diferencia (sutil) entre apuntadores y arreglos. Sin embargo:    anomb es un arreglo verdadero de 200 elementos de dos dimensiones tipo char. }. "Ene". "Feb". Considera: char *nomb[10].. Se puede indicar que se hace un manejo más eficiente del espacio haciendo uso de un arreglo de apuntadores y usando un arreglo bidimensional. . char anomb[][15] = { "No mes". Lo cual gráficamente se muestra en la figura 1. "Mar". En donde es válido hacer nomb[3][4] y anomb[3][4] en C. nos estaremos refiriendo a la dirección del primer elemento que se encuentran en el tercer renglón de la matriz supuesta. El acceso de los elementos anomb en memoria se hace bajo la siguiente fórmula 20*renglon + columna + dirección_base En cambio nomb tiene 10 apuntadores a elementos.2. declara un apuntador a un arreglo de 35 enteros. "Ene"... .. "Feb". char anomb[10][20].

a[i][j] . arreglo de apuntadores.Figura 1. no se puede deducir inmediatamente como fue declarado a :  Como un arreglo de 10 arreglos de tamaño 20 int a[10][20]. Diferentes formas de declarar a[i][j]: Cuando se ve la referencia a un arreglo de dos dimensiones.  Para poder direccionar un elemento de un apuntador de apuntadores se sigue la regla: tab[i][j] * ( *(tab + i) + j) .2: Arreglo de 2 dimensiones VS.  Como un arreglo de tamaño 20 de vectores de longitud variable int *a[10].  Como un apuntador a un arreglo de enteros de tama~no 20 int (* a)[20].  Como un apuntador de apuntadores a enteros int **a.

(los nombres son por convención): argc es el número de argumentos en la línea de comandos. ( *argv[] ) apunta a la cadena que contiene el nombre del comando. y. por lo que la única preocupación del programador es usarla. int *x. la cual regresa un apuntador al bloque de memoria requerida si se pudo o un apuntador a nulo en otro caso. x = &y. i++) printf(''Argumento %d :'' %s''. tener primeramente una localidad física de memoria. Esta estructura de datos es creada por el sistema operativo. uno por cadena Ejemplo de uso: main( int argc. Fallas comunes con apuntadores: A continuación se muestran dos errores comunes que se hacen con los apuntadores:  int *x *x = 100. digamos int y. cuando comienza la ejecución Cuando se invoca el main() se le puede pasar dos argumentos. argv[] es un apuntador a un arreglo de cadena de caracteres que contienen los argumentos. (Unix u otro). no generarla. for (i=0. *x = 100. i!argc.  Indirección no válida: Supongamos que se tiene una función llamada malloc() la cual trata de asignar memoria dinámicamente (en tiempo de ejecución). char *argv[]) { int i.). No asignar un apuntador a una dirección de memoria antes de usarlo: lo adecuado será. }   Ya que el primer elemento del arreglo.ARGUMENTOS EN LA LÍNEA DE COMANDOS:     Existe una forma de transmitr al programa los argumentos de la línea de comando. . argc es al menos igual a 1. o parámetros.

Un buen programa en C debe revisar lo anterior. y por lo tanto no se podrá hacer: *p = 'y'. Existe un error en el código anterior. int (*p)(char *a). int p(char *a). El código correcto deberá ser: p = (char *) malloc(100). int *p(char *a). int *p[10]. 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 función que devuelve un apuntador a entero p es una función que acepta un argumento que es un apuntador a carácter. Supongamos que se tiene un apuntador char *p Considerar: *p = (char *) malloc(100): /* pide 100 bytes de la memoria */ *p = 'y'. por lo que el código anterior puede ser reescrito como: p = (char *) malloc(100): /* pide 100 bytes de la memoria */ if ( p == NULL ) { printf("Error: fuera de memoria\n"). Apuntadores de mayor complejidad: int *p.char *malloc() -. } *p = 'y'.una función de la biblioteca estándar que se verá más adelante. Ahora si malloc no puede regresar un bloque de memoria. entonces p es nulo. ¿Cuál es? El * en la primera línea ya que malloc regresa un apuntador y *p no apunta a ninguna dirección. exit(1). int (*p)[10]. dev un apuntador a entero p es un apuntador a función que acepta un argumento que es un apuntador . dev un entero p es una función que acepta un argumento que es un apuntador a carácter. int *p(void).

itq. p es una función que acepta un argumento que es un apuntador a carácter. cada función devuelve un ente p es un arreglo de 10 apuntadores a función. int p(char *a[]). dev un apuntador a un arreglo de 10 enteros p es un apuntador a función que acepta un argumento que es un apuntador a arreglo de caracteres..mx/ac/rogomez/Tutorial-LengC/apuntadores.mx/vidatec/maestros/sis/mlopez/Tutorial/apunt. del autor Luís Joyanes Aguilar. int (*p)(char (*a)[]). dev un apuntador a entero p es una función que acepta un argumento que es un apuntador a un arreglo caracteres.fismat.carácter. devuelve un apuntador a entero int (*p(char *a))[10]. int *(*p[10])(char a).. 15.umich.htm http://www. devuelve un apuntador a entero p es un apuntador a una función que acepta un argumento que es un apuntador arreglo de apuntadores a caracteres. BIBLIOGRAFÍA El presente articulo fue realizado con la ayuda de:   El libro “Programación en C++”.htm http://garota. cada función acepta un argumento es un apuntador a carácter y devuelve un entero p es un arreglo de 10 apuntadores a función. char *(*p[10])(char * a). devuelve un apuntador a entero p es una función que acepta un argumento que es un apuntador a un arreglo apuntadores a caracteres.com/eztigma/apuntadores. devuelve un apuntador a entero p es un apuntador a función que acepta un argumento que es un arreglo de apuntadores a caracteres. devuelve un apuntador a entero p es un apuntador a una función que acepta un argumento que es un arreglo apuntadores a caracteres.edu.geocities.743.mx/mn1/manual/node9.html http://www. int (*p[10])(char * a). int(*p[10])(void). Y las siguientes paginas de Internet: http://webdia. y devuelve un apuntador a entero p es un arreglo de 10 apuntadores a función.html http://www. cada función acepta un argumento es un carácter.ldc. int *p(char (*a)[]). int *p(char *a[]). int *(*p)(char (*a)[]).html 18 INTEGRANTE:  Eduardo R.itesm. devuelve un apuntador a entero p es una función que acepta un argumento que es un arreglo de caracteres. devuelve un apuntador a entero p es una función que acepta un argumento que es un apuntador a un arreglo caracteres. int *p(char a[]). devuelve un apuntador a entero p es una arreglo de 10 apuntadores a función.cem. editorial Mc Graw Hill. cada función acepta un argumento es un carácter. y devuelve un apuntador a carácter. Aranguren P. int p(char (*a)[]).ve/~gabro/teaching/CI2126/Clase1_Apuntadores.681 .usb. int *(*p)(char *a[]).

char *mensaje.Dominicana Costa Rica Guatemala Bolivia Uruguay El Salvador .Condiciones de Uso . en Salamanca desde 1998 .GRUPO: 02 FECHA DE ENTREGA: 28/05/2007 int *contPtr. El Rincón del Vago. unsugned int *nosigno. float *res. cont.Contacto footer w eb Buscador © Copyright 2011 Orange     Publicidad Contáctanos Mapa web Acerca de Orange                   Mexico USA Colombia Argentina Chile Perú España Venezuela Ecuador Brasil Puerto Rico Panamá Rep.

2.3) El programa puede parecer a primera vista muy sencillo.1) Quedaría del siguiente modo: . el programa no se podría enlazar. La primera solución intuitiva: . 2. 2. En primer lugar vamos a leer y escribir una cadena. Introducción No tiene ejercicios. Si ponemos dos funciones main() ocurre lo mismo.2) Si en un programa no ponemos la función main(). Aquí encontrará los ejercicios resueltos por capítulos (También puede descargarse un fichero comprimido con todos los fuentes de los ejercicios) PARTE I 1. hay otros tipos de comentarios como los de C++: empezar un comentario tipo C y ahora lo acabo. el compilador da un error de redefinición de una función. */ / * Que comentario más precioso * / / / Este es más precioso todavía. Conceptos básicos 2.    Paraguay Nicaragua Honduras Cuba C++ Estándar Programación con el Estándar ISO y la Biblioteca de Plantillas (STL) © Paraninfo Thomson Learning 2001 Ejercicios resueltos por capítulos.

las sentencias se convertirían en: ".6) Sí es correcta. cout void main() { double d1. // Y pasar a la línea siguiente } El problema es que esto únicamente nos lee la primera palabra de una cadena (esto se explicará en el capítulo de entrada/salida). Tipos de datos 3. // Cadena de hasta 19 caracteres cin >> s.#include <iostream> // USAMOS: cin.1) La función es: int Convierte(char c) { return int(c .5) El programa correcto es éste: #include <iostream. } 2. */ La solución sería definir de nuevo las sentencias como: /* cout << "/* Me pillaste *""/". .7) Este comentario es erróneo. Por ello. cout << "La suma es: " << d1 + d2 << endl } 2. out << "Introduce dos reales: ". d2. 2. Hemos dicho que los comentarios no se detectan en las cadenas. cin >> d1 >> d2. Aunque no se comprenda de momento. No se detecta su apertura pero sí su clausura. cout void main() { char s[20].h> // USAMOS: cout void main() { cout << "Hola mundo".4) Aquí está el programa: #include <iostream> // USAMOS: cin. la solución se encuentra en el fichero EJ02_03. // Concatenación de cadenas */ 3.'0'). // Leer la primera palabra cout << endl << s // Escribir en nueva línea la cadena << endl.CPP 2. Pues no es completamente cierto.

4) Función que compara dos cadenas: . else min= b. if (a < b) if (a < c) min= a. else if (b > c) min= c. de dos números: int Mcd(int a. // Código de error while (a != b) if (a < b) b= b .CPP 4.b.2) Sí que es válido ya que en C++ todos los tipos integrales son compatibles.1) El listado es funcionalmente correcto pero sintácticamente no.CPP 4. Aunque sería mucho mejor explicitar las conversiones: b= (byte)w. // Igual que la anterior return a. e. Faltan los puntos y comas de las cuatro sentencias de asignación. // b-= a. La segunda dará 24 porque 014 está en octal que es 12 en decimal.a. else min= c. 4.3.4) La primera dará error ya que 8 no es un dígito octal y por tanto 08 es un error. d= (dword)w. // a-= b.D.2) Programa que cuenta el número de ocurrencias en una cadena de las 5 vocales en 5 variables diferentes: a.3) Una función que calcule el M. 4. 3. Ya se verá else a= a .} // Usando int() en vez de (int) se ahorra un par de paréntesis 3. // Igual que la anterior. u. Usaremos la función Leer_Cadena() del ejercicio 2. i. El programa está en EJ04_02.3) Su longitud es 9 tomando sizeof(int) == 2.C. w= (word)l. Control de Flujo 4. 3. o. int b) { if (a <= 0 || b <= 0) return -1. // Al final el mcd está en a y en b (a == b) } Un ejemplo de uso de la función está en EJ04_03.

(long j = 0) // Incorrecto // Lástima porque era una buena idea 4. La condición del bucle está formada por el operador de asignación (=) y no el operador de comparación (==). d) (int i = 0). al ser no nulo.7) En este ejercicio se ha pretendido aumentar la atención del lector en este error común y sutil pero difícil de detectar. c. con lo que el resultado del programa es que sólo muestra un 0. c) int i= 0. int j= 0. además de asignar 10 a la variable i. Recordemos que la sentencia: for(a. while (s1[i] || s2[i]) { // Hasta terminar las dos if (s1[i] < s2[i]) return -1. es que devuelve el valor 10. j= 0. // Correcto // Dos declaraciones de tipo entero while . // La cadena 1 es mayor que la 2 i++. // La cadena 1 es menor que la 2 else if (s1[i] > s2[i]) return 1. se convierte en: { a. long j= 0.. las sentencias anteriores son: a) int i= 0. c). } } Por tanto.. Si después lo negamos con el operador ! obtenemos falso.CPP 4. // Incorrecto while . while(b) { d. char *s2) { int i= 0. b.int StrCmp(char *s1.. b) int i= 0. // Las cadenas son iguales } Esta función es similar a strcmp() de la librería estándar <cstring> del C++.5) Sólo la b) es correcta. ya que el resultado de la asignación i=10. . con lo que el bucle sale después de la primera iteración.CPP 4. Un ejemplo de uso de la función está en EJ04_04.6) La solución se encuentra en el fichero EJ04_06. // Incorrecto // Dos declaraciones separadas por una coma while . } return 0. que es un valor cierto.

3) Se supone que tenemos dos valores enteros almacenados en dos variables reales.1) 5.CPP . preferiblemente).4) NO ES VÁLIDO PORQUE EL OPERADOR COMA NO SE PUEDE UTILIZAR EN ESE PARTE DEL FOR. El compilador crea variables temporales para almacenar estas constantes y así ya puede tomar la dirección. Si además hacemos coincidir la llamada a Rand() con un factor externo (tiempo. En este caso invierte el vector de caracteres s (no es una cadena porque no acaba en '\0').. } 6.CPP 6. int b= 2. El compilador no sabe si llamar a la función con un argumento o llamar a la segunda usando parámetros por defecto. } 5.3) Es sintácticamente correcto.4.CPP 4.CPP 6.8) La solución se encuentra en el fichero EJ04_08.6) La solución se encuentra en el fichero EJ06_06.CPP 4. Yo lo haría así: float Resto(float a. 5. El programa se encuentra en EJ05_05. 42) es completamente correcta ya que no hay ambigüedad.9) La solución se encuentra en el fichero EJ04_09.1) La solución se encuentra en el fichero EJ06_01.2) La solución se encuentra en el fichero EJ06_02. int c= 3) { // .10) La solución se encuentra en el fichero EJ04_10.5) Sí que es correcto y sería equivalente a: void f(int a= 1.1) Es simple: x & (x .CPP 4.CPP 5. esta función es casi impredecible. Funciones 6.4) La llamada f(25) es ambigua. float b) { return float((long)a % (long)b). La llamada f(17. Operadores 5.5) Con algo parecido a esto sería suficiente para que pareciera aleatorio. 6. El resultado en s será ACABATOR. De todas formas no es un buen estilo de programación pasar constantes por referencia porque aunque la función modifique su valor no nos podemos dar cuenta. 6.CPP 6.11) La solución se encuentra en el fichero EJ04_11. Si cogemos uno de los dos incementos y lo ponemos al final del bucle sí que funciona.

// Accedo a la 'f' de la decl. // Accedo a la 'f' de la decl. no es correcto ya que los dos tienen el mismo campo local automático. // Error: mismo campo.Campo local estático. 2) } } float f.3) Como hemos visto en el caso anterior. Campo global. 5. 5 ::f= 3. 2. // Decl 2. f vale 0 void Funcion(float f) { // Decl. // Decl1. Variables 7. 4 a= 5. Se almacena en la pila f= 2.2) Este sería un programa que volvería loco al propio Bjarne Stroustrup: void Funcion(float f). de datos. 1 s= 4.5. en el s.Campo local automático. // Decl. locales tienen el mismo campo auto float a. Campo local automático. // Decl.1) Las variables estáticas se inicializan a 0. de datos. // Error: parámetros y var. s vale 0 { float f. // Este auto es opcional // Decl. 7. Las otras dos también darían error. 7. Es mejor explicitar: int a= 0.4) Dará un error en la definición const int a ya que las constantes se deben inicializar en el momento de la definición.7. a vale ? static float f. Campo prototipo float f. 7. Se almac. No se recomienda usar la declaración de 'a' de ese modo. // Accedo a la 's' de la decl.3. Se almacena en el seg. Se almacena en pila.5) No sería equivalente a: const char * Var. 3 // No hay forma de acceder al parámetro 'f' de la función (Decl. Se almacena en pila float f.4. Por tanto a valdrá 0 y b tendrá un valor indefinido dependiendo del compilador. . Las variables automáticas no. Campo de bloque. // Error! Redefinimos la variable global. 7. static float s. // Accedo a la 'a' de la decl.

3. f vale 0 void Funcion(float f) { // Decl. 3 // No hay forma de acceder al parámetro 'f' de la función (Decl. a vale ? static float f. en el s.6) El programa A funciona correctamente. 5. 4 a= 5. de datos. de datos.1) En C++. // Accedo a la 'f' de la decl. 1 s= 4. // Decl. . // Error: parámetros y var. 2) } } float f. Ya se vio que extern sólo es aplicable a variables de tipos no compuestos. Se almacena en pila float f. // Decl1. // Error: mismo campo.sino a: char * const Var. s vale 0 { float f. Campo global. static float s. El programa B da error porque no sabemos cómo es la estructura. El programa C funcionaría si no se tratara de una estructura. // Este auto es opcional // Decl. 5 ::f= 3. porque typedef no es una macro. Se almacena en el seg. las constantes tienen tipo por lo que el compilador asignará: . 7. Se almacena en pila.5. // Accedo a la 's' de la decl. Sobrecarga y conversiones 8.7) Este sería un programa que volvería loco al propio Bjarne Stroustrup: void Funcion(float f).Campo local automático. Coincidencia exacta con Print(int ). 7. // Decl 2. Campo de bloque. locales tienen el mismo campo auto float a. // Error! Redefinimos la variable global. // Decl.Se almac. Campo prototipo float f.4. no podemos definir una variable de ella.la primera es un int . por tanto. Campo local automático. 8. // Accedo a la 'f' de la decl. // Accedo a la 'a' de la decl. Se almacena en la pila f= 2. 2.Campo local estático.

Por tanto. No hay promoción. sólo les da un nombre diferente. 8.la segunda es un double.7) Como no hay conversión trivial. 8. por tanto. c) Utilizar conversiones explícitas (cast) 8. No hay coincidencia exacta ni trivial. Concretamente. 2.CPP 8. Pasos: Primero: no hay coincidencia exacta. 8.12) En C++. Podríamos haberlo solventado poniendo 2. Tercero: conversión estándar.CPP 8.6) Daría error al haber conversión trivial entre const T y T.5) La solución se encuentra en el fichero EJ08_05.la tercera es un char. fallará porque hay una ambigüedad. b) Forzar que las constantes sean del tipo requerido. No hay coincidencia exacta ni trivial.2F. Por tanto daría error de ambigüedad.2) Sí. se llama sin ningún problema. En general. .3) No porque tomará f() como float y no como una función. 8.El literal 0 es un int. se llama a Print(int ). las posibles soluciones a los problemas que aparecen (como el de la segunda llamada) son: a) Declarar variables auxiliares del tipo que se desee. 8.9) La solución se encuentra en el fichero EJ08_09... La tercera sigue estos pasos: Primero: no hay coincidencia exacta. pero la hay a los dos. no hay promociones.. Se trata de conversiones de línea.4) La solución se encuentra en el fichero EJ08_04. el proceso es bien diferente: 1.CPP 8. se podría definir perfectamente. Segundo: no hay promoción posible. Por tanto se llama a f(double ). 8.El literal 0.CPP 8. Segundo: no hay promoción.10) La solución se encuentra en el fichero EJ08_10. Por tanto. Pero las conversiones estándar de un tipo aritmético puede ser a cualquier otro tipo aritmético. Pasos: Primero: coincidencia exacta.11) Son correctas.0 es un double. pero hay conversión estándar aritmética.8) Las dos primeras llamadas invocan a sus funciones correspondientes sin ningún problema. Hay conversión estándar. no le damos preferencia a la que no tiene signo. typedef no crea tipos nuevos distintos. Tercero: hay conversión estándar de int a char y de int a .13) Para las cinco llamadas. Pero hay promoción con int. no hay coincidencia exacta o trivial. 8. dará un error de llamada a no-función ("call of non-function") ya que estamos intentando llamar a un float como si fuera una función.

4. Como si está permitido lo contrario. Segundo: hay promoción de float a double. El segundo programa. 3. La solución se encuentra en el fichero EJ09_02.double. la segunda llamda es correcta (mismo tipo). porque no hay conversión estándar desde int a enum.4) La solución se encuentra en el fichero EJ09_04. ya que no sabe si llamar a ff(fc) con signo.2) Invierte una cadena. Pasos: Primero: no hay coincidencia exacta. ya que F sólo se puede aplicar a constantes reales.0F es un float. Por tanto se llama a f(void *).. void 8. Por tanto se llama a f(double ). El acceso (*p= 10) será válido hasta que pongamos (delete p. la combinación dos es perfectamente correcta. ¡Qué complicados son los complicadores! ff(fc) sin signo o 9. La combinación tercera también lo es. pero al cerrarse el bloque la variable 10) puede ser catastrófico.. en cambio. Punteros 9. Pasos: Primero: no hay coincidencia exacta. llamando cada una a su correspondiente función. funciona correctamente ya que el carácter a tratar se almacena en el 'heap' y no en la pila. Tercero: hay conversión estándar entre char * y *. } 9. así al cerrar el bloque no destruimos ninguna variable ya que no hemos definido ninguna tampoco. { p= &a.El literal 0F da error de sintaxis. Segundo: no hay promoción.El literal 0. int a.CPP .15) El compilador da un error de ambigüedad.CPP 9.El literal cadena es un char *.1) El primero carga en p la dirección de la variable a se destruye con lo que el acceso posterior de (*p= a (p= &a). 8.)..CPP 9. dijimos que la constante 0 tiene conversión estándar con cualquier puntero. pero la primera no.14) Para la primera combinación. Por tanto habrá error de ambigüedad al no poder elegir ninguna de las tres funciones. } *p= 10.3) La solución se encuentra en el fichero EJ09_03. Además. Una mejor solución sería: void main() { char *p. 5.

pero s apunta a una dirección indefinida. Tampoco es muy recomendable hacer lo que se ha hecho en el ejercicio 1.5) La solución se encuentra en el fichero EJ09_05. . delete []s. usar una unión anónima es más limpio aunque con punteros se ve físicamente que comparten la misma memoria. } También podríamos haber usado: #include <iostream.6) Ese programa es muy peligroso. al final del programa el compilador se encarga de hacer todos los delete que falten.h> void main() { char *s. Y con f. trabajar con punteros puede ser peligroso. Además no se puede asegurar que la salida sea igual que la entrada. cin >> s. En fin. s= new int[100]. // Suponemos que con 100 caracteres es suficiente cin >> s. ya que si tenemos: char c. En este caso. cout << s. int *pi= (int *)&f. estropeando lo que hay después en memoria. un acceso a (*pi) a (*pf) excedería del tamaño del carácter. es necesario. char *pc= (char *)&f.7) No ocurre nada. pero a veces como en ese ejercicio. Además. *pi. int *pi= (int *)&c.h> void main() { char s[100]. que en este caso es el puntero que accede.9. c. que este es uno de los errores más graves y típicos del C++. podemos estar estropeando código. Claramente. que está casi asegurado que el sistema se quede bloqueado o lo que en el argot se conoce como "colgado". Aquí. puede que en un primer momento funcione. se puede decir. datos de nuestro o de otro programa. 9. Leemos una cadena en s. i. por ello. cout << s. *pc accederíamos a lo mismo que con la unión: f. Más tarde el error aparecerá inesperadamente de forma catastrófica. De todas formas. es muy recomendable no olvidarse de ponerlo porque si es en una función que se llama 1000 veces acabaremos con el 'heap' lleno!.8) Para hacer lo que se nos pide en el ejercicio habría que hacer uso de punteros: float f.CPP 9. La solución es reservar la memoria que vamos a usar: #include <iostream. float *pf= (float *)&c. } 9.

1) La solución se encuentra en el fichero EJ10_01.3) Tenemos un tipo reloj y tres funciones: reloj Start_Timer(). 9.4) Usando las funciones necesarias del ejercicio anterior veamos EJ10_04. sino porque el C++ no lo detecta como error y dependiendo de la implementación. Además tenemos una función Calibrar(int ) para calibrar durante unos segundos la función Delay(). El puntero retornado en p es indefinido y la dirección a la que apunte no está reservada. No retorna NULL como podríamos imaginar en un principio. En muchas máquinas saldrá Fact3() la más rápida y Fact2() la más lenta. etc. del mismo modo que delete no modifica el puntero. no donde apuntan. Lo único que sabemos con seguridad es que si hacemos lo correcto. puede ser que no ocurra nada o se convierta en un desastre. Si lo sustituyéramos por (*s == *t) tampoco ya que sólo compararía el primer elemento. 10.9. si tienen antememorias (cachés). // Crea un reloj y lo pone en marcha double Get_Timer(reloj &). 9. // Retorna el tiempo en segundos desde que se creo este reloj double Stop_Timer(reloj &).CPP 10. Eficiencia y Optimización 10.5) Se prueba en el siguiente ejercicio.12) Intentar borrar sólo una parte del vector reservado es una barbaridad. no tendremos ningún problema. sino simplemente libera la memoria. El listado de la implementación es EJ10_03.CPP alias(i) fuera equivalente en . 10. delete p sólo borraría el primer elemento. equivalentes y ninguno de ellos da error. 10. obviamente. 10.CPP 10.CPP 10. si son máquinas RISC o CISC.2) La solución se encuentra en el fichero EJ10_02.CPP.6) La solución se encuentra en el fichero EJ10_06.CPP 10.9) El programa compara los punteros.8) La solución se encuentra en el fichero EJ10_08. Esto depende de cómo estén orientados los procesadores. en el caso de que no fuera const. Queda como ejercicio hacer una función que compare cadenas.11) Los dos son. no porque sea ilógico pensarlo. Además.10) No es correcto porque hemos definido p como un puntero a enteros constantes sobre los cuales nos podemos hacer un delete. // Igual que Get_Timer() pero además destruye el reloj Además se ha implementado una función de retardo Delay(unsigned long ) que tarda tantos milisegundos como se le pasen en su parámetro. 9. En el siguiente capítulo también se verán algunas funciones de comparación. completamente al contrario de lo que podríamos pensar en un principio.7) La función al ser inline haría que cualquier aparición de sentido y eficiencia a i.

} inline int Mult9(int a) { return Mult8(a) + a. 10.11) Se trataría de lo siguiente: inline int Mult3(int a) { return Mult2(a) + a. } inline int Mult4(int a) { return a << 2. } Según vamos aumentando iremos perdiendo en eficiencia.10) La multiplicación por potencias de dos se puede realizar por medio de desplazamientos de bit. } inline int Mult5(int a) { return Mult4(a) + a. Ejemplos para 2. 4 y 8 serían: inline int Mult2(int a) { return a << 1. La reutilización de unas funciones en otras no ralentiza ya que son inline. } inline int Mult6(int a) { return Mult4(a) + Mult2(a).CPP 10.10. Las funciones para la divisiones son similares pero utilizando el operador >>. } inline int Mult8(int a) { return a << 3 } que por las pruebas que se han realizado son ligeramente más rápidas que la multiplicación normal.9) Una forma de implementar el algoritmo quicksort() está en EJ10_09. } inline int Mult7(int a) { return Mult(6) + a. Esto depende mucho de la máquina. En general: .

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 asignación. Para la gente que empieza puede quedar más claro poniendo: delete this.CPP. while (b) { if ((b | 1) == b) // bit es 1 r+= a. lo utilizamos como fuente en la siguiente sentencia. 10. } return r. 10. El primer objeto Obj1 llama al Pon de la clase c1 con el parámetro 3.12) Es correcto ya que en los macros los comentarios no son expandidos.CPP 10. a <<= 1. que es lo mismo que antes pero ahora se ve que el puntero this al que hemos hecho un delete. Al hacer Obj3.2) El programa es completamente correcto. } que ya no es eficiente. El segundo objeto Obj2 llama al Pon de la clase c2 sin parámetros por lo que se toma el parámetro 1 por defecto que es lo que se almacena en Obj2. 11. 11.CPP PARTE II 11. int b) { int r= 0.Valor.int Mult(int a. Por tanto Obj1. b >>= 1.1) Al hacer delete this estamos liberando la memoria que ocupa el objeto actual por lo que el siguiente this= Ultimo ya no es válido porque el Ultimo puede haber perdido su valor. 11.13) El algoritmo se encuentra en EJ10_13. Por ello. Esta solución y medidas de tiempo se encuentran en el fichero EJ10_11. this= this->Ultimo.CPP . Esto se verá mejor cuando se vea preprocesamiento. Clases 11.Valor se pone a 3.5) La solución se encuentra en el fichero EJ11_05.Valor= 10 no modificamos ningún otro objeto ni de c1 y mucho menos de c2 que no tiene nada que ver.14) La solución se encuentra en el fichero EJ10_14.3) Las dos son inline. se suele utilizar el puntero this para acceder a los atributos de una clase cuando queda comprometida la claridad.

.10) La solución se encuentra en el fichero EJ11_10.CPP 11. no quita para que definamos exactamente los mismos métodos. Otra solución.. public: void f1(). En este caso la solución sería cambiar de orden f1() y f2(). }. inline void clase::f2() { . La cuarta sentencia.11) Si hacemos la implementación de los complejos en forma polar. incluso los constructores.. . o. La quinta sentencia también al utilizar el operador de campo de clase. int clase::Estatuto= 23. Deberemos hacer: class clase { static int Estatuto. que en este caso ocurrirá cuando lleguemos a main().6) La solución se encuentra en el fichero EJ11_06. La segunda modifica el miembro c2. así las funciones no son evaluadas hasta que se expanden. 11. no podemos saber si están implementados en forma rectangular o en forma polar..CPP 11. es no definir ninguna inline. void f2(). } Una curiosa solución es poner las dos funciones inline.12) La primera sentencia modifica el parámetro c1.13) No se puede. 11. pasadas ya las definiciones de f1() y f2(). Solventando este problema no funcionaría tampoco porque cuando se llama a una función inline debe tener su implementación ya definida. La tercera modifica la variable global c3.11..7) La solución se encuentra en el fichero EJ11_07..f1(). evidentemente.9) En primer lugar no funcionaría porque hemos definido los métodos privados. f2(). } void main() { clase o. 11. class clase { . . }.CPP 11. modifica el miembro c1 al usar this. . } void clase::f1() { . Por tanto.. si sólo viésemos las declaraciones de los métodos.

yy).15) No podemos acceder a a porque f() es una función estática y por tanto no tenemos el parámetro implícito this para poder acceder a los miembros.2) No es correcta ya que punto(c.RE().IM()). 11.o definir un método estático para acceder a int clase::Estatuto. Aunque no tiene mucho sentido. Estatuto. si no. 11. se debe seguir poniendo.IM()) crea un objeto temporal en el cuerpo de la función punto(complejo c) y no modifica 'x' e 'y'. y. No se pone retorno i) operador de asignación j) destructor k) Error! Los destructores no tienen parámetros 12. La solución sería: class punto { private: double x. 12.1) Los métodos 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 conversión de (int *) a c1 f) constructor de conversión de float a cl si se toma el último argumento por defecto. el método f() será privado con lo que no lo podremos llamar. public: void Pon(double xx. double yy) { Pon(xx. } }. y= yy. el primero es que como no hemos puesto ningún modificador de acceso y se trata de 'class'. } punto(double xx.RE(). Creación de objetos 12. En segundo lugar. c. De todas formas la sentencia: 11.3) Tiene dos problemas.CPP 12. double yy) { x= xx.14) Perfectamente. } punto(const complejo & c) { Pon(c. no . c.16) La solución se encuentra en el fichero EJ11_16. constructor normal g) operador suma h) operador de conversión de cl a int.

13) Es correcto aunque es más recomendable definir la unión dentro de una clase. sizeof no puede sobrecargarse.CPP 13. 12.CPP 12. Y no hay ninguna conversión en un solo paso para hacer coincidir los parámetros. 12. Esto es debido a que los dos se construyen en la lista de inicialización. liberando la memoria. o a: f(Objeto. 12.16) Al llamarse a la función Nada() que parece que no hace nada. No sabemos si llamar a f(A(Objeto)). que de la forma que tenemos definida la cadena haría un delete s. ya que al haber otro constructor.10) Sí se pueden definir miembros (atributos y métodos) 12.8) Ver EJ12_08. En este caso. Lo único que sabemos con seguridad es que x pasará a valer a antes de que y pase a valer b. 12. Cuando hiciéramos cout << c1.4) Dependerá del orden en que están definidos dentro de una clase.14) Genera ambigüedad. esta última restricción es una garantía de seguridad de que el objeto si es constante no va a ser modificado. 12. 12.11) El operador volatile.0 no). Herencia y Polimorfismo . Al llegar al final del cuerpo de la función (en seguida porque no hace nada). 12. Esto lo suele avisar el compilador por medio de un error al final del programa del tipo "Null pointer assignment" 12.6) Se creará un objeto temporal por lo que el objeto constante no puede ser modificado por mucha referencia de que se trate.5) Para la primera no.12) En primer lugar. Las dos últimas son perfectamente válidas. En segundo lugar. 12. se crea un objeto temporal usando el constructor copia. En la segunda sí será posible (en la versión 2. pero no se puede asegurar. nunca deberemos hacer una asignación a this y mucho menos un delete.17) La solución se encuentra en el fichero EJ12_17. Lo peor no es esto. ya no está definido el constructor por defecto.15) No funcionaría porque en C++ no se buscan conversiones multinivel. sino que al llegar al final de la función se destruiría c1 volviendo a llamar a delete s que ya está borrado. 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 función. ya que hemos liberado la memoria que ocupa y puede ser utilizada por cualquier otro.operator A ()).podemos llamar a funciones no constantes desde objetos constantes. falta el punto y coma final de la clase. se retornaría llamando al destructor del objeto temporal. El constructor copia que tenemos definido sólo copia los atributos. probablemente salga la cadena por pantalla. 12.

double) y tendrá además g(double.5) La solución vale para cualquier tipo: template <class T> int SizeOf_EnBits(T v) { return sizeof(T) * 8.4) La longitud es 4 + 4 + 4 = 12 suponiendo 4 la longitud de int. 13.CPP.4) Que no se puede hacer coincidir (C int.1) Sí que podemos compilar ese programa. si heredamos las dos en una clase C. C valdría . 14. 14.3) Ver EJ14_03. Por tanto B heredará g(int. Sería preferible todos externos. En cambio las funciones g() son funciones totalmente diferentes ya que tienen parámetros distintos.3) La primera crea un objeto dinámico de la clase cuadrado y toma su dirección en c1 que es un puntero a cuadrilatero. En estos casos se recomienda poner la palabra virtual para dejarlo más claro.6) Son los dos virtuales ya que si definimos un destructor como virtual en una clase base. no tiene sentido heredar dos veces ya se virtual o no virtual. incluir (composición). cuadrado *c2= (cuadrado *)new cuadrilatero. Se deja como ejercicio averiguar si teniendo dos clases A y B. 4 la longitud de float y 4 la longitud del puntero a la tabla de métodos virtuales (suponiendo punteros de 32 bits). Si se quiere incluir dos veces una clase se hace precisamente eso.13. La asignación h) es incorrecta por el mismo motivo que la e). En el segundo lugar podríamos usar un cast pero si los métodos no son virtuales puede ser peligroso. 13. // También válido } *) con (int).5) Las funciones f() darán error ya que tienen los mismos parámetros y distinto tipo de retorno. La asignación f) nos muestra que esto es imposible incluso utilizando casts. 13. los destructores en las clases heredadas también serán virtuales.2) Porque el tipo A no está incluido en los parámetros de la función.CPP 14. Se han definido algunos métodos internos y otros externos para mostrar el acceso a vector. Si hubiera sido (C) no habría problema. 14. una con destructor virtual y la otra normal. int). f() dará error.2) No. La segunda sentencia es incorrecta ya que no se puede asignar un puntero a un cuadrilatero a un puntero a un cuadrado. Ya sabemos que el retorno no cuenta. 13. Plantillas 14. Pero la i) es correcta porque siempre podemos pasar de un puntero de un tipo a un puntero de otro tipo utilizando casts. 14. 13.1) La asignación e) es incorrecta ya que no podemos asignar un clase derivada con una clase base. //return sizeof v * 8.7) La solución se encuentra en el fichero EJ13_07. pero en el momento que usemos la función La solución es simplemente borrar la primera declaración ya que la segunda la incluye. ¿el destructor de C será virtual? 13.

estarían permitidas pero no funcionarían de manera correcta: ++l1++. la incluimos dentro del campo de la función.5) Sí que compilaría y enlazaría. Por eso no lo vamos a usar.H2. 16.H1. Por último.12. este artificio de estructura modular es un poco largo de realizar y difícil de entender para el que lo desarrolla. Aquí se definen los miembros privados. Esto sirve para que tengamos varias listas operando sobre los mismos datos. El fichero EJ16_03. que vamos a destruir más veces que a construir.1) Porque ya vienen provistas del método de protección contra redefiniciones que hemos explicado. deberíamos copiar toda la estructura y sólo copiamos la dirección.H está claro como el agua. En resumidas cuentas. EJ16_03.H1 en la parte privada de la clase y después incluye fuera a EJ16_03. Errores y Excepciones 16. pero la solución es simple: typedef clase1<int> clase1_int. Al tratarse de una estructura dinámica. pero como en este caso sólo la utilizamos aquí. No se puede saber si está implementada dinámica o estáticamente. 15. COMENTARIOS: Los operadores de postincremento y postdecremento retornan por valor. clase2 <clase1_int> a. operaciones como la siguiente.H como vemos. Se compone de tres ficheros EJ16_03. Es el fichero EJ16_03.H2. Modularidad 16. hay un fichero que lo prueba todo. Como se observa lo único que ve el usuario son los métodos de la lista. 16. En primer lugar incluye EJ16_03. Es de resaltar la presencia interna de nodo.H1.H2. no se sabe nada de sus miembros privados. queda limpio de toda implementación. Pasemos ahora a la implementación de los métodos. el otro operador actuaría sobre un objeto temporal retornado por el primero. ni estáticos. sólo lo imprescindible que debe conocer el que usa esta clase. sí que destruimos toda la estructura. Se podría haber definido como clase amiga de clista. EJ16_03. Pero nadie puede dudar que el fichero EJ16_03. La parte privada de la clase (los atributos) está en el fichero EJ16_03. Pero cuando destruimos los objetos temporales. Sólo incrementaría una vez l1. De todas formas. cada vez que llamemos implícitamente al constructor copia (por ejemplo con objetos temporales).H. por lo que no son visibles externamente y no habría conflicto entre ellas.CPP. Esto suele ser peligroso por los objetos temporales y porque la destrucción de uno implica que se ha liberado el espacio al que apuntan todos.3) Aquí viene la solución al ejercicio anterior.2) Funcionaría muy mal ya que no hemos definido el constructor copia y el operador de asignación. Están en el fichero EJ16_03.CPP que nos lo prueba todo. Así. 16.6) No. El último método (Alias) se suele incluir para hacer referencias. este fichero sólo debe incluir la especificación. Al tener los dos el atributo const tienen acceso privado al módulo. En resumen. sería mucho más . Además tenemos un fichero EJ16_03.

eof()) break. cin.put(c).conveniente.CPP 18. if (cin. cin >> c. la salida sería: setw(5) actúa sobre otro . } que no utiliza manipuladores. while (1) { char c. cout << c. Entrada y salida 18.h> #include <iomanip. // Fin copia cout.h> void main() { cin >> resetiosflags(ios::skipws). if (!cin) break. 18. #include <iostream. poner una sola declaración en una cabecera e incluirla en los dos módulos. Además.1) La solución se encuentra en el fichero EJ18_01.3) El programa debe incluir algunos manipuladores y flags para que no se ignoren los caracteres blancos. Introducción a las Librerías Estándar No tiene ejercicios. 18. } } También se podía haber hecho así: while (1) { char c.2) En cada caso saldría: a) 00103 b) 10 // Todavía no había hecho efecto c) a 18. PARTE III 17.4) No ya que el setw(100) actúa sobre un stream (cin) y el (cout).get(c).

dat" const int Largo = 7. const char *fn= "test. Utilizamos entonces el constructor ofstream(int fh): fstream Stream_de_la_impresora(4). Ya que estamos con la programación orientada a objetos. 18. } // Al destruirse se cierra { fstream f(fn. s[i]= '\0'. Principalmente.7) La solución es: int i= 42.5) No ya que ya está sobrecargado en <iostream. 2). Si queremos utilizar buffer: char *Buffer= new char [1024].6) Tenemos aquí un programa que produce un volcado hexadecimal de un fichero de entrada a otro de salida. f. 18. cin >> s[i]. 18. Si se omiten estos ficheros se cogerán por defecto la entrada y salida por pantalla estándar. // Poner caracter nulo de terminación de cadena } .8) Simplemente hay que saber el código del descriptor de la impresora (que suele ser 4). ofstream Str_de_la_impr(4.h> en las clases istream y ostream. f. es más lógico utilizar constructores y destructores. { fstream f(fn. f.00069 18.write((const char *)&i.seekp(Largo. ios::out | ios::binary). } // Al destruirse se cierra También podíamos haber llamado a los destructores explícitamente. ios::beg). ios::in | ios::binary). lo que no hay que hacer es mezclar los dos métodos.CPP 18. 1024). f. Ver EJ18_06. // No pasar los caracteres blancos for(int i= 0.9) La función Leer_Cadena() la definimos así: #include <iomanip. ios::beg).read((char *)&i.seekg(Largo. Buffer.h> // resetiosflags void Leer_Cadena(char *s) { cin >> resetiosflags(ios::skipws). 2). i++) // Leer hasta '\0' if (s[i] == '\n') // Se ha pulsado INTRO break.

1-2) La solución se encuentra en el fichero EJ20_01. 19. 21. Contenedores y adaptadores 21. 20. '\n'. 21.CPP 19.4) La solución se encuentra en los ficheros EJ21_04a.8) La solución se encuentra en el fichero EJ21_08.CPP 22.7) La solución se encuentra en el fichero EJ21_07.CPP 21.CPP 21.CPP.2) La solución se encuentra en el fichero EJ21_02. Introducción a la STL 20.CPP 21.CPP 19.3) La solución se encuentra en los ficheros EJ20_03a.CPP 21.CPP y EJ21_03b.CPP 21. Cadenas y Numéricos 19.3) La solución se encuentra en los ficheros EJ21_03a.1) La solución se encuentra en el fichero EJ22_01. EJ20_03b.CPP 20.2) La solución se encuentra en el fichero EJ19_02.En primer lugar hacemos que no se quiten los caracteres blancos.4) La solución se encuentra en el fichero EJ19_04.CPP 20.CPP.6) La solución se encuentra en el fichero EJ21_06.5) La solución se encuentra en el fichero EJ21_05.CPP 21. Al final deberemos poner el carácter nulo ya que el stream no lo inserta. Luego leemos hasta encontrar uno de estos dos caracteres '\0'.CPP 19.CPP . Objetos-funciones y algoritmos 22.5) La solución se encuentra en el fichero EJ19_05.CPP y EJ20_03c.CPP.1) La solución se encuentra en el fichero EJ19_01.CPP.9) La solución se encuentra en el fichero EJ21_09.4) La solución se encuentra en el fichero EJ20_04.5) La solución se encuentra en el fichero EJ20_05.1) La solución se encuentra en el fichero EJ21_01. Éste último se producirá cuando pulsemos la tecla de retorno.CPP 20.CPP 21.CPP y EJ21_04b.

CPP 22.5) La solución se encuentra en el fichero EJ22_05.CPP 22.CPP 22.4) La solución se encuentra en el fichero EJ22_04.7) La solución se encuentra en el fichero EJ22_07.1) Está en INTERPRETE.CPP 22. El Proceso de Desarrollo con C++ 23.22. José Hernández Orallo y Mª Carmen Juan Lizandra .3) La solución se encuentra en el fichero EJ22_03.CPP 22.6) La solución se encuentra en el fichero EJ22_06.CPP © 2001 Paraninfo Thomson Learning y los autores: Última actualización: Ir a la página principal 12 de noviembre de 2001.2) La solución se encuentra en el fichero EJ22_02.CPP 23. Enrique Hernández Orallo.