metodología de la programación

303
UNIVERSIDAD DE GRANADA Grado en Ingeniería Informática METODOLOGÍA DE LA PROGRAMACIÓN Curso: 2011/2012 Clase: Primero - Grupo: B Aviso legal: los archivos están sujetos a derechos de propiedad intelectual y su titularidad corresponde a los usuarios que los han subido a SWAD. Esto es solo una recopilación de toda la asignatura impartida en la UGR.

Upload: juan-ubia

Post on 11-Mar-2016

239 views

Category:

Documents


9 download

DESCRIPTION

Recopilación de la asignatura.

TRANSCRIPT

Page 1: Metodología de la Programación

UNIVERSIDAD DE GRANADA

Grado en Ingeniería

Informática METODOLOGÍA DE LA

PROGRAMACIÓN

Curso: 2011/2012 Clase: Primero - Grupo: B

Aviso legal: los archivos están sujetos a derechos de propiedad intelectual y su titularidad corresponde a los usuarios que los han subido a SWAD. Esto es solo una

recopilación de toda la asignatura impartida en la UGR.

Page 2: Metodología de la Programación

TEORÍA

Curso: 2011/2012 Clase: Primero - Grupo: B

Page 3: Metodología de la Programación

Metodología de la ProgramaciónGrado en Ingeniería Informática

Curso 2011/2012

Francisco J. Cortijo Bon

Departamento de Ciencias de la Computacióne Inteligencia Artificial

ETS de Ingenierías Informática y de TelecomunicaciónUniversidad de Granada

[email protected]

.

Page 4: Metodología de la Programación

Contenidos

I. Punteros y memoria dinámica 1

I.1. El tipo de dato puntero . . . . . . . . . . . . . . . . . . . . 2

I.1.1. Declaración . . . . . . . . . . . . . . . . . . . . . . . 2

I.1.2. Operador de dirección . . . . . . . . . . . . . . . . . 3

I.1.3. Operador de indirección . . . . . . . . . . . . . . . . 6

I.1.4. Punteros a punteros . . . . . . . . . . . . . . . . . . 8

I.1.5. Punteros y funciones . . . . . . . . . . . . . . . . . 9

I.1.6. Vectores de punteros . . . . . . . . . . . . . . . . . 13

I.1.7. El operador de asignación sobre punteros . . . . . . 14

I.1.8. Operadores relacionales . . . . . . . . . . . . . . . . 17

I.1.9. Operadores aritméticos . . . . . . . . . . . . . . . . 19

I.1.10. const y punteros . . . . . . . . . . . . . . . . . . . . 21

I.2. struct y punteros . . . . . . . . . . . . . . . . . . . . . . . 22

I.2.1. El operador flecha (->) . . . . . . . . . . . . . . . . . 24

3

I.2.2. struct con punteros . . . . . . . . . . . . . . . . . . 24

I.3. Vectores y punteros . . . . . . . . . . . . . . . . . . . . . . 26

I.3.1. Paso de vectores a funciones . . . . . . . . . . . . . 28

I.3.2. Paso de “partes” de vectores a funciones . . . . . . 31

I.4. Matrices y punteros . . . . . . . . . . . . . . . . . . . . . . 32

I.4.1. Paso de matrices a funciones . . . . . . . . . . . . . 36

I.5. Cadenas y punteros . . . . . . . . . . . . . . . . . . . . . . 37

I.5.1. Iniciación de cadenas de caracteres . . . . . . . . . 38

I.5.2. Funciones de lectura/escritura de cadenas . . . . . . 39

I.5.3. Funciones de gestión de cadenas . . . . . . . . . . . 41

I.6. Matrices bidimensionales y vectores de punteros . . . . . . 49

I.7. La memoria dinámica . . . . . . . . . . . . . . . . . . . . . 65

I.7.1. La estructura de la memoria . . . . . . . . . . . . . . 65

I.7.2. Los operadores new y delete . . . . . . . . . . . . . 68

I.7.3. Objetos dinámicos compuestos . . . . . . . . . . . . 75

I.7.4. Reserva de memoria dentro de las funciones . . . . 81

I.7.5. Vectores dinámicos . . . . . . . . . . . . . . . . . . 83

I.7.6. Matrices dinámicas . . . . . . . . . . . . . . . . . . 88

II. Funciones 95

II.1. Las funciones en C++ . . . . . . . . . . . . . . . . . . . . . 96

Page 5: Metodología de la Programación

II.1.1. Paso de argumentos por valor . . . . . . . . . . . . 98

II.2. La función main() . . . . . . . . . . . . . . . . . . . . . . . 99

II.2.1. Paso de argumentos a la función main() . . . . . . . 101

II.3. Referencias . . . . . . . . . . . . . . . . . . . . . . . . . . 105

II.3.1. Paso de argumentos por referencia . . . . . . . . . . 108

II.3.2. Devolución en una función de una referencia . . . . 111

II.4. Parámetros con valores por defecto . . . . . . . . . . . . . 114

II.5. Sobrecarga de funciones . . . . . . . . . . . . . . . . . . . 117

II.6. Funciones inline . . . . . . . . . . . . . . . . . . . . . . . . 120

II.7. Ejemplo: Prototipos . . . . . . . . . . . . . . . . . . . . . . 123

III. Clases 149

III.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . 150

III.2. Constructores . . . . . . . . . . . . . . . . . . . . . . . . . 156

III.3. Modularización . . . . . . . . . . . . . . . . . . . . . . . . . 160

III.4. Destructor . . . . . . . . . . . . . . . . . . . . . . . . . . . 171

III.5. Prioridad de ejecución . . . . . . . . . . . . . . . . . . . . 172

III.6. El constructor de copia . . . . . . . . . . . . . . . . . . . . 175

III.7. Funciones inline en clases . . . . . . . . . . . . . . . . . . 182

III.8. El puntero this . . . . . . . . . . . . . . . . . . . . . . . . . 183

III.9. Sobrecarga de operadores . . . . . . . . . . . . . . . . . . 186

III.9.1. Sobrecarga del operador = . . . . . . . . . . . . . . . 189

III.9.2. Código reutilizable . . . . . . . . . . . . . . . . . . . 196

III.9.3. Operador [] . . . . . . . . . . . . . . . . . . . . . . 200

III.9.4. Operadores aritméticos . . . . . . . . . . . . . . . . 208

III.9.5. Operadores de inserción y extraccción sobre flujos . 217

III.10.Objetos y miembros const . . . . . . . . . . . . . . . . . . 223

III.11.Miembros static . . . . . . . . . . . . . . . . . . . . . . . . 229

IV. Gestión de E/S. Ficheros 235

IV.1. Flujos de E/S . . . . . . . . . . . . . . . . . . . . . . . . . . 236

IV.1.1. La biblioteca iostream . . . . . . . . . . . . . . . . . 236

IV.1.2. Flujos de Salida . . . . . . . . . . . . . . . . . . . . 238

IV.1.3. Flujos de Entrada . . . . . . . . . . . . . . . . . . . 241

IV.1.4. Evaluación del estado de un flujo . . . . . . . . . . . 252

IV.1.5. E/S sin formato . . . . . . . . . . . . . . . . . . . . . 253

IV.1.6. Redirección y encauzamiento . . . . . . . . . . . . . 256

IV.1.7. Personalizar las E/S . . . . . . . . . . . . . . . . . . 262

IV.2. Ficheros. Introducción . . . . . . . . . . . . . . . . . . . . 276

IV.2.1. Apertura y cierre de ficheros . . . . . . . . . . . . . 276

IV.2.2. Nombres de fichero . . . . . . . . . . . . . . . . . . 287

IV.2.3. Flujos como argumentos . . . . . . . . . . . . . . . 292

Page 6: Metodología de la Programación

IV.2.4. La función eof() . . . . . . . . . . . . . . . . . . . . 305

IV.2.5. Ficheros binarios . . . . . . . . . . . . . . . . . . . . 308

IV.2.6. Modos de apertura . . . . . . . . . . . . . . . . . . . 322

IV.2.7. Funciones de posicionamiento . . . . . . . . . . . . 325

.

Page 7: Metodología de la Programación

Tema I

Punteros y memoria dinámica

Objetivos:

� Conocer y manejar el tipo de dato puntero.

� Conocer la estructura y gestión de la memoria desde la perspectivade un programador.

� Entender cómo un programa puede gestionar datos usando la di-rección de memoria en la que se almacenan.

� Conocer cómo puede gestionarse la memoria (su reserva y libe-ración) para obtener exactamente la cantidad de memoria que seprecisa.

Para cualquier sugerencia, aportación o notificación de erratas en estas transparen-

cias, por favor, enviar un e-mail a Francisco J. Cortijo

[email protected]

Punteros y memoria dinámicaEl tipo de dato puntero → 2

I.1. El tipo de dato puntero

Un puntero es un dato que contiene la dirección de memoria de otro dato,incluyendo una dirección especial llamada dirección nula, representadaen C++ por el valor 0.

Con más precisión se diría, que contiene la dirección de memoria dondeempieza a almacenarse el otro dato.

I.1.1. Declaración

Declaración de un dato de tipo puntero a <tipo_base>

<tipo_base> * <nombre_variable_puntero>;

Pueden declararse varios punteros en la misma declaración:

int *ptr, *otro_ptr, i; // ptr y otro_ptr son punteros a int// pero i es de tipo int

Observad que el * se asocia al nombre de la variable, no al tipo base.

Page 8: Metodología de la Programación

Punteros y memoria dinámicaEl tipo de dato puntero → Operador de dirección 3

Ejemplos:

int * ptr_a_entero; // ptr_a_entero es de tipo "puntero a int"double *ptr_a_double; // ptr_a_double es de tipo "puntero a double"

Queremos conseguir lo siguiente:

I.1.2. Operador de dirección

El operador & devuelve la dirección de memoria de una variable.

&<variable>

El operador & se utiliza habitualmente para asignar valores a datos detipo puntero.

int un_entero = 5;int *ptr_a_entero;

ptr_a_entero = &un_entero;

un_entero es una variable de tipo int, por lo que la expresión &un_enteroes la dirección de memoria donde comienza un entero y, por tanto, puedeser asignada al puntero ptr_a_entero.

Punteros y memoria dinámicaEl tipo de dato puntero → Operador de dirección 4

Se dice que ptr_a_entero apunta a un_entero.

Puede inicializarse un puntero en la declaración:

int i = 5;int *ptri = &i;

Otros ejemplos:

int un_entero = 5;int *ptr_a_entero;ptr_a_entero = &un_entero;

double un_double = 23.47;double *ptr_a_double;ptr_a_double = &un_double;

Page 9: Metodología de la Programación

Punteros y memoria dinámicaEl tipo de dato puntero → Operador de dirección 5

Un caso interesante:

int v [5] = {2, 6, 3, 5, 3};int *p;

p = &v[0];

� v es un vector de int

� v[0] es un int

� &v[0] es la dirección de memoria de un int

� p = &v[0] hace que p tenga la dirección de memoria del primer ele-mento del vector v

En definitiva: podemos emplear un puntero para indicar el comienzo deun vector.

Pero también podríamos escribir:

p = &v[2];

p

0 4321

2 6 3 5 3

v

Punteros y memoria dinámicaEl tipo de dato puntero → Operador de indirección 6

I.1.3. Operador de indirección

El operador * se aplica a un puntero y se emplea para acceder a la variableapuntada por un puntero.

*<puntero>

*<puntero> devuelve el contenido del objeto apuntado por <puntero>. Si<puntero> fue declarado como

<tipo_base> * <puntero>;

entonces *<puntero> es de tipo <tipo_base>

char c, *ptrc;ptrc = &c;*ptrc = ’A’; // equivalente a c = ’A’

ptrc es un puntero a caracter que contiene la dirección de c, por tanto, laexpresión *ptrc es el objeto apuntado por el puntero, es decir, c.

IMPORTANTE: *<puntero> es una exresión de tipo <tipo_base> y puedeemplearse donde esté permitido el uso de <tipo_base>. Por ejemplo,

int *ptr;int entero = 5;double resultado;

ptr = &entero;resultado = pow (*ptr, 2) // 5^2

*ptr = 6;resultado = pow (*ptr, 2) // 6^2

Page 10: Metodología de la Programación

Punteros y memoria dinámicaEl tipo de dato puntero → Operador de indirección 7

Ejemplos:

int un_entero = 5;int *ptr_a_entero;ptr_a_entero = &un_entero;*ptr_a_entero = 9;cout << *ptr_a_entero;

double un_double = 23.47;double *ptr_a_double;ptr_a_double = &un_double;*ptr_a_double = 53.45;cout << *ptr_a_double;

Ejercicio. Declarad dos punteros a dos variables. Intercambiad el conte-nido de dichas variables, usando los punteros.

Punteros y memoria dinámicaEl tipo de dato puntero → Punteros a punteros 8

I.1.4. Punteros a punteros

Un puntero puede contener la dirección de memoria de otro puntero. De-cimos que el primero es un puntero a puntero, porque ”apunta” a un pun-tero.

Ejemplo:

int n = 5;int *p_int; // "p_int" apunta a un "int"int **p_p_int; // "p_p_int" apunta a un "int *"

p_int = &n; // (1)p_p_int = &p_int; // (2)

Izda: Después de (1). Dcha: Después de (2)

Page 11: Metodología de la Programación

Punteros y memoria dinámicaEl tipo de dato puntero → Punteros y funciones 9

I.1.5. Punteros y funciones

Un dato de tipo puntero puede ser un argumentoformal de una función.

� Como un puntero contiene direcciones de memoria, en la llamadaa la función se indicará la dirección de memoria (&)

� La función gestionará el objeto apuntado con el operador de indi-reccción (*)

Cuidado:

� El puntero es una variable local: el valor almacenado en el punteropuede modificarse libremente, y este cambio no afecta al objetocuya dirección se usó en la llamada a la función.

� Si el puntero no se modifica, pero sí el objeto apuntado, el cambiose refleja al finalizar la llamada a la función, ya que realmente seactúa sobre el objeto usado en la llamada, no sobre una copia.

Punteros y memoria dinámicaEl tipo de dato puntero → Punteros y funciones 10

int main (void){

int var1 = 1;int var2 = 2;

cout << var1 << " " << var2 << "\n"; // 1 2intercambia (&var1, &var2);cout << var1 << " " << var2 << "\n"; // 2 1

}

void intercambia (int *n1, int *n2){

int tmp; // almacenamiento temporal

tmp = *n1;*n1 = *n2;*n2 = tmp;

}

Estado de la pila cuando empieza a ejecutarse lafunción intecambia y al finalizar su ejecución

Page 12: Metodología de la Programación

Punteros y memoria dinámicaEl tipo de dato puntero → Punteros y funciones 11

Un puntero puede referenciar a datos en diferentes zonas de la memoria.

int global = 10; // variable global :-(

int main (void) {int var1 = 1; // variable local a main()cout << var1 << "\n";reset (&var1);cout << var1 << "\n";

}

void reset (int *p) {int local = 5; // A - (figura)*p = 0; // B - (figura) Acceso a variable de main()p = &local; // C - (figura) Apunta a variable de reset()

*p = 0; // D - (figura) Acceso a variable de reset()p = &global; // E - (figura) Apunta a variable global

*p = 0; // F - (figura) Acceso a variable global}

Punteros y memoria dinámicaEl tipo de dato puntero → Punteros y funciones 12

void reset (int *p){

int local = 5; // A - (figura)*p = 0; // B - (figura) Acceso a variable de main()p = &local; // C - (figura) Apunta a variable de reset()

*p = 0; // D - (figura) Acceso a variable de reset()p = &global; // E - (figura) Apunta a variable global

*p = 0; // F - (figura) Acceso a variable global}

Page 13: Metodología de la Programación

Punteros y memoria dinámicaEl tipo de dato puntero → Vectores de punteros 13

I.1.6. Vectores de punteros

Diferenciar: int v1[4]; int *v2[4];

/*****************************************************/// Programa: vec_pun.cpp// Declaracion y uso de un vector de punteros/*****************************************************/

#include <iostream>using namespace std;

int main (void){

const int TOPE = 10;

int *v[TOPE]; // Vector de TOPE punteros a enterosint i, a = 5, b = 10;

// Iniciación de los punterosv[0] = v[1] = &a; // v[0] y v[1] apuntan a "a"v[2] = v[3] = &b; // v[2] y v[3] apuntan a "b"

int total_utilizados = 4;for (i = 0; i < total_utilizados; i++) // Mostrar contenido

cout << *(v[i]) << " "; // de los objetosreturn (0); // referenciados

} // por "v[i]"

Punteros y memoria dinámicaEl tipo de dato puntero → El operador de asignación sobre punteros 14

Estado de la memoria: A) tras la declaración, B) tras la iniciación de los v[i].

Resultado de la ejecución:

5 5 10 10

I.1.7. El operador de asignación sobre punteros

Si un puntero de tipo puntero a <tipo_base> aparece en la parte izquierdade una asignación, éste puede recibir una dirección de memoria:

� resultado de aplicar el operador dirección & sobre una variable detipo <tipo_base>

int i = 5;int *ptri = &i;

Page 14: Metodología de la Programación

Punteros y memoria dinámicaEl tipo de dato puntero → El operador de asignación sobre punteros 15

� de otro puntero del mismo tipo.

int n = 5;int *ptr, *copia_ptr;ptr = &n; // *ptr es 5copia_ptr = ptr; // *copia_ptr es 5

� la dirección nula

int *ptr = 0;

La asignación debe hacerse con punteros del mismo tipo.

int n = 5;int *p1 = &n;int *p2 = p1;char *ptr = &n; // ERROR: n es de tipo int

Puede “moldearse” el puntero para que “interprete” un dato de otro tipo:

int n = 5;int *p1 = &n;char *ptr = reinterpret_cast<char *>(&n);

Un puntero debe estar correctamente inicializado.

� Puede provocar errores en tiempo de ejecución:

int *ptr; // ptr contiene una direccion "basura"*ptr = 10; // Escribe "10" en un lugar indeterminado

� Puede producir resultados inesperados (basura)

int *ptr; // ptr contiene una direccion "basura"cout << *ptr;

Punteros y memoria dinámicaEl tipo de dato puntero → El operador de asignación sobre punteros 16

Ejercicio. Describir la salida de los siguientes códigos, siendo:

int entero = 5;int *ptr;

a) entero = *ptr * entero;cout << entero;

b) ptr = &entero;entero = entero * *ptr ;entero++;cout << *ptr << " " << entero;

c) ptr = &entero;entero = entero**ptr ; // Estilo de escritura :-(entero = entero*ptr ; // <- ?

Page 15: Metodología de la Programación

Punteros y memoria dinámicaEl tipo de dato puntero → Operadores relacionales 17

I.1.8. Operadores relacionales

Los operadores relacionales <, >, <=, >=, != y == son aplicables a datos detipo puntero.

Al usar estos operadores el valor del puntero (la dirección de memoriaque almacena) se comporta como un número entero.

Operadores != y ==

int *p1, *p2;int n1 = 5, n2 = 10;

p1 = &n1;p2 = p1;

if (p1 == p2) cout << "Punteros iguales\n"";else cout << "Punteros diferentes\n";if (*p1 == *p2) cout << "Valores iguales\n"";else cout << "Valores diferentes\n";

Punteros y memoria dinámicaEl tipo de dato puntero → Operadores relacionales 18

int *p1, *p2;int n1 = 5, n2 = 5;

p1 = &n1;p2 = &n2;

if (p1 == p2) cout << "Punteros iguales\n"";else cout << "Punteros diferentes\n";if (*p1 == *p2) cout << "Valores iguales\n"";else cout << "Valores diferentes\n";

Los operadores <, >, <= y >= tienen sentido para conocer la posición re-lativa de un objeto respecto a otro en la memoria. Solo tienen utilidadcuando los dos punteros referencian a objetos cuyas posiciones relati-vas son conocidas (por ejemplo, elementos del mismo vector).

p==q es falsa

p!=q es verdadera

*p==*q es verdadera

p<q es verdadera

p>q es falsa

p<=q es verdadera

p>=q es falsa

Page 16: Metodología de la Programación

Punteros y memoria dinámicaEl tipo de dato puntero → Operadores aritméticos 19

I.1.9. Operadores aritméticos

Los operadores aritméticos +, -, ++, --, += y -= son aplicables a datos detipo puntero.

Al usar estos operadores el valor del puntero (la dirección de memoriaque almacena) se comporta CASI como un número entero: la suma oresta de un valor n a un puntero hace que su valor se incremente o de-cremente en n*sizeof(<tipo_base>)

En definitiva, se modifica la dirección del puntero adecuadamente, parareferenciar a otro elemento del mismo tipo situado después (suma) o an-tes (resta) en la memoria. El salto se hace en unidades del <tipo_base> (ycada unidad vale sizeof(<tipo_base>) bytes).

int v [5] = {2, 6, 3, 5, 3};int *p;

p = &v[2];

p

0 4321

2 6 3 5 3

v

pp

A B

0 4321

2 6 3 5

0 4321

2 6 3 5 3 3

v v

A) Efecto de ejecutar p++ (p=p+1). B) Efecto de ejecutar p+=2 (p=p+2)

Punteros y memoria dinámicaEl tipo de dato puntero → Operadores aritméticos 20

¿Qué devuelve q -p ?

Ejercicio. Ejecutar el siguiente fragmento de programa e interpretar elresultado.

int n = 255;

unsigned char *p = reinterpret_cast<char *>(&n);

for (int i=0; i<sizeof(n); i++, p++)cout << (int) (*p) << "\n";

Page 17: Metodología de la Programación

Punteros y memoria dinámicaEl tipo de dato puntero → const y punteros 21

I.1.10. const y punteros

Si se dispone de una variable de tipo puntero, podemos contemplar trescasos:

� const int *p;

Puntero a un dato constante

No se permite modificar el entero al que apunta p, pero sí la direc-ción almacenada en p

� int * const p;

Puntero constante a un dato

No se permite modificar la dirección almacenada en p, pero sí elvalor entero al que apunta p.

� const int * const p;

Puntero constante a un dato constante

No se permite modificar, ni el valor de p, ni el valor al que apunta p.

Punteros y memoria dinámicastruct y punteros → 22

I.2. struct y punteros

Podemos apuntar a datos struct con punteros, y en ese caso el operador* devuelve el struct.

Todo lo explicado es válido también cuando el puntero contiene la direc-ción de memoria de un dato de un tipo no elemental, como un struct:

struct TipoAlumno{int codigo;int edad;double notas[2];

};

TipoAlumno un_alumno; // structTipoAlumno *ptr_a_alumno; // puntero a struct

un_alumno.codigo = 34;un_alumno.edad = 19;un_alumno.notas[0] = 4.3;un_alumno.notas[1] = 9.8

Ejercicio. Apuntad con ptr_a_alumno a un_alumno y asignadle valores aun_alumno a través del puntero ptr_a_alumno

Page 18: Metodología de la Programación

Punteros y memoria dinámicastruct y punteros → 23

La asignación entre punteros funciona igual cuando trabajamos con pun-teros a struct.

struct TipoStruct{int Codigo;double Salario;

};

TipoStruct *ptr_a_struct_1;TipoStruct *ptr_a_struct_2;TipoStruct mi_struct;

mi_struct.Codigo = 100;mi_struct.Salario = 2500.55; // A (ver figura)

ptr_a_struct_1 = &mi_struct;ptr_a_struct_2 = ptr_a_struct_1; // B (ver figura)

cout << (*ptr_a_struct_1).Codigo; // 100cout << (*ptr_a_struct_2).Codigo; // 100

Punteros y memoria dinámicastruct y punteros → El operador flecha (->) 24

I.2.1. El operador flecha (->)

La sintaxis (*puntero).campo puede simplificarse empleando el operadorflecha (->) quedando una expresión más clara: puntero->campo

struct TipoStruct{int Codigo;double Salario;

};...............TipoStruct *ptr_a_struct_1;TipoStruct *ptr_a_struct_2;TipoStruct mi_struct;

mi_struct.Codigo = 100;mi_struct.Salario = 2500.55;

ptr_a_struct_1 = &mi_struct;cout << ptr_a_struct_1->Codigo;

ptr_a_struct_2 = ptr_a_struct_1;cout << ptr_a_struct_2->Codigo;

I.2.2. struct con punteros

Un struct puede contener campos de tipo puntero.

Sabemos que la asignación entre dos struct realiza una copia literal (cam-po a campo). Por tanto, si el campo es un puntero, se producirá una asig-nación entre punteros, es decir, se copia la dirección de memoria quecontiene y los dos punteros apuntarán al mismo dato (peligro potencial).

Page 19: Metodología de la Programación

Punteros y memoria dinámicastruct y punteros → struct con punteros 25

struct TipoStruct{int dato;double *puntero;

};TipoStruct mi_struct_1, mi_struct_2;

double real = 5.8;mi_struct_1.dato = 4;mi_struct_1.puntero = &real; // A (ver figura)

mi_struct_2 = mi_struct_1; // B (ver figura)

cout << *(mi_struct_1.puntero); // Imprime 5.8cout << *(mi_struct_2.puntero); // Imprime 5.8

Ejercicio. ¿Qué consecuencia tiene la ejecución de esta instrucción?

*(mi_struct_2.puntero) = 8.7;

Punteros y memoria dinámicaVectores y punteros → 26

I.3. Vectores y punteros

En C++ podemos ver y usar el nombre de un vector como un punteroconstante al primer elemento del mismo.

int v [5] = {2, 6, 3, 5, 3};

cout << *v << "\n"; // 2 (el valor del primer elemento)

for (int i=0; i<5; i++)cout << *(v+i) ;

En definitiva, escribir &v[0] equivale a escribir v.

Si queremos usar un puntero -independiente- para referenciar al primerelemento del vector podemos hacer:

int *p;

p = &v[0]; // poco usualp = v; // lo usual (por comodidad)

OJO: Eso no significa que punteros y vectores sean iguales

� Si p = v según la equivalencia p = &v[0]

Entonces *p == *(&v[0])

Como * y & son opearaciones complementarias se anulan y

*p == v[0]

� p+1 == &v[1], entonces,

*(p+1) == *(&v[1]) == v[1]

� En general, p+i == &v[i], por lo que *(p+i) == *(&v[i]) == v[i]

Page 20: Metodología de la Programación

Punteros y memoria dinámicaVectores y punteros → 27

Resumen:

1. Podemos ver y usar el nombre de un vector como un puntero cons-tante al primer elemento del mismo.

2. Si p es un puntero al inicio de un vector v podemos acceder a loselementos de v indistintamente:

� Empleando la notación convencional v[i] ó p[i]

� Empleando la notación basada en punteros *(v+i) ó *(p+i)

int v [5] = {2, 6, 3, 5, 3}; int v [5] = {2, 6, 3, 5, 3};int *p = v;

cout << *v << "\n"; cout << *p << "\n";

for (int i=0; i<5; i++) for (int i=0; i<5; i++)cout << *(v+i); cout << *(p+i);

for (; p<v+5; p++)cout << *p;

int v [5] = {2, 6, 3, 5, 3}; int v [5] = {2, 6, 3, 5, 3};int *p = v;

for (int i=0; i<5; i++) for (int i=0; i<5; i++)cout << v[i]; cout << p[i];

Punteros y memoria dinámicaVectores y punteros → Paso de vectores a funciones 28

I.3.1. Paso de vectores a funciones

Claves:

� Un vector puede verse como un puntero constante a su primer ele-mento.

� En una función podemos “recibir” direcciones de memoria si elparámetro formal es un puntero.

Entonces:

� Se pasa el nombre del vector (recordad que equivale a la direcciónde memoria del primer elemento.

� Se recibe en un puntero al tipo base del vector, que contendrá ladirección de memoria del primer elemento del vector.

void ImprimeVectorInt (int *ptr_int, const int num){

for (int i=0; i<num; i++)cout << ptr_int[i]; // tambien *(ptr_int+i)

}

int main (void){

const int Max = 5;int v [Max] = {2, 6, 3, 5, 3};

ImprimeVectorInt (v,Max); // tambien: ImprimeVectorInt (&v[0],Max);}

Page 21: Metodología de la Programación

Punteros y memoria dinámicaVectores y punteros → Paso de vectores a funciones 29

Por supuesto, también podemos pasar como parámetro actual un punterocualquiera no constante:

void ImprimeVectorInt (int *ptr_int, const int num){for (int i=0 ; i< num ; i++)

cout << ptr_int[i];}

int main(void){const int Max = 5;int v [Max] = {2, 6, 3, 5, 3};int *ptr;

ptr = v;

ImprimeVectorInt (ptr, Max); // ptr_int = ptr}

Desde la función podemos acceder a las componentes para modificarlas:

void PonCeros (int *ptr_int, const int num){for (int i=0 ; i< num ; i++)

ptr_int[i] = 0;}int main(void){

const int Max = 5;int v [Max] = {2, 6, 3, 5, 3};

PonCeros (v, Max);}

Punteros y memoria dinámicaVectores y punteros → Paso de vectores a funciones 30

Para evitar modificar por accidente las componentes usamos, comosiempre, const:

void PonCeros (const int *ptr_int, const int num){for (int i=0 ; i< num ; i++)

ptr_int[i] = 0; // Error de compilación}int main(void){

const int Max = 5;int v [Max] = {2, 6, 3, 5, 3};PonCeros (v, Max);

}

Otra manera alternativa de recibir un vector en una función:

void f (int v[], int num) void f (int *v, int num){ {...... ......} }

Ejemplo:

void ImprimeVectorInt (int vector[], const int num){

for (int i=0; i<num; i++)cout << vector[i];

}int main (void){

const int Max = 5;int v [Max] = {2, 6, 3, 5, 3};ImprimeVectorInt (v , Max);

}

Page 22: Metodología de la Programación

Punteros y memoria dinámicaVectores y punteros → Paso de “partes” de vectores a funciones 31

I.3.2. Paso de “partes” de vectores a funciones

Haremos que la función que recibe el vector “crea” que éste comienza enuna posición diferente.

int a[20];......

int f (int *p);

Una llamada de este tipo:

f (&a[2]); // equivalentemente, f (a+2);

hará que la función f() crea que el vector empieza en la posición 2 dea, por lo que para la función, p[0] será en realidad a[2], p[1] será enrealidad a[3], y así sucesivamente.

Variables de f()

&a[2]

p

?

19

Variables de main()

? ? ? ? ?

a

0 1 32 4

Variables de f()

?

19

A

Bp

Variables de main()

? ? ? ? ?

a

0 1 32 4

p[0] p[1] p[2] p[17]

A) Correspondencia entre parámetros actuales y formales el la llamada a f(). B)Estado de la memoria tras establecer la correspondencia entre parámetros actuales

y formales.

Punteros y memoria dinámicaMatrices y punteros → 32

La función podrá acceder a las casillas p[-1] y p[-2] para leer y escribiren éstas sin ningún problema: la memoria asignada a estas casillas estáreservada.

Ejercicio. ¿Qué consecuencia tiene la ejecución de esta instrucción?

f (&a[-1])

I.4. Matrices y punteros

/*********************************************************************/// Fichero: representacion.cpp// Las matrices se representan en memoria por filas (secuencialmente)/*********************************************************************/

#include <iostream>#include <iomanip>using namespace std;

const int FILS = 2;const int COLS = 3;const int ALTS = 2;

int main (void){

int m2D[FILS][COLS] = {{1,2,3}, {4,5,6}};int m3D[FILS][COLS][ALTS]={{{1,2},{3,4},{5,6}},

{{7,8},{9,10},{11,12}}};int f, c, a, i; // "f", "c", y "a" son indicesint *pm; // puntero de acceso a cada casilla

Page 23: Metodología de la Programación

Punteros y memoria dinámicaMatrices y punteros → 33

// Recorrido "convencional" (dos indices)

cout << "\nRecorr. convencional 2D:\n";

for (f=0; f<FILS; f++) {cout << " Fila " << f << ":";for (c=0; c<COLS; c++)

cout << setw(3) << m2D[f][c];cout << endl;

}

// Recorrido secuencial de matriz 2D (puntero)

cout << "\nRecorr. secuencial 2D:\n";pm = &m2D[0][0]; // primera casilla de "m2D"for (i=0; i<FILS*COLS; i++, pm++) cout << setw(3) << *pm;

// Recorrido "convencional" (tres indices)

cout << "\nRecorr. convencional 3D:\n";for (f=0; f<FILS; f++) {

cout << " Fila " << f << ":" << endl;for (c=0; c<COLS; c++) {

cout << " Columna " << c << ":";for (a=0; a<ALTS; a++) cout << setw(3) << m3D[f][c][a];cout << endl;

}}

// Recorrido secuencial de matriz 3D (puntero)cout << endl;cout << "Recorr. secuencial 3D:" << endl;

Punteros y memoria dinámicaMatrices y punteros → 34

pm = &m3D[0][0][0]; // primera casilla de "m3D"

for (i=0; i<FILS*COLS*ALTS; i++, pm++)cout << setw(3) << *pm;

cout << endl << endl;return (0);

}

Resultado de la ejecución:

Recorr. convencional 2D:Fila 0: 1 2 3Fila 1: 4 5 6

Recorr. secuencial 2D:1 2 3 4 5 6

Recorr. convencional 3D:Fila 0:

Columna 0: 1 2Columna 1: 3 4Columna 2: 5 6

Fila 1:Columna 0: 7 8Columna 1: 9 10Columna 2: 11 12

Recorr. secuencial 3D:1 2 3 4 5 6 7 8 9 10 11 12

Page 24: Metodología de la Programación

Punteros y memoria dinámicaMatrices y punteros → 35

Detalle: recorrido secuencial de m2D:

pm

m2D2 31 4 5 6

m2D2 31 4 5 6

Fila 0 Fila 1 Fila 0 Fila 1

A B

pm

A) pm referencia a m2D[0][0]. B) Después de imprimir m2D[0][0], se incrementa pm

m2D2 31 4 5 6

m2D2 31 4 5 6

Fila 0 Fila 1 Fila 0 Fila 1

A B

pmpm

A) pm referencia a m2D[0][2]. B) Después de imprimir m2D[0][2], se incrementa pm

Punteros y memoria dinámicaMatrices y punteros → Paso de matrices a funciones 36

I.4.1. Paso de matrices a funciones

Cuando se pasa una matriz a una función, se escribe el nombre de lamatriz:

const int fils = 10;const int cols = 20;

int m [fils][cols];

......

f (m, fils, cols);......

La función que recibe la matriz puede hacerlo de dos maneras:

1. Notación “clásica”.

void f (int a [][cols], int fils, int cols){......}

Es necesario especificar el número de columnas, para que el com-pilador sepa cómo calcular la posición de un elemento dado unnúmero de fila y columna.

El número de filas es irrelevante para el compilador (aunque es im-portante saberlo para no provocar errores en tiempo de ejecución).

Page 25: Metodología de la Programación

Punteros y memoria dinámicaCadenas y punteros → 37

2. Con un puntero al primer subvector(primera fila),

void f (int (*a) [20]){

......}

Importante: a es un puntero a un vector de 20 enteros.

Ejercicio. Escribir una función que reciba una matriz de esta manera (co-mo puntero a un vector), y que imprima todos sus elementos.

I.5. Cadenas y punteros

Una cadena clásica de caracteres (cadena estilo C) no es más que unvector de caracteres que contiene un carácter especial, ’\0’ (carácternulo) que indica el fin de la cadena: delimitador de fin de cadena.

Una constante literal de tipo cadena es de tipo const char *:

cout << "Hola";

Un vector de caracteres no tiene porqué ser una cadena, a no ser que:

1. Se inicie de forma adecuada.

2. Las funciones que manejan cadenas añadan el carácter ’\0’:

a) De forma automática, utilizando funciones de lectura o de ges-tión de cadenas (cstring)

b) De forma “manual” con funciones construidas por el progra-mador.

Punteros y memoria dinámicaCadenas y punteros → Iniciación de cadenas de caracteres 38

I.5.1. Iniciación de cadenas de caracteres

1. Notación de corchetes.

� Puede especificarse el tamaño.

char saludo1[5] = {’H’,’o’,’l’,’a’,’\0’};

Precaución: Hay que reservar para el ’\0’.

Puede reservarse más de lo necesario.

� Sin especificar el tamaño.

char saludo1[] = {’H’,’o’,’l’,’a’,’\0’};

Se reserva lo estrictamente necesario.

En ambos casos:

a) Se copia el contenido del literal en el vector.

b) Es posible modificar la cadena:

saludo1[1] = ’a’;

2. Notación de punteros.

char *saludo2 = "Hola";

Recordemos que un una constante literal de tipo cadena es de tipoconst char *

a) Esta inicialización copia la dirección de memoria de la cons-tante literal (hola) en el puntero saludo2

b) No es posible modificar la cadena:

saludo2[1] = ’a’; // ERROR

Page 26: Metodología de la Programación

Punteros y memoria dinámicaCadenas y punteros → Funciones de lectura/escritura de cadenas 39

I.5.2. Funciones de lectura/escritura de cadenas

El operador << está sobrecargado para las cadenas de caracteres clási-cas.

// Fichero: EscribeCadenas.cpp#include <iostream>using namespace std;

int main (void){

char saludo0[5] = {’H’,’o’,’l’,’a’,’\0’};char saludo1[] = {’H’,’o’,’l’,’a’,’\0’};char *saludo2 = "Hola";cout << saludo0 << " " << saludo1 << " "

<< saludo2 << endl<< endl;

return (0);}

% EscribeCadenasHola Hola Hola

Punteros y memoria dinámicaCadenas y punteros → Funciones de lectura/escritura de cadenas 40

Para lectura de cadenas proponemos:

istream & getline (char *p, int n);

Lee, como mucho n − 1 caracteres de la entrada estándar.

Termina antes si se introduce ’\n’ (ENTER). Los caracteresleidos los copia (por orden) en p, salvo el ’\n’, que lo susti-tuye por ’\0’.

La memoria referenciada por p debe estar reservada y sersuficiente.

// Fichero: LeeCadena.cpp

#include <iostream>using namespace std;

int main (void){

const int TAM = 80;char cad[TAM];cout << "\nIntroducir cadena: ";cin.getline (cad, TAM);cout << "Cadena: "<< cad<<endl;return (0);

}

% LeeCadenaIntroducir cadena: Una cadena multipalabraCadena: Una cadena multipalabra

Page 27: Metodología de la Programación

Punteros y memoria dinámicaCadenas y punteros → Funciones de gestión de cadenas 41

I.5.3. Funciones de gestión de cadenas

Declaradas en cstring

1. Funciones más relevantes.

char* strcpy (char* cs, const char* ct);

Copia de cadenas. Copia la cadena ct en cs, incluyendo elcarácter terminador ’\0’.

Devuelve cs (en la práctica, void).

Nota: cs debe tener suficiente espacio.

char* strcat (char* cs, const char* ct);

Concatenación de cadenas. Concatena la cadena ct a lacadena cs.

Devuelve cs (en la práctica, void).

Nota: s debe tener suficiente espacio.

size_t strlen (const char* cs);

Longitud de una cadena.

Devuelve la longitud de cs.

Punteros y memoria dinámicaCadenas y punteros → Funciones de gestión de cadenas 42

// Fichero: cadenas1.cpp

#include <iostream>#include <cstring>using namespace std;

int main (void){

char saludo1[20] = {’H’,’o’,’l’,’a’,’\0’};// Hay 15 casillas no usadas en "saludo1"

char *nombre1 = "Pepe";char *espacio = " ";char cad[100]; // No inicializada (ni ’\0’)

strcpy (cad, saludo1);strcat (cad, espacio);strcat (cad, nombre1);cout << "Cadena compuesta: " << cad << endl;

cout << "Saludo: " << ’|’ << saludo1 << ’|’<<" Long = "<< strlen(saludo1)<<endl;

return (0);}

% cadenas1Cadena compuesta: Hola PepeSaludo: |Hola| Long = 4

Page 28: Metodología de la Programación

Punteros y memoria dinámicaCadenas y punteros → Funciones de gestión de cadenas 43

int strcmp (const char* cs, const char* ct);

Comparación de cadenas. Compara cs y ct. Devuelve unvalor negativo si cs < ct, cero si cs = ct, o positivo si cs >

ct.

char* strstr (const char* cs, const char* ct);

Búsqueda de subcadenas. Devuelve un puntero a la prime-ra ocurrencia de ct en cs, o 0 si no se encuentra.

// Fichero: cadenas2.cpp

#include <iostream>#include <string>using namespace std;

int main (void){

const int TOPE=80;char c1[TOPE];char c2[TOPE];

cout << "\nIntroducir cadena 1: ";cin.getline (c1, TOPE);cout << "\nIntroducir cadena 2: ";cin.getline (c2, TOPE);bool iguales = !strcmp(c1,c2);

cout << endl;

if (iguales)cout <<’|’<< c1 <<’|’<< " y "

Punteros y memoria dinámicaCadenas y punteros → Funciones de gestión de cadenas 44

<<’|’<< c2 <<’|’<< " son iguales";

else {cout <<’|’<< c1 <<’|’<< " y "

<<’|’<< c2 <<’|’<< " NO son iguales ==> ";

if (strcmp(c1,c2) > 0)cout <<’|’<< c1 <<’|’<<" > "<<’|’<< c2 <<’|’;

elsecout <<’|’<< c1 <<’|’<<" < "<<’|’<< c2 <<’|’;

}cout << endl << endl;

if (strstr(c1, c2))cout <<’|’<< c2 <<’|’<< " es subcadena de "

<<’|’<< c1 <<’|’;else

cout <<’|’<< c2 <<’|’<< " NO es subcadena de "<<’|’<< c1<<’|’;

cout << endl << endl;

return (0);}

Page 29: Metodología de la Programación

Punteros y memoria dinámicaCadenas y punteros → Funciones de gestión de cadenas 45

2. Funciones sobre partes de cadenas.

char* strncpy (char* cs, const char* ct, size_t n);

Copia como mucho n caracteres de ct en cs, incluyendo elcarácter terminador ’\0’. Rellena con ’\0’ si la longitud dect es menor que n.

Devuelve cs (ver strcpy()).

char* strncat (char* cs, const char* ct, size_t n);

Concatena como mucho n caracteres de ct a la cadena csy añade ’\0’.

Devuelve cs (ver strcat()).

int strncmp (const char* cs,const char* ct,size_t n);

Compara como mucho n caracteres de cs y ct (los prime-ros).

Devuelve un valor negativo si cs < ct, cero si cs = ct, opositivosi cs > ct (igual que strcmp()).

3. Funciones de gestión de bloques de memoria (sucesiones de by-tes).

void* memcpy (void* cs, const void* ct, size_t n);

Copia n bytes de ct en cs. Devuelve cs. No funciona correc-tamente si ct y cs se solapan.

void* memmove (void* cs, const void* ct, size_t n);

Copia n bytes de ct a cs. Devuelve cs. Funciona correcta-mente aunque ct y cs se solapen.

Punteros y memoria dinámicaCadenas y punteros → Funciones de gestión de cadenas 46

void* memset (char* cs, int v, size_t n);

Fija los primeros n bytes de cs al valor v, sustituyendo loque hubiera. Devuelve cs.

int memcmp (const void* cs, const void* ct, size_t n);

Compara los primeros n bytes de cs con ct. Devuelve unvalor negativo si cs < ct, cero si cs = ct, o positivo si cs >

ct.

void* memchr (const char* cs, int c, size_t n);

Devuelve un puntero a la primera ocurrencia de c en losprimeros n caracteres de cs, o 0 si no se encuentra.

// Fichero: cadenas3.cpp

#include <iostream>#include <cstring>using namespace std;

int main (){

// memset() y memcpy()

char barra[6], superbarra[26];memset (barra, ’*’, 5);memset (&(barra[6]), ’\0’, 1); // barra[6]=’\0’;memcpy (superbarra, barra, 4);superbarra[4] = ’+’;memcpy (&(superbarra[5]), barra, 4);superbarra[9] = ’+’;superbarra[10] = ’\0’;

Page 30: Metodología de la Programación

Punteros y memoria dinámicaCadenas y punteros → Funciones de gestión de cadenas 47

cout << " Barra es: |" << barra << "|\n";cout << "SuperBarra es: |" << superbarra << "|\n\n";

// memcpy()

char orig[]="Ejemplo";char copia[40];

memcpy (copia,orig,strlen(orig)+1);cout << " Orig es: |" << orig << "|\n";cout << "Copia es: |" << copia << "|\n\n";

// memmove()

char cad[] = "memmove puede ser muy util.....";cout << " Antes: |" << cad << "|\n";memmove (cad+22, cad+18, 8);cout << "Despues: |" << cad << "|\n\n";

return (0);}

% cadenas3

Barra es: |*****|SuperBarra es: |****+****+|

Orig es: |Ejemplo|Copia es: |Ejemplo|

Antes: |memmove puede ser muy util.....|Despues: |memmove puede ser muy muy util.|

Punteros y memoria dinámicaCadenas y punteros → Funciones de gestión de cadenas 48

4. Otras.

char* strerror (int n);

Mensajes de error predefinidos. Devuelve un puntero a lacadena definida en la implementación que corresponde alerror n.

char* strchr (const char* cs, int c);

Búsqueda de caracteres (1). Devuelve un puntero a la pri-mera ocurrencia de c en cs, o 0 si no se encuentra.

char* strrchr (const char* cs, int c);

Búsqueda de caracteres (2). Devuelve un puntero a la últi-ma ocurrencia de c en cs, o 0 si no se encuentra.

Page 31: Metodología de la Programación

Punteros y memoria dinámicaMatrices bidimensionales y vectores de punteros → 49

I.6. Matrices bidimensionales y vectoresde punteros

int a[4][5];int *b[4];

40 321

1

2

0

3

1

2

0

3

ba

Representación en memoria de la matriz int a[4][5] y del vector int *b[4]

Con estas declaraciones, las expresiones:

a[3][4] b[3][4]

son referencias sintácticamente válidas a un entero.

¡OJO! Aunque es posible acceder al elemento b[3][4], esta zona de me-moria no está reservada (no se ha inicializado de ninguna forma).

Escribir y/o leer sobre esta estructura de datos (en la situación actual)presenta serios problemas:

� Escribir sobre b[i][j] producirá resultados inesperados, posible-mente haga que termine la ejecución del programa por un error entiempo de ejecución.

� Leer los valores de estas casillas hace que obtengamos valores“basura” ya que ni b[i] ni b[i][j] han sido inicializados.

Punteros y memoria dinámicaMatrices bidimensionales y vectores de punteros → 50

La iniciación de las zonas de memoria referenciadas por b[i] debe hacer-se de forma explícita:

1. De forma estática

1.1. Usando un vector de punteros.

1.2. Usando una matriz bidimensional.

2. Con funciones de asignación de memoria dinámica.

(Pronto...)

// Fichero: vecpun.cpp

#include <iostream>#include <iomanip>

using namespace std;

int main (){

const int FILS = 3;const int COLS = 5;

int a[FILS][COLS];int *b[FILS];

// Inicializacion de "a"

for (int cont=1, f=0; f<FILS; f++)for (int c=0; c<COLS; c++)

a[f][c] = cont++;

Page 32: Metodología de la Programación

Punteros y memoria dinámicaMatrices bidimensionales y vectores de punteros → 51

cout << "Recorr. convencional de \"a\":\n";

for (int f=0; f<FILS; f++) {cout << " Fila " << f << ":";for (int c=0; c<COLS; c++)

cout << setw(3) << a[f][c];cout << endl;

}cout << endl;

// Asignacion a los punteros de "b"

for (int fb=0, fa=FILS-1; fa >=0 ; fa--, fb++)b[fb] = &(a[fa][0]);

cout << "Recorr. convencional de \"b\": \n";for (int f=0; f<FILS; f++) {

cout << " Fila " << f << ":";for (int c=0; c<COLS; c++)

cout << setw(3) << b[f][c];cout << endl;

}cout << endl;return (0);

}

%vecpun

Recorr. convencional de "a": Recorr. convencional de "b":Fila 0: 1 2 3 4 5 Fila 0: 11 12 13 14 15Fila 1: 6 7 8 9 10 Fila 1: 6 7 8 9 10Fila 2: 11 12 13 14 15 Fila 2: 1 2 3 4 5

Punteros y memoria dinámicaMatrices bidimensionales y vectores de punteros → 52

1. Vector de punteros a carácter.

char *meses1[] = {"!Erroneo!", "Enero", "Febrero", "Marzo"};

’E’ ´r´ ´o´ ´\0´´n´ ´e´

´¡´ ’E’ ´r´ ´r´ ´o´ ´n´ ´e´ ´\0´´!´´o´

2

0

1

3

meses1

´r´ ´o´´\0´’M’ ´a´ ´z´

´e´ ´r´ ´e´ ´r´ ´o´´\0´’F’ ´b´

Ragged arrays, o vectores “a jirones”.

2. Matriz bidimensional de caracteres.

char meses2[][10] = {"!Erroneo!", "Enero", "Febrero", "Marzo"};

’E’ ´r´ ´o´ ´\0´´n´ ´e´

´e´ ´r´ ´e´ ´r´ ´o´´\0´’F’ ´b´

´¡´ ’E’ ´r´ ´r´ ´o´ ´n´ ´e´ ´\0´´!´´o´

2

0

1

3

meses2

0 1 2 3 4 5 6 7 8 9

´r´ ´o´´\0´’M’ ´a´ ´z´

Page 33: Metodología de la Programación

Punteros y memoria dinámicaMatrices bidimensionales y vectores de punteros → 53

1. La ventaja de utilizar vectores de punteros frente a matrices di-mensionadas es que cada línea puede tener un número arbitrariode columnas, optimizándose el espacio en memoria.

2. Un vector de punteros (convenientemente inicializado) se compor-ta como una matriz bidimensional, ya que se puede acceder a loselementos de esta estructura de datos mediante índices, como side una matriz se tratara.

Diferencia clave:

En un vector de punteros las “filas” no tienenporqué estar almacenadas de forma secuencial en

memoria.

Paso de un vector de punteros a una función:

� Se pasa el nombre del vector.

� Se recibe con una de estas dos alternativas:

1. En un puntero a datos del tipo base del vector.

2. Un vector con un número indeterminado de casillas.

f (m, fils); f (meses1, fils);...... ......

void f (char **p, int fils) void f (char *p[], fils){ {

...... ......} }

Punteros y memoria dinámicaMatrices bidimensionales y vectores de punteros → 54

Paso de un vector de punteros a una funcion

Page 34: Metodología de la Programación

Punteros y memoria dinámicaMatrices bidimensionales y vectores de punteros → 55

Vectores “a jirones” usados en el programa de la baraja

Estructura de datos básica:

int baraja [PALOS][CARTAS_PALO] = {0};

2

0

1

3

0 1 2 3 4 5 6 7 8 9

baraja

10 11

1

2

3

4

5

6 7

8 910

11 12

1415

13

16

1819

20

21 22

23

24

25 26

27

29 30 3132

33

34

37

40

4143

4445

46

47

4817

35362842

39

38

Un ejemplo de la matriz baraja

Punteros y memoria dinámicaMatrices bidimensionales y vectores de punteros → 56

Resultado de la ejecución:

Cinco de Espadas Tres de Oros Cuatro de EspadasNueve de Bastos As de Copas Siete de OrosNueve de Oros Tres de Bastos Siete de BastosCuatro de Bastos Cuatro de Copas Seis de Copas

Caballo de Oros Rey de Espadas Dos de EspadasAs de Bastos Cinco de Oros Nueve de Espadas

Siete de Espadas Nueve de Copas Dos de BastosCinco de Bastos Caballo de Espadas Siete de Copas

Dos de Oros Ocho de Oros Sota de BastosOcho de Copas As de Oros Cuatro de OrosRey de Oros Seis de Oros Rey de BastosRey de Copas Caballo de Copas Sota de Copas

Seis de Bastos Caballo de Bastos Seis de EspadasOcho de Espadas Cinco de Copas Tres de CopasDos de Copas Tres de Espadas As de Espadas

Ocho de Bastos Sota de Espadas Sota de Oros

/************************************************/// Fichero: baraja.cpp// Mezcla aleatoriamente un mazo de cartas./************************************************/

#include <iostream>#include <iomanip>#include <cstdlib>#include <ctime>using namespace std;

const int PALOS = 4; // Num. Palosconst int CARTAS_PALO = 12; // Cartas/paloconst NUM_CARTAS = PALOS*CARTAS_PALO // Num. Cartasconst int COLS = 3; // Columnas para el resultado

Page 35: Metodología de la Programación

Punteros y memoria dinámicaMatrices bidimensionales y vectores de punteros → 57

void barajar (int baraja[PALOS][CARTAS_PALO]);void mostrar (int baraja[PALOS][CARTAS_PALO], char *palos[PALOS],

char *nombres[CARTAS_PALO]);

/*****************************************************************/

int main (void){

// Declaracion e iniciacion de "nombres" y "palos"

char *palos[PALOS] = {"Oros", "Copas", "Espadas", "Bastos"};char *nombres[CARTAS_PALO] = {"As", "Dos", "Tres", "Cuatro",

"Cinco", "Seis", "Siete", "Ocho","Nueve", "Sota", "Caballo", "Rey"};

// Decl. e inic. de "baraja": determina el orden de las cartas

int baraja [PALOS][CARTAS_PALO] = {0};

barajar (baraja); // barajar el mazomostrar (baraja, palos, nombres); // resultado

return (0);}

Punteros y memoria dinámicaMatrices bidimensionales y vectores de punteros → 58

/*****************************************************************/// Funcion: barajar// Tarea: Ordena las cartas aleatoriamente.// Recibe: int baraja[][CARTAS_PALO], matriz 2D de enteros que// determina el orden final. P.e. si baraja[0][0]// (As de Oros) es 20, el As de Oros sera la carta num 20./*****************************************************************/

void barajar (int baraja[][CARTAS_PALO]){

int carta, fila, col;time_t t;

// Inicializa el generador con el reloj del sistemasrand ((int) time(&t));

// para todas las cartas del mazo

for (carta=1; carta <= NUM_CARTAS; carta++) {

// asigna un numero (orden) a cada carta si baraja[fila][col]==0

do { col = rand() % CARTAS_PALO; // columnafila = rand() % PALOS; // fila

} while (baraja[fila][col] != 0);baraja[fila][col] = carta;

// numero de orden de la carta de palo "fila" y nombre "col".}

}

Page 36: Metodología de la Programación

Punteros y memoria dinámicaMatrices bidimensionales y vectores de punteros → 59

/*****************************************************************/// Funcion: mostrar// Tarea: Muestra el mazo (en COLS columnas)despues de barajar.// Recibe: int baraja[][CARTAS_PALO], matriz 2D que// determina el orden.// char **palos, mat. de cads. con los nbres. de los palos.// char **nombres, mat. de cads. con los nbres. de las cartas./*****************************************************************/

void mostrar (int baraja[][CARTAS_PALO], char **palos, char **nombres){

char c; // puede ser ’\n’ o ’\t’

// para todas las cartas del mazo

for (int carta=1; carta <= NUM_CARTAS; carta++)

for (int fila=0; fila<PALOS; fila++)

for (int col=0; col<CARTAS_PALO; col++)

// Mostrar si en la casilla [fila][col]// esta el numero buscado.

if (baraja[fila][col] == carta) {c = (((carta % COLS == 0)||

(carta == NUM_CARTAS)) ? ’\n’:’\t’);cout << setw(8) << nombres[col] << " de " << setw(10)

<< palos[fila] << " " << c;}

cout << endl;}

Punteros y memoria dinámicaMatrices bidimensionales y vectores de punteros → 60

Una mejora:

� Propuesta: representar cada carta por una estructura (struct) deforma que los datos sean:

– el palo (palo)

– el nombre de la carta (nombre)

y los valores de cada campo sean cadenas de caracteres (punte-ros a las cadenas estáticas referenciadas por las matrices palos ynombres):

struct carta {char *palo; // punt. a cadena de "palos"char *nombre; // punt. a cad.de "nombres"

};

� Ahora, una baraja es un vector de NUM_CARTAS estructuras de tipocarta:

carta baraja[NUM_CARTAS];

� A la hora de barajar, procesamos las catras secuencialmente: des-de la primera (As de Oros) a la última (Rey de bastos), generandoun número aleatorio comprendido entre 0 y NUM_CARTAS-1.

� Antes de “incluir” la carta, ver si la posición ya está ocupada:

int control[NUM_CARTAS] = {0};

Si control[i] == 0, libre,si control[i] == 1, ocupada.

Page 37: Metodología de la Programación

Punteros y memoria dinámicaMatrices bidimensionales y vectores de punteros → 61

´O´ ’r’ ´o´ ´s´´\0´ ´\0´

´\0´´D´ ´o´ ´s´

´\0´

´\0´´R´ ´e´ ´y´

´o´´a´

´\0´

´\0´’C’ ´o´ ´p´ ´a´ ´s´

’E’ ´s´ ´p´ ´a´ ´d´ ´a´ ´s´

’B’ ´s´ ´t´ ´\0´´s´

2

0

1

3

´A´ ’s’

nombres

2

0

1

´T´ ´r´ ´e´ ´s´

11

baraja

0 1 2 47

palos

Estado de la memoria para una ordenación particular de cartas

/**************************************************************/// Fichero: baraja2.c// Mezcla aleatoriamente un mazo de cartas.// Otra implementacion utilizando un vector de estructuras./**************************************************************/

#include <iostream>#include <iomanip>#include <cstdlib>#include <ctime>using namespace std;

const int PALOS = 4; // Palosconst int CARTAS_PALO = 12; // Cartas/paloconst NUM_CARTAS = PALOS*CARTAS_PALO;// Num. Cartasconst int COLS = 3; // Num. columnas del resultado

Punteros y memoria dinámicaMatrices bidimensionales y vectores de punteros → 62

struct carta { // Definicion del tipo de datos cartachar *palo; // punt. a una cadena de "palos"char *nombre; // punt. a cadena de "nombres"

};

void barajar (carta baraja[NUM_CARTAS],char *palos[PALOS],char *nombres[CARTAS_PALO]);

void mostrar (carta baraja[NUM_CARTAS],char *palos[PALOS],char *nombres[CARTAS_PALO]);

int main (void){

// Declaracion e iniciacion de "nombres" y "palos"char *palos[PALOS]={"Oros", "Copas", "Espadas", "Bastos"};char *nombres[CARTAS_PALO] =

{"As", "Dos", "Tres", "Cuatro", "Cinco", "Seis","Siete", "Ocho", "Nueve", "Sota", "Caballo", "Rey"};

// Declaracion de "baraja": orden de cartascarta baraja[NUM_CARTAS];

barajar (baraja, palos, nombres); // barajarmostrar (baraja, palos, nombres); // resultadoreturn (0);

}

Page 38: Metodología de la Programación

Punteros y memoria dinámicaMatrices bidimensionales y vectores de punteros → 63

/**************************************************************/// Funcion: barajar// Tarea: Ordena las cartas aleatoriamente.// Recibe: carta baraja[NUM_CARTAS], vector de estructuras// de tipo "carta" que determina el orden final.// char **palos, matriz de cadenas (palos).// char **nombres, matriz de cadenas (cartas)./**************************************************************/

void barajar (carta baraja[NUM_CARTAS],char **palos, char **nombres)

{int p, c, orden;int control[NUM_CARTAS] = {0};time_t t;

// Iniciar el generador con el reloj del sistema.srand ((int) time(&t));

// Para todas las cartas del mazo en orden sec.:// desde el As de Oros, hasta el Rey de Bastos.

for (p=0; p < PALOS; p++) // palos

for (c=0; c < CARTAS_PALO; c++) { // nombres// Asigna un numero a cada carta si no ha// sido procesada (control[orden] == 0)

do {orden = rand() % NUM_CARTAS;

} while (control[orden] != 0);

Punteros y memoria dinámicaMatrices bidimensionales y vectores de punteros → 64

(baraja[orden]).palo = palos[p];(baraja[orden]).nombre = nombres[c];control[orden] = 1;

}}

/**************************************************************/// Funcion: mostrar// Tarea: Muestra el mazo de carta barajado// Recibe: carta baraja[NUM_CARTAS], vector de estruct. de tipo// "carta" cuyo orden determina el orden.// char **palos, matriz de cad. (palos).// char **nombres, matriz de cad. (cartas)./**************************************************************/

void mostrar (carta baraja[NUM_CARTAS],char **palos,char **nombres){

// Para todas las cartas del mazo

for (int n=1; n <= NUM_CARTAS; n++)

cout << (baraja[n-1]).nombre << " de "<< left << setw(10) << (baraja[n-1]).palo<< (((n%COLS==0)||(n==NUM_CARTAS))?’\n’:’\t’);

}

Page 39: Metodología de la Programación

Punteros y memoria dinámicaLa memoria dinámica → 65

I.7. La memoria dinámica

Objetivo: optimizar el uso de la memoria

� Crear variables (reserva de memoria) durante la ejecución del pro-grama (dinámica) y trabajar con ellas mientras se necesiten.

� Eliminarlas (liberación de memoria) cuando ya no sean necesarias.

I.7.1. La estructura de la memoria

� Memoria estática + Código: Se fija en tiempo de compilación y nocambia.

� Memória dinámica = Montón (Heap) + Pila (Stack): Se gestiona entiempo de ejecución y cambia.

Punteros y memoria dinámicaLa memoria dinámica → La estructura de la memoria 66

� Segmento de código

– Contiene las instrucciones que se ejecutan.

– Evidentemente, no se modifica.

– Desde nuestro punto de vista no tiene más interés.

� Memoria estática

– Contiene las variables globales, static y las constantes.

– Se reserva antes de la ejecución del programa.

– Permanece fija durante la ejecución.

– No requiere ninguna gestión del programador.

Page 40: Metodología de la Programación

Punteros y memoria dinámicaLa memoria dinámica → La estructura de la memoria 67

� La pila (Stack )

– Gestiona las llamadas a funciones durante la ejecución del pro-grama.

– Cada vez que se realiza una llamada a una función se crea unentorno para la gestión de las variables locales, y dirección deretorno que se libera cuando acaba su ejecución.

– La reserva y liberación de esta memoria la realiza el sistemaoperativo de manera automática durante la ejecución.

� El montón (Heap)

– Es una zona de memoria donde se reservan y liberan "tro-zos"durante la ejecución de los programas, según sus nece-sidades y de acuerdo a las instrucciones del programa.

– El montón y la pila comparten la memoria dinámica: no hay unazona definida para cada una de ellas.

Punteros y memoria dinámicaLa memoria dinámica → Los operadores new y delete 68

I.7.2. Los operadores new y delete

El operador new

<tipo_base> * p;p = new <tipo_base>;

� new reserva una zona de memoria en el Heap del tamaño adecuadopara almacenar un dato del tipo <tipo_base> (sizeof(<tipo_base>)bytes), devolviendo la dirección de memoria donde empieza la zonareservada.

� Si new no puede reservar espacio (p.e. no hay suficiente memoriadisponible), se genera una excepción y el programa termina.

Ejemplo (simple):

int *p, q = 10; // (1) - ver figura

p = new int; // (2) - ver figura

*p = q; // (3) - ver figura

Page 41: Metodología de la Programación

Punteros y memoria dinámicaLa memoria dinámica → Los operadores new y delete 69

Notas:

1. Observar que p se declara como un puntero más.

2. Se pide memoria en el Heap para guardar un dato int. Si hay es-pacio para satisfacer la petición, p apuntará al principio de la zonareservada por new. Si no nay espacio se lanzará una excepción y elprograma terminará su ejecución.

3. El objeto referenciado por p se utiliza de la manera habitual.

Ejemplo (con gestión de errores):

int *p, q = 10; // 1

try {p = new int; // 2

}catch(runtime_error excepcion){

cout << "Error de memoria: " << excepcion.what();}

*p = q; // 3

La instrucción crítica (new) se encierra en un bloque try. En este caso, sino nay espacio y falla el operador new se lanzará una excepción que setrata en el bloque catch y después de mostrar información acerca de laexcepción generada el programa terminará su ejecución.

Punteros y memoria dinámicaLa memoria dinámica → Los operadores new y delete 70

El operador new (nothrow)

Hay una versión “anticuada” de new que previene del lanzamiento de ex-cepciones (algunos sistemas operativos no son capaces de gestionar ex-cepciones).

<tipo_base> * p;p = new (nothrow) <tipo_base>;

Ejemplo:

#include <new>......

int *p, q = 10;

p = new (nothrow) int;if (p==0) { // if (!p)

cerr << "Error en la reserva\n";exit(1);

}*p = q;

Notas:

1. Requiere la inclusión del fichero de cabecera new

2. Si no nay espacio y new no puede asignar memoria p tomará el valor0 (dirección nula).

Page 42: Metodología de la Programación

Punteros y memoria dinámicaLa memoria dinámica → Los operadores new y delete 71

El operador delete

delete puntero;

delete permite liberar la memoria del Heap que previamente se había re-servado y que se encuentra referenciada por puntero.

Ejemplo (simple):

int *p, q = 10;

p = new int;

*p = q;...delete p;

El objeto referenciado por por p deja de ser “operativo” y la memoria queocupaba está disponible para nuevas peticiones con new.

Importante:

� El puntero p no modifica su valor. Algunos programadores piensanque después de hacer delete el puntero queda con valor 0, pero noes así.

� En realidad delete solo marca como libre el bloque que ocupa *p

� El objeto apuntado por p sigue existiendo y sigue estando accesi-ble después de hacer delete.

� El uso de *p después de hacer delete es absolutamente inseguro ypeligroso. En definitiva, está prohibido.

Punteros y memoria dinámicaLa memoria dinámica → Los operadores new y delete 72

� Para acceder a la variable *ptr, debemos reservar previamente lamemoria. Después de ejecutar el operador delete, ya no podremosacceder a ella.

int main(){double *ptr;

*ptr = 5.6; // Resultado impredecible!ptr = new double;*ptr = 5.6;cout << *ptr; // Ok. Imprime 5.6.....

delete ptr;*ptr = 7.1; // Resultado impredecible!

}

� delete de un puntero no asignado tiene consecuencias impredeci-bles.

int *ptr;

delete ptr; // Error ejecución impredecible

� Se puede hacer delete del puntero nulo aunque no tiene ningúnefecto.

int *ptr;

ptr = 0;delete ptr; // No da ningún error.

Page 43: Metodología de la Programación

Punteros y memoria dinámicaLa memoria dinámica → Los operadores new y delete 73

� Si ejecutamos dos new sobre el mismo puntero, la variable del heapcreada en primer lugar, permanece inaccesible, consumiendo re-cursos.

int *ptr;

ptr = new int;*ptr = 6; // (1) ver figura

ptr = new int; // :-( Dejamos en el heap un dato inaccesible// y creamos otro dato nuevo en el heap

*ptr = 7; // (2) ver figuradelete ptr; // :-)

ptr = new int;*ptr = 8; // (3) ver figura

(1) (2) (3)

Punteros y memoria dinámicaLa memoria dinámica → Los operadores new y delete 74

Ejercicio. ¿Cual será la salida del siguiente fragmento de código?

#include <iostream>using namespace std;

int main (){int *p1, *p2;

p1 = new int;*p1 = 42;p2 = p1;cout << *p1 << " y " << *p2 << endl;

*p2 = 53;cout << *p1 << " y " << *p2 << endl;

p1 = new int;*p1 = 88;cout << *p1 << " y " << *p2 << endl;return 0;

}

Page 44: Metodología de la Programación

Punteros y memoria dinámicaLa memoria dinámica → Objetos dinámicos compuestos 75

I.7.3. Objetos dinámicos compuestos

Para el caso de objetos compuestos (p.e. struct) la metodología a seguires la misma, aunque teniendo en cuenta las especificidades de los tiposcompuestos.

En el caso de los struct, la instrucción new reserva la memoria necesariapara almacenar todos y cada uno de los campos de la estructura.

struct TipoPersona{string nombre;string DNI;

};TipoPersona *yo;

yo = new TipoPersona;

cin >> (*yo).nombre; // cin >> yo->nombre;cin >> (*yo).DNI; // cin >> yo->DNI;

......

delete yo;

Objetos dinámicos autoreferenciados

Motivación: Disponer de objetos que contengan referencias (apunten a)otro(s) objeto(s) del mismo tipo.

Punteros y memoria dinámicaLa memoria dinámica → Objetos dinámicos compuestos 76

struct TipoPersona{string nombre;string DNI;

};struct TipoNodo{

TipoPersona info;TipoNodo *next;

};

TipoNodo *p;

p = new TipoNodo; // Pedimos memoria para el primer nodo

(p->info).nombre = "Ana Ruiz Ruiz";(p->info).DNI = "12345678A";

Page 45: Metodología de la Programación

Punteros y memoria dinámicaLa memoria dinámica → Objetos dinámicos compuestos 77

p->next = new TipoNodo; // Pedimos memoria para un nuevo nodo// y queda "enlazado" con el primero

((p->next)->info).nombre = "José Abad García";((p->next)->info).DNI = "87654321B";((p->next)->next = 0; // Marca el final

Punteros y memoria dinámicaLa memoria dinámica → Objetos dinámicos compuestos 78

Si seguimos creando nodos las expresiones pueden ser tremendamentecomplejas si se emplea un único puntero, de ahí que se usen punterosauxiliares.

struct TipoPersona{string nombre;string DNI;

};struct TipoNodo{

TipoPersona info;TipoNodo *next;

};

TipoNodo *p, *aux;

p = new TipoNodo; // Pedimos memoria para el primer nodo

(p->info).nombre = "Ana Ruiz Ruiz";(p->info).DNI = "12345678A";

(p->info).next = new TipoNodo; // Pedimos memoria para un nuevo nodo// y queda "enlazado" con el primero

aux = p->next; // aux apunta al nuevo nodo

(aux->info).nombre = "José Abad García";(aux->info).DNI = "87654321B";aux->next = 0; // Marca el final

Page 46: Metodología de la Programación

Punteros y memoria dinámicaLa memoria dinámica → Objetos dinámicos compuestos 79

Ejercicio. ¿Qué hace este fragmento de código?

struct TipoNodo{int info;TipoNodo *next;

};

TipoNodo *p, *end;int n;

p = 0; // inicialización a la direccion nula

// Primera lectura

cout << "Introduzca valor (0 para terminar): ";cin >> n;

if (n != 0) {

p = new TipoNodo; // Pedimos memoria para el primer nodo

p->info = n; // Guardamos el valor leido en el nodop->next = 0; // Este nodo va a ser, por ahora, el ultimo

end = p; // el ultimo tambien es el primero (solo hay uno)

// Segunda lectura

cout << "Introduzca valor (0 para terminar): ";cin >> n;

Punteros y memoria dinámicaLa memoria dinámica → Objetos dinámicos compuestos 80

while (n != 0) {

// Pedimos memoria para el siguiente nodo

end->next = new TipoNodo;

end = end->next; // Actualizamos la posicion del ultimo

end->info = n; // Guardamos el valor leido en el nuevo nodoend->next = 0; // Este nodo va a ser, por ahora, el ultimo

// Siguiente lectura

cout << "Introduzca valor (0 para terminar): ";cin >> n;

} // while (n != 0)

} // if (n != 0)

TipoNodo *aux = p; // Colocamos aux al principio

while (aux != 0) {

cout << aux->info << "\n";aux = aux->next; // adelantamos aux

}

Page 47: Metodología de la Programación

Punteros y memoria dinámicaLa memoria dinámica → Reserva de memoria dentro de las funciones 81

I.7.4. Reserva de memoria dentro de las funcio-nes

Todas las variables locales a una función se almacenan en la pila y sepierden al terminar la función. Esto también ocurre con un puntero local.

La memoria que reservemos al ejecutar new sobreun puntero, permanece en el Heap cuando termine

de ejecutarse la función

double val = 8.5;CreaDouble (val);...void CreaDouble(double valor){

double *ptr = new double;*ptr = valor;

}

Punteros y memoria dinámicaLa memoria dinámica → Reserva de memoria dentro de las funciones 82

Al finalizar la ejecución de la función, en el heap se queda la zona dememoria reservada por ptr sin poder liberarla. Para liberarla, devolvemosla correspondiente posición de memoria:

Una función puede devolver un puntero

double *CreaDouble(double valor){

double *ptr;

ptr = new double;*ptr = valor;return ptr;

}

int main(){double *nuevo, val=8.5;

nuevo = CreaDouble(val);cout << *nuevo;......delete nuevo;......

}

La zona reservada en el Heap dentro de CreaDouble() permanece durantela ejecución del programa (hasta que se libere con delete).

Page 48: Metodología de la Programación

Punteros y memoria dinámicaLa memoria dinámica → Vectores dinámicos 83

I.7.5. Vectores dinámicos

Hasta ahora sólo podemos crear un vector conociendo a priori el númeromínimo de elementos que podrá tener. P.e. int vector[22];

Para reservar la memoria estrictamente necesaria se empleará el opera-dor new []

<tipo_base> * p;p = new <tipo_base> [num];

Reserva una zona de memoria en el Heap para almacenar num datos detipo tipo, devolviendo la dirección de memoria inicial.

La liberación se realiza con delete []

delete [] puntero;

Libera (realmente pone como disponible) la zona de memoria previamen-te reservada por una orden new [] y que está referencia por puntero.

Con la utilización de esta forma de reserva dinámica, podemos crear vec-tores que tengan justo el tamaño necesario. Podemos, además, crearlojusto en el momento en el que lo necesitamos y destruirlo cuando dejede ser útil.

Punteros y memoria dinámicaLa memoria dinámica → Vectores dinámicos 84

Ejemplo:

#include <iostream>using namespace std;

int main(void){

int *v, n;cout << "Numero de casillas: ";cin >> n;

// Reserva de memoriav = new int [n];

// Procesamiento del vector dinamico:// lectura y escritura de su contenido

for (int i= 0; i<n; i++) {cout << "Valor en casilla "<<i<< ": ";cin >> v[i];

}cout << endl;

for (int i= 0; i<n; i++)cout << "En la casilla " << i<< " guardo: "<< v[i]<< endl;

// Liberar memoria

delete [] v;

return (0);}

Page 49: Metodología de la Programación

Punteros y memoria dinámicaLa memoria dinámica → Vectores dinámicos 85

Algunas cuestiones:

� Para acceder a v[i] el compilador da i saltos (tan grandes como in-dique el tipo base del puntero), a partir de la posición donde apuntael puntero v.

� Si ponemos delete vector en vez de delete [] vector, el resultadoes impredecible

� No se pueden añadir ni quitar componentes de un vector dinámico.

� El SO reserva memoria. Al hacer new, el SO devuelve la direccióninicial dónde se ha reservado memoria. Y el SO sabe cuantos by-tes hay reservados de dicha dirección inicial. Por lo tanto, puedehacerse delete [] con otro puntero distinto al que se le hizo el new(apuntando, claro está, a la misma dirección)

double *v;double *ptr;v = new double[20];

ptr = v;delete [] ptr; // Correcto

v = new double[20];ptr = &v[2];delete [] ptr; // Error imprevisible;

Punteros y memoria dinámicaLa memoria dinámica → Vectores dinámicos 86

Ejemplo: Una función que devuelve un vector dinámico como copia deotro (automático) que recibe como argumento.

#include <iostream>using namespace std;

int * copia_vector (int *v, int n){

int * copia = new int [n];for (int i= 0; i<n; i++)

copia[i] = v[i];

return (copia);

int main(void){

int v1[30], *v2=0, m;

cout << "Numero de casillas: ";cin >> m;

// Rellenar el vector

for (int i= 0; i<m; i++) {cout << "Valor en casilla "<<i<< ": ";cin >> v1[i];

}cout << endl;

// copiar en v2 (dinamico) el vector v1

v2 = copia_vector (v1, m);

Page 50: Metodología de la Programación

Punteros y memoria dinámicaLa memoria dinámica → Vectores dinámicos 87

// Escribir v2

for (int i=0; i<m; i++)cout << "En la casilla " << i<< " guardo: "<< v2[i]<< endl;

// Liberar memoria

delete [] v2;

return (0);}

Un error muy común a la hora de construir una función que copie unvector es el siguiente:

int *copia_vector1(int *v, int n){

int copia[100]; // o cualquier otro valor mayor o igual que n

for (int i= 0; i<n; i++)copia[i] = v[i];

return (copia);}

Al ser copia una variable local no puede ser usada fuera del ámbito de lafunción en la que está definida.

Punteros y memoria dinámicaLa memoria dinámica → Matrices dinámicas 88

I.7.6. Matrices dinámicas

Problema:

Gestionar matrices 2D de forma dinámica, en tiempo de ejecución.

Motivación:

� El lenguaje proporciona matrices estáticas para las que debe cono-cerse el tamaño en tiempo de compilación. En el caso de matrices2D, el compilador debe conocer el número de filas y columnas.

� Necesitamos poder crear y trabajar con matrices 2D cuyo tamaño(filas y columnas) sea el que requiera el problema que se va a re-solver.

En particular, posibilitaremos:

� Creación de matrices dinámicas.

� Destrucción de matrices dinámicas.

� Acceso mediante índices.

Aproximaciones:

1. Datos guardados en filas independientes (Matriz2D_1)

2. Datos guardados en una única fila (Matriz2D_2)

Page 51: Metodología de la Programación

Punteros y memoria dinámicaLa memoria dinámica → Matrices dinámicas 89

Solución 1 (Matriz2D_1)

0

1

2

3

4

0 1 2 3 4 cols−1

matriz

fils−1

0 1 2 3 4 cols−1

0 1 2 3 4 cols−1

Observe que redefinimos el tipo int ** para darle un nombre que ocultala implementación: Matriz2D_1

Matriz2D_1.h

#ifndef MATRIZ2D_1#define MATRIZ2D_1

typedef int ** Matriz2D_1;

Matriz2D_1 CreaMatriz2D_1 (int fils, int cols);void LiberaMatriz2D_1 (Matriz2D_1 matriz, int fils, int cols);void PintaMatriz2D_1 (Matriz2D_1 matriz, int fils, int cols);

#endif

Punteros y memoria dinámicaLa memoria dinámica → Matrices dinámicas 90

Matriz2D_1.cpp

#include <iostream>#include <iomanip>#include "Matriz2D_1.h"using namespace std;

Matriz2D_1 CreaMatriz2D_1 (int fils, int cols){

Matriz2D_1 matriz = new int * [fils]; // puntero local a un// vector de punteros

for (int f=0; f<fils; f++) {matriz[f] = new int [cols]; // "matriz[f]" apunta a un

} // vector dinamico de intreturn (matriz);

}

void LiberaMatriz2D_1 (Matriz2D_1, int fils, int cols){

for (int f=0; f<fils; f++)delete [] matriz[f]; // Libera una fila

delete [] matriz; // Libera el vector de punteros}

void PintaMatriz2D_1 (Matriz2D_1 matriz, fils, int cols){

for (int f=0; f<fils; f++) {for (int c=0; c<cols; c++)

cout << setw(4) << matriz[f][c]; // acceso a un elementocout << endl; // cada fila se muestra en una linea diferente

}}

Page 52: Metodología de la Programación

Punteros y memoria dinámicaLa memoria dinámica → Matrices dinámicas 91

Solución 2 (Matriz2D_2)

1 filaa

matriz

0

1

2

3

4

fils−1

0 1

a2 fila n−esima fila

fils*cols−12 x cols−1cols−1

Observe que redefinimos el tipo int ** para darle un nombre que ocultala implementación: Matriz2D_2

Matriz2D_2.h

#ifndef MATRIZ2D_2#define MATRIZ2D_2

typedef int ** Matriz2D_2;

Matriz2D_2 CreaMatriz2D_2 (int fils, int cols);void LiberaMatriz2D_2 (Matriz2D_2 matriz, int fils, int cols);void PintaMatriz2D_2 (Matriz2D_2 matriz, int fils, int cols);

#endif

Punteros y memoria dinámicaLa memoria dinámica → Matrices dinámicas 92

Matriz2D_2.cpp

#include <iostream>#include <iomanip>#include "Matriz2D_2.h"using namespace std;

Matriz2D_2 CreaMatriz2D_2 (int fils, int cols){

Matriz2D_2 matriz = new int * [fils]; // puntero local a un// vector de punteros

matriz[0] = new int [fils*cols]; // vector de datos: todos// estan en una sola fila

for(int f=1; f<fils ; f++)matriz[f] = matriz[f-1] + cols; // apuntar con "matriz[f]"

// al inicio de la fila "f"return (matriz);

}

void LiberaMatriz2D_2 (Matriz2D_2 matriz, int fils, int cols){

delete [] matriz[0]; // Libera el vector de datosdelete [] matriz; // Libera el vector de punteros

}void PintaMatriz2D_2 (Matriz2D_2 matriz, fils, int cols){

for (int f=0; f<fils; f++) {for (int c=0; c<cols; c++)

cout << setw(4) << matriz[f][c]; // acceso a un elementocout << endl; // cada fila se muestra en una linea diferente

}}

Page 53: Metodología de la Programación

Punteros y memoria dinámicaLa memoria dinámica → Matrices dinámicas 93

Ejemplo de utilización

#include <iostream>#include <iomanip>

#include "Matriz2D_1.h"#include "Matriz2D_2.h"

using namespace std;

int main (void){

Matriz2D_1 m1; // "m1" y "m2" seran matricesMatriz2D_2 m2; // dinamicas 2D.

int filas, cols;

// Leer num. de filas y columnas

cout << "Numero de filas : ";cin >> num_filas;cout << "Numero de columnas : ";cin >> num_cols;

// Crear matrices dinamicas

cout << "Creando Matriz 1 ("<< filas << "X"<< cols << ")" << endl;m1 = CreaMatriz2D_1 (filas, cols);

cout << "Creando Matriz 2 ("<< filas << "X"<< cols << ")" << endl;m2 = CreaMatriz2D_2 (filas, cols);

Punteros y memoria dinámicaLa memoria dinámica → Matrices dinámicas 94

// Rellenarlas (observar el acceso por indices)

cout << endl << "Rellenando matrices" << endl;

for (int f=0; f<filas; f++)for (int c=0; c<cols; c++) {

m1[f][c] = ((f+1)*10)+c+1;m2[f][c] = ((f+1)*10)+c+1;

}

// Mostrar su contenido

cout << endl << "Matriz 1:" << endl;PintaMatriz2D_1 (m1, filas, cols);

cout << endl << "Matriz 2:" << endl;PintaMatriz2D_2 (m2, filas, cols);

// Liberar la memoria ocupada

cout << endl << "Liberando matriz 1" << endl;LiberaMatriz2D_1 (m1, filas, cols);

cout << "Liberando matriz 2" << endl << endl;LiberaMatriz2D_2 (m2, filas, cols);

return (0);}

Page 54: Metodología de la Programación

Tema II

FuncionesObjetivos:

� Profundizar en la necesidad de escribir programas modulares.

� Comprender la gestión que realiza la pila durante la ejecución delprograma en las llamadas a funciones y en su retorno.

� Entender la importancia de la función main() como punto de entra-da para la ejecución del programa.

� Conocer cómo pueden proporcionarse parámetros a la funciómmain() y cómo puede conocerse el valor devuelto por main().

� Conocer las referencias y la devolución por referencia.

� Distinguir el paso por valor del paso por referencia.

� Conocer cómo se pueden asignar valores por defecto a los pará-metros de una función.

� Entender el mecanismo de sobrecarga de funciones.

� Saber qué son funciones inline y sus limitaciones.Para cualquier sugerencia, aportación o notificación de erratas en estas transparen-

cias, por favor, enviar un e-mail a Francisco J. Cortijo

[email protected]

FuncionesLas funciones en C++ → 96

II.1. Las funciones en C++

Las funciones

� Permiten generalizar algoritmos...

... que se aplican a diferentes datos (y tipos de datos).

� Evitan reescribir algoritmos más de una vez...

... y reutilizar el código, evitando además, versiones inconsistentesdel mismo algoritmo.

� Permiten hacer abstracción procedural...

... de manera que empleamos código ya escrito (encapsulado enfunciones) como si fueran instrucciones del lenguaje.

� Permiten construir programas modulares...

... agrupando funciones “similares” (o relacionadas) en el mismofichero de código fuente para formar bibliotecas, por ejemplo.

Page 55: Metodología de la Programación

FuncionesLas funciones en C++ → 97

� La declaración o prototipo de una función indica al compilador:

1. su nombre,

2. el número y tipo de argumentos con los que la función puedeser llamada, y

3. el tipo de dato devuelto por la función (si no devolviera nada,se indicará mediante la palabra reservada void)

En el prototipo no es necesario indicar ningún nombre para losparámetros.

int Maximo (double *, int);

� La definición de una función incluye, además de lo expresado en ladeclaración, lo que se llama el cuerpo de la función, delimitado porlos caracteres { y } donde se indican las acciones a realizar (lasinstrucciones a ejecutar).

Todas la funciones que son llamadas en unfichero, han debido ser definidas en el ficheroantes de ser llamadas, o han sido declaradas

previamente.

� Parámetros formales: los que aparecen en la cabecera o prototipo.

int Maximo (double *v, int num_elementos){...}

v y num_elementos son parámetros formales.

� Parámetros reales o argumentos: las variables, literales o expresio-nes con las que se llama a una función (los parámetros que apare-cen en la llamada.

FuncionesLas funciones en C++ → Paso de argumentos por valor 98

Cada parámetro actual se corresponde de forma única con un pa-rámetro formal.

int m;...m = Maximo (vector, 500);...

vector y 500 son parámetros reales.

Cuando se realiza una llamada a una función, se crean automáticamentelos parámetros formales como variables locales, almacenándose en lapila, en el entorno creado para dicha función, asignándoseles el valor delargumento que aparece en la llamada.

Debe haber correspondencia en número y tipo entre parámetros reales yformales.

II.1.1. Paso de argumentos por valor

En un paso por valor, el parámetro formal es unavariable local cuyo valor inicial es el del parámetro

actual. Son variables distintas.

� Es la manera en la que por defecto se pasan los argumentos.

� Se crea una copia del argumento en la pila. De hecho, el parámetroformal es una variable local de la función.

� Los cambios realizados en los parámetros formales el cuerpo dela función no afectan a los parámetros actuales, es decir, los ar-gumentos permanecen inalterables al finalizar la ejecución de lafunción.

Page 56: Metodología de la Programación

FuncionesLa función main()→ 99

� Si el argumento es un puntero (se pasa una dirección de memoria),su valor no puede ser modificado (al finalizar la ejecución de lafunción sigue manteniendo su valor), pero sí pueden modificarselos objetos a los que referencian.

Cuando se pasa un vector v a una función (el parámetro actual sue-le escribirse como v en lugar de &v[0]) pueden modificarse los va-lores guardados en el vector. En este caso ni siquiera se puedemodificar v (actúa como un puntero constante)

II.2. La función main()

main() es una función especial, siendo el punto de arranque de ejecuciónde cualquier programa en C++

En cualquier programa de C++ debe existir una ysólo una función main().

main() usualmente implementa el algoritmo principal y controla la ejecu-ción de un programa, realizando llamadas a otras funciones.

main() es una función sobrecargada:

int main (void); int main (int argc, char * argv[]));

Si no se proporcionan argumentos desde la línea de órdenes (prompt) oéstos no se consideran por el programa se emplea la primera versión,mientras que si se suministran argumentos desde la línea de órdenes seimplementará la segunda.

FuncionesLa función main()→ 100

En cualquier caso siempre devuelve un valor int:

� Un programa termina de forma normal cuando se ha terminado deejecutar la última instrucción de la función main(). En ese caso, pordefecto, se devuelve el valor 0 al proceso desde el que se invocó alprograma (la shell desde la que se ejecuta el programa).

Evidentemente, puede hacerse explícito el valor de retorno paraexpresar que la ejecución ha sido correcta:

return 0;

También podría devolverse un valor diferente para indicar al pro-ceso que lanzó el programa que se ha detectado alguna situaciónerrónea, por ejemplo:

return 1;

� En algunos casos pueden existir por razones variadas, otros pun-tos de terminación del programa que se activan llamando a la fun-ción exit():

void exit (int status);

– La ejecución de exit() finaliza la ejecución del programa demanera “controlada” y “limpia” (se cierran los flujos abiertos,se borran los ficheros temporales creados) y se devuelve elcontrol al proceso que ejecutó el programa. Normalmente sellama a esta función para finalizar el programa cuando se de-tecta una situación de error que no permite seguir la ejecucióndel programa.

– status el el valor que se devuelve al proceso desde el que seinvocó al programa. Generalmente, el valor 0 o EXIT_SUCCESSindica que todo ha ido bien, y cualquier otro valor, o la cons-tante EXIT_FAILURE indica un error o que el programa terminapor alguna razón inesperada.

Page 57: Metodología de la Programación

FuncionesLa función main()→ Paso de argumentos a la función main() 101

� En linux podemos consultar el valor devuelto por el programa queacaba de ejecutarse escribiendo echo $^ Por ejemplo, programa1 és-te es un programa que se ejecuta normalmente:

% programa1% echo $^0

mientras que en programa2 se produce algún error:

% programa2% echo $^1

II.2.1. Paso de argumentos a la función main()

� Motivación.

Manejamos habitualmente programas a los que se les proporcio-nan los datos sobre los que operan desde la línea de órdenes(prompt del sistema) al mismo tiempo que se invoca su ejecución.Por ejemplo:

% echo holahola% echo adiosadios

� Para poder gestionar estos valores por el programa, debe emplear-se la versión extensa de la función main():

int main (int argc, char *argv[])

donde:

FuncionesLa función main()→ Paso de argumentos a la función main() 102

int main (int argc, char *argv[])

int argc El número de argumentos suministrados,

incluído el nombre del programa.

char *argv[] Proporciona los argumentos en sí.

Se almacenan en un vector de cadenas clásicas.

Ejemplo II.2.1.

// saludo.cpp#include <iostream>using namespace std;

int main (int argc, char *argv[]){

if (argc==2) { // perfectocout << "Hola, " << argv[1] << endl;cout << "Mi nombre es " << argv[0] << endl;return 0; // OK

}else

if (argc==1) { // ningun argumentocout <<"Eres muy callado: dime tu nombre." << endl;return 1; // situacion anomala (error)

}else { // demasiados argumentos

cout <<"Hablas demasiado: solo tu nombre." << endl;return 2; // situacion anomala (error)

}}

Page 58: Metodología de la Programación

FuncionesLa función main()→ Paso de argumentos a la función main() 103

% saludo Paco % saludoHola, Paco Eres muy callado: dime tu nombre.Mi nombre es saludo % echo $^% echo $^ 10 %%

% saludo Paco Paco PacoHablas demasiado: solo tu nombre.% echo $^2%

Ejemplo II.2.2. % imprimir datos.txt impresora1 portrait

argc = 4

argv [0] = "imprimir"

argv [1] = "datos.txt"

argv [2] = "impresora1"

argv [3] = "portrait"

argv [argc] = argv [4] = 0

argc

4

argv

"imprimir"

"datos.txt"

"impresora1"

"portrait"

NULL

0

2

3

1

4

FuncionesLa función main()→ Paso de argumentos a la función main() 104

Ejemplo II.2.3./************************************************/// Programa: echo1.cpp/************************************************/#include<iostream>using namespace std;

int main (int argc, char **argv) {for (int i = 1; i < argc; i++)

cout << argv[i] << ((i < argc-1) ? " ": "");cout << endl;return (0);

}

Ejemplo II.2.4./************************************************/// Programa: echo2.cpp/************************************************/#include<iostream>using namespace std;

int main (int argc, char **argv) {while (--argc > 0)

cout << *++argv << ((argc > 1) ? " ": "");cout << endl;return (0);

}

Page 59: Metodología de la Programación

FuncionesReferencias → 105

II.3. Referencias

Una variable de tipo referencia es un alias (un segundo nombre) para unavariable o constante,

int a=5;int &r = a; // "r" es una referencia a la variable "a"

Si el nombre de una variable es una etiqueta asociada a una dirección dememoria, una referencia sería otra etiqueta asociada a la misma direcciónde memoria, de forma que podemos utilizar indistintamente cualquiera delas dos etiquetas para acceder a dicha dirección de memoria y recuperaro modificar la información.

Aunque internamente un referencia funciona como un puntero constantea un objeto, cuando se utiliza, directamente se desreferencia y representael objeto con el que ha sido inicializado.

Con las declaraciones e inicializaciones anteriores, puede emplearse in-distintamente, a y r para acceder a la misma zona de memoria.

a = 10;r = 20;cout << a << " " << r; // 20 20

FuncionesReferencias → 106

Importante:

� Las variables de referencia deben ser inicializadas cuando secrean, antes de usarse.

� La inicialización de una referencia no es una asignación, aunquesintácticamente coincida; la inicialización de una referencia espe-cifica el objeto al que la varible de tipo referencia apunta.

� Una referencia a un objeto, no puede ser cambiada a otro objeto,ya que internamente se comporta como un puntero constante alobjeto.

� En el caso de que una variable referencia sea inicializada a unaconstante, la referencia debe ser constante.

Situaciones en las que no se inicializan las variables referencia:

� En la declaración de parámetros formales.

void f (int& a);

� En la declaración del tipo devuelto por una función.

int& f(int b);

� Cuando se declara un miembro de una clase como varible de refe-rencia.

class Ejemplo { int& a; };

� En la declaración de variables de referencia externas.

extern int& a;

Page 60: Metodología de la Programación

FuncionesReferencias → 107

Una referencia contiene la dirección de un objeto, pero se comporta sin-tácticamente como un objeto. Por ejemplo, si i es una referencia, i++incrementará el valor del objeto en una unidad. Es como si existiera unamacro predefinida, de forma que cuando aparece i++ se convertirá i a(*p) donde p contendrá la dirección del objeto.

Cuando se esté programando, una referencia debeser considerada como un objeto, nunca como un

puntero.

Diferencias fundamentales entre referencias y punteros:

� No existen referencias nulas, una referencia simpre está asociadaa un objeto, sin embargo a los punteros sí se les puede asignar ladireccción nula.

� Una vez que una referencia es asociada a un objeto, ésta no puedeser asociada a otro objeto, al contrario que a un puntero, que sí sele puede asignar una nueva direción de memoria, después de quehaya sido inicializado.

� Una referencia debe ser inicializada cuando es creada, en cambiolos punteros pueden ser inicializados después de haber sido crea-dos.

El uso normal de las referencias es, el paso de argumentos a funciones,la devolución de refencias en las funciones, y el uso en operadores so-brecargados.

FuncionesReferencias → Paso de argumentos por referencia 108

II.3.1. Paso de argumentos por referencia

En C++ es posible el paso por referencia real, mediante referencias.

void incremento (int &);...int n = 1;incremento (n);cout << n; // 2...

void incremento (int &valor){

valor++;}

En un paso por referencia, el parámetro formal esuna referencia al parámetro actual. Son la misma

variable.

� La llamada a la función hace que el parámetro formal coincida conel argumento (aunque internamente se pase la dirección de me-moria del objeto con el que ha sido inicializada la variable de re-ferencia), pero no se copia el valor del argumento en el parámetroformal.

� Cualquier cambio realizado dentro del cuerpo de la función sobreel parámetro formal considerado como una referencia (siempre queno sea constante), afecta a la variable pasada como argumento.

Puede “simularse” el paso por referencia empleando punteros como pa-rámetros formales:

Page 61: Metodología de la Programación

FuncionesReferencias → Paso de argumentos por referencia 109

// Paso por referencia real // paso por referencia "simulado"

void swap (int& v1, int& v2) void swap (int * pv1, int * pv2){ {

int tmp = v1; int tmp = *pv1;v1 = v2; *pv1 = *pv2;v2 = tmp; *pv2 = tmp;

} }int main() int main(){ {

int x, y; int x, y;... ...swap(x, y); swap(&x, &y);... ...

} }

Paso por referencia real - paso por referencia simulado

Cuando se pasan por referencia las variables x e y, los parámetros for-males v1 y v2 son alias para las variables x e y, respectivamente, de lafunción main(). Observad que v1 (resp. v2) no es un puntero, ni una copiade x, (resp. y). Por tanto, todas las modificaciones que se realican en v1(resp. v2), también se realizan en x (resp. y).

FuncionesReferencias → Paso de argumentos por referencia 110

Cuando se simula el paso por referencia, los parámetros reales son lasdirecciones de memoria de las variables (&x y &y). Los parámetros for-males serán, en consecuencia, punteros (pv1 y pv2). Estos dos punterosson variables locales de la función y el paso de argumentos se realiza,realmente, por valor. El acceso al contenido se realiza con el operador *(*pv1 y *pv2)

Las referencias tanto en la entrada como en lasalida de las funciones, son preferibles a los

punteros siempre que no necesitemos reasignar ladireccion del objeto, o cuando exista la posibilidad

de introducir o devolver la dirección nula

Emplearemos el paso por referencia en vez de por valor:

1. Cuando queramos modificar el objeto en la función.

2. Cuando el objeto sea muy grande.

En este caso quizá no queramos cambiar el valor del parámetroactual, pero evitamos realizar una copia del objeto, con lo cual:

� Se economiza espacio en la pila.

� Se reduce el tiempo de ejecución.

struct Grande {int n1, n2;double v1, v2, v3, v4, v5;string cad1, cad2;// ocupa mucho espacio

};

void f1 (Grande param1); // paso por valorvoid f2 (Grande & param2); // paso por referencia

Page 62: Metodología de la Programación

FuncionesReferencias → Devolución en una función de una referencia 111

En el caso de no querer modificar el objeto y que este sea grande,debemos declarar una referencia constante:

void f3 (const Grande & param3);

En el paso por referencia, el argumento siempredebe ser una variable, no una constante, ni una

expresión.

Los argumentos que pueden emplearse para llamar a una función con unparámetro formal por referencia deben ser l-value, es decir que puedanaparecer a la izquierda de un operador como el de asignación (es decir,que pueden recibir un valor).

swap (1, 3); // Error: los literales no son l-values.// (no tiene sentido, p.e. 1 = 8)

swap (x+5, c); // Error: las expresiones numericas no son// l-values (no tiene sentido, p.e. x+ 5 = 8)

swap (x, y); // OK, las variables son l-valuesswap (a[i], a[i + 7]); // OK, los arrays son l-values

II.3.2. Devolución en una función de una refe-rencia

Una función puede devolver una referencia. Existen dos razones para queuna función devuelva una referencia a un objeto:

1. Cuando se realiza una llamada a una función, si pasamos un objetopor valor como argumento, se realiza una copia del mismo; de igualforma si se devuelve un objeto por una función, se realiza una copiapreviamente de dicho objeto.

FuncionesReferencias → Devolución en una función de una referencia 112

En este sentido, si el objeto es bastante grande, para ser más efi-ciente -eliminando la necesidad de realizar una copia temporalmen-te en la pila- es preferible que el argumento pasado a la función seapor referencia, y por la misma razón, la devolución del objeto seapor referencia.

2. Cuando el tipo devuelto es una referencia puede ser usado comoun l-value. La mayor parte de los aperadores sobrecargados permi-ten esta posibilidad, en particular el operador de asignación.

Cuando las funciones devuelven un objeto, se llama al constructor decopia, y devuelven una copia del objeto (el que aparece como argumentode return()), por consiguiente, si la devolución es por valor, se puedendevolver variables, literales o expresiones que incluyan variables localesdeclaradas dentro de la función.

La devolución por valor es el método más apropiado para devolver varia-bles declaradas dentro de la función.

Cuando una función devuelve una referencia hay que tener cuidado conque el objeto al que se está haciendo referencia no sea del ámbito de lafunción ( variable local o un objeto temporal), ya que al salir de la función,no existirá; sin embargo sí se puede devolver una variable estática.

Ejemplo II.3.1. En este ejemplo puede ver cómo el uso de referen-cias a variable locales de una función que deja de existir produceresultados erróneos.

...

int & funcion (void);int & funcion2 (void);

Page 63: Metodología de la Programación

FuncionesReferencias → Devolución en una función de una referencia 113

int main (){

int & ri = funcion ();

cout << "ri= " << ri << endl;cout << "funcion2()= " << funcion2 () << endl;cout << "ri= " << ri << endl;cout << "funcion()= " << funcion () << endl;

}

int & funcion(){

int x = 10; // var. localreturn (x);

}

int & funcion2(){

int x = 0; // var. localreturn (x);

}

La ejecución de ese programa produce los siguiente resultados:

ri= 10funcion2()= 0ri= 274148040funcion()= 10

pero pudieran dar otros valores. �

FuncionesParámetros con valores por defecto → 114

Ejemplo II.3.2.

int v[]={3, 44, 35, 70, 4, 86, 22};...int f1 (int v[], int i) int & f2 (int v[], int i){ {

return (v[i]); return (v[i]);} }

f1(v, 2) devuelve un dato int, 35. mientras que f2(v, 2) devuelveuna referencia a un dato int, un alias al entero cuya dirección dememoria es &v[2]

¿Qué muestra el siguiente código?

cout << f1 (v, 2) << " " << f2 (v, 2) << endl;

¿Por qué es correcta la siguiente instrucción?

f2 (v,2) = 100;

¿Qué muestra ahora el siguiente código?

cout << f1 (v, 2) << " " << f2 (v, 2) << endl;

II.4. Parámetros con valores por defecto

En C++ se permite indicar valores por defecto para algunos o todos losparámetros formales, que se asumirán en la llamada a la función.

Se recomiendan cuando se realizan múltiples llamadas a una función, ca-

Page 64: Metodología de la Programación

FuncionesParámetros con valores por defecto → 115

si siempre con los mismos argumentos. Por ejemplo, considerar la fun-ción getline(), función miembro de la clase cin.

Los parámetros por defecto en la definición de la función, apareceráncomo los otros parámetros normales, se diferencian en que se escribe,explícitamente, el valor que se le asigna por defecto. Sintácticamente, losparámetros que tienen valores por defecto se escriben a la derecha de losque no tienen valores por defecto.

El valor por defecto de una declaración puede ser una constante, unaconstante global, una variable global e incluso una llamada a una función.

Cuando se realiza una llamada a una función con parámetros por defectoy no se especifican tantos argumentos en la llamada como parámetrosformales hay, la correspondencia se hace de izquierda a derecha, de ma-nera que serán los últimos argumentos los que tomen los valores pordefecto.

// no tiene parametros por defectovoid f1 (int a, int b) f1 (5, 10); // a=5, b=10{ f1 (5); // ERROR...}// El ultimo parametro tiene valor por defectovoid f2 (int a, int b=100) f2 (5, 10); // a=5, b=10{ f2 (5); // a=5, b=100...}// Los dos parametros tienen valores por defectovoid f3 (int a=50, int b=100) f3 (5, 10); // a=5, b=10{ f3 (5); // a=5, b=100... f3 (); // a=50, b=100}

FuncionesParámetros con valores por defecto → 116

Ejemplo II.4.1. La función potencia se usa con bastante frecuencia,si bien es muy raro calcular potencias con exponentes altos, y pocofrecuente calcular potencias con exponentes mayores que 2. Así,podemos asumir que el valor más frecuente del expnente es 2, porlo que si en la llamada a la función no se especifica el exponentese asume que es 2. Esto obliga a que este argumento sea el últimoen la cabecera de la función.

long potencia (long base, int exponente=2){

long resultado;

if (exponente == 2)resultado = base * base;

else{

resultado=base;for(int i=1; i < exponente; i++)

resultado *= base;}return resultado;

}

int main(){

cout << "potencia(5) = " << potencia(5) << endl;cout << "potencia(4, 3)= " << potencia(4,3) << endl;

}

Page 65: Metodología de la Programación

FuncionesSobrecarga de funciones → 117

II.5. Sobrecarga de funciones

Las funciones se diferencian, entre otras cosas, por su nombre.

C++ permite el uso de funciones sobrecargadas, que son aquellas quetienen el mismo nombre y se diferencian en los tipos y/ó número y/ó or-den de los parámetros formales. Así, es posible tener dos o más funcio-nes con el mismo nombre siempre y cuando sea posible distinguirlasmediante el tipo y número de sus parámetros formales.

Cuando se realiza una llamada a una función sobrecargada, se activaránen el siguiente orden:

� Coincidan exactamente los argumentos, con el número y tipo desus parámetros formales

� Solo se tengan que realizar promociones de tipos (de menor a ma-yor)

� Tenga que realizar conversiones de tipos propios del compilador

� Necesite conversiones de tipos definidas por el usuario.

Si no ocurre ninguna de las situaciones anteriores, se obtendrá un error.

La firma de una función es el conjunto de su nombre y la lista ordenadade los tipos de parámetros formales (obviando el modificador const y elsímbolo de referencia &).

No se pueden sobrecargar funciones que solo se diferencien en el tipodevuelto. Como las firmas no pueden coincidir, no puede considerarseuna diferencia aquella que esté basada en el modificador const o en elsímbolo de referencia &.

Un caso típico de sobrecarga de funciones, son algunas funciones mate-

FuncionesSobrecarga de funciones → 118

máticas que se definen para distintos tipos de datos: int, float, etc.

Ejemplo II.5.1.

struct Punto {double X;double Y;

}struct Rectangulo {

Punto inf_izda;Punto sup_dcha;

}struct Circulo {

Punto centro;double radio;

}struct Triangulo {

Punto vertice1;Punto vertice2;Punto vertice3;

}

void Dibujar (Punto p);void Dibujar (Rectangulo r);void Dibujar (Circulo c, double r);void Dibujar (Triangulo t);...

Page 66: Metodología de la Programación

FuncionesSobrecarga de funciones → 119

int main (){

Punto pto;Rectangulo rec;Circulo circ;Triangulo triang;...Dibujar (pto);Dibujar (rec);Dibujar (circ);Dibujar (triang);...

}

Ejemplo II.5.2.void f1 (int x){

cout << "int x=" << x << endl;}void f2 (int x, int y){

cout << "int x=" << x << " int y=" << y << endl;}void f2 (double x, double y){

cout << "double x=" << x << " double y=" << y << endl;}

FuncionesFunciones inline → 120

int main (){

f1 (3.4); // conversion implicita: int x=3f1 (3); // int x=3

f2 (2, 4); // int x=2 int y=4f2 (3.7, 9.2); // double x=3.7 double y=9.2f2 (2, 9.9); // Ambiguof2 (4.5, 8); // Ambiguof2 (4.5, static_cast<double>(5)); // double x=4.5 double y=5f2 (4.5, 5.0); // double x=4.5 double y=5

}

II.6. Funciones inline

Motivación

� Cuando una función es llamada múltiples veces, cada vez que esllamada se reproduce la misma secuencia de pasos: guardar esta-do, copia de parámetros, salto, reserva de variables locales, ejecu-ción de las instrucciones y retorno al punto de llamada.

� Sería más eficiente, si no se realizara la llamada, sino que se eje-cutara directamente el código de la función.

No siempre es posible.

Page 67: Metodología de la Programación

FuncionesFunciones inline → 121

Pueden emplearse macros del preprocesador(#define) para esta tarea.

1. Las macros, no obstante, no realizan comprobación de tipos y elcódigo generado.

2. El código compilado y generado puede ser muy extenso.

C++ proporciona las funciones inline, que permite ubicar el código de lafunción en el lugar de la llamada (sustitución), si el compilador lo consi-dera oportuno: se trata de una sugerencia al compilador.

Al evitar las tareas asociadas a la llamad y retorno, la ejecución es másrápida, aunque aumenta el volumen del ejecutable.

Formato: preceder la declaración con inline.

Nota: Cuando las funciones miembro de una clase son definidas dentrode la propia clase, no necesitan que se les antepongan la palabra inline,implícitamente son consideradas inline.

Sólo deberían definirse funciones inline, cuando el cuerpo de la funcióncontenga muy poco código.

// Tabla de valores y los tres tipos de IVA asociados

#include <iostream>#include <iomanip>using namespace std;

const int GENERAL = 18;const int REDUCIDO = 8;const int SUPERREDUCIDO = 4;

FuncionesFunciones inline → 122

inline float iva (const int tipo, float valor){

return ((tipo*valor)/100);}

int main (){

cout.setf (ios::fixed);

for (int v=1000; v<10000; v+=1000) {cout << setw (8) << v;cout << setw (10) << setprecision(2) << iva (GENERAL, v);cout << setw (10) << setprecision(2) << iva (REDUCIDO, v);cout << setw (10) << setprecision(2) << iva (SUPERREDUCIDO, v);cout << endl;

}}

Page 68: Metodología de la Programación

FuncionesEjemplo: Prototipos → 123

II.7. Ejemplo: Prototipos

Un prototipo (también llamado ejemplo) es un vector d-dimensional(patrón) que tiene asociado una etiqueta numérica que indica la clasea la que pertenece. Se trata de calcular y mostrar la media de cada clasea partir de un conjunto de prototipos almacenado en un fichero de texto.

Análisis

Entradas:

El programa recibirá N prototipos de dimensión d que pertenecen a J

clases. Los prototipos se proporcionan en un fichero de prototipos, quese supone que es correcto, y cuyas especificaciones son:

1. Es un fichero de texto.2. Cada línea contiene un único prototipo y cada prototipo se encuen-

tra en una sola línea ⇒ el fichero contendrá tantas líneas comoprototipos.

3. No se impone ningún orden entre los prototipos.

4. Si los prototipos son de dimensión d, cada línea está formada pord + 1 columnas:

a) Las primeras d columnas son valores reales y corresponden alos valores de los d atributos.

b) La última columna contiene un valor entero que indica su clase.

c) Las columnas están separadas por un número indeterminadode espacios en blanco.

5. El conjunto de etiquetas es completo, siendo la menor 1. Así, paraun problema en el que J = 3, por ejemplo, existen prototipos declase 1, 2 y 3 únicamente.

FuncionesEjemplo: Prototipos → 124

Ejemplo:

� 2 clases: 1 (Mujer) y 2 (Hombre).

� 2 atributos: 1 (Peso) y 2 (Altura).

78.4 175 266.3 170 160.4 162 172.4 171 2

........

En definitiva, el programa requiere conocer:

1. El nombre del fichero de prototipos (cadena).

2. El número de prototipos, N (entero).

3. El número de atributos, d (entero).

4. El número de clases, J (entero).

Nota: Los valores de N , d y J pueden calcularse examinando el ficherode entrada, aunque en este momento no se dispone de suficientesconocimientos.

Salidas:

El programa debe mostrar los valores medios de las J clases. Como losdatos de entrada son de dimensión d, se mostrará para cada una de lasJ clases, d valores: media del atributo 1, . . . , media del atributo d.

Los valores medios calculados deben ser reales.

Page 69: Metodología de la Programación

FuncionesEjemplo: Prototipos → 125

Relación entre Entradas y Salidas:

La media del atributo i para la clase j, mji, se calcula de manera trivial:

mji =1

Nj

Nj∑

k=1

pkji

donde:

� Nj es el número de prototipos de la clase j.� pk

j es el prototipo k-ésimo de la clase j.� pk

jies el valor del atributo i del prototipo k-ésimo de la clase j.

Diseño

Tipos de datos:

El número de prototipos y dimensión de los mismos es desconocido apriori por lo que los prototipos se guardarán en memoria dinámica.

Prototipo.

La representación de un prototipo requiere:

� La etiqueta de la clase (int)

� Los valores de los atributos (vector de d valores float). El valor ded es, a priori, desconocido ⇒ memoria dinámica.

struct prototipo {

float *atributos; // Valores de los atrs.int clase; // Etiqueta de clase

};

FuncionesEjemplo: Prototipos → 126

1 110.36 78.33 12.55

0 1 2 3

0.00

Nota: Índices 0..d (d+1 casillas)

Conjunto de prototipos.

� El número de prototipos es, a priori, desconocido ⇒ memoria di-námica. Usaremos un vector (dinámico) de punteros a prototipo.

� Para facilitar el paso de parámetros, añadimos una nueva referen-cia:

typedef prototipo ** CtoProt;

Por ejemplo, si S se declara de tipo CtoProt y se inicializa adecuadamente:

S

1 110.36 78.33 12.55

2 49.92 93.29

1 107.45 69.23 10.45

44.672

3

1

0 0 1 2 3

0.00

0.00

0.00

X

Nota: Índices 0..N (N+1 casillas)

Page 70: Metodología de la Programación

FuncionesEjemplo: Prototipos → 127

Medias.

Se necesitan J × d datos float, pero:

El número de clases, J , y la dimensionalidad de los datos, d,es, a priori, desconocido.

Consecuencia: matriz con J filas y d columnas que resida en memoriadinámica.

22.66.90.02

1

0 1 20

medias

3

X

20.57.30.0

21.57.00.0

Algoritmo:

Algoritmo básico.

1. Obtener entradas: nombre del fichero de prototipos y los paráme-tros asociados (N , J y d).

2. Copiar los prototipos del fichero en memoria.

3. Calcular las medias.

4. Mostrar las medias.

FuncionesEjemplo: Prototipos → 128

Refinamiento.

� Los parámetros N , J y d dependen del fichero, por lo que su en-trada puede hacerse en dos pasos:

1.1 Obtener nombre del fichero de prototipos.

Se obtiene de cin.

Previsión 1: tomarlo de la línea de órdenes.

1.2 Obtener los parámetros asociados (N , J y d).

Se obtienen de cin.

Previsión 2: calcularlos automáticamente.

� El programa debería mostrar más información para asegurar quefunciona correctamente:

1.3 Mostrar los valores de entrada.

2.1 Copiar los prototipos del fichero en memoria.

2.2 Mostrar el conjunto de prototipos.

� Conjunto de prototipos y medias en memoria dinámica ⇒ liberarla.

Algoritmo refinado.

1. Obtener nombre del fichero de prototipos.2. Obtener los parámetros asociados (N , J y d).3. Mostrar los valores de entrada.4. Copiar los prototipos del fichero en memoria.5. Mostrar el contenido del conjunto de prototipos.6. Calcular las medias.7. Mostrar las medias.8. Liberar la memoria ocupada.

Page 71: Metodología de la Programación

FuncionesEjemplo: Prototipos → 129

Descomposición modular:

En primera instancia: un módulo para cada paso.

1. Obtener nombre del fichero de prototipos.

void ObtenerNombreFichero (string & nbre);

Devuelve (ref.) una cadena: el nombre del fichero de proto-tipos.

2. Obtener los parámetros asociados (N , J y d).

void ObtenerDatos (string nombre, int &N, int &J, int &d);

Devuelve (ref.) los valores de N, J y d asociados al ficheronombre.

3. Mostrar los valores de entrada.

void MostrarDatos (string nombre, int N, int J, int d);

Muestra en cout los valores de N, J y d asociados al ficheronombre.

4. Copiar los prototipos del fichero en memoria.

CtoProt RellenaPrototipos (string nombre, int N, int d)

Crea un cto. de N prototipos de dimensión d y lo inicializaa partir del fichero nombre.

Devuelve el conjunto creado e inicializado.

No se requiere reserva previa de memoria.

5. Mostrar el contenido del conjunto de prototipos.

void PintaPrototipos (CtoPrtot prot, int N, int d)

Muestra el contenido del cto. prot, compuesto por N proto-tipos de dimensión d.

FuncionesEjemplo: Prototipos → 130

6. Calcular las medias.

float ** CreaYCalculaMedias (int J, int d, int N, CtoProt prot)

Crea una matriz dinámica bidimensional (J filas y d colum-nas) y la inicializa calculando las medias del conjunto prot,compuesto por N prototipos de dimensión d de J clases.

Devuelve la matriz dinámica creada e inicializada.

No se requiere reserva previa de memoria.

7. Mostrar las medias.

void PintaMedias (int J,int d,float **mu)

Muestra los valores guardados en la matriz dinámica bidi-mensional mu, que tiene J filas y d columnas.

8. Liberar la memoria ocupada.

La liberación de memoria involucra a dos módulos:

void LiberaPrototipos (CtoProt prot,int N);

Libera la memoria ocupada por el conjunto prot, que tieneN prototipos.

void LiberaMedias (int J, float **mu);

Libera la memoria ocupada por la matriz mu, que tiene Jfilas.

9. Módulos adicionales:

CtoProt ReservaPrototipos (int N, int d);

Reserva memoria para alojar a N prototipos de dimensiónd.

Devuelve el conjunto reservado, pero no inicializado.

Llamado por RellenaPrototipos().

Page 72: Metodología de la Programación

FuncionesEjemplo: Prototipos → 131

float ** ReservaMatriz2D (int fils,int cols)

Reserva memoria para alojar una matriz dinámica bidimen-sional de float que tiene fils filas y cols columnas.

Devuelve la matriz reservada, pero no inicializada.

Llamada por CreaYCalculaMedias().

void LiberaMatriz2D (float **matriz, int fils,int cols)

Libera la memoria reservada para la matriz dinámica bidi-mensional de float llamada matriz, para la que se reservaespacio para fils filas y cols columnas.

Llamada por LiberaMedias().

El separar la reserva de la inicialización tiene la ventaja de que si serequiere otra función que necesite reservar memoria para un con-junto de prototipos (p.e., hacer una copia en otro conjunto, extraera un nuevo conjunto los de una clase dada, etc.) puede reutilizarse.

El mismo comentario puede aplicarse a las funciones que crean yliberan matrices dinámicas 2D.

Modularidad a nivel de ficheros:

Modelo de compilación separada de C/C++

� prots.h

– Definición de los tipos de datos ofertados.

– Declaración de las funciones ofertadas.

� prots.cpp

– Implementación de las funciones ofertadas.

– Implementación de las funciones privadas. En este caso, úni-camente ReservaPrototipos().

FuncionesEjemplo: Prototipos → 132

� demo_prots.cpp

Contiene únicamente la función main().

� Makefile

Especificación de dependencias entre ficheros para la creación delejecutable.

demo_prots

prots.h

demo_prots.o

prots.oprots.cpp

demo_prots.cpp

Codificación

prots.h

#ifndef PROTS#define PROTS

// Definicion de los tipos "prototipo" y "CtoProt"

struct prototipo {float *atributos; // Valores de los atributosint clase; // Etiqueta de clase

};typedef prototipo ** CtoProt;

Page 73: Metodología de la Programación

FuncionesEjemplo: Prototipos → 133

// Funciones para obtener y mostrar los valores de los// parametros asociados al fichero de prototipos

void ObtenerNombreFichero (string & nbre);void ObtenerDatos (string nombre,int &N,int &J,int &d);void MostrarDatos (string nombre,int N,int J,int d);

// Funciones para cargar/liberar prototipos// en memoria y su procesamiento.

CtoProt RellenaPrototipos (string nombre,int N,int d);void LiberaPrototipos (CtoProt prot, int N);void PintaPrototipos (CtoProt prot, int N, int d);

// Funciones asociadas a medias.

float ** CreaYCalculaMedias (int J, int d, int N, CtoProt prot);void PintaMedias (int J, int d, float **media);void LiberaMedias (float **media, int J, int d);

#endif

prots.cpp

#include <iostream>#include <iomanip>#include <fstream>#include <string>#include <new>using namespace std;

#include "prots.h"

FuncionesEjemplo: Prototipos → 134

// Funciones privadas:CtoProt ReservaPrototipos (int N, int d);float ** ReservaMatriz2D (int fils, int cols);void LiberaMatriz2D (float **matriz, int fils, int cols);

// *****************************************************************void ObtenerNombreFichero (string & nbre){

cout << endl << "Nombre del fichero de prototipos: ";cin >> nbre;

}// *****************************************************************void ObtenerDatos (string nombre,int &N,int &J,int &d){

cout << "Introducir los valores de los parametros ";cout << "asociados al fichero: "<< nombre << endl;cout << " Num. de prototipos: ";cin >> N;cout << " Num. de clases: ";cin >> J;cout << " Num. de atributos: ";cin >> d;

}// *****************************************************************void MostrarDatos (string nombre, int N, int J, int d){

cout << "Fichero: "<< nombre << endl;cout << " Num. de prototipos: " << N << endl;cout << " Num. de clases: " << J << endl;cout << " Num. de atributos: " << d << endl;

}

Page 74: Metodología de la Programación

FuncionesEjemplo: Prototipos → 135

prots.cpp

CtoProt ReservaPrototipos (int N, int d){

CtoProt prot;prot = new (nothrow) prototipo * [N+1];if (!prot) {

cerr << "No hay mem. para prots. (1)" << endl;exit (1);

}prot[0] = 0; // Puntero nulo

for (int p=1; p<=N; p++) {prot[p] = new (nothrow) prototipo;if (!prot[p]) {

cerr << "No hay mem. para prots. (2)"<<endl;exit (2);

}(prot[p])->atributos = new (nothrow) float [d+1];

if (!(prot[p])->atributos) {cerr << "No hay mem. para prots. (3)"<<endl;exit (3);

}} // for p

return (prot);}

FuncionesEjemplo: Prototipos → 136

CtoProt RellenaPrototipos (string nombre,int N,int d){

CtoProt prot;ifstream fprot;int clase;float valor;

// Reservar memoria para "N" prots. de dim. "d".

prot = ReservaPrototipos (N, d);

// Rellenar "prot" a partir del fichero

fprot.open (nombre.c_str(), ios::in);

for (int p=1; p<=N; p++) {

(prot[p]->atributos)[0] = 0.0;for (int atr=1; atr<=d; atr++) {

fprot >> valor;(prot[p]->atributos)[atr] = valor;

}

fprot >> clase;prot[p]->clase = clase;

} // for p

fprot.close();

return (prot);}

Page 75: Metodología de la Programación

FuncionesEjemplo: Prototipos → 137

void LiberaPrototipos (CtoProt prot, int N){

for (int p=1; p<=N; p++) {delete [] ((prot[p])->atributos);delete prot[p];

}delete [] prot;

}

// *****************************************************************

void PintaPrototipos (CtoProt prot, int N, int d){

cout << endl << endl;cout << "Prototipos leidos y guardados:" << endl;

cout.setf (ios::fixed);cout.setf (ios::showpoint);cout.precision (2);

for (int p=1; p<=N; p++) {

cout << "Prot. "<< setw(3) << p <<": ";for (int atr=1; atr<=d; atr++) {

cout<<setw(6)<<(prot[p]->atributos)[atr]<<" ";}cout << "["<<prot[p]->clase<<"]"<<endl;

} // for p}

FuncionesEjemplo: Prototipos → 138

float ** CreaYCalculaMedias (int J, int d, int N, CtoProt prot){

float **mu, *patron;int *cont;float valor;

cont = new (nothrow) int [J+1];if (!cont) {

cerr << "No hay mem. para contadores (1)"<< endl;exit (4);

}mu = ReservaMatriz2D (J+1, d+1);if (!mu) {

cerr << "No hay memoria para medias" << endl;exit (2);

}mu[0] = 0; // Puntero nulo

// Inicializacionfor (int j=1; j<=J; j++)

for (int atr=0; atr<=d; atr++) {mu[j][atr] = 0.0;cont[j] = 0;

}

// Calculo

for (int p=1; p<=N; p++) {for (int atr=1; atr<=d; atr++) {

patron = prot[p]->atributos;mu[prot[p]->clase][atr] += patron[atr];

}

Page 76: Metodología de la Programación

FuncionesEjemplo: Prototipos → 139

cont[prot[p]->clase]++;} // for p

for (int j=1; j<=J; j++)for (int atr=1; atr<=d; atr++)

mu[j][atr] /= cont[j];

delete [] cont;return (mu);

}

// *****************************************************************

void PintaMedias (int J, int d, float **mu){

cout << endl << endl;cout <<"Valores medios (por clase):"<< endl<< endl;

cout.setf (ios::fixed);cout.setf (ios::showpoint);cout.precision (2);for (int j=1; j<=J; j++) {

cout << "Clase " << setw(3) << j << ": ";for (int atr=1; atr<=d; atr++) {

cout << setw(8) << mu[j][atr];}cout << endl;

}cout << endl;

}// *****************************************************************

FuncionesEjemplo: Prototipos → 140

void LiberaMedias (float **mu, int J, int d){

LiberaMatriz2D (mu, J+1, d+1);}

float ** ReservaMatriz2D (int fils, int cols){

bool error = false;float ** matriz;

//"matriz" apunta a un vect. de punt. a filas

matriz = new (nothrow) float * [fils];

if (!matriz) {cerr << "Error en reserva (1)"<< endl;matriz = 0;

}

else { // Se ha creado el vector de punt. a filas

for (int f=0; (f<fils) && !error; f++) {

// "matriz[f]" apuntara a un vector de int

matriz[f] = new (nothrow) float [cols];

if (!matriz[f]) {

cerr << "Error en reserva (2)"<<endl;error = true; // Detiene el ciclo for

Page 77: Metodología de la Programación

FuncionesEjemplo: Prototipos → 141

// Libera la memoria ya reservada

for (int i=f-1; i>=0; i--)delete [] matriz[i];

delete [] matriz;matriz = 0; // Puntero nulo

}} // for f

}return (matriz);

}

// *****************************************************************

void LiberaMatriz2D (float **matriz,int fils,int cols){

for (int f=0; f<fils; f++)delete [] matriz[f];

delete [] matriz;}// *****************************************************************

FuncionesEjemplo: Prototipos → 142

demo_prots.cpp

#include <string>

using namespace std;

#include "prots.h"

int main (void){

string nombre; // Nombre del fichero de prototiposCtoProt prot; // ED para guardar prototiposint N; // Num. de prototiposint J; // Num. de clasesint d; // Num. de atributos

float ** medias; // ED para calcular y guardar//las medias (por clase)

// Obtener (de "cin") el nombre del fichero.// Mas adelante se tomara de la linea de ordenes.

ObtenerNombreFichero (nombre);

// Obtener los parametros asociados al fichero.// En una version futura el calculo es automatico

ObtenerDatos (nombre, N, J, d );

// Mostrar (en "cout") los parametros asociados al fichero.

MostrarDatos (nombre, N, J, d );

Page 78: Metodología de la Programación

FuncionesEjemplo: Prototipos → 143

// Crear y rellenar la ED "prot" a partir// del fichero de prototipos.

prot = RellenaPrototipos (nombre, N, d);

// Mostrar los datos leidos y guardados en "prot"

PintaPrototipos (prot, N, d);

// Calcular y mostrar las medias (por clase)

medias = CreaYCalculaMedias (J, d, N, prot);PintaMedias (J, d, medias);

// Liberar la memoria ocupada

LiberaPrototipos (prot, N);LiberaMedias (medias, J, d);

return (0);}

FuncionesEjemplo: Prototipos → 144

demo_prots

prots.h

demo_prots.o

prots.oprots.cpp

demo_prots.cpp

Makefile

SOURCE = sourceBIN = binINCLUDE = includeOBJ = obj

all : prots.o demo_prots.o demo_prots

prots.o : $(SOURCE)/prots.cpp $(INCLUDE)/prots.hg++ -c -o $(OBJ)/prots.o -I$(INCLUDE) $(SOURCE)/prots.cpp

demo_prots.o : $(SOURCE)/demo_prots.cpp $(INCLUDE)/prots.hg++ -c -o $(OBJ)/demo_prots.o -I$(INCLUDE) \$(SOURCE)/demo_prots.cpp

demo_prots : $(OBJ)/demo_prots.o $(OBJ)/prots.og++ -o $(BIN)/demo_prots $(OBJ)/demo_prots.o \$(OBJ)/prots.o

Page 79: Metodología de la Programación

FuncionesEjemplo: Prototipos → 145

Pruebas

� Suposición básica:

El fichero de prototipos es correcto.

� Pruebas sobre los valores de entrada:

1. Es un fichero de prototipos (.prot)

Proporcionar nombres sin extensión .prot

2. Existe el fichero de prototipos

Probar nombres de ficheros que no existen.

3. Son coherentes los valores de N , J y d con el contenido delfichero

Nota: N , J y d se calcularán automáticamente ⇒ estaprueba no se realizará.

� Pruebas de cálculo.

1. Prueba de valores extremos:

Media de una clase que tiene un único prototipo.

Resultados de las pruebas.

1. Sobre el nombre del fichero de prototipos.

ObtenerNombreFichero() no comprueba nada: acepta cualquiernombre.

2. Sobre la existencia del fichero de prototipos.

No se realiza ninguna comprobación de la existencia del fichero.RellenaPrototipos() abre un fichero que no existe e intenta leer deél: errores.

Puede hacerse en la función ObtenerNombreFichero(), una vez que

FuncionesEjemplo: Prototipos → 146

se ha validado el nombre proporcionado.

3. Prueba de cálculo.

No se detectó ningún problema.

Conclusiones.

1. Validar el nombre en ObtenerNombreFichero().

2. Comprobar la existencia del fichero en ObtenerNombreFichero().

3. Escribir un módulo específico para comprobar la existencia de unfichero:

bool ExisteFichero (string & nbre);

Comprueba la existencia del fichero llamado nombre y sudisponibilidad para ser abierto para lectura.

Este módulo puede ser privado para prots.cpp

Codificación (2)

prots.h

¡¡No hay cambios!!

.

prots.cpp

Añadir, a la lista de funciones privadas:

bool ExisteFichero (string & nbre);

Sustituir el módulo ObtenerNombreFichero():

Page 80: Metodología de la Programación

FuncionesEjemplo: Prototipos → 147

void ObtenerNombreFichero (string & nbre){

int pos; // Posicion de ".prot" en "nbre"

cout << endl << "Nombre del fichero de prototipos: ";cin >> nbre;cout << endl;

// Filtro de entrada para admitir unicamente// nombres terminados en ".prot"

pos = nbre.find (".prot");if ((pos < 0) || ((pos + 5) != nbre.length())) {

cerr << "Error: Nombre de fichero incorrecto ";cerr << "(debe tener extension .prot)" << endl;cerr << endl;exit (1);

}// Comprobar la existencia del fichero.if (!ExisteFichero (nbre)) {

cerr << "Error: El fichero " << nbre;cerr << " no puede abrirse." << endl << endl;exit (1);

}}

Añadir, al final del fichero, la definición de ExisteFichero ():

bool ExisteFichero (string &nombre){

ifstream fichero;

FuncionesEjemplo: Prototipos → 148

bool problema;

fichero.open (nombre.c_str());

problema = fichero.fail();

if (!problema) fichero.close();

return ((problema) ? false : true);}

.

demo_prots.cpp

No hay cambios!!

.

Page 81: Metodología de la Programación

Tema III

Clases

Objetivos:

� Profundizar en el concepto de clase, reforzando el concepto de en-capsulamiento.

� Reforzar la necesidad de crear métodos constructor y destructorde una clase.

� Reforzar la metodología de contrucción del constructor de copia.

� Introducir y desarrollar la sobrecarga de los operadores más usua-les ( =, [], «, », + ), en ejemplos concretos.

� Conocer el concepto de objeto y miembro const.

� Conocer y presentar un ejemplo de miembros static.

Para cualquier sugerencia, aportación o notificación de erratas en estas transparen-

cias, por favor, enviar un e-mail a Francisco J. Cortijo

[email protected]

ClasesIntroducción → 150

III.1. Introducción

Las clases permiten la construcción de tipos definidos por el usuario,extendiendo el conjunto de tipos elementales.

En un lenguaje orientado a objetos, éstos son el centro del lenguaje:

Los objetos contienen datos y funciones(métodos) que permiten manipular esos datos.

Una clase encapsula:

� Datos (los datos miembro o campos).

– Todos los objetos que pertenecen a una misma clase contienendichos datos, aunque con diferentes valores.

– Determinan el estado o propiedades de cada objeto.

� Funciones que los manipulan (las funciones miembro o métodos).

– Todos los objetos que pertenecen a la misma clase compartenestas funciones (no son propias o particulares de cada objeto).

– Determinan el comportamiento de los objetos de la clase.

Una instancia de una clase es un objeto. Un objeto es, a una clase, lo queuna variable a un tipo.

class MiClase{// Declaracion de datos miembro// Declaracion de metodos

};MiClase objeto1, objeto2; // dos objetos de clase "MiClase"

Page 82: Metodología de la Programación

ClasesIntroducción → 151

Cada objeto tendrá sus propios datos miembros(excepto si se declaran static) y sólo existe una

copia de los métodos aplicable a todos los objetosde la clase.

Ocultación de información: En la declaración de una clase, y para cadamiembro (campo o método), debe especificarse el ámbito desde el cualse puede acceder a dicho miembro. Esto permite proteger los datos demodificaciones indeseadas. Para este fín se usan los modificadores deacceso:

� private

Sólo se permite el acceso desde los métodos de la clase.Es el valor por defecto.

� public

Los miembros públicos son visibles dentro y fuera del ob-jeto, donde las reglas de ámbito lo permitan.

En los métodos de la clase basta con escribir su nombre.En otras funciones y métodos hay que especificar el nom-bre del objeto, un punto, y el nombre del miembro.

� protected

Se permite su uso en los métodos de la clase y en los delas clases derivadas mediante herencia.

Nota: En esta asignatura no se trabajará con este tipo deacceso, ya que no se estudia con detalle el mecanismo deherencia.

ClasesIntroducción → 152

El encapsulamiento y ocultación de información permite:

� Que los usuarios no puedan hacer mal uso de los datos propiosde un objeto, proporcionando la integridad de los datos, por tantopromoviendo un software más robusto.

� Separación efectiva representación-implementación. Ocultar la im-plementación de las funciones, propiciando disponer de los dere-chos propios en la elaboración de software, y lo que es más impor-tante, poder modificar la implementación sin que afecte al usuario.

Es habitual que las clases ofrezcan un conjunto defunciones públicas a través de las cuales se puede

actuar sobre los datos miembro (privados).Estas funciones forman la interfaz de la clase.

Otra ventaja del uso de las clases es la posibilidad de utilizar ciertos ope-radores “tradicionales” (+, - +=, =, , =, ...) mediante la sobrecarga de losmismos (sección III.9)

Page 83: Metodología de la Programación

ClasesIntroducción → 153

Declaración de datos miembro:

class Polinomio {private:

float * Coef;int Grado;int MaxGrado;

// Metodos...

};

En una declaración no se asignan valores a los campos:no hay reserva de memoria. Esta tarea se reserva a los métodosconstructores (sección III.2).

Declaración de métodos.

� Como cualquier función en C++.

� Se trata de especificar los prototipos de los métodos de la clase.En algunos casos, incluso su definición (funciones inline, sec-ción III.7).

class Polinomio {// Campos......public:

void PonCoeficiente (int i, float c);int LeeGrado (void) const;float LeeCoeficiente (int i) const;float Evalua (float x) const;void PintaPolinomio (const char * const msg) const;

}

ClasesIntroducción → 154

� Un método const impide la modificación de los datos miembro delobjeto al que se aplican.

int LeeGrado (void) const;float LeeCoeficiente (int i) const;float Evalua (float x) const;void PintaPolinomio (const char * const msg) const;

� Es usual disponer de funciones miembro públicas que modifican(funciones “set”) y/o leen (funciones “get”) el valor de los datosprivados.

void PonCoeficiente (int i, float c);int LeeGrado (void) const;float LeeCoeficiente (int i) const;

� Pueden encontrase métodos públicos que realicen ciertos cálculossobre el objeto.

float Evalua (float x) const;

� También es común encontrar métodos públicos para leer desde undispositivo de entrada un objeto y para mostrar en un dispositivode salida un objeto.

void PintaPolinomio (const char * const msg) const;

Estas tareas suelen hacerse sobrecargando los operadores >> y <<(sección III.9.5).

� Es normal proporcionar “métodos especiales”: constructores (sec-ción III.2) y en el caso en el que haya reserva de memoria dinámica,aparecerá el destructor (sección III.4).

� Finalmente, pueden definirse funciones privadas, que serán habi-tualmente funciones de utilidad (auxiliares) para los métodos pú-blicos.

Page 84: Metodología de la Programación

ClasesIntroducción → 155

Toda clase dispone por defecto de un constructor sin argumentos, de unconstructor de copia, de un destructor y de un operador de asignación:

#include <iostream>using namespace std;

class Test {}; // Una clase minimalistaTest global; // Constructor de oficio

void funcion (void){

cout << "Ejecutando: funcion\n";

Test local_f; // Actua el constructor de oficio

cout << "Saliendo de: funcion\n";} // Destructor de oficio

int main (void){

cout << "Ejecutando : main\n";

Test local_main_1, local_main_2; // Constructor de oficio

funcion ();

local_main_2 = local_main_1; // Operador de asignacion de oficio

cout << "Saliendo de: main\n";return (0);

} // Destructor de oficio

ClasesConstructores → 156

III.2. Constructores

� Cuando se crea un objeto de una clase siempre se llama automáti-camente a un constructor.

Polinomio pol1;Polinomio * pol2 = new Polinomio;

� Se emplean para iniciar los objetos de una clase.

Polinomio pol3 (15); // Establece MaxGrado=15

� Es particularmente útil para reservar memoria, si es necesario, pa-ra ciertos campos del objeto. Su liberación se realiza, en ese caso,con el destructor.

Cuando el constructor se encarga de pedirmemoria dinámicamente, debe implementarse el

operador de asignación

� Pueden existir varios constructores para una clase. Este es unbuen ejemplo de sobrecarga.

� Sintácticamente, un constructor tiene el mismo nombre que la cla-se en la que está declarado y no devuelve nada.

CUIDADO: Un constructor no es una función void.

� Se declara(n) en la sección public.

¿Qué ocurre si en una clase no se define ningún constructor?

El compilador crea un constructor de oficio, sin argumentos, que nohace nada, simplemente permite crear objetos de la clase.

Page 85: Metodología de la Programación

ClasesConstructores → 157

En cualquier caso, nuestro consejo es:

Siempre debería implementarse, al menos, elconstructor básico (sin parámetros) equivalente alconstructor por defecto, pero con la diferencia que

ahora el programador pueda controlar ypersonalizar la creación e iniciación del objeto.

#include <string>#include <iostream>using namespace std;

class Test{

private:string msg;

public:Test (void) // Constructor basico{

msg = "VACIO";cout << " Constructor 1 de Test " << "--> " << msg << "\n";

}Test (string cad) // Constructor con parametros{

msg = cad;cout << " Constructor 2 de Test " << "--> " << msg << "\n";

}};Test global ("global"); // Objeto global

ClasesConstructores → 158

void funcion (void){

cout << "Ejecutando : funcion\n";Test local_f ("local a funcion()");cout << "Saliendo de: funcion\n";

}

int main(void){

cout << "Ejecutando : main\n";Test local_m ("local a main()");

funcion ();

local_m = global; // operador de asignacionTest local_vacia;

cout << "Saliendo de: main\n";return (0);

}

Su ejecución produce:

Constructor 2 de Test --> globalEjecutando : main

Constructor 2 de Test --> local a main()Ejecutando : funcion

Constructor 2 de Test --> local a funcion()Saliendo de: funcion

Constructor 1 de Test --> VACIOSaliendo de: main

Page 86: Metodología de la Programación

ClasesConstructores → 159

En el caso de la clase Polinomio proponemos inicialmente dos construc-tores sencillos:

class Polinomio{

private:float * Coef;int Grado;int MaxGrado;

public:

// Constructor sin parametrosPolinomio (void){

MaxGrado = 10; // valor "por defecto" para el grado maximoGrado = 0;Coef = new float [MaxGrado+1];for (int i=0; i<= MaxGrado; i++)

Coef[i] = 0.0;}

// Constructor con parametrosPolinomio (int grado){

MaxGrado = grado;Grado = 0;Coef = new float [MaxGrado+1];for (int i=0; i<= MaxGrado; i++)

Coef[i] = 0.0;}

};

ClasesModularización → 160

Recomendación: Iniciar los datos miembro en la sección de iniciación delconstructor.

// Constructor sin parametros (alternativa)Polinomio (void) : MaxGrado(10), Grado(0){

Coef = new float [MaxGrado+1];for (int i=0; i<= MaxGrado; i++) Coef[i] = 0.0;

}// Constructor con parametros (alternativa)Polinomio (int grado) : MaxGrado(grado), Grado(0){

Coef = new float [MaxGrado+1];for (int i=0; i<= MaxGrado; i++) Coef[i] = 0.0;

}

III.3. Modularización

En todos los ejemplos mostrados hasta ahora la definición de los méto-dos se hace al mismo tiempo que la declaración de la misma.

Diferenciar declaración - definición.

En un primer paso (no definitivo, pero útil en casos simples):

� la declaración de la clase (incluye los prototipos de los métodos) yla implementación de éstos pueden escribirse en el mismo fichero.

� en la definición de los métodos debe aclararse explícitamente queson métodos de una clase y debe hacerse con el operador :: yaque su declaración está oculta dentro de la declaración de la clase.

Page 87: Metodología de la Programación

ClasesModularización → 161

#include <string>#include <iostream>using namespace std;

// declaracion de la clase Test con los prototipos de los metodosclass Test{

private:string msg;

public:Test (void); // Constructor basicoTest (string cad); // Constructor con parametros

};

// definicion de un constructor de la clase TestTest :: Test (void) {

msg = "VACIO";cout << " Constructor 1 de Test " << "--> " << msg << "\n";

}

// definicion de un constructor de la clase TestTest :: Test (string cad){

msg = cad;cout << " Constructor 2 de Test " << "--> " << msg << "\n";

}

Test global ("global"); // Objeto global

// ...... El resto es igual

Podemos seguir avanzando en la modularización, siguiendo en la mismalínea en la que venimos trabajando. La estrategia a seguir será:

ClasesModularización → 162

� Escribir la declaración de la clase en un fichero .h: contendrá ladeclaración de campos y métodos (sus prototipos).

� Escribir la implementación de los métodos en un fichero .cpp: con-tendrá el código que se ejecutará cuando se llame a los métodosde la clase. Se empleará el operador ::

Test.h

#ifndef TEST#define TEST

#include <string>using namespace std;

class Test{private:

string msg;

public:Test (void); // Constructor basicoTest (string cad); // Constructor con parametros

};#endif

Page 88: Metodología de la Programación

ClasesModularización → 163

Test.cpp

#include <string>#include <iostream>#include "Test.h"using namespace std;

Test :: Test (void) {msg = "VACIO";cout << " Constructor 1 de Test " << "--> " << msg << "\n";

}

Test :: Test (string cad){msg = cad;cout << " Constructor 2 de Test " << "--> " << msg << "\n";

}

DemoTest.cpp

#include <iostream>#include "Test.h"using namespace std;

Test global ("global"); // Objeto global

void funcion (void){cout << "Ejecutando : funcion\n";

Test local_f ("local a funcion()");

cout << "Saliendo de: funcion\n";}

ClasesModularización → 164

int main(void){

cout << "Ejecutando : main\n";

Test local_m ("local a main()");

funcion ();

local_m = global;Test local_vacia;

cout << "Saliendo de: main\n";return (0);

}

Page 89: Metodología de la Programación

ClasesModularización → 165

Ejemplo: Polinomio (1)

Presentamos una aplicación que usa el tipo de dato Polinomio, imple-mentado mediante una clase. La declaración de la clase se ofrece enPolinomio.h y su definición en Polinomio.cpp.

DemoPolinomio.cpp

#include <iostream>#include <iomanip>#include "Polinomio.h"using namespace std;

int main (void){

cout.setf (ios::showpoint);cout.setf (ios::fixed);

Polinomio p1;p1.PintaPolinomio("p1 inic-def");p1.PonCoeficiente(2, 3.0); // 3.0 X^2p1.PintaPolinomio("p1 con coef 2=3.0");

ClasesModularización → 166

p1.PonCoeficiente(4,-10.5); // 3.0 X^2 - 10.5 X^4p1.PintaPolinomio("p1 con coef 2=3.0, 4=-10.5");

cout << "p1(1) = " << setw(6) << setprecision(2)<< p1.Evalua(1) << endl << endl;

Polinomio p2 (5);p2.PintaPolinomio("p2 inic-MaxGrado=5");

return (0);}

El resultado de la ejecución de este código será:

p1 inic-defMaxGrado = 10 Grado = 0

p1 con coef 2=3.0MaxGrado = 10 Grado = 2

3.00 X^2

p1 con coef 2=3.0, 4=-10.5MaxGrado = 10 Grado = 4

3.00 X^2 -10.50 X^4

p1(1) = -7.50

p2 inic-MaxGrado=5MaxGrado = 5 Grado = 0

Page 90: Metodología de la Programación

ClasesModularización → 167

Polinomio.h

#ifndef POLINOMIO#define POLINOMIO

class Polinomio{

private:float * Coef;int Grado;int MaxGrado;

public:Polinomio (int GradoMaximo = 10); // Constructor unificado

// Otros metodosvoid PonCoeficiente (int i, float c);int LeeGrado (void) const;float LeeCoeficiente (int i) const;

float Evalua (float x) const;void PintaPolinomio (const char * const msg) const;void PonCero (void);

};

#endif

ClasesModularización → 168

Polinomio.cpp

#include <iostream>#include <iomanip>#include <cmath>#include "Polinomio.h"using namespace std;

// Constructor unificadoPolinomio :: Polinomio (int GradoMaximo): MaxGrado(GradoMaximo),Grado(0){

Coef = new float [MaxGrado+1];for (int i=0; i<= MaxGrado; i++)

Coef[i] = 0.0;}

// Devuelve el grado del polinomioint Polinomio :: LeeGrado (void) const{

return (Grado);}

// Establece el valor del coeficiente de grado ivoid Polinomio :: PonCoeficiente (int i, float valor){

if ((i<0) || (i>MaxGrado)) {cerr << "\nError: grado incorrecto\n\n";exit (1);

}Coef[i] = valor;if (i > Grado) Grado = i;

}

Page 91: Metodología de la Programación

ClasesModularización → 169

// Devuelve el valor del coeficiente de grado ifloat Polinomio :: LeeCoeficiente (int i) const{

if ((i<0) || (i>MaxGrado)) {cerr << "\nError: grado incorrecto\n\n";exit (1);

}else

return (Coef[i]);}

// Evalua el polinomio en el valor xfloat Polinomio :: Evalua (float x) const{

float res=0.0;

for (int i=1; i<=Grado; i++)if (Coef[i]!=0) res += (Coef[i] * pow(x,i));

return (res);}

// Metodo que pone a cero todos los coeficientesvoid Polinomio :: PonCero (void){

for (int i=0; i<=Grado; i++)Coef[i] = 0.0;

}

ClasesModularización → 170

// Muestra en cout un polinomiovoid Polinomio::PintaPolinomio (const char * const msg) const{

cout.setf (ios::showpoint);cout.setf (ios::fixed);cout.setf (ios::right);

// cabecera

cout << msg << endl;cout << " MaxGrado = " << setw(2) << MaxGrado;cout << " Grado = " << setw(2) << Grado << endl;cout << " ";

// termino independiente (grado 0)

if (Coef[0]!=0)cout << setw(6) << setprecision(2) << Coef[0] << " ";

// restantes terminos (grado 1,2,...)

for (int i=1; i<=Grado; i++)

if (Coef[i]!=0)cout << setw(6) << setprecision(2) << Coef[i]

<< " X^" << i << " ";

cout << endl << endl ;}

Page 92: Metodología de la Programación

ClasesDestructor → 171

III.4. Destructor

� El destructor es un método que es llamado automáticamente cuan-do un objeto deja de existir, y se aplica sobre el objeto que va adesaparecer.

� Sólo hay un destructor para una clase.

� No hay que hacer ninguna llamada explícita al destructor.

� Sintaxis: No admite parámetros ni devuelve ningún valor. Tiene elmismo nombre que la clase, precedido por el carácter ˜

� Si no se especifica ninguno, el compilador proporciona un destruc-tor de oficio.

Su implementación tiene sentido cuando elconstructor ha reservado memoria

dinámicamente.

Ejemplo. En la clase Polinomio basta con añadir:

En Polinomio.h En Polinomio.cpp

class Polinomio{ Polinomio :: ~Polinomio (void)...... {public: delete [] Coef;

...... }// Destructor~Polinomio (void);......

};

ClasesPrioridad de ejecución → 172

III.5. Prioridad de ejecución

En cuanto a los constructores:

� Los objetos globales se crean primero, antes de la ejecución decualquier función (incluso main()).

� A continuación se ejecuta la función main() y se crean los objetoslocales a ésta.

� Cuando se llama a cualquier función y ésta empieza su ejecuciónse crean los objetos locales a ella.

En cuanto a los destructores, actúan cuando un objeto deja de existir:

� Si es una variable local: al finalizar la ejecución de la función.

� Si es una variable global: al finalizar la ejecución del programa.

Cuando la ejecución llega a la declaración de un objeto static se llamaal constructor. El destructor actúa al finalizar la ejecución del programa.

Regla: Los destructores se ejecutan en ordeninverso a la ejecución de los constructores

respectivos.

Page 93: Metodología de la Programación

ClasesPrioridad de ejecución → 173

#include <string>#include <iostream>using namespace std;

class Test{private:

string msg;

public:Test (void);Test (string cad);~Test (void);

};

Test :: Test (void){msg = "VACIO";cout << " Constructor 1 de Test " << "--> " << msg << "\n";

}

Test :: Test (string cad){msg = cad;cout << " Constructor 2 de Test " << "--> " << msg << "\n";

}

Test :: ~Test (void){cout << " Destructor de Test " << "----> " << msg << "\n";

}

Test global ("global"); // Objeto global

ClasesPrioridad de ejecución → 174

void funcion (void){

cout << "Ejecutando : funcion\n";Test local_f ("local a funcion()");cout << "Saliendo de: funcion\n";

}

int main(void){

cout << "Ejecutando : main\n";Test local_m ("local a main()");funcion ();Test local_vacia;cout << "Saliendo de: main\n";return (0);

}

Su ejecución produce este resultado:

Constructor 2 de Test --> globalEjecutando : main

Constructor 2 de Test --> local a main()Ejecutando : funcion

Constructor 2 de Test --> local a funcion()Saliendo de: funcion

Destructor de Test ----> local a funcion()Constructor 1 de Test --> VACIO

Saliendo de: mainDestructor de Test ----> VACIODestructor de Test ----> local a main()Destructor de Test ----> global

Page 94: Metodología de la Programación

ClasesEl constructor de copia → 175

III.6. El constructor de copia

C++ permite iniciar un objeto en el momento de su creación con los datosde otro objeto de la misma clase.

int orig; // iniciacion por defectoorig = 5; // asignacion ("orig" ya existe)...int copia1 (orig); // iniciacion y copiaint copia2 = orig; // iniciacion y copia (identica a la anterior)

� Aunque sintácticamente parezca una asignación (por el uso delsímbolo =) no lo es: el objeto que “recibe” el valor no existe.

� Si no se especifica un constructor de copia, el compilador propor-ciona un constructor de copia de oficio.

� El constructor de copia de oficio realiza la copia bit a bit (tambiénllamada copia superficial) de los datos miembro.

Esto es válido en algunas ocasiones.

No es válido, sin embargo, cuando el objeto requiere memoria di-námicamente (que suele ocurrir en las clases más complejas e im-portantes): se necesita implementar un constructor de copia.

class Polinomio{......public:......Polinomio (const Polinomio & otro); // Constructor de copia......

};

ClasesEl constructor de copia → 176

Notas:

� El objeto “origen” no debe modificarse, de ahí que esté etiquetadocomo const

� No se pasa realmente el objeto “origen” sino una referencia a éste:se consigue un ahorro en la ocupación de la memoria y en el tiempode ejecución.

// Constructor de copiaPolinomio::Polinomio (const Polinomio & otro) :

MaxGrado(otro.MaxGrado), Grado(otro.Grado){

// Reserva de la propia memoria para coeficientesCoef = new float [MaxGrado+1];

// Copia de los valores de los coeficientesfor (int i=0; i<= MaxGrado; i++)

Coef[i] = otro.Coef[i];}

¿ Cómo se usa?

Polinomio p1; // constructor sin argumentos

p1.PintaPolinomio("p1 inic-def");p1.PonCoeficiente(2, 3.0);p1.PintaPolinomio("p1 con coef 2=3.0");p1.PonCoeficiente(4,-10.5);p1.PintaPolinomio("p1 con coef 2=3.0, 4=-10.5");cout << "p1(1) = " << setw(6) << setprecision(2)

<< p1.Evalua(1) << endl << endl;

Page 95: Metodología de la Programación

ClasesEl constructor de copia → 177

La ejecución de este código produce este resultado:

p1 inic-defMaxGrado = 10 Grado = 0

p1 con coef 2=3.0MaxGrado = 10 Grado = 2

3.00 X^2

p1 con coef 2=3.0, 4=-10.5MaxGrado = 10 Grado = 4

3.00 X^2 -10.50 X^4

p1(1) = -7.50

Una vez creado, iniciado y procesado adecuadamente p1 hacemos actuaral constructor de copia:

......Polinomio p3 (p1); // constructor de copiap3.PintaPolinomio("p3 copia de p1");

Polinomio p4 = p1; // constructor de copiap4.PintaPolinomio("p4 copia de p1");......

Es importante comprender que p1, p3 y p4, aún siendo (lógicamente) igua-les tienen cada uno su propia zona de memoria (son físicamente diferen-tes). La ejecución de este código produce este resultado:

p3 copia de p1 p4 copia de p1MaxGrado = 10 Grado = 4 MaxGrado = 10 Grado = 4

3.00 X^2 -10.50 X^4 3.00 X^2 -10.50 X^4

ClasesEl constructor de copia → 178

¿Cuándo se usa el constructor de copia?

1. Cuando se declara un objeto y se inicia a partir de otro de la mismaclase. Este caso ya se ha tratado.

Polinomio p1;// asignar valores a p1

Polinomio p3 (p1); // constructor de copiaPolinomio p4 = p1; // constructor de copia

2. Cuando una función recibe un objeto por valor.

Cada parámetro formal es una variable local y secrea e inicia con el constructor de copia.

Por ejemplo, podemos añadir una función en Polinomio.h (fuera dela clase Polinomio) con el siguiente prototipo:

bool PolinomiosIguales (const Polinomio, const Polinomio);

implementada en Polinomio.cpp de la siguiente manera:

bool PolinomiosIguales (const Polinomio p1, const Polinomio p2){

bool iguales = (p1.LeeGrado()!=p2.LeeGrado())? false:true;

// Si los grados son diferentes no hace falta seguir,// pero si son iguales hay que comparar los coeficientes// uno a uno, hasta acabar o encontrar una discrepancia

Page 96: Metodología de la Programación

ClasesEl constructor de copia → 179

if (iguales) {

int grado = 0;bool sigo = true;

while (sigo && grado < p1.LeeGrado()) {

double coef1 = p1.LeeCoeficiente(grado);double coef2 = p2.LeeCoeficiente(grado);

if (coef1 != coef2) {iguales = false;sigo = false;

}else grado++;

} // while (sigo && grado < p1.LeeGrado())

} // if (iguales)

return iguales;}

Observando la cabecera de la función PolinomiosIguales() se veque p1 y p2 se reciben por valor. Eso significa que cuando se lla-me a la función habrán dos variables locales llamadas p1 y p2 quetomarán sus valores de los objetos de tipo Polinomio empleadoscomo parámetros reales en la llamada.

Será el constructor de copia quien cree las variables locales p1 yp2 en la pila e inicie sus campos a partir de los parámetros realesempleados en la llamada.

ClasesEl constructor de copia → 180

Por ejemplo, con este código, podemos ampliar DemoPolinomio.cpp:

......p3.PonCoeficiente(5, 8.0);p3.PintaPolinomio("p3 cambiado");

if (PolinomiosIguales (p1,p3))cout<<"p1 y p3 son iguales\n";

elsecout << "p1 y p3 NO son iguales\n";

if (PolinomiosIguales (p1,p4))cout<<"p1 y p4 son iguales\n";

elsecout << "p1 y p4 NO son iguales\n";

y la ejecución de estas nuevas líneas produce como resultado:

p3 cambiadoMaxGrado = 10 Grado = 5

3.00 X^2 -10.50 X^4 8.00 X^5

p1 y p3 NO son igualesp1 y p4 son iguales

3. Cuando una función devuelve un objeto.

El valor (el objeto) que se devuelve se creó localmente en la fun-ción. Para que pueda ser devuelto a la función que hace la llamadadebe copiarse temporalmente a un objeto.

Esta tarea la hace automáticamente el constructor de copia.

Por ejemplo, podemos añadir una función en Polinomio.h (fuera dela clase Polinomio) con el siguiente prototipo:

Page 97: Metodología de la Programación

ClasesEl constructor de copia → 181

Polinomio PolinomioUnidad (int grado);

implementada en Polinomio.cpp de la siguiente manera:

Polinomio PolinomioUnidad (int grado){

Polinomio unidad; // constructor unificado

for (int i=0; i<=grado; i++)unidad.PonCoeficiente (i, 1.0);

return (unidad); // devuelve una copia del objeto local}

Será el constructor de copia quien, antes de devolver el control ala función que hizo la llamada, copie el objeto local unidad a unavariable temporal para poder ser devuelto.

Por ejemplo, con este código, podemos ampliar DemoPolinomio.cpp:

......Polinomio p5 = PolinomioUnidad (3); // constructor de copiap5.PintaPolinomio("p5 unidad");

y la ejecución de estas nuevas líneas produce como resultado:

...p5 unidad

MaxGrado = 10 Grado = 31.00 1.00 X^1 1.00 X^2 1.00 X^3

Implementar siempre el constructor de copia.

ClasesFunciones inline en clases → 182

III.7. Funciones inline en clases

Recordemos que la etiqueta inline indica (“sugiere” o “recomienda”) alcompilador que ponga una copia del código de esa función en el lugardonde se haga una llamada en lugar de realizar la llamada.

Ventaja: Tiempo de ejecución menor.

Desventaja: Programas de mayor tamaño (varias copias del código).

class Polinomio{......public:

......// Este metodo es "inline" porque se indica asi// de manera explicita en su definicion

int LeeGrado1 (void) const;

// Este metodo es "inline" de manera implicita:// se declara y define en la misma clase

int LeeGrado2 (void) const {return (Grado);};......

};......

// Indicacion EXPLICITA del caracter inline del metodoinline int Polinomio:: LeeGrado1 (void) const{

return (Grado);}

Page 98: Metodología de la Programación

ClasesEl puntero this→ 183

Aunque no se haya indicado explícitamentte, el método LeeGrado2() esuna función inline porque se declara y define en la misma clase.

En estos casos se muestra la implementación al usuario de la clase: serompe la “ocultación de la información”.

III.8. El puntero this

El puntero this es un puntero predefinidoaccesible desde todos los métodos no estáticos

de una clase.Contiene la dirección del objeto sobre el cual seestá aplicando el método que se está ejecutando

(el objeto implícito).

� Los métodos static no tienen este puntero.

� Como this es un puntero al objeto sobre el que se está aplican-do el método en ejecución, se puede acceder a los miembros delobjeto (campos u otros métodos) mediante el operador -> usandola expresión this->miembro y se puede hacer referencia al objetocompleto mediante la expresión *this

� Sabemos que los métodos de un objeto puede usar los datosmiembro empleando solamente su nombre, y no es preciso refe-rirse de forma explícita al objeto sobre el que se aplican (éste esun argumento implícito).

� Si en una función u operador miembro queremos referirnos de ma-nera explícita al objeto sobre el cual se está aplicando podemos

ClasesEl puntero this→ 184

hacerlo empleando el puntero this. Es válido, aunque innecesarioescribir this para referirnos a los miembros de una clase.

Por ejemplo, en el método LeeGrado():

// Devuelve el grado del polinomioint Polinomio :: LeeGrado (void) const{

return (Grado);}

podemos sustituir la instrucción return (Grado) por

return (this->Grado);

� La expresión *this se usa normalmente para referirse al objeto ac-tual desde el método en ejecución.

Por ejemplo, en el método LeeGrado() podemos sustituir la instruc-ción return (Grado) por

return (*(this).Grado);

El uso habitual de la expresión *this es otro, y es el de devolver elobjeto actual desde el método en ejecución:

return (*this);

(Remitimos a la implementación del operador de asignación en lasección III.9.1 para más información)

� Una de las situaciones en las que this es imprescindible es la degarantizar evitar la autorreferencia. Por ejemplo:

if (&Object != this) { // se ejecuta cuando NO... // exista autorreferencia

}

Page 99: Metodología de la Programación

ClasesEl puntero this→ 185

La expresión &Object devuelve la dirección de memoria de Object.

– Como this es un puntero, y contiene una dirección de memo-ria, la expresión condicional &Object != this es válida y serátrue cuando Object sea un objeto diferente al objeto implícito.

– Cuando la expresión es falsa (o sea, &Object == this) el objetoimplícito (sobre el que se está ejecutando el método) y el ob-jeto recibido como argumento a través de Object son el mismoobjeto.

Remitimos a la implementación del operador de asignación en lasección III.9.1 para más información.

Nota avanzada

El puntero this no es parte del objeto (puede comprobarse con la ins-trucción sizeof(), por ejemplo).

Cuando se llama a un método no estático sobre un objeto se pasa alcompilador la dirección del objeto como un argumento oculto para elmétodo. Por ejemplo, la siguiente llamada:

MiFecha.PonMes( 3 );

puede interpretarse como

PonMes( &MiFecha, 3 );

de manera que la dirección del objeto está disponible para la funciónmiembro usando el puntero this.

ClasesSobrecarga de operadores → 186

III.9. Sobrecarga de operadores

C++ permite sobrecargar la mayoría de los operadores disponibles.

Objetivo: que el programador de una clase emplee los operadores prede-finidos de C++ más adecuados en el contexto de cada clase (por ejemplo,el operador + para la suma de polinomios, el operador >> para la lecturade polinomios, etc.).

Polinomio p1(25), p2;cin >> p1;cin >> p2;

Polinomio PolSuma = p1 + p2;cout << PolSuma;

Polinomio PolProducto = p1 * p2;Polinomio PolDoble = 2.0 * p1;

cout << PolProducto;cout << PolDoble;

Limitaciones:

1. Puede modificarse la definición de un operador pero no su gra-mática o sintaxis (esto es, número de operandos, precedencia yasociatividad).

2. Un operando, al menos, debe ser un objeto de la clase en la que sedefine el operador.

Un operador puede estar, a su vez, sobrecargado, de manera que actúesegún sea el tipo de los objetos que tiene como operandos.

Page 100: Metodología de la Programación

ClasesSobrecarga de operadores → 187

La sobrecarga de los operadores no es automática, el programador debeimplementar esta sobrecarga. Puede hacerse empleando dos estrategias:

1. Escribiendo funciones miembro de la clase.

Esta estrategia es válida para reescribir:

� Operadores unarios.

� Operadores no unarios que modifican el primer operando (p.e.,la asignación con =).

En este caso, el primer operando debe ser un objeto de la clase: elargumento implícito.

2. Funciones amigas (friend) de la clase.

Esta estrategia es válida para reescribir operadores que no puedanser reescritos con funciones miembro, en particular:

� Operadores que actúan sobre varios objetos sin modificarlos.

En cualquier caso, el número de argumentos debe ser el esperadopor el operador.

Cualquier operador se sobrecarga escribiendo la definición de una fun-ción de la manera habitual, salvo que el nombre de la función es algopeculiar: la palabra operator seguida del símbolo del operador que sesobrecarga. Por ejemplo:

operator +operator >=...

ClasesSobrecarga de operadores → 188

Operadores que pueden sobrecargarse:

+ - * / % ^ & | != < > += -= *= /= %= ^=&= |= << >> >>= <<= == != <=>= && || ++ -- ->* , -> []() new delete new[] delete[]

Operadores que no pueden sobrecargarse:

. .* :: ?: sizeof

Es un error suponer que al sobrecargar unoperador automáticamente se sobrecargan

operadores relacionados.

Por ejemplo, al sobrecargar + no se sobrecarga automáticamente +=, ni alsobrecargar == lo hace automáticamente !=.

Los operadores sólo se sobrecarganexplícitamente: no hay sobrecarga implícita.

Page 101: Metodología de la Programación

ClasesSobrecarga de operadores → Sobrecarga del operador = 189

III.9.1. Sobrecarga del operador =

� Como es conocido, el compilador proporciona de oficio el opera-dor de asignación en las clases en las que éste no se implementeexplícitamente.

� El funcionamiento del operador de asignación de oficio es el dehacer una copia superficial: se realiza una copia exacta (bit a bit)de un objeto en otro.

� Problema crítico:

Si no se ha sobrecargado este operador y el objetoasignado (parte derecha de la asignación) hareservado memoria dinámicamente, la copia

superficial hace que los dos objetos referencien ala misma zona de memoria.

(Este problema se puso de manifiesto en la presentación delconstructor de copia)

Ejemplo III.9.1. Para mostrar el efecto indeseado que produce eloperador de asignación de oficio si se usa sobre objetos que mane-jan memoria dinámica, basta con ejecutar el siguiente código queemplea la clase Polinomio

#include <iostream>#include <iomanip>#include "Polinomio.h"using namespace std;

ClasesSobrecarga de operadores → Sobrecarga del operador = 190

int main (void){

cout.setf (ios::showpoint);cout.setf (ios::fixed);

Polinomio p1; // actua el constructor

p1.PonCoeficiente(2, 3.0);p1.PonCoeficiente(3,-4.5);p1.PintaPolinomio("p1 con coef 2=3.0, 3=-4.5");

Polinomio p2; // actua el constructor

p2 = p1; // actua el operador de asignacion de oficiop2.PintaPolinomio("p2 despues de p2=p1");

p1.PonCoeficiente(2,9.9);p1.PintaPolinomio("p1 despues de p1.PonCoeficiente(2,9.9)");

p2.PintaPolinomio("p2 despues de p1.PonCoeficiente(2,9.9)");

return (0);}

Su ejecución produce el siguiente resultado:

p1 con coef 2=3.0, 3=-4.5MaxGrado = 10 Grado = 3

3.00 X^2 -4.50 X^3

p2 despues de p2=p1MaxGrado = 10 Grado = 3

3.00 X^2 -4.50 X^3

Page 102: Metodología de la Programación

ClasesSobrecarga de operadores → Sobrecarga del operador = 191

p1 despues de p1.PonCoeficiente(2,9.9)MaxGrado = 10 Grado = 3

9.9 X^2 -4.50 X^3

p2 despues de p1.PonCoeficiente(2,9.9)MaxGrado = 10 Grado = 3

9.9 X^2 -4.50 X^3

1. Observad que la última modificación que se realiza sobre p1se traduce en una modificación indeseada de p2: es un efectocolateral debido a que los objetos p1 y p2 comparten la mismazona del heap.

2. Se produce un error de ejecución al finalizar el programa yaque el destructor de p2 falla al liberar la memoria dinámica aso-ciada a ese objeto: ésta ya fue liberada con el objeto p1.

Conclusión:

Si los objetos de la clase reservan memoriadinámicamente se deberá sobrecargar el operador

de asignación.

Se trata de un operador binario en el que se modifica el primer operando:se implementa como una función miembro cuyo esquema es:

TIPO & operator = (const TIPO & origen)

Una vez implementado, la instrucción a=b; equivale a a.operator = (b);

ClasesSobrecarga de operadores → Sobrecarga del operador = 192

TIPO & operator = (const TIPO & origen)

� El primer operando es el objeto implícito: no aparece explícitamen-te en la declaración.

� El segundo operando (el origen) es el argumento explícito: se suelepasar por referencia (por economía) y const (no debería modificar-se).

� Devuelve una referencia (la del objeto que recibe la petición deasignación, el objeto implícito (*this)), lo que permitirá, por ejem-plo, encadenar asignaciones.

Ampliaremos la clase Polinomio de la siguiente manera:

En Polinomio.h:

class Polinomio{......public:......// Operador de asignacionPolinomio & operator = (const Polinomio & otro);

};

En Polinomio.cpp:

Polinomio & Polinomio :: operator = (const Polinomio & otro){

if (this != &otro) // Importantisimo: evitar autoasignacion{

MaxGrado = otro.MaxGrado; // copia del valor del objeto "otro"Grado = otro.Grado; // copia del valor del objeto "otro"

Page 103: Metodología de la Programación

ClasesSobrecarga de operadores → Sobrecarga del operador = 193

Coef = new float [MaxGrado+1]; // pide "su" memoria

for (int i=0; i<= MaxGrado; i++)Coef[i] = otro.Coef[i];

}return (*this); // devuelve el objeto implicito:

// parte izquierda de la asignación}

Cada objeto tiene su propia memoria para alojar los valores de los coefi-cientes. Esta zona de memoria es independiente de la de los otros obje-tos, por lo que no hay efectos colaterales y en consecuencia, el destruc-tor actúa correctamente.

Ahora, la ejecución del código anterior produce el siguiente -correcto-resultado:

p1 con coef 2=3.0, 3=-4.5MaxGrado = 10 Grado = 3

3.00 X^2 -4.50 X^3

p2 despues de p2=p1MaxGrado = 10 Grado = 3

3.00 X^2 -4.50 X^3

p1 despues de p1.PonCoeficiente(2,9.9)MaxGrado = 10 Grado = 3

9.9 X^2 -4.50 X^3

p2 despues de p1.PonCoeficiente(2,9.9)MaxGrado = 10 Grado = 3

3.00 X^2 -4.50 X^3

ClasesSobrecarga de operadores → Sobrecarga del operador = 194

Es más, como adelantábamos, por el hecho de devolver una referencia,pueden encadenarse varias instrucciones de asignación:

......Polinomio p3, p4;p4 = p3 = p2;

p3.PintaPolinomio("p3 despues de p4 = p3 = p2");p4.PintaPolinomio("p4 despues de p4 = p3 = p2");

y el resultado de la ejecución es:

p3 despues de p4 = p3 = p2MaxGrado = 10 Grado = 3

3.00 X^2 -4.50 X^3

p4 despues de p4 = p3 = p2MaxGrado = 10 Grado = 3

3.00 X^2 -4.50 X^3

¡¡Cuidado!!

Sabemos que a=b; equivale a a.operator = (b);

a=b=c; equivale a a = (b.operator = (c));

a=b=c; NO es (a.operator = (b)) = c;

Problema:

¿Qué ocurre si el objeto al que se asigna el nuevo valor (parte izquierdade la asignación) tiene contenido (reservó memoria dinámicamente)?

Page 104: Metodología de la Programación

ClasesSobrecarga de operadores → Sobrecarga del operador = 195

p1 y p2 antes de p1=p2

Polinomio p1, p2 (5);p1.PonCoeficiente(2, 3.0);p1.PonCoeficiente(4,-10.5);p2.PonCoeficiente(5,2.0);

p1 = p2;

p1 y p2 después de p1=p2

ClasesSobrecarga de operadores → Código reutilizable 196

¡¡Cuidado!! Se pierde la memoria que reservó el constructor de p1

Solución: Antes de la copia efectiva, liberar memoria:

Polinomio & Polinomio :: operator = (const Polinomio & otro){

if (this != &otro) // Importantisimo: evitar autoasignacion{

delete [] Coef; // Liberar memoria reservada

MaxGrado = otro.MaxGrado;Grado = otro.Grado;Coef = new float [MaxGrado+1]; // Reservar nueva memoria

for (int i=0; i<= MaxGrado; i++)Coef[i] = otro.Coef[i];

}return (*this); // devuelve el objeto implicito:

// parte izquierda de la asignación}

III.9.2. Código reutilizable

El operador = y el constructor de copia tienen prototipos parecidos (reci-ben una referencia constante a otro objeto de la clase):

Polinomio & operator = (const Polinomio & otro);Polinomio (const Polinomio & otro);

y realizan tareas parecidas sobre el objeto.

Page 105: Metodología de la Programación

ClasesSobrecarga de operadores → Código reutilizable 197

Sin embargo:

� El constructor actúa sobre un objeto que se está creando, por loque no tiene sentido comprobar si this != &otro

� El constructor es el que reserva, inicialmente, memoria: no tienesentido liberarla.

Las asignaciones que se realizan entre los datos miembros son iguales¿porqué no unificarlas?

Proponemos emplear una función auxiliar privada (solo po-drá ser usada por los métodos de la clase).

void Copia (const Polinomio & otro);

Buscando otras tareas comunes:

� La reserva de memoria la realizan todos los constructores, ademásdel operador de asignación.

� La liberación de la memoria la realizan el destructor y el operadorde asignación.

La reserva (resp. la liberación) podría llegar a ser unas tarea muy comple-ja. Repetir el código da lugar a programas difícilmente mantenibles, porlo que proponemos emplear, también, funciones auxiliares privadas:

void PideMemoria (int n);

void LiberaMemoria (void);

Actualizaremos la clase Polinomio adecuadamente para incorporar estasnuevas funciones:

ClasesSobrecarga de operadores → Código reutilizable 198

Polinomio.h .

class Polinomio{private: // Datos miembro

......public: // Constructores, destructor, etc.

......private: // NUEVO: Funciones auxiliares privadas

void Copia (const Polinomio & otro);void PideMemoria (int n);void LiberaMemoria (void);

};

Polinomio.cpp .

void Polinomio :: Copia (const Polinomio & otro){

MaxGrado = otro.MaxGrado;Grado = otro.Grado;

PideMemoria (MaxGrado+1); // Reserva con el metodo privado

for (int i=0; i<=MaxGrado; i++)Coef[i] = otro.Coef[i];

}void Polinomio :: PideMemoria (int n){

Coef = new float [n+1];}

void Polinomio :: LiberaMemoria (void){

delete [] Coef;}

.

Page 106: Metodología de la Programación

ClasesSobrecarga de operadores → Código reutilizable 199

Con esta novedad, los métodos afectados son:

� Los constructores.

� El destructor.

� El operador de asignación.

por lo que cambiaremos estos métodos por los siguientes:

// Constructor unificadoPolinomio :: Polinomio (int GradoMaximo):

MaxGrado(GradoMaximo), Grado(0){

PideMemoria (MaxGrado+1); // Reserva memoria

for (int i=0; i<= MaxGrado; i++)Coef[i] = 0.0;

}

// Constructor de copiaPolinomio :: Polinomio (const Polinomio & otro){

Copia (otro); // Copia desde el otro objeto}

// DestructorPolinomio :: ~Polinomio (void){

LiberaMemoria (); // Liberar memoria reservada}

ClasesSobrecarga de operadores → Operador [] 200

// Operador de asignacionPolinomio & Polinomio :: operator = (const Polinomio & otro){

if (this != &otro) // Importantisimo: evitar autoasignacion{

LiberaMemoria (); // Liberar memoria reservadaCopia (otro); // Copia desde el otro objeto

}

return (*this); // devuelve el objeto implicito:// parte izquierda de la asignación

}

III.9.3. Operador []

El operador [] es empleado habitualmente para acceder a elementos deuna colección en la que la posición de los elementos es importante. Dehecho, el acceso se realiza mediante un índice, un número que indica laposición del elemento.

En nuestro caso, puede emplearse este método de acceso para referirnosa los coeficientes del polinomio, considerando que los coeficientes sonlos elementos de la colección y empleando como índice el grado.

Hasta ahora, hacemos: Desde ahora, queremos:

p1.PonCoeficiente (0, 6.4); p1[0] = 6.4;

if (p1.LeeCoeficiente (i) != 0) if (p1[i] != 0)

Recordar: objeto[i] equivale a objeto.operator[](i)

Page 107: Metodología de la Programación

ClasesSobrecarga de operadores → Operador [] 201

� El operador [] es un operador binario:

– El primer operando (objeto) es el objeto de la clase y es implí-cito (no aparece con ningún nombre en la implementación delmétodo). Puede modificarse.

Consecuencia: Se implementa como una función miembro.

– El segundo operando indica la posición en la colección.

� Muy Importante: Permitimos que la expresión objeto[i] pueda em-plearse, indistintamente, en la parte derecha e izquierda de unaasignación, por lo que, necesariamente, la función que implementael operador devuelve una referencia al tipo base de la colección.

Polinomio.h .

class Polinomio{......public:

......float & operator [] (const int indice);......

};

Polinomio.cpp .

float & Polinomio :: operator [] (const int indice){

if ((indice<0) || (indice>MaxGrado)) {cerr << "\nError: grado incorrecto\n\n";exit (1);

}if (indice > Grado)

Grado = indice; // !!PROBLEMA!!return (Coef[indice]);

}.

ClasesSobrecarga de operadores → Operador [] 202

¡¡Problema!!

La instrucción problemática “parchea” algunos casos:

Polinomio p1; // p1.Grado = 0 p1[1] = 3.0; // p1.Grado = 1p1[0] = 1.0; // p1.Grado = 0 p1[4] = 4.0; // p1.Grado = 4

Sin embargo, es errónea si hacemos:

p1[6] = 0.0; // p1.Grado = 6 !!NO!!

incluso si:

cout << p1[7]; // p1.Grado = 7 !!NO!!

Conclusión: No puede mantenerse la coherencia si empleamos el datomiembro Grado y sobrecargamos el operador [].

Solución: descartar el dato miembro Grado y “sustituirlo” poruna función auxiliar privada

int Grado (void) const;

Su cometido será calcular el grado cuando sea necesario: Seleccionar laposicion mayor de entre todos los coeficientes diferentes de cero.

Es necesaria un amplia remodelación de la clase.

� El uso del operador [] hace innecesarios los métodosPonCoeficiente() y LeeCoeficiente().

� La nueva función privada Grado() hace inecesario el métodoLeeGrado().

� Los métodos PintaPolinomio(), Evalua() y PonCero() deben modi-ficarse, porque acceden al campo Grado, ahora descartado.

Page 108: Metodología de la Programación

ClasesSobrecarga de operadores → Operador [] 203

Polinomio.h

#ifndef POLINOMIO#define POLINOMIO

class Polinomio{

private:float * Coef;int MaxGrado;

public:Polinomio (int GradoMaximo = 10); // Constructor unificadoPolinomio (const Polinomio & otro); // Constructor de copia~Polinomio (void); // Destructor

Polinomio & operator = (const Polinomio & otro); // Op.de asignacionfloat & operator [] (const int indice); // Operador []

float Evalua (float x) const;void PintaPolinomio (const char * const msg) const;void PonCero (void);

private:// Funciones auxiliares privadasint Grado (void) const;void Copia (const Polinomio & otro);void PideMemoria (int n);void LiberaMemoria (void);

};#endif

ClasesSobrecarga de operadores → Operador [] 204

Polinomio.cpp

#include <iostream>#include <iomanip>#include <cmath>

#include "Polinomio.h"

using namespace std;

// Constructor unificadoPolinomio :: Polinomio (int GradoMaximo): MaxGrado(GradoMaximo){

PideMemoria (MaxGrado+1); // Reserva memoria

for (int i=0; i<= MaxGrado; i++)Coef[i] = 0.0;

}

// Constructor de copiaPolinomio :: Polinomio (const Polinomio & otro){

Copia (otro); // Copia desde el otro objeto}

// DestructorPolinomio :: ~Polinomio (void){

LiberaMemoria (); // Liberar memoria reservada}

Page 109: Metodología de la Programación

ClasesSobrecarga de operadores → Operador [] 205

// Operador de asignacionPolinomio & Polinomio :: operator = (const Polinomio & otro){

if (this != &otro) // Importantisimo: evitar autoasignacion{

LiberaMemoria (); // Liberar memoria reservadaCopia (otro); // Copia desde el otro objeto

}return (*this); // devuelve el objeto implicito:

// parte izquierda de la asignación}

// Operador []float & Polinomio :: operator [] (const int indice){

if ((indice<0) || (indice>MaxGrado)) {cerr << "\nError: grado incorrecto\n\n";exit (1);

}return (Coef[indice]);

}

// Evalua el polinomio en el valor xfloat Polinomio :: Evalua (float x) const{

float res=0.0;int grado = Grado();

for (int i=1; i<=grado; i++)if (Coef[i]!=0) res += (Coef[i]*pow(x,i));

return (res);}

ClasesSobrecarga de operadores → Operador [] 206

// Muestra en cout un polinomiovoid Polinomio::PintaPolinomio (const char * const msg) const{

cout.setf (ios::showpoint);cout.setf (ios::fixed);cout.setf (ios::right);

int grado = Grado();

cout << msg << endl;cout << " MaxGrado = " << setw(2) << MaxGrado;cout << " Grado = " << setw(2) << grado << endl;cout << " ";

if (Coef[0]!=0)cout << setw(6) << setprecision(2) << Coef[0] << " ";

for (int i=1; i<=grado; i++)if (Coef[i]!=0)

cout <<setw(6) << setprecision(2)<< Coef[i] << " X^" << i << " ";

cout << endl << endl ;}

// Metodo que pone a cero todos los coeficientesvoid Polinomio :: PonCero (void){

int grado = Grado();for (int i=0; i<=grado; i++)

Coef[i] = 0.0;}

Page 110: Metodología de la Programación

ClasesSobrecarga de operadores → Operador [] 207

// Funcion auxiliar: copia los campos privados// (incluyendo los datos guardados en la memoria dinamica)void Polinomio :: Copia (const Polinomio & otro){

MaxGrado = otro.MaxGrado;

PideMemoria (MaxGrado+1);for (int i=0; i<=MaxGrado; i++)

Coef[i] = otro.Coef[i];}

// Funcion auxiliar: reserva la memoria dinamica necesariavoid Polinomio :: PideMemoria (int n){

Coef = new float [n+1];}

// Funcion auxiliar: libera la memoria dinamicavoid Polinomio :: LiberaMemoria (void){

delete [] Coef;}

// Funcion auxiliar: calcula el grado del polinomioint Polinomio :: Grado (void) const{

int i;bool sigo = true;for (i=MaxGrado; (i>=0) && sigo; i--)

if (Coef[i] != 0.0) sigo = false;return (i+1);

}

ClasesSobrecarga de operadores → Operadores aritméticos 208

III.9.4. Operadores aritméticos

El objetivo es emplear los operadores aritméticos (+, -, etc.) para sumar,restar, etc. datos de tipo Polinomio.

Operador +

Deseamos escribir:

Polinomio p1, p2,p3;......p3 = p1 + p2;

en lugar de, por ejemplo, p3 = SumaPolinomios (p1, p2);

El operador + es un operador binario en el que los dos operandos debenser siempre de tipo Polinomio y donde no se modifica ningún operando:

Podría implementarse con una función friend o con unafunción miembro

El operador + se sobrecarga con este prototipo:

Polinomio operator + (const Polinomio & otro);

declarándose como un método público de la clase Polinomio.

Las dos expresiones son equivalentes:

p3 = p1 + p2; p3 = p1.operator + (p2);

aunque la primera es más natural y directa.

Page 111: Metodología de la Programación

ClasesSobrecarga de operadores → Operadores aritméticos 209

En Polinomio.cpp añadiremos:

// Operador +Polinomio Polinomio::operator + (const Polinomio & otro){

int maxgr1 = MaxGrado;int maxgr2 = otro.MaxGrado;int MayorMaxGrado = (maxgr1 > maxgr2) ? maxgr1 : maxgr2;

Polinomio tmp (MayorMaxGrado);

int gr1 = Grado();int gr2 = otro.Grado();int MenorGrado = (gr1 > gr2) ? gr2 : gr1;

// sumar los coeficientes de los monomios de grado comunfor(int i=0; i<= MenorGrado; i++) // sumar coeficientes

tmp.Coef[i] = Coef[i] + otro.Coef[i];

if (gr1 > gr2) // copiar los coeficientes de "*this"

for(int i=MenorGrado+1; i<=gr1; i++)tmp.Coef[i] = Coef[i];

else // copiar los coeficientes de "otro"

for(int i=MenorGrado+1; i<=gr2; i++)tmp.Coef[i] = otro.Coef[i];

return (tmp);}

ClasesSobrecarga de operadores → Operadores aritméticos 210

Observad que en esta implementación actúan:

1. El constructor que recibe un argumento, cuando se crea tmp y seinicia con el mayor grado de los dos polinomios que se suman.

2. El constructor de copia, antes de devolver el polinomio resultantede la suma.

Operador *

El operador * puede sobrecargarse para implementar el producto de dospolinomios.

Podremos emplear un método, como hicimos con el operador +:

El operador * se sobrecarga con este prototipo:

Polinomio operator * (const Polinomio & otro);

declarándose como un método público de la clase Polinomio.

Las dos expresiones son equivalentes:

p3 = p1 * p2; p3 = p1.operator * (p2);

aunque la primera es más natural y directa.

Page 112: Metodología de la Programación

ClasesSobrecarga de operadores → Operadores aritméticos 211

En Polinomio.cpp añadiremos:

// Operador *Polinomio Polinomio::operator * (const Polinomio & otro){

int maxgr1 = MaxGrado;int maxgr2 = otro.MaxGrado;int MayorMaxGrado = (maxgr1 > maxgr2) ? maxgr1 : maxgr2;

Polinomio tmp (MayorMaxGrado);

for (int g1=0; g1 <= MaxGrado; g1++)for (int g2=0; g2 <= otro.MaxGrado; g2++)

tmp.Coef[g1+g2] += Coef[g1]*otro.Coef[g2];

return (tmp);}

Si se desea permitir, además, la multiplicación de un polinomio por undato float, por ejemplo:

Polinomio p3 = p1 * 2.0;

que equivale a:

Polinomio p3 = p1.operator * (2.0);

y no se proporciona otra implementación, pueden producirse efectosinesperados (por conversión implícita) aunque no se producen erroresde compilación. El resultado dependerá del compilador.

ClasesSobrecarga de operadores → Operadores aritméticos 212

La siguiente instrucción, en cambio, si provoca errores de compilación:

Polinomio p4 = 2.0 * p1;

¿Por qué?

La multiplicación de un polinomio por un escalar es una operación fre-cuente, y no queremos restringir el orden en el que se escriben estosoperadores. Queremos que el operador * se permita en estos casos:

1. p = p1 * p2;

2. p = p1 * 2.0;

3. p = 2.0 * p1;

pero el caso 3 no puede implementarse con una función miembro (el pri-mer argumento, el implícito, no es un objeto de la clase) por lo que seemplea una función friend:

Una función friend de una clase puede acceder ala parte privada de esa clase, aunque no sea una

función miembro de la clase.

Un operador para el que no pueda asegurarse que el primer argumentosea siempre un objeto de la clase no se implementará como una funciónmiembro.

En el caso de un operador en el que algunaversión deba implementarse con una función

friend se recomienda sobrecargar el operador confunciones friend, con tantas versiones como

casos se permitan.

Page 113: Metodología de la Programación

ClasesSobrecarga de operadores → Operadores aritméticos 213

Polinomio.h

class Polinomio {public:

......// Tres sobrecargas para el operador *friend Polinomio operator * (const Polinomio & p1,

const Polinomio & p2);friend Polinomio operator * (const Polinomio & p, const float c);friend Polinomio operator * (const float c, const Polinomio & p);......

};

Polinomio.cpp

Esta función sustituye al anterior método.

// Operador * para multiplicar dos polinomios (funcion friend)Polinomio operator * (const Polinomio & p1, const Polinomio & p2){

int maxgr1 = p1.MaxGrado;int maxgr2 = p2.MaxGrado;int MayorMaxGrado = (maxgr1 > maxgr2) ? maxgr1 : maxgr2;

Polinomio tmp (MayorMaxGrado);

for (int g1=0; g1 <= maxgr1; g1++)for (int g2=0; g2 <= maxgr2; g2++)

tmp.Coef[g1+g2] += p1.Coef[g1]*p2.Coef[g2];

return (tmp);}

ClasesSobrecarga de operadores → Operadores aritméticos 214

� La etiqueta friend se especifica únicamente en la declaración.

� Las funciones friend no son miembros de la clase, de ahí que nose defina así:

Polinomio Polinomio :: operator * (const Polinomio & p1,const Polinomio & p2)

{...

}

Añadiremos dos nuevas funciones que nos permitan realizar el productode un polinomio por un escalar:

// Operador * (cte * polinomio)Polinomio operator * (const float c, const Polinomio & p){

Polinomio tmp (p.MaxGrado);

for (int i=0; i<= tmp.MaxGrado; i++)tmp.Coef[i] = c * p.Coef[i];

return (tmp);}

// Operador * (polinomio * cte)Polinomio operator * (const Polinomio & p, const float c){

return (c * p);}

Page 114: Metodología de la Programación

ClasesSobrecarga de operadores → Operadores aritméticos 215

DemoPolinomio.cpp

#include <iostream>#include <iomanip>#include "Polinomio.h"using namespace std;

int main (void){

cout.setf (ios::showpoint);cout.setf (ios::fixed);

Polinomio p1 (25);p1.PintaPolinomio("p1 creado");

Polinomio p2;p2.PintaPolinomio("p2 creado");

Polinomio p3 = p1 + p2;p3.PintaPolinomio("p3 despues de p3 = p1 + p2");

// p1(X) = 1.0 + 5.0 X + 3.0 X^2p1[0] = 1.0;p1[1] = 5.0;p1[2] = 3.0;p1.PintaPolinomio("p1 inicial");

// p2(X) = 2.0 + 2.0 X + 4.0 X^4p2[0] = 2.0;p2[1] = 2.0;p2[4] = 4.0;p2.PintaPolinomio("p2 inicial");

ClasesSobrecarga de operadores → Operadores aritméticos 216

p3 = p1 + p2;p3.PintaPolinomio("p3 despues de p3 = p1 + p2");

Polinomio p4 = p1 * p2;p4.PintaPolinomio("p4 despues de p4 = p1 * p2");

Polinomio p5 = p1 * 2.0;p5.PintaPolinomio("p5 despues de p5 = p1 * 2.0");

Polinomio p6 = 2.0 * p1;p6.PintaPolinomio("p6 despues de p6 = 2.0 * p1");

return (0);}

Su ejecución produce el siguiente resultado:

p1 creadoMaxGrado = 25 Grado = 0

p2 creadoMaxGrado = 10 Grado = 0

p3 despues de p3 = p1 + p2MaxGrado = 25 Grado = 0

p1 inicialMaxGrado = 25 Grado = 2

1.00 5.00 X^1 3.00 X^2

Page 115: Metodología de la Programación

ClasesSobrecarga de operadores → Operadores de inserción y extraccción sobre flujos 217

p2 inicialMaxGrado = 10 Grado = 4

2.00 2.00 X^1 4.00 X^4

p3 despues de p3 = p1 + p2MaxGrado = 25 Grado = 4

3.00 7.00 X^1 3.00 X^2 4.00 X^4

p4 despues de p4 = p1 * p2MaxGrado = 25 Grado = 6

2.00 12.00 X^1 16.00 X^2 6.00 X^3 4.00 X^420.00 X^5 12.00 X^6

p5 despues de p5 = p1 * 2.0MaxGrado = 25 Grado = 2

2.00 10.00 X^1 6.00 X^2

p6 despues de p5 = 2.0 * p1MaxGrado = 25 Grado = 2

2.00 10.00 X^1 6.00 X^2

III.9.5. Operadores de inserción y extraccción so-bre flujos

El objetivo es emplear los operadores << y >> de manera que puedainsertarse en el flujo cout un objeto de tipo Polinomio y puedan tomarsede cin los coeficientes de un polinomio para ser asignados a un objetode tipo Polinomio.

ClasesSobrecarga de operadores → Operadores de inserción y extraccción sobre flujos 218

Por ejemplo:

Polinomio p1;......cin >> p1; // "lectura" de un polinomio......cout << p1; // "escritura" de un polinomio

La orden cout << p1 equivale a cout.operator << (p1).

La orden cin >> p1 equivale a cin.operator >> (p1).

1. La implementación de estos operadores en el contexto de cout ocin involucra el uso de las clases ostream e istream.

Ambas están declaradas en el fichero de cabecera iostream, don-de los operadores << y >> están sobrecargados para los tiposbásicos y para la clase string.

2. En ambas intervienen dos operandos: el primero es un argumentoimplícito y el segundo es el objeto de la clase.

3. El argumento implícito no puede modificarse.

� para << es de tipo ostream & (en este caso, cout) e indica elflujo de salida en el que se va a insertar el objeto.

� para >> es de tipo istream & (en este caso, cin) e indica elflujo de entrada del que se va a extraer el objeto.

4. El segundo argumento (el explícito) es el objeto de la clase. Pue-de pasarse por valor o referencia, aunque se prefiere hacerlo porreferencia (Polinomio &) por economía.

5. Las dos devuelven una referencia al argumento implícito. Esto per-mite que puedan encadenarse varias instrucciones de inserción /extracción.

Page 116: Metodología de la Programación

ClasesSobrecarga de operadores → Operadores de inserción y extraccción sobre flujos 219

Estos operadores no pueden ser funciones miembro de la clase en la quese declaran ya que el primer operando (el implícito) no es un objeto de laclase:

Estamos sobrecargando operadores de las clases ostream eistream y no podemos añadir funciones miembro a éstas.

Se declararán como funciones friend si necesitan acceder a la parte pri-vada de la clase Polinomio.

Polinomio.h

Debemos incluir el fichero de cabecera iostream para indicarle al compi-lador dónde encontrar las declaraciones de las clases ostream e istream.

Como vamos a acceder a la parte privada de la clase Polinomio declara-mos las sobrecargas como funciones friend:

......#include <iostream>using namespace std;......class Polinomio{......public:

......// Sobregargas de << y >>friend ostream & operator << (ostream &, const Polinomio &);friend istream & operator >> (istream &, Polinomio &);......

};

ClasesSobrecarga de operadores → Operadores de inserción y extraccción sobre flujos 220

Polinomio.cpp

// Operador >>ostream & operator << (ostream & out, const Polinomio & p){

out.setf (ios::showpoint);out.setf (ios::fixed);out.setf (ios::right);

int grado = p.Grado();

// Cabeceraout << "---------------------------------\n";out << " MaxGrado = " << setw(2) << p.MaxGrado;out << " Grado = " << setw(2) << grado << endl;out << " ";

if (p.Coef[0]!=0) // termino independienteout << setw(6) << setprecision(2) << p.Coef[0] << " ";

for (int i=1; i<=grado; i++) // resto de terminos

if (p.Coef[i]!=0)out <<setw(6)<< setprecision(2)

<< p.Coef[i] << " X^" << i << " ";

out << "\n---------------------------------\n\n";

return (out); // devuelve la referencia al objeto ostream}

Page 117: Metodología de la Programación

ClasesSobrecarga de operadores → Operadores de inserción y extraccción sobre flujos 221

// Operador >>istream & operator >> (istream & in, Polinomio & p){

int ValGrado;float ValCoef;bool sigo = true;

while (sigo) {

// Leer grado (Max = "p.MaxGrado", -1 para terminar)in >> ValGrado;

if (ValGrado < 0) sigo = false;else {

// Leer coeficiente de grado "ValGrado"in >> ValCoef;

p[ValGrado] = ValCoef;}

}return (in); // devuelve la referencia al objeto istream

}

En el último ejemplo podemos sustituir la instruccion:

p6.PintaPolinomio("p6 despues de p6 = 2.0 * p1");

por:

cout << "p6 despues de p6 = 2.0 * p1\n" << p6;

ClasesSobrecarga de operadores → Operadores de inserción y extraccción sobre flujos 222

que produce como resultado:

p6 despues de p6 = 2.0 * p1---------------------------------

MaxGrado = 25 Grado = 22.00 10.00 X^1 6.00 X^2

---------------------------------

Respecto a la lectura, podemos añadir la siguientes instrucciones:

......Polinomio p7;cin >> p7;cout << "p7 leido\n" << p7;

y después de su ejecución podríamos obtener como resultado:

222.25-5.501-1

p7 leido---------------------------------

MaxGrado = 10 Grado = 51.00 22.20 X^2 -5.50 X^5

---------------------------------

Page 118: Metodología de la Programación

ClasesObjetos y miembros const→ 223

III.10. Objetos y miembros const

Parámetros formales: ¿por valor o por referencia? Consideraremos:

1. El tamaño.

En objetos o tipos no elementales debería hacerse por referencia.

2. ¿Puede modificarse el argumento?

Si no queremos modificarlo debemos indicar que se trata de un ob-jeto constante (const), tanto en el prototipo como en la definición.

Al declarar un objeto const no hay posibilidad de modificarlo: se produceun error en tiempo de compilación si intentaramos modificarlos.

Iniciación de miembros const.

Los datos miembro const y las referencias sedeben iniciar mediante un constructor con la lista

de iniciación.

Iniciación incorrecta:

int VarGlobal = 10;

class UnaClase {private:

const float C = 0.16; // ERRORint & ref = VarGlobal; // ERROR

......};

ClasesObjetos y miembros const→ 224

Debería iniciarse mediante un constructor:

int VarGlobal = 10;

class UnaClase {private:

const float C;int & ref;

public:UnaClase (void);......

};UnaClase :: UnaClase (void) : C(0.16), ref(VarGlobal) {

......}

Es obligatoria la iniciación de un objeto de otraclase que sea miembro de la clase considerada,

usando iniciadores de miembros.

#include <iostream>using namespace std;

class Clase1 {private:

int Campo1Clase1;int Campo2Clase1;

public:Clase1 (int v1=0, int v2=0);friend ostream & operator << (ostream &, const Clase1 &);

};

Page 119: Metodología de la Programación

ClasesObjetos y miembros const→ 225

class Clase2{

private:Clase1 Campo1Clase2;int Campo2Clase2;

public:Clase2 (int v1=0, int v2=0, int v3=0);friend ostream & operator << (ostream &, const Clase2 &);

};

Clase1 :: Clase1 (int v1, int v2){

Campo1Clase1 = v1;Campo2Clase1 = v2;

}

Clase2 :: Clase2 (int v1, int v2, int v3): Campo1Clase2 (v1, v2){

Campo2Clase2 = v3;}

ostream & operator << (ostream & out,const Clase2 & o){

out <<"---------------------------------\n";out <<"Campo1Clase2: "<< o.Campo1Clase2<< endl;out <<"Campo2Clase2: "<< o.Campo2Clase2<< endl;out <<"---------------------------------\n\n";

return (out);}

ClasesObjetos y miembros const→ 226

ostream & operator << (ostream & out,const Clase1 & o){

out <<"\n ..............................\n";out <<" Campo1Clase1: "<< o.Campo1Clase1<< endl;out <<" Campo2Clase1: "<< o.Campo2Clase1<< endl;out <<" ..............................\n";

return (out);}

int main(void){

Clase2 obj(1,2,3), obj2(55), obj3;

cout << "obj: \n" << obj << "\n\n";cout << "obj2: \n" << obj2 << "\n\n";cout << "obj3: \n" << obj3 << "\n\n";

return (0);}

Page 120: Metodología de la Programación

ClasesObjetos y miembros const→ 227

La ejecución produce este resultado:

obj:---------------------------------Campo1Clase2:

..............................Campo1Clase1: 1Campo2Clase1: 2..............................

Campo2Clase2: 3---------------------------------obj2:---------------------------------Campo1Clase2:

...................Campo1Clase1: 55Campo2Clase1: 0...................

Campo2Clase2: 0---------------------------------obj3:---------------------------------Campo1Clase2:

...................Campo1Clase1: 0Campo2Clase1: 0...................

Campo2Clase2: 0---------------------------------

ClasesObjetos y miembros const→ 228

Funciones const y no const

Si no deseamos que una función miembro pueda modificar el valor de losdatos debe expresarse como const, tanto en la declaración:

class Polinomio{......float Evalua (float x) const;......

}

como en la definición:

float Polinomio :: Evalua (float x) const{......

}

Las funciones declaradas const pueden acceder a los miembros const.

Es un error que una función miembro const llamea otra función miembro no const.

Una función se puede sobrecargar como const y no const, de forma queel compilador eligirá la correcta en función de que el objeto en cuestiónsea const o no.

Objetos const.

Un objeto constante es un objeto que no puede modificarse, por lo quecualquier intento de modificación es un error sintáctico.

Page 121: Metodología de la Programación

ClasesMiembros static→ 229

No se puede llamar desde objetos constantes, afunciones no constantes: el compilador

deshabilita, para los objetos const, el acceso a lasfunciones miembro no const.

Aunque un constructor no es una función const, sí se puede utilizar parainiciar un objeto const.

const Polinomio PolConst(5);

Incluso es posible que el constructor tenga que realizar una llamada aotra función que no sea const, pero en el momento que se crea el objetoya se atendrá a las normas de los objetos constantes, hasta que se activeel destructor (que tampoco es const).

III.11. Miembros static

¿Pueden existir algunos datos miembro de una clase que sean comunesa todos los objetos de la clase?

Sí: miembros static.

� No se necesita una copia para cada objeto.

� Los miembros static existen aunque no existan objetos de la clase(reserva en la declaración).

� Pueden ser públicos o privados.

� Los datos miembro static no se inician en la declaración de la cla-se, sino en el fichero de definición de la clase (.cpp).

No debe especificarse el modificador static.

Sólo pueden iniciarse una sola vez.

ClasesMiembros static→ 230

TIPO Clase::MiembroStatic = ValorInicial;

Caso típico de uso de datos static: contabilizar el número de objetos quehay creados.

Libros.h

#ifndef LIBROS#define LIBROS

#include <string>

using namespace std;

class Libro {

private:string Titulo;int NumPags;static int NumLibros;

public:Libro (void);Libro (string, int);~Libro (void);Libro & operator = (const Libro & otro);void Pinta (void);static int CuantosLibros (void);

};#endif

Page 122: Metodología de la Programación

ClasesMiembros static→ 231

Acceso:

� Miembros static públicos:

– Cuando no existen objetos de la clase:

Clase::MiembroPublicoStatic

– Si existen objetos de la clase se accede de la manera habitual,aunque puede accederse como antes (aconsejable).

� Miembros static privados: a través de funciones públicas staticde la clase. Acceso habitual.

� Los datos static tienen características de datos globales pero sualcance es el ámbito de la clase.

Libros.cpp

#include <iostream>#include "Libros.h"using namespace std;

int Libro::NumLibros = 0; // Iniciacion

Libro :: Libro (string titulo, int num) {Titulo = titulo;NumPags = num;NumLibros++;

}

Libro :: Libro (void) {Titulo = "";NumPags = 0;

}

ClasesMiembros static→ 232

Libro & Libro :: operator = (const Libro & otro){if (this != &otro){

this->Titulo = otro.Titulo;this->NumPags = otro.NumPags;NumLibros++;

}}Libro :: ~Libro (void){

NumLibros--;}void Libro :: Pinta (void){

cout << Titulo << " " << NumPags << endl;}int Libro :: CuantosLibros (void){

return (NumLibros);}

Funciones static:

� Son funciones genéricas: no actan sobre ningún objeto concreto.

� Si una función sólo accede a datos miembro static puede decla-rarse static.

Se invoca con el operador . (si existe algn objeto de la clase) o conel operador :: (si no existen).

� El modificador static sólo aparece en la declaración de la función,no en la definición.

� No pueden hacer llamadas a funciones no static, ni a datos miem-bro no static.

� No pueden utilizar el puntero this ya que éste hace referencia alobjeto concreto de la clase sobre la que se está trabajando.

Page 123: Metodología de la Programación

ClasesMiembros static→ 233

DemoLibros.cpp

#include <iostream>#include "Libros.h"using namespace std;

int main (void){

const int MAX = 10;Libro Coleccion[MAX];string titulo;int num;

cout << "Libros al empezar = " << Libro::CuantosLibros() <<"\n\n";cout << "Introduzca datos (* en Titulo para terminar)\n\n";

bool sigo = true;

while (sigo){

int pos = Libro::CuantosLibros();

cout << "Libro " << pos+1 << endl << " Titulo: ";cin >> titulo;

sigo = (titulo != "*") ? true : false;

if (sigo){cout << " Paginas: ";cin >> num;Coleccion[pos] = Libro (titulo, num);

}

ClasesMiembros static→ 234

if (pos+1 == MAX){sigo = false;cout << "\nCUIDADO: Coleccion llena.\n\n";

}}int TotalLibros = Libro::CuantosLibros();cout << "Libros al terminar = " << TotalLibros << endl << endl;

for (int pos=0; pos<TotalLibros; pos++)Coleccion[pos].Pinta();

return (0);}

Un ejemplo de ejecución:

Libros al empezar = 0Introduzca datos (* en Titulo para terminar)

Libro 1Titulo: PrimeroPaginas: 100

Libro 2Titulo: OtroPaginas: 200

Libro 3Titulo: *

Libros al terminar = 2

Primero 100Otro 200

Page 124: Metodología de la Programación

Tema IV

Gestión de E/S. Ficheros

Objetivos:

� Conocer el concepto de flujo como el mecanismo abstracto de co-municación entre la memoria y los dispositivos.

� Conocer cómo se realiza la E/S con buffer.

� Conocer cómo personalizar la manera de realizar E/S.

� Ser capaz de crear, leer, escribir y actualizar archivos.

� Saber cómo realizar E/S sin formato.

Para cualquier sugerencia, aportación o notificación de erratas en estas transparen-

cias, por favor, enviar un e-mail a Francisco J. Cortijo

[email protected]

Gestión de E/S. FicherosFlujos de E/S → 236

IV.1. Flujos de E/S

� La E/S se produce en forma de flujos.

� Flujo: Una secuencia de bytes.

– En una operación de entrada, los bytes fluyen de un dispositivo(teclado, unidad de disco,. . . ) hacia la memoria.

– En una operación de salida, los bytes fluyen de la memoriahacia un dispositivo (terminal, unidad de disco, impresora, . . . ).

� La aplicación es quien da significado al contenido (bytes) del flujo:éstos pueden representar caracteres, datos “binarios” (según surepresentación interna), imágenes, sonidos, video,. . .

� Un flujo proporciona un canal de comunicación entre:

1. Memoria y dispositivos de E/S.

2. Memoria y ficheros.

IV.1.1. La biblioteca iostream

� Flujos por defecto.

Al empezar la ejecución de un programa en C++ se dispone de tresflujos (si se incluye iostream.h):

– cin. Entrada estándar (asociado por defecto al teclado). Objetode la clase istream

– cout. Salida estándar (asociado por defecto a la consola). Ob-jeto de la clase ostream

– cerr. Salida de errores estándar (asociado por defecto a la con-sola). Objeto de la clase ostream. No usa buffer.

Page 125: Metodología de la Programación

Gestión de E/S. FicherosFlujos de E/S → La biblioteca iostream 237

� Ficheros de cabecera para E/S.

– iostream. Operaciones básicas de E/S y declaración de los ob-jetos cin, cout y cerr.

– iomanip. Para E/S con formato (personalizar la E/S).

– fstream. Para E/S con ficheros.

� Clases y objetos de E/S.

ifstream

ios

iostream

fstream

istream ostream

ofstream

Clases:

– ostream: Operaciones de salida.

cout y cerr son objetos de esta clase.

– istream. Operaciones de entrada.

cin es un objeto de la clase istream.

– iostream. Operaciones de E/S.

– ifstream. Operaciones de E desde un fichero.

– ofstream. Operaciones de S hacia un fichero.

– fstream. Operaciones de E/S con ficheros.

Gestión de E/S. FicherosFlujos de E/S → Flujos de Salida 238

IV.1.2. Flujos de Salida

� Clase ostream.

� Facilidades para:

– Salida de datos de tipos estándar con el operador(sobrecargado) <<

– Salida de caracteres con put()

– Salida sin formato con write().

– Salida de enteros en dec., octal y hex.

– Salida de números reales con diversas precisiones, con puntosdecimales o en notación científica.

– Salidas con campos de anchuras prefijadas y posibilidad derellenar los "huecos” con caracteres.

. . . . . . . . .

IV.1.2.1. El operador <<

� Se evalúa de izquierda a derecha.

� Puede recibir como argumento alguno de los tipos para los que es-tá sobrecargado, devuelve una referencia a un objeto de la claseostream, que convierte los valores de los tipos recibidos en carac-teres y los envía a la salida.

� Está sobrecargado para:

– Tipos estándar (tipos predefinidos de C++: int, float, . . . ).

– Cadenas (literales) de caracteres.

– Punteros.

Page 126: Metodología de la Programación

Gestión de E/S. FicherosFlujos de E/S → Flujos de Salida 239

Ejemplo que demuestra la sobrecarga de <<

// Fichero: demo_cout.cpp

#include <iostream>using namespace std;

int main (){

int n = 5;float r = 7.33;char *cad = "Hola";int *pi = &n;float *pf = &r;

cout << "Literal de cadena" << endl;cout << n << endl;cout << r << endl;cout << *pi << " " << pi << endl;cout << *pf << " " << pf << endl;cout << cad << " " << static_cast<void *>(cad)<<endl;return (0);

}

% demo_coutLiteral de cadena57.335 0xbffff8347.33 0xbffff830Hola 0x8048908

Gestión de E/S. FicherosFlujos de E/S → Flujos de Salida 240

IV.1.2.2. Función put()

ostream & put (char c);

La función put() recibe un argumento de tipo carácter y lo pone en elflujo de salida sobre el que se aplica. Devuelve una referencia a ostream.

// Fichero: demo_put.cpp

#include <iostream>using namespace std;

int main (){

char c1=’H’, c2=’o’, c3=’l’, c4=’a’;cout << c1 << c2 << c3 << c4 << endl;cout.put (c1);cout.put (c2);cout.put (c3);cout.put (c4);cout.put (’\n’);cout.put(c1).put(c2).put(c3).put(c4).put(’\n’);return (0);

}

% demo_putHolaHolaHola

Page 127: Metodología de la Programación

Gestión de E/S. FicherosFlujos de E/S → Flujos de Entrada 241

IV.1.3. Flujos de Entrada

� Clase istream.

� Facilidades para:

– Lectura de datos de tipos estándar con el operador(sobrecargado) >>

– Entrada de caracteres con get()

– Entrada de líneas con getline()

– Entrada sin formato con read().

– Consultar el fin de fichero con eof().

. . . . . . . . .

IV.1.3.1. El operador >>

� Se evalúa de izquierda a derecha.

� Forma "palabras” extrayendo caracteres del flujo: considera quelos espacios son separadores.

� Si encuentra el carácter fin de fichero (EOF) devuelve 0. Si no, con-vierte la "palabra” al tipo adecuado y lo almacena en memoria, de-volviendo una referencia a un objeto de la clase istream.

// Fichero: demo_cin.cpp#include <iostream>using namespace std;int main (){

int n1, n2;

Gestión de E/S. FicherosFlujos de E/S → Flujos de Entrada 242

cout << "\nIntroducir los valores de dos enteros: ";cin >> n1 >> n2;cout << " La suma es: " << (n1 + n2) << endl;cout << " " << n1 << ((n1 == n2)? " es" : " no es");cout << " igual a " << n2 << endl;return (0);

}

Ejemplo que demuestra la sobrecarga de <<

// Fichero: demo_cin2.cpp#include <iostream>using namespace std;int main (){

int n;float r;char cad[50];

cout << "\nIntroducir valores para: \n";cout << " Entero: ";cin >> n;cout << " Real: ";cin >> r;cout << " Cadena: ";cin >> cad;cout << "\nValores leidos: \n";cout << " Entero: " << n << endl;cout << " Real: " << r << endl;cout << " Cadena: " << cad << endl << endl;return (0);

}

Page 128: Metodología de la Programación

Gestión de E/S. FicherosFlujos de E/S → Flujos de Entrada 243

% demo_cin2Introducir valores para:

Entero: 5Real: 7.33Cadena: Una cadena

Valores leidos:Entero: 5Real: 7.33Cadena: Una

IV.1.3.2. La función eof()

bool eof ()

Es una función miembro de la clase ios. Devuelve true si enel flujo se encuentra el fin de fichero.

El carácter EOF puede introducirse en cin pulsando Ctrl+D (Linux) oCtrl+Z (MS-DOS).

// Fichero: suma_int.cpp#include <iostream>using namespace std;

int main (){

int n, cont=0, sum=0;

cout << "\n(Suma acumulada = " << sum << "). ";cout << "Introducir entero n. " << cont+1 << " : ";cin >> n;

Gestión de E/S. FicherosFlujos de E/S → Flujos de Entrada 244

while (!cin.eof()){sum += n;cont++;cout << "(Suma acumulada = " << sum << "). ";cout << "Introducir entero n. "<< cont+1 << " : ";cin >> n;

}

cout << "\n\nLa suma total de los " << cont;cout << " enteros introducidos es " << sum;cout << endl;return (0);

}

% suma_int(Suma acumulada = 0). Introducir entero n. 1 : 1(Suma acumulada = 1). Introducir entero n. 2 : 2(Suma acumulada = 3). Introducir entero n. 3 : 3(Suma acumulada = 6). Introducir entero n. 4 : (CTRL+D)

La suma total de los 3 enteros introducidos es 6

Page 129: Metodología de la Programación

Gestión de E/S. FicherosFlujos de E/S → Flujos de Entrada 245

El operador >> devuelve 0 cuando encuentra el fin de fichero en el flujode entrada sobre el que se aplica.

// Fichero: suma_int2.cpp#include <iostream>using namespace std;

int main (){

int n;int cont=0, sum=0;

cout << "\n(Suma acumulada = " << sum << "). ";cout << "Introducir entero n. " << cont+1 << " : ";

while ((cin >> n) != 0) { // while (cin >> n)sum += n;cont++;cout << "(Suma acumulada = " << sum << "). ";cout << "Introducir entero n. " << cont+1 << " : ";

}

cout << "\n\nLa suma total de los " << cont;cout << " enteros introducidos es " << sum;cout << endl;

return (0);}

% suma_int2(Suma acumulada = 0). Introducir entero n. 1 : 1(Suma acumulada = 1). Introducir entero n. 2 : 2(Suma acumulada = 3). Introducir entero n. 3 : 3(Suma acumulada = 6). Introducir entero n. 4 : (CTRL+D)

La suma total de los 3 enteros introducidos es 6

Gestión de E/S. FicherosFlujos de E/S → Flujos de Entrada 246

IV.1.3.3. Funciones get() y getline()

� Función get() sin argumentos.

int get ()

Lee un carácter desde el flujo, devolviendo el carácter en-contrado. Si encuentra el carácter fin de fichero devuelveEOF.

// Fichero: eco.cpp#include <iostream>using namespace std;

int main (){

char c;

while ((c = cin.get()) != EOF)cout.put (c);

return (0);}

% ecoEsto es una prueba de entradaEsto es una prueba de entradacon la funcion get (CTRL+D)con la funcion get

Page 130: Metodología de la Programación

Gestión de E/S. FicherosFlujos de E/S → Flujos de Entrada 247

� Función get() con un argumento.

istream & get (char & c)

Lee un carácter desde el flujo y lo guarda en la variable querecibe como argumento. Devuelve 0 si encuentra el carác-ter fin de fichero. En otro caso, devuelve una referencia alobjeto de la clase istream con el que se llamó.

// Fichero: demo_get.cpp#include <iostream>using namespace std;

int main (){

char c1, c2, c3;char c4, c5, c6;

cout << "Introduce una palabra que tenga ";cout << "6 o mas caracteres: ";

cin.get (c1);cin.get (c2);cin.get (c3);

cin.get(c4).get(c5).get (c6);

cout << "\nLos tres primeros: ";cout.put(c1).put(c2).put(c3).put(’\n’);cout << "Los tres siguientes: ";cout.put(c4).put(c5).put(c6).put(’\n’);return (0);

}

Gestión de E/S. FicherosFlujos de E/S → Flujos de Entrada 248

% demo_getIntroduce una palabra que tenga 6 o mas caracteres:estereotipo

Los tres primeros: estLos tres siguientes: ere

� Lectura de cadenas: Función get() con dos/tres argumentos y fun-ción getline().

– El operador >> está sobrecargado para poder leer una palabra.

– get() con dos o tres parámetros:

istream & get (char *p,int n,char del=’\n’);

Lee, como mucho, n-1 caracteres desde el flujo de entrada.Termina antes si encuentra del (por defecto, ’\n’).

No inserta del. En su lugar, inserta ’\0’

⇒ del permanece en el flujo.

// Fichero: demo_get_cadenas.cpp

#include <iostream>using namespace std;int main (){

const int TAM = 80;char cad1[TAM], cad2[TAM];

cout << endl;cout << "Introducir una cadena: ";cin.get (cad1, TAM);

Page 131: Metodología de la Programación

Gestión de E/S. FicherosFlujos de E/S → Flujos de Entrada 249

cout << "Introducir otra cadena: ";cin.get (cad2, TAM);

cout << endl;cout << "\nPrimera cadena : " << cad1;cout << "\nSegunda cadena : " << cad2;cout << endl;return (0);

}

% demo_get_cadenasIntroducir una cadena: esta es la primeraIntroducir otra cadena:

Primera cadena : esta es la primeraSegunda cadena :%

– Función ignore()

istream & ignore (int n=1, char del=EOF);

Descarta, como mucho, n caracteres del flujo de entra-da (por defecto, 1). Termina antes si encuentra del, quetambién lo descarta (por defecto, EOF).

................cout << "Introducir una cadena: ";cin.get (cad1, TAM);

cin.ignore(TAM, ’\n’); // Elimina ’\n’ de cin

cout << "Introducir otra cadena: ";................

Gestión de E/S. FicherosFlujos de E/S → Flujos de Entrada 250

// Fichero: lee_y_suma.cpp#include <iostream>#include <cstdlib>using namespace std;

int main (){

const int TAM = 256;const int NUM_LIN = 3;char cad[TAM];int suma, cont;

while (!cin.eof()) {for (cont=0,suma=0; cont<NUM_LIN; cont++) {

cin.get (cad, TAM, ’ ’);cin.ignore (TAM, ’ ’);suma += atoi(cad);

}if (!cin.eof()) {

cout << "Suma: " << suma << endl;cin.ignore (TAM, ’\n’);

}} // whilereturn (0);

}

% lee_y_suma1 2 3Suma = 64 5 6Suma = 15(CTRL+D)

Page 132: Metodología de la Programación

Gestión de E/S. FicherosFlujos de E/S → Flujos de Entrada 251

– Función getline()

istream & getline (char *p,int n,char del=’\n’);

Como get(), pero elimina el delimitador del flujo de en-trada.

// Fichero: demo_getline_cadenas.cpp

#include <iostream>using namespace std;

int main (){

const int TAM = 80;char cad1[TAM], cad2[TAM];

cout << endl;cout << "Introducir una cadena: ";cin.getline (cad1, TAM);

cout << "Introducir otra cadena: ";cin.getline (cad2, TAM);

cout << endl;cout << "\nPrimera cadena : " << cad1;cout << "\nSegunda cadena : " << cad2;cout << endl;

return (0);}

Gestión de E/S. FicherosFlujos de E/S → Evaluación del estado de un flujo 252

% demo_getline_cadenas

Introducir una cadena: esta es la primeraIntroducir otra cadena: y esta, la segunda

Primera cadena : esta es la primeraSegunda cadena : y esta, la segunda

Para leer cadenas se aconseja el uso de getline() frente a get().

IV.1.3.4. Funciones peek() y putback()

� peek() consulta el siguiente carácter del flujo de entrada y lo de-vuelve, pero no lo extrae de éste.

� putback() devuelve al flujo de entrada el carácter obtenido previa-mente con un get().

IV.1.4. Evaluación del estado de un flujo

� Los objetos de iostream mantienen una serie de indicadores o ban-deras que informan del estado del flujo.

� int clear() borra todos los indicadores de error que estuvieranactivados.

� Se consultan a través de las funciones miembro (booleanas):

Page 133: Metodología de la Programación

Gestión de E/S. FicherosFlujos de E/S → E/S sin formato 253

eof() Devuelve true si el objeto istream

sobre el que se aplica encuentra EOF.

bad() Devuelve true si se intenta realizar

una operación no válida.

fail() Devuelve true si bad() es true

o cuando falla una operación.

good() Devuelve true si todas las

anteriores son false

IV.1.5. E/S sin formato

istream & read (char *p, int n);

Lee del flujo de entrada n bytes y los copia en el buffer cuyadirección indica p.

int gcount ();

Devuelve el número de caracteres leidos en la última opera-ción de entrada.

ostream & write (const char *p, int n);

Escribe en el flujo de salida n bytes, que toma del buffer cuyadirección indica p.

Gestión de E/S. FicherosFlujos de E/S → E/S sin formato 254

// Fichero: tamanio.cpp

#include <iostream>using namespace std;

int main (){

const int TAM_BUFFER = 10;char buffer[TAM_BUFFER];int tam = 0;

while (cin.read(buffer, TAM_BUFFER)) {tam += TAM_BUFFER;

}tam += cin.gcount();

cout << "\nTamanio = " << tam << endl;

return (0);}

% tamanioEste.es.un.ejemplo(ENTER)para.tamanio(CTRL+D)Tamanio = 31

Page 134: Metodología de la Programación

Gestión de E/S. FicherosFlujos de E/S → E/S sin formato 255

// Fichero: copia.cpp

#include <iostream>using namespace std;

int main (){

const int TAM_BUFFER = 10;char buffer[TAM_BUFFER];

while (cin.read(buffer, TAM_BUFFER)) {cout.write(buffer, TAM_BUFFER);

}cout.write(buffer, cin.gcount());

return (0);}

% copiaEste.es.un.ejemplo(ENTER)Este.es.unde.copia.de.la(ENTER).ejemplode.copia.deentrada(ENTER).laentrad(CTRL+D)a%

Gestión de E/S. FicherosFlujos de E/S → Redirección y encauzamiento 256

IV.1.6. Redirección y encauzamiento

� Al empezar la ejecución de un programa en C++ se dispone de losflujos cin, cout y cerr siempre que se incluya iostream

� Los sistemas operativos proporcionan mecanismos para cambiarla entrada y salida estándar y encauzarla desde/a otros programas.

– Redirección de entrada: <

– Redirección de salida: >

– Encauzamiento (pipes): |

Puede redireccionarse la entrada siempre que elprograma utilice el el objeto cin, y puede

redireccionarse la salida siempre que el programautilice el objeto cout.

// Fichero: eco.cpp#include <iostream>using namespace std;

int main (){

char c;

while ((c = cin.get()) != EOF)cout.put (c);

return (0);}

Page 135: Metodología de la Programación

Gestión de E/S. FicherosFlujos de E/S → Redirección y encauzamiento 257

// Fichero: cuenta_lineas.cpp#include <iostream>using namespace std;

int main (){

char c;int contador = 0;

while ((c = cin.get()) != EOF)if (c == ’\n’) contador++;

cout << "Num. de lineas = " << contador << endl;return (0);

}

1. Redirección de salida

Esto es una\n prueba de redireccion\n

ecoPrograma:

Terminal

Esto es una prueba de redireccion%

EOF

Fichero: fichero_eco

Entrada por defecto

Salida por defecto

%eco > fichero_eco

Redir. de salida: eco > fichero_eco

Gestión de E/S. FicherosFlujos de E/S → Redirección y encauzamiento 258

% eco > fichero_ecoEsto es una (ENTER)prueba de redireccion (ENTER)(CTRL+D)

% cat fichero_ecoEsto es unaprueba de redireccion

% cuenta_lineas > fichero_cuentaEsto es una (ENTER)prueba de redireccion (ENTER)(CTRL+D)

% cat fichero_cuentaNumero de lineas = 2

2. Redirección de entrada.

Esto es una\n prueba de redireccion\n

EOF

Fichero: fichero_eco

Terminal

Numero de lineas = 2

Salida por defecto

%

%cuenta_lineas < fichero_eco

Entrada por defecto

Programa:cuenta_lineas

Redir. de entrada: cuenta_lineas < fichero_eco

% cuenta_lineas < fichero_ecoNumero de lineas = 2

Page 136: Metodología de la Programación

Gestión de E/S. FicherosFlujos de E/S → Redirección y encauzamiento 259

3. Redirección de entrada y salida.

% cuenta_lineas < fichero_eco > fichero_cuenta

Esto es una\n prueba de redireccion\n

EOF

Fichero: fichero_eco

Programa:cuenta_lineas

Terminal

Salida por defecto

%cuenta_lineas < fichero_eco > fichero_cuenta%

Fichero: fichero_cuenta

Numero de lineas = 2

EOF

Entrada por defecto

Redirección de entrada y salida:cuenta_lineas <fichero_eco >fichero_cuenta

4. Encauzamiento (pipes).

La salida de un programa se pasa directamente como la entrada deotro, sin ficheros intermedios.

% eco | cuenta_lineasEsto es una (ENTER)prueba de redireccion (ENTER)(CTRL+D)Numero de lineas = 2

Gestión de E/S. FicherosFlujos de E/S → Redirección y encauzamiento 260

Redirección y encauzamiento pueden combinarse:

% eco < fich_E | cuenta_lineas

% eco < fich_E | cuenta_lineas > fich_S

Como parece lógico, ¡No está permitido redireccionar una salida yencauzarla!

% prog1 | prog2 | prog3 | prog4

% prog1 < fich_E | prog2 | prog3 | prog4 > fich_S

Otros ejemplos

% cuenta_lineas < fichero_ecoNum. de lineas = 2

� Usando tamanio:

% tamanio < fichero_ecoTamanio = 34% cuenta_lineas < fichero_eco | tamanioTamanio = 19

� Usando copia:

% copia < fichero_ecoEsto es unaprueba de redireccion

% eco < fichero_ecoEsto es unaprueba de redireccion

Page 137: Metodología de la Programación

Gestión de E/S. FicherosFlujos de E/S → Redirección y encauzamiento 261

� eco y copia pueden emplearse para copiar ficheros:

% eco < fichero_eco > copia_fichero_eco

% copia < copia_fichero_ecoEsto es unaprueba de redireccion

% copia < fichero_eco > copia2_fichero_eco

% eco < copia2_fichero_ecoEsto es unaprueba de redireccion

% ls -l *eco*-rw-r--r-- 1 pepe ... 34 ... copia2_fichero_eco-rw-r--r-- 1 pepe ... 34 ... copia_fichero_eco-rw-r--r-- 1 pepe ... 34 ... fichero_eco

% tamanio < fichero_ecoTamanio = 34% tamanio < copia_fichero_ecoTamanio = 34% tamanio < copia2_fichero_ecoTamanio = 34

Gestión de E/S. FicherosFlujos de E/S → Personalizar las E/S 262

IV.1.7. Personalizar las E/S

� Mediante:

1. Manipuladores de flujo.

2. "Banderas” de estado del flujo.

� Recursos en iomanip.

� Manipuladores

– Un manipulador es una función a la que se llama de una ma-nera no tradicional. La función manipuladora, a su vez, llama auna función miembro.

– C++ proporciona manipuladores de flujo para realizar tareas deformato:

◦ Inserción de saltos de línea: endl.

◦ Base: setbase(), dec, oct y hex.

◦ Precisión:setprecision() y precision()

◦ Anchura: setw() y width().

◦ Relleno: setfill() y fill().

Page 138: Metodología de la Programación

Gestión de E/S. FicherosFlujos de E/S → Personalizar las E/S 263

� "Banderas” de estado del flujo.

– Todo flujo tiene unos indicadores de estado que pueden acti-varse o desactivarse (p.e. mostrar el signo o no).

– Activación:

A) cout.setf (ios::showpos);

B) cout << setiosflags (ios::showpos);

– Desactivación:

A) cout.unsetf (ios::showpos);

B) cout << resetiosflags (ios::showpos);

– Al activar una bandera se desactiva automáticamente otra queestuviera activa, si son excluyentes.

ios::fixed Escribir números reales en

notación de punto fijo.

Se descativa ios::scientific

ios::scientific Escribir números reales en

notación científica (E).

Se descativa ios::fixed

ios::showpoint Mostrar siempre el punto

decimal y los ceros a la

derecha en números reales.

ios::showpos Mostrar el signo.

Gestión de E/S. FicherosFlujos de E/S → Personalizar las E/S 264

ios::right Alineación a la derecha.

Se descativa ios::left

ios::left Alineación a la izquierda.

Se descativa ios::right

ios::showbase Al mostrar un número, poner

el prefijo 0 si se muestra oct

ó 0x si se muestra hex.

ios::uppercase Mostrar en mayúsculas 0X

y la letra E en not. científica.

ios::dec Los enteros deben tratarse

ios::oct en base decimal, octal o

ios::hex hexadecimal.

IV.1.7.1. Manipuladores. Base

// Fichero: base.cpp

#include <iostream>#include <iomanip>using namespace std;int main (){

int n;

cout << "\nIntroduzca un numero entero: ";cin >> n;

Page 139: Metodología de la Programación

Gestión de E/S. FicherosFlujos de E/S → Personalizar las E/S 265

cout << n << " en hexadecimal: " << hex << n << endl;cout << dec << n << " en octal: "<< oct << n << endl;cout << setbase(10) << n << " en dec.: "<< n << endl;

return (0);}

% baseIntroduzca un numero entero: 2626 en hexadecimal: 1a26 en octal: 3226 en dec.: 26

// Fichero: base2.cpp

#include <iostream>#include <iomanip>using namespace std;

int main (){

int n;

cout << "\nIntroduzca un numero entero: ";cin >> n;

cout << setiosflags (ios::showbase); // idem. con:// cout.setf (ios::showbase);

cout.setf (ios::uppercase); // idem. con:// cout << setiosflags (ios::uppercase);

Gestión de E/S. FicherosFlujos de E/S → Personalizar las E/S 266

cout << n << " en hexadecimal: " << hex << n << endl;cout << dec << n << " en octal: "<< oct << n << endl;cout << setbase(10) << n << " en dec.: "<< n << endl;

cout.unsetf (ios::uppercase); // idem. con:// cout << resetiosflags (ios::uppercase);

cout << "Recuerde que " << dec << n<< " en hexadecimal es " << hex << n << endl;

return (0);}

% base2Introduzca un numero entero: 2626 en hexadecimal: 0X1A26 en octal: 03226 en dec.: 26Recuerde que 26 en hexadecimal es 0x1a

IV.1.7.2. Manipuladores. Precisión

// Fichero: precision.cpp

#include <iostream>#include <iomanip>#include <cmath>using namespace std;

int main (){

const double v = 2.0;double r = sqrt(v);

Page 140: Metodología de la Programación

Gestión de E/S. FicherosFlujos de E/S → Personalizar las E/S 267

cout << setiosflags (ios::fixed);cout << "\nRaiz cuadrada de "<< v

<< " con precision 0-9.\n";cout << "\nPrecision con func. precision():\n";for (int dec=0; dec < 10; dec++) {

cout.precision (dec);cout << " " << dec << ": "

<< "|" << r << "|" << endl;}cout << "\nPrecision con manip. setprecision():\n";for (int dec=0; dec < 10; dec++)

cout << setprecision (dec) << " " << dec << ": "<< "|" << r << "|" << endl;

return (0);}

% precisionRaiz cuadrada de 2.000000 con precision 0-9.

Precision con func. precision():0: |1|1: |1.4|2: |1.41|3: |1.414|4: |1.4142|5: |1.41421|6: |1.414214|7: |1.4142136|8: |1.41421356|9: |1.414213562|

Gestión de E/S. FicherosFlujos de E/S → Personalizar las E/S 268

Precision con manip. setprecision():0: |1|1: |1.4|2: |1.41|3: |1.414|4: |1.4142|5: |1.41421|6: |1.414214|7: |1.4142136|8: |1.41421356|9: |1.414213562|

IV.1.7.3. Manipuladores. Ancho

// Fichero: ancho.cpp#include <iostream>#include <iomanip>#include <cmath>using namespace std;

int main (){

const double v = 2.0;double r = sqrt(v);

cout << setiosflags (ios::fixed);

cout << "\nRaiz cuadrada de " << v<< " con precision 0-9.\n";

cout << "\nPrecision con func. "<< "precision() y width():\n";

Page 141: Metodología de la Programación

Gestión de E/S. FicherosFlujos de E/S → Personalizar las E/S 269

for (int dec=0; dec < 10; dec++) {cout.width(5);cout << dec << ":" << "|" ;cout.precision (dec);cout.width(11);cout << r << "|" << endl;

}

cout << "\nPrecision con manip. setprecision() y setw():\n";

for (int dec=0; dec < 10; dec++) {cout << setw (5) << dec << ":" << "|" ;cout << setprecision (dec) << setw (11) << r << "|" << endl;

}return (0);

}

% anchoRaiz cuadrada de 2.000000 con precision 0-9.

Precision con func. precision() y width():0:| 1|1:| 1.4|2:| 1.41|3:| 1.414|4:| 1.4142|5:| 1.41421|6:| 1.414214|7:| 1.4142136|8:| 1.41421356|9:|1.414213562|

Gestión de E/S. FicherosFlujos de E/S → Personalizar las E/S 270

Precision con manip. setprecision() y setw():0:| 1|1:| 1.4|2:| 1.41|3:| 1.414|4:| 1.4142|5:| 1.41421|6:| 1.414214|7:| 1.4142136|8:| 1.41421356|9:|1.414213562|

IV.1.7.4. Manipuladores. Relleno

// Fichero: relleno.cpp#include <iostream>#include <iomanip>#include <cmath>using namespace std;

int main (){

const double v = 2.0;double r = sqrt(v);

cout << setiosflags (ios::fixed);

cout << "\nRaiz cuadrada de " << v << " con precision 0-9.\n";

cout << "\nRelleno con func. fill():\n";

Page 142: Metodología de la Programación

Gestión de E/S. FicherosFlujos de E/S → Personalizar las E/S 271

for (int dec=0; dec < 10; dec++) {cout.width(5);cout.fill (’.’);cout << dec << ":" << "|" ;cout.precision (dec);cout.width(15);cout.fill (’*’);cout << r << "|" << endl;

}cout << "\nRelleno con manip. setfill():\n";for (int dec=0; dec < 10; dec++) {

cout << setw (5) << setfill(’.’) << dec <<":"<<"|";cout << setprecision (dec) << setw (15)

<< setfill (’*’) << r << "|" << endl;}return (0);

}

% rellenoRaiz cuadrada de 2.000000 con precision 0-9.

Relleno con func. fill():....0:|**************1|....1:|************1.4|....2:|***********1.41|....3:|**********1.414|....4:|*********1.4142|....5:|********1.41421|....6:|*******1.414214|....7:|******1.4142136|....8:|*****1.41421356|....9:|****1.414213562|

Gestión de E/S. FicherosFlujos de E/S → Personalizar las E/S 272

Relleno con manip. setfill():....0:|**************1|....1:|************1.4|....2:|***********1.41|....3:|**********1.414|....4:|*********1.4142|....5:|********1.41421|....6:|*******1.414214|....7:|******1.4142136|....8:|*****1.41421356|....9:|****1.414213562|

// Fichero: relleno2.cpp

#include <iostream>#include <iomanip>using namespace std;

int main (){

const int TAM = 5;float v[TAM] = {10.5, 6.33, 334.5, 55.7643, -5.3};

cout << setiosflags (ios::fixed);cout << "\nCon funciones miembro:\n";

for (int n=0; n < TAM; n++) {cout.setf (ios::left);cout.width(3);cout.fill (’.’);cout << n << " : ";

Page 143: Metodología de la Programación

Gestión de E/S. FicherosFlujos de E/S → Personalizar las E/S 273

cout.unsetf (ios::left);cout.setf (ios::right);cout.precision (5);cout.width(15);cout.fill (’*’);cout << v[n] << endl;cout.unsetf (ios::right);

}

cout << "\nCon manipuladores:\n";

for (int n=0; n < TAM; n++) {cout << setiosflags (ios::right)

<< setw (3) << setfill(’.’) << n << " : ";cout << resetiosflags (ios::right);cout << setiosflags (ios::left) << setprecision (5)

<< setw (15) << setfill (’*’) << v[n] << endl;cout << resetiosflags (ios::left);

}return (0);

}

% relleno2Con funciones miembro:0.. : *******10.500001.. : ********6.330002.. : ******334.500003.. : *******55.764304.. : *******-5.30000

Con manipuladores:..0 : 10.50000*******..1 : 6.33000********..2 : 334.50000******..3 : 55.76430*******..4 : -5.30000*******

Gestión de E/S. FicherosFlujos de E/S → Personalizar las E/S 274

// Fichero: tabla.cpp#include <iostream>#include <iomanip>using namespace std;

int main (){

const int NUM = 34;

cout.setf (ios::uppercase);cout.setf (ios::right);

cout << setw(10) << "DEC"<< setw(5) << "OCT"<< setw (5) << "HEX"<< endl;

for (int n=0; n<NUM; n++) {cout.fill(’ ’);cout.setf (ios::dec);cout << setw (3) << n << " :";cout.unsetf (ios::dec);

cout.fill(’.’);cout << setw (5) << setiosflags (ios::dec) << n;cout.unsetf (ios::dec);

cout << setw (5) << setiosflags (ios::oct) << n;cout.unsetf (ios::oct);

cout << setw (5) << setiosflags (ios::hex) << n;cout.unsetf (ios::hex);cout << endl;

}return (0);

}

Page 144: Metodología de la Programación

Gestión de E/S. FicherosFlujos de E/S → Personalizar las E/S 275

% tablaDEC OCT HEX

0 :....0....0....01 :....1....1....12 :....2....2....23 :....3....3....34 :....4....4....45 :....5....5....56 :....6....6....67 :....7....7....78 :....8...10....89 :....9...11....9

10 :...10...12....A11 :...11...13....B12 :...12...14....C13 :...13...15....D14 :...14...16....E15 :...15...17....F16 :...16...20...1017 :...17...21...1118 :...18...22...1219 :...19...23...1321 :...21...25...1522 :...22...26...1623 :...23...27...1724 :...24...30...1825 :...25...31...1926 :...26...32...1A27 :...27...33...1B28 :...28...34...1C29 :...29...35...1D30 :...30...36...1E31 :...31...37...1F32 :...32...40...2033 :...33...41...21

Gestión de E/S. FicherosFicheros. Introducción → 276

IV.2. Ficheros. Introducción

� Motivación: Conservar datos de forma permanente: accesibles pa-ra diferentes programas y ejecuciones.

� Los datos se organizan en ficheros, que se ubican en dispositivosde almacenamiento masivo.

� C++ ve a cada fichero como una secuencia de bytes, terminadospor EOF.

EOF

0 1 2 3 4 n-4 n-3 n-2 n-1

Representación de un fichero de n bytes

� El procesamiento de ficheros tiene muchas similitudes con la ges-tión de E/S.

(Recordar la jerarquía de clases)

� Las operaciones a nivel físico las realiza el sistema operativo ⇒ elprogramador no debe preocuparse de cómo se hacen.

IV.2.1. Apertura y cierre de ficheros

� Procedimiento para utilizar un fichero en un programa en C++:

1. En primer lugar, se abre,

2. después se procesa y,

3. finalmente, cuando se haya terminado su procesamiento, secierra.

Page 145: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Apertura y cierre de ficheros 277

� Apertura de ficheros.

En realidad, la apertura consiste en asociar un flujo a un fichero:

A) Si el fichero se va a utilizar para lectura, se le asocia un flujode entrada (un objeto de la clase ifstream).

B) Si el fichero se va a utilizar para escritura, se le asocia un flujode salida (un objeto de la clase ofstream).

– Hay que incluir el fichero de cabecera fstream

Métodos open().

– Apertura de un fichero para lectura:

#include <fstream>....

ifstream fi; // Declaracion del flujo de entrada "fi"

// Asociar el flujo de entrada "fi" a "fichero_eco"

fi.open ("fichero_eco");....// Compacta: ifstream fi ("fichero_eco");

– Apertura de un fichero para escritura:

#include <fstream>....ofstream fo; // Declaracion del flujo de salida "fo"

// Asociar el flujo de salida "fo" a "copia_fichero_eco"

fo.open ("copia_fichero_eco");....// Compacta: ofstream fo ("copia_fichero_eco");

Gestión de E/S. FicherosFicheros. Introducción → Apertura y cierre de ficheros 278

� Cierre de ficheros.

En realidad, el cierre consiste en desasociar un flujo de un fichero.

Una vez cerrado el fichero, el flujo puede conectarse a otro fichero(abriéndolo convenientemente).

Métodos close().

...// Desasociar el flujo de entrada "fi" de "fichero_eco"

fi.close ();...

...// Desasociar el flujo de salida "fo" de "copia_fichero_eco"

fo.close ();...

Una vez cerrado el fichero, no se puede volver a usar a no ser quese abra de nuevo (no hay flujo de comunicación entre el fichero ymemoria).

Es importante cerrar un fichero:

1. Asegura que el archivo no quedará dañado (inconsistencia fí-sica).

2. Se libera el buffer: los datos que se escriben se copian real-mente en el disco.

3. Pone el carácter EOF en el flujo de S.

Page 146: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Apertura y cierre de ficheros 279

� Procesamiento.

Clave: Herencia

1. ifstream deriva de istream

Un objeto de clase ifstream tiene la misma funcionali-dad que otro de la clase istream, en particular, que cin.

2. ofstream deriva de ostream

Un objeto de clase ofstream tiene la misma funciona-lidad que otro de la clase ostream, en particular, quecout.

// Fichero: escribe_letra_A.cpp#include <iostream>#include <fstream>using namespace std;

int main (){

ofstream fo;

fo.open ("letra_A"); // Aperturafo << ’A’ << endl; // Procesamientofo.close(); // Cierrereturn (0);

}

% escribe_letra_A% cat letra_AA% ls -l-rw-r--r-- 1 pepe alumnos 2 Mar 15 11:15 letra_A

Gestión de E/S. FicherosFicheros. Introducción → Apertura y cierre de ficheros 280

// Fichero: demo_out.cpp#include <fstream>using namespace std;int main (){

int n = 5, *pi = &n;float r = 7.33, *pf = &r;char *cad = "Hola";

ofstream fo;

fo.open ("sal_demo_out");fo << "Literal de cadena" << endl;fo << n << endl << r << endl;fo << *pi << " "<< pi << endl << *pf << " "<< pf << endl;fo << cad << " "<< static_cast <void *> (cad)<< endl;fo.close ();

return (0);}

% demo_out% ls -l-rw-r--r-- 1 pepe alumnos 72 abr 17 10:42 sal_demo_out% cat sal_demo_outLiteral de cadena57.335 0xbffff82c7.33 0xbffff828Hola 0x8048b18

Page 147: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Apertura y cierre de ficheros 281

// Fichero: demo_in.cpp#include <fstream>#include <iostream>using namespace std;

int main (){

int n;float r;char cad[50];

ifstream fi ("ent_demo_in");fi >> n >> r >> cad;fi.close ();

cout << "\nValores leidos: \n";cout << " Entero: " << n << endl;cout << " Real: " << r << endl;cout << " Cadena: " << cad << endl << endl;return (0);

}

% cat ent_demo_in57.33Una cadena% demo_inValores leidos:

Entero: 5Real: 7.33Cadena: Una

Gestión de E/S. FicherosFicheros. Introducción → Apertura y cierre de ficheros 282

// Fichero: escribe_letra_B.cpp

#include <iostream>#include <fstream>#include <cstdlib>using namespace std;

int main (){

ofstream fo;ifstream fi;char c;

fo.open ("letra_B"); // Aperturafo << ’B’ << endl; // Procesamientofo.close(); // Cierre

fi.open ("letra_B"); // Aperturafi >> c; // Procesamientofi.close(); // Cierre

cout << "Caracter leido: " << c << endl;return (0);

}

% escribe_letra_BCaracter leido: B% cat letra_BB% ls -l-rw-r--r-- 1 pepe alumnos 2 Mar 15 12:06 letra_B

Page 148: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Apertura y cierre de ficheros 283

Comprobar el resultado de open()

� En modo E (lectura). Puede fallar si el fichero no existe o no setiene permiso para lectura.

fi.open ("letra_B"); // Aperturaif (fi.fail()) {

cerr << "Error: no pudo abrirse letra_B\n";exit (1);

}

Alternativamente:

!fi en lugar de fi.fail()

� En modo S (escritura). Puede fallar si no hay espacio disponible ono se tiene permiso para escritura.

fo.open ("letra_B"); // Aperturaif (fo.fail()) {

cerr << "Error: no pudo crearse letra_B\n";exit (1);

}

Alternativamente:

!fo en lugar de fo.fail()

Gestión de E/S. FicherosFicheros. Introducción → Apertura y cierre de ficheros 284

// Fichero: escribe_letra_A.cpp

#include <iostream>#include <fstream>#include <cstdlib>using namespace std;

int main (){

ofstream fo;

fo.open ("letra_A"); // Apertura

// Comprobar si se ha podido crear// el fichero "letra_A"

if (fo.fail()) { // Abortar la ejecucioncerr << "Error: no pudo crearse letra_A\n";exit (1);

}fo << ’A’ << endl; // Procesamientofo.close(); // Cierre

return (0);}

Page 149: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Apertura y cierre de ficheros 285

// Fichero: escribe_letra_B.cpp

#include <iostream>#include <fstream>using namespace std;int main (){

ofstream fo;ifstream fi;char c;

fo.open ("letra_B"); // Aperturaif (!fo) { // Comprobar si se ha podido crear "letra_B"

cerr << "Error: no pudo crearse letra_B\n";exit (1);

}fo << ’B’ << endl; // Procesamientofo.close(); // Cierre

fi.open ("letra_B"); // Aperturaif (!fi) { // Comprobar si se ha podido abrir "letra_B"

cerr << "Error: no pudo abrirse letra_B\n";exit (1);

}fi >> c; // Procesamientofi.close(); // Cierre

cout << "Caracter leido: " << c << endl;return (0);

}

Gestión de E/S. FicherosFicheros. Introducción → Apertura y cierre de ficheros 286

// Fichero: suma_int_file.cpp

#include <iostream>#include <iomanip>#include <fstream>using namespace std;int main (){

ifstream fi;int n, cont=0, sum=0;

fi.open ("datos");if (!fi) {

cerr << "Error: no pudo abrirse datos\n";exit (1);

}

cout<< "\n(Suma acumulada = "<<setw(5)<< sum<< "). ";while (fi >> n) {

cout <<"Valor leido num. "<<setw(3)<<cont+1<<" : "<< setw(3) << n << endl;

sum += n;cont++;cout <<"(Suma acumulada = "<<setw(5)<< sum<< "). ";

}cout << "\nLa suma total de los " << cont;cout << " enteros leidos es " << sum << endl;

fi.close();return (0);

}

Page 150: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Nombres de fichero 287

% cat datos24438% suma_int_file(Suma acumulada = 0). Valor leido num. 1 : 2(Suma acumulada = 2). Valor leido num. 2 : 44(Suma acumulada = 46). Valor leido num. 3 : 3(Suma acumulada = 49). Valor leido num. 4 : 8(Suma acumulada = 57).La suma total de los 4 enteros leidos es 57

IV.2.2. Nombres de fichero

� open() recibe como argumento un char *

� El argumento se interpreta como la dirección de memoria de unacadena clásica:

una sucesión de caracteres delimitada por el carácter nulo (’\0’)que se interpreta como el delimitador de fin de cadena.

=⇒ no es un objeto string.

� En nuestra discusión supondremos que los nombres de fichero nocontienen espacios en blanco.

� ¿Cómo tomar el nombre del fichero?

1. Lectura del nombre con el operador >>

2. Tomar el nombre de la línea de órdenes.

3. Tomar el nombre de un objeto string.

Gestión de E/S. FicherosFicheros. Introducción → Nombres de fichero 288

1. Lectura del nombre con el operador >>

......ifstream if;char nombre[255];......cout << "Nombre del fichero: \n";cin >> nombre;......if.open (nombre);......

// Fichero: type.cpp#include <iostream>#include <fstream>#include <cstdlib>using namespace std;

int main (){

ifstream f;char nombre[255];char c;

cout << "\nNombre del fichero: ";cin >> nombre;

f.open (nombre);if (!f) {

cerr << "Error: no puedo abrir " << nombre << endl;exit (1);

}

Page 151: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Nombres de fichero 289

while ((c = f.get()) != EOF) cout.put (c);f.close();return (0);

}

2. Tomar el nombre de la línea de órdenes.

// Fichero: type2.cpp#include <iostream>#include <fstream>#include <cstdlib>using namespace std;

int main (int argc, char **argv){

ifstream f;char c;

if (argc != 2) {cerr << "Error: Num. de params. erroneo\n";cerr << "Uso: "<< argv[0]<<" <fichero>\n";exit (1);

}f.open (argv[1]);if (!f) {

cerr << "Error: no puedo abrir " << argv[1] << endl;exit (1);

}while ((c = f.get()) != EOF) cout.put (c);f.close();return (0);

}

Gestión de E/S. FicherosFicheros. Introducción → Nombres de fichero 290

3. Tomar el nombre de un objeto string.

// Fichero: type3.cpp#include <fstream>#include <string>#include <cstdlib>using namespace std;

int main (int argc, char **argv){

ifstream f;string nombre;char c;

cout << "\nNombre del fichero: ";cin >> nombre;

f.open (nombre.c_str());if (!f) {

cerr << "Error: no puedo abrir " << nombre << endl;exit (1);

}while ((c = f.get()) != EOF) cout.put (c);f.close();return (0);

}

Page 152: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Nombres de fichero 291

Ejemplo

Comprobar si existe un fichero:

/*****************************************/bool ExisteFichero (const string &nombre){

ifstream fichero;bool problema;

fichero.open (nombre.c_str());problema = fichero.fail();if (!problema) fichero.close();return ((problema) ? false : true);

}

/*****************************************/

bool ExisteFichero (char *nombre){

ifstream fichero;bool problema;

fichero.open (nombre);problema = fichero.fail();if (!problema) fichero.close();return ((problema) ? false : true);

}

/*****************************************/

Gestión de E/S. FicherosFicheros. Introducción → Flujos como argumentos 292

IV.2.3. Flujos como argumentos

� Un flujo puede ser argumento de una función.

� Restricción: debe pasarse por referencia.

Ejemplo: ”Asear” un fichero

sucio.dat limpio.dat

37.10 -4.8765 +37.100003.545 -7.554 22.0 -4.87650

+3.54500-7.55400

6.77777 88.33459 +22.00000-3.2342424e2 +6.77777

+88.33459-323.42424

/***************************************************/// Fichero: asear.cpp

#include <iostream>#include <fstream>#include <iomanip>#include <cstdlib>using namespace std;

Page 153: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Flujos como argumentos 293

int main (int argc, char **argv){

ifstream fi;ofstream fo;void asear (ifstream & entrada, ofstream & salida,

int num_dec, int ancho );

if (argc != 3) {cerr << "Error: Num. de params. incorrecto\n";cerr << "Uso: "<< argv[0]<< " <fichE> <fichS>\n";exit (1);

}

fi.open (argv[1]);if (!fi) {

cerr << "Error: no puedo abrir "<<argv[1]<<endl;exit (1);

}

fo.open (argv[2]);if (!fo) {

cerr << "Error: no puedo crear "<<argv[2]<<endl;exit (1);

}asear (fi, fo, 5, 12);

fi.close();fo.close();

return (0);}

Gestión de E/S. FicherosFicheros. Introducción → Flujos como argumentos 294

/***************************************************/void asear (ifstream & entrada, ofstream & salida,

int num_dec, int ancho ){

double num;

salida.setf (ios::fixed);salida.setf (ios::showpoint);salida.setf (ios::showpos);salida.precision (num_dec);

cout.setf (ios::fixed);cout.setf (ios::showpoint);cout.setf (ios::showpos);cout.precision (num_dec);

while (entrada >> num) {cout << setw (ancho) << num << endl;salida << setw (ancho) << num << endl;

}}

Page 154: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Flujos como argumentos 295

Este programa es similar al wc de Linux.

// Fichero: cuenta_cosas.cpp

#include <fstream>#include <stdlib>#include <cctype>#include <iomanip>using namespace std;

void cuenta (ifstream & f, int &l, int& p, int& c);

/************************************************/

int main (int argc, char **argv){

ifstream fi;int nlineas, npalabras, ncaracteres;int tot_lineas,tot_palabras,tot_caracteres;int i, num_args = argc;

if (argc == 1) {cerr << "Error: Num. de params. erroneo\n";cerr << "Uso: " << argv[0]<< " <fich1> ";cerr << "[<fich2>...<fichn>]\n\n";exit (1);

}

tot_lineas = tot_palabras = tot_caracteres = 0;

Gestión de E/S. FicherosFicheros. Introducción → Flujos como argumentos 296

for (i=1; i<=num_args-1; i++) {

fi.open (argv[i]);

if (!fi) {cerr << "Error: no puedo abrir " << argv[i] << endl;

}

else {cuenta (fi, nlineas, npalabras, ncaracteres);fi.close ();

tot_caracteres += ncaracteres;tot_lineas += nlineas;tot_palabras += npalabras;

cout << setw(7) << nlineas<< setw(8) << npalabras<< setw(8) << ncaracteres<< " " << argv[i] << endl;

} // else de: if (!fi)

} //for (i=1; i<=num_args-1; i++)

if (num_args > 2)cout << setw(7) << tot_lineas

<< setw(8) << tot_palabras<< setw(8) << tot_caracteres << " total\n";

return (0);}

/************************************************/

Page 155: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Flujos como argumentos 297

void cuenta (ifstream& f, int& nl, int& np, int& nc){

bool en_palabra=true;char c;

nl = np = nc = 0;

while ((c = f.get ()) != EOF) {

nc++;

if (isspace(c)) {

if (en_palabra) {np++;en_palabra = false;

}if (c == ’\n’) nl++;

}else // no es separador

if (!en_palabra) en_palabra=true;

} // while ((c = fi.get ()) != EOF) {}

/************************************************/

Gestión de E/S. FicherosFicheros. Introducción → Flujos como argumentos 298

Ejemplo

Presentaremos dos versiones de un programa (similar al cat) que poneen cout (siempre) lo que recibe del flujo de entrada.

Versión 1:

Copia en cout:

1. Lo que recibe de cin (hace el eco de la entrada) cuando el programase llama sin argumentos.

% mi_catEsto es una prueba(ENTER)Esto es una pruebade mi_cat(ENTER)de mi_cat(CTRL+D)

2. Lo que recibe de un fichero, cuando el programa se llama con unargumento: el nombre del fichero.

% mi_cat textoEsto es una pruebade mi_cat

// Fichero: mi_cat.cpp

#include <fstream>#include <cstdlib>using namespace std;

void copiar (ostream & salida, istream & entrada);

Page 156: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Flujos como argumentos 299

int main (int argc, char **argv){

ifstream fi;

if (argc > 2) {cerr << "Error: Num. de params. erroneo\n";cerr << "Uso: "<<argv[0]<<" [<ficheroE>]\n";exit (1);

}

if (argc == 1)copiar (cout, cin);

else {fi.open (argv[1]);if (!fi) {

cerr << "Error: no puedo abrir " << argv[1] << endl;exit (1);

}copiar (cout, fi);fi.close();

}return (0);

}

/************************************************/

void copiar (ostream & salida, istream & entrada){

int c;while ((c = entrada.get()) != EOF) salida.put (c);

}/************************************************/

Gestión de E/S. FicherosFicheros. Introducción → Flujos como argumentos 300

Versión 2:

Copia en cout:

1. Como en la versión anterior, lo que recibe de cin (hace el eco de laentrada) cuando el programa se llama sin argumentos.

2. Lo que recibe de una lista (indeterminada) de ficheros, cuando elprograma se llama con al menos, un argumento: cada argumentoes el nombre de un fichero.

// Fichero: mi_cat2.cpp

#include <fstream>#include <cstdlib>using namespace std;

void copiar (ostream & salida, istream & entrada);

int main (int argc, char **argv){

ifstream fi;

if (argc == 1)copiar (cout, cin);

else {

for (int i=1; i<argc; i++) {fi.open (argv[i]);if (!fi) {

cerr << "Error: no puedo abrir " << argv[i] << endl;}copiar (cout, fi);

Page 157: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Flujos como argumentos 301

fi.close();

} // for}return (0);

}

/************************************************/

void copiar (ostream & salida, istream & entrada){

int c;

while ((c = entrada.get()) != EOF)salida.put (c);

}

/************************************************/

% mi_cat2 letra_A pp letra_BAError: no puedo abrir ppB% mi_cat2 letra_A pp letra_B > rdoError: no puedo abrir pp% mi_cat2 rdoAB

Gestión de E/S. FicherosFicheros. Introducción → Flujos como argumentos 302

IMPORTANTE:

1. Si una función toma un flujo de entrada como argumento y quere-mos que sea cin en algunos casos y un flujo asociado a un ficherode entrada en otros, se empleará un parámetro formal de tipo refe-rencia a istream.

2. Si una función toma un flujo de salida como argumento y queremosque sea cout en algunos casos y un flujo asociado a un fichero desalida en otros, se empleará un parámetro formal de tipo referenciaa ostream.

3. Si algún argumento es siempre un flujo asociado a un fichero desalida o de entrada, basta con emplear un parámetro formal de ti-poreferencia a ofstream o referencia a ifstream.

// Fichero: espaciado.cpp#include <fstream>#include <cstdlib>using namespace std;

void espaciado (ofstream & s, ifstream & e, int n);

int main (int argc, char **argv){

ifstream fi;ofstream fo;int n;

if ((argc < 3) || (argc > 4)) {cerr << "Error: Num. de params. erroneo\n";cerr << "Uso: " << argv[0]<< "<fichE> <fichS>[<lin>]\n";exit (1);

Page 158: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Flujos como argumentos 303

}if (argc == 3) // No se da valor a <lin>

n = 0; // valor por defectoelse {

n = atoi(argv[3]);if (n < 0) {

cerr << "Error: <lin> debe ser >= 0\n";exit (1);

}}

fi.open (argv[1]);if (!fi) {

cerr << "Error: no puedo abrir "<< argv[1] << endl;exit (1);

}fo.open (argv[2]);if (!fo) {

cerr << "Error: no puedo crear "<< argv[2] << endl;exit (1);

}

espaciado (fo, fi, n);

fi.close ();fo.close ();return (0);

}

/************************************************/

void espaciado (ofstream & s, ifstream & e, int n)

Gestión de E/S. FicherosFicheros. Introducción → Flujos como argumentos 304

{int c;

while ((c = e.get()) != EOF) {s.put (c);if (c == ’\n’)

for (int i=1; i<=n; i++) s.put (c);} // while

}/************************************************/

% espaciado limpio.dat limpio_def.dat% cat limpio_def.dat

+37.10000-4.87650+3.54500-7.55400

+22.00000+6.77777

+88.33459-323.42424

% espaciado limpio.dat limpio_2.dat 2% cat limpio_2.dat

+37.10000

-4.87650

+3.54500....%

Page 159: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → La función eof() 305

IV.2.4. La función eof()

� La función eof() puede aplicarse a cualquier flujo de entrada, y enparticular, a objetos ifstream.

� Utilizar eof() resulta la estrategia más adecuada para comprobar sise ha alcanzado el fin de un fichero.

� La estrategia de leer carácter a carácter y comprobar si se ha leidoel carácter EOF sólo es válida para ficheros de texto.

� eof() devuelve true cuando se intenta leer más allá del fin del fi-chero:

Debe emplearse la lectura adelantada.

Ejemplo

En los ficheros mi_cat.cpp y mi_cat2.cpp, sustituir la función copiar()por:

void copiar2 (ostream & salida, istream & entrada){

int c;

c = entrada.get(); // Lectura adelantada

while (!entrada.eof()) {salida.put (c);c = entrada.get();

}}

Gestión de E/S. FicherosFicheros. Introducción → La función eof() 306

c

0 1 2 3

EOF’a’ ’b’ ’c’’b’

c

0 1 2 3

EOF’a’ ’b’ ’c’’a’

c

0 1 2 3

EOF’a’ ’b’ ’c’?

c

0 1 2 3

EOF’a’ ’b’ ’c’’c’

FE

0 1 2 3

EOF’a’ ’b’ ’c’

0 1 2 3

EOF’a’ ’b’ ’c’

c

A B

C D

A) Contenido de prueba. B) Efecto de la apertura

C) Lectura (adelantada) del primer carácter. D) Lectura del segundo

E) Lectura del tercer carácter. F) Intento de lectura: se sobrepasa EOF

//Fichero: mi_cp.cpp

#include <fstream>#include <cstdlib>using namespace std;

void CopiaFich (ofstream & sal, ifstream & ent);

Page 160: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → La función eof() 307

int main (int argc, char **argv){

ifstream fi;ofstream fo;

if (argc != 3) {cerr << "Error: Num. de params. erroneo\n";cerr << "Uso: " << argv[0]<< " <fichE> <fichS>\n";exit (1);

}

fi.open (argv[1]);if (!fi) {

cerr << "Error: no puedo abrir "<< argv[1] << endl;

exit (1);}

fo.open (argv[2]);if (!fo) {

cerr << "Error: no puedo crear "<< argv[2] << endl;

exit (1);}

CopiaFich (fo, fi);

fi.close ();fo.close ();

return (0);}

Gestión de E/S. FicherosFicheros. Introducción → Ficheros binarios 308

/************************************************/

void CopiaFich (ofstream & sal, ifstream & ent){

int c;

c = ent.get(); // Lectura adelantada

while (!ent.eof()) {sal.put (c);c = ent.get();

}}/************************************************/

IV.2.5. Ficheros binarios

� Se considera que el fichero que se va a procesar se va a tratar anivel de bytes: no se interpreta su contenido.

� Flujo binario: consiste en una sucesión de bytes terminado por lamarca de fin de fichero. Es más general que un flujo de texto.

Ejemplo

Supongamos una aplicación que debe guardar en un fichero una serie den números enteros positivos (representados como unsigned int).

Page 161: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Ficheros binarios 309

Supongamos que n = 5 y se genera la siguiente secuencia:

12345, 34, 4567345, 8845, 98567485.

Esta serie puede almacenarse en un fichero en formato texto o binario:

1. Texto. Criterio: almacenar cada entero en una línea del fichero oseparados por un espacio o tabulador (indiferente).

a) Si suponemos que sizeof(unsigned int) es 4, el máximo ente-ro sin signo que puede utilizarse es 4294967295 (ver en climitsla definición #define UINT_MAX 4294967295).

b) Si los datos se generan de forma uniforme podemos tener va-lores desde 1 a 10 cifras, con la misma probabilidad a priori.

Cada número ocupará tanto espacio como cifras tenga, por loque el tamaño del fichero será la suma del número de total decifras de los n números y del número de separadores.

c) El tamaño del fichero será de 31 bytes:

26 cifras y 5 separadores (figura A).

2. Binario. Cada valor se almacena según su representación interna(una copia exacta de como está en memoria).

a) Cada valor se almacenaría exactamente con 4 bytes.

b) No se necesitan separadores.

c) El tamaño del fichero será de 20 bytes:

4 bytes/dato × 5 datos (figura B).

Gestión de E/S. FicherosFicheros. Introducción → Ficheros binarios 310

’\n’’1’ ’4’ ’5’ ’3’ ’4’ ’4’ ’5’’\n’ ’6’ ’7’’3’ ’3’ ’4’ ’5’

’\n’

’2’

’8’ ’8’ ’4’ ’5’’\n’’9’ ’8’ ’5’ ’6’ ’7’ ’4’ ’8’ ’5’’\n’EOF

Representacionbinaria de12345

Representacionbinaria de34

Representacionbinaria de4567345

Representacionbinaria de8845

Representacionbinaria de98567485

EOF

A

B

A) Representación en formato texto B) En formato binario

Salvo en circunstancias muy extrañas (en términos de probabilidad) laadopción del formato binario para estos ficheros de datos resulta másventajosa.

� No se requiere especificar nada para trabajar en modo binario conun fichero.

� Emplear las funciones read() y write().

Page 162: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Ficheros binarios 311

// Fichero: tamanio2.cpp#include <fstream>#include <iomanip>#include <cstdlib>using namespace std;

int main (int argc, char **argv){

const int TAM_BUFFER = 1024;unsigned char buffer [TAM_BUFFER];ifstream fi;int sum = 0;

if (argc != 2) {cerr << "Error: Num. de params. erroneo\n";cerr << "Uso: " << argv[0]<< " <fich>\n";exit (1);

}fi.open (argv[1]);if (!fi) {

cerr << "Error: no puedo abrir " << argv[1] << endl;exit (1);

}

while (fi.read(buffer, TAM_BUFFER))sum += TAM_BUFFER;

sum += fi.gcount();fi.close ();

cout.setf (ios::fixed);cout << "\nFichero: " << argv[1];cout << setw(10) << sum << " bytes, ";cout << setprecision(2) << setw(8) << sum/1024.0<< " Kbytes\n\n";

return (0);}

Gestión de E/S. FicherosFicheros. Introducción → Ficheros binarios 312

% tamanio2 datos

Fichero: datos 2050 bytes, 2.00 Kbytes

0 1 2 1023

1024

1025

2047

2048

2049

datosFichero:

0 1 2 1023

buffer

sum

0

Apertura del fichero.

0 1 2 1023

1024

1025

2047

2048

2049

datosFichero:

0 1 2 1023

buffer

sum

1024

Lectura del primer bloque

Page 163: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Ficheros binarios 313

0 1 2 1023

1024

1025

datosFichero:

2047

2048

2049

0 1 2 1023

buffer

sum

2048

Lectura del segundo bloque

0 1 2 1023

1024

1025

datosFichero:

2047

2048

2049

0 1 2 1023

buffer

sum

2050

Lectura (parcial) del tercer y último bloque

Gestión de E/S. FicherosFicheros. Introducción → Ficheros binarios 314

// Fichero: copy_file2.cpp#include <fstream>#include <cstdlib>using namespace std;

int main (int argc, char **argv){

const int TAM_BUFFER = 1024;unsigned char buffer [TAM_BUFFER];

ifstream fi;ofstream fo;

if (argc != 3) {cerr << "Error: Num. de params. erroneo\n";cerr << "Uso: " << argv[0]<< " <fichE> <fichS>\n";exit (1);

}fi.open (argv[1]);if (!fi) {

cerr << "Error: no puedo abrir " << argv[1] << endl;exit (1);

}fo.open (argv[2]);if (!fo) {

cerr << "Error: no puedo crear " << argv[2] << endl;exit (1);

}

while (fi.read (buffer, TAM_BUFFER))fo.write (buffer, TAM_BUFFER);

fo.write(buffer, fi.gcount());

Page 164: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Ficheros binarios 315

fi.close ();fo.close ();return (0);

}

0 1 2 1023

1024

1025

Fichero: datos.dup

2047

2048

2049

datosFichero:

0 1 2 1023

buffer

Apertura de datos y creación de datos.dup

Fichero: datos.dup

2047

2048

2049

datosFichero:

buffer

0 1 2 1023

1024

1025

0 1 2

1023

0 1 2 1023

Copia del primer bloque

Gestión de E/S. FicherosFicheros. Introducción → Ficheros binarios 316

datosFichero:

2047

1023

1024

1025

Fichero: datos.dup

2048

2049

0 1 2 1023

buffer

0 1 2

1023

0 1 2

1024

1025

2047

Copia del segundo bloque

datosFichero:

2047

2048

2049

0 1 2 1023

1024

1025

Fichero: datos.dup

buffer

0 1 2 1023

2047

2048

2049

1023

1024

1025210

Copia del tercer y último bloque (no está completo)

Page 165: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Ficheros binarios 317

Ejemplo

Se trata de rellenar un fichero con números aleatorios (rellena_aleat) yde leer su contenido (pinta_aleat).

// Fichero: rellena_aleat.cpp

#include <fstream>#include <cstdlib>#include <ctime>#include <iomanip>using namespace std;

int main (int argc, char **argv){

const int MAX_LINE=8;ofstream fo;int num, max;int n;

if (argc != 4) {cerr << "Error: Num. de params. erroneo\n";cerr << "Uso: " << argv[0]<< " <fichS> " << "<num> <max>\n";exit (1);

}num = atoi(argv[2]);if (num <= 0) {

cerr << "Error: <num> debe ser >= 0\n";exit (1);

}

Gestión de E/S. FicherosFicheros. Introducción → Ficheros binarios 318

max = atoi(argv[3]);if (max <= 0) {

cerr << "Error: <max> debe ser >= 0\n";exit (1);

}

fo.open (argv[1]);if (!fo) {

cerr << "Error: no puedo crear "<< argv[1] << endl;

exit (1);}

cout << "\nEl fichero " << argv[1]<< " contendra " << num << " enteros.\n";

cout << "Sus valores estaran en el rango 0.."<< (max-1) << "\n";

srand (time (NULL));

for (int i=1; i<=num; i++) {n = rand() % max;fo.write ((const char *) (&n), sizeof (int));cout << setw (6) << n;if (i%MAX_LINE==0) cout << "\n";

}cout << endl;

fo.close();

return (0);}

Page 166: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Ficheros binarios 319

% rellena_aleat fich_aleat1 22 100El fichero fich_aleat1 contendra 22 enteros.Sus valores estaran en el rango 0..99

6 99 15 64 63 88 62 9926 44 97 27 80 49 74 7292 27 13 12 0 3

// Fichero: pinta_aleat.cpp

#include <fstream>#include <cstdlib>#include <iomanip>using namespace std;

bool ExisteFichero (char *nombre);int tamanio (char *nombre);

/*****************************************/

int main (int argc, char **argv){

const int MAX_LINE=8;ifstream fi;int tam, num, n;

if (argc != 2) {cerr << "Error: Num. de params. erroneo\n";cerr << "Uso: " << argv[0]<< " <fichE>\n";exit (1);

}

Gestión de E/S. FicherosFicheros. Introducción → Ficheros binarios 320

if (!ExisteFichero(argv[1])) {cerr << "Error: no puedo abrir " << argv[1] << endl;exit (1);

}

tam = tamanio (argv[1]);cout << "\nFichero: " << argv[1] << " (";cout << tam << " bytes).\n";

num = tam / sizeof(int);cout << "Contiene : " << num << " enteros.\n\n";

fi.open (argv[1]);

for (int i=1; i<=num; i++) {fi.read ((char *) (&n), sizeof (int));cout << setw (6) << n;if (i%MAX_LINE==0) cout << "\n";

}cout << endl;

fi.close();return (0);

}

/*****************************************/bool ExisteFichero (char *nombre){

ifstream fichero;bool problema;

Page 167: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Ficheros binarios 321

fichero.open (nombre);problema = fichero.fail();if (!problema) fichero.close();

return ((problema) ? false : true);}

/*****************************************/

int tamanio (char *nombre){

const int TAM_BUFFER = 1024;unsigned char buffer [TAM_BUFFER];ifstream fi;int sum = 0;

fi.open (nombre);while (fi.read(buffer, TAM_BUFFER))

sum += TAM_BUFFER;

sum += fi.gcount();fi.close();

return (sum);}/*****************************************/

% ls -l......-rw-r--r-- 1 pepe alumnos 88 abr 22 18:48 fich_aleat1......

Gestión de E/S. FicherosFicheros. Introducción → Modos de apertura 322

% pinta_aleat fich_aleat1

Fichero: fich_aleat1 (88 bytes).Contiene : 22 enteros.

6 99 15 64 63 88 62 9926 44 97 27 80 49 74 7292 27 13 12 0 3

IV.2.6. Modos de apertura

� Comportamiento predeterminado de un objeto ofstream al abrirlo:

– Si no existe, crearlo.

– Si existe, truncarlo (borrar su contenido).

� Para modificarlo, dar un segundo argumento al constructor del ob-jeto ofstream:

ios::in Abrir para lectura.

ios::out Abrir para escritura.

ios::app Posición activa: final. Para añadir al final.

ios::ate Posición activa: final. Puede escribirse

en cualquier sitio.

ios::trunc Predeterminado.

ios::nocreate Si el archivo no existe, falla la apertura.

ios::noreplace Si el archivo existe, falla la apertura.

Puede consultarse (como siempre) el resultado de la apertura conla función fail().

Page 168: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Modos de apertura 323

// Fichero: concatena.cpp#include <fstream>#include <cstdlib>#include <iomanip>using namespace std;

void concatenar (ofstream & fo, ifstream & fi);

/************************************************/

int main (int argc, char **argv){

ifstream fi;ofstream fo;

if (argc < 3) {cerr << "Error: Num. de params. erroneo\n";cerr << "Uso: "<< argv[0]<<" <fichE1> [<fichE2>";cerr << "...<fichEn>] <fichS>\n";exit (1);

}

fo.open (argv[argc-1], ios::app); // Adicionif (!fo) {

cerr << "Error: no puedo abrir " << argv[argc-1] << endl;exit (1);

}for (int i=1; i<argc-1; i++) {

fi.open (argv[i]);if (!fi) {

cerr << "Error: no puedo abrir " << argv[i] << endl;}

Gestión de E/S. FicherosFicheros. Introducción → Modos de apertura 324

fo << setw(24) << setfill(’-’) << "-\n";fo << "Fichero: " << argv[i] << endl;fo << setw(24) << setfill(’-’) << "-\n";

concatenar (fo, fi);fi.close();

}fo.close();return (0);

}/************************************************/void concatenar (ofstream & s, ifstream & e){

const int TAM_BUFFER = 1024;unsigned char buffer [TAM_BUFFER];

while (e.read (buffer, TAM_BUFFER))s.write (buffer, TAM_BUFFER);

s.write(buffer, e.gcount());}/************************************************/

% concatena letra_A letra_B resultado% more resultado-----------------------Fichero: letra_A-----------------------A-----------------------Fichero: letra_B-----------------------B

Page 169: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Funciones de posicionamiento 325

% concatena fichero_eco resultado

% more resultado-----------------------Fichero: letra_A-----------------------A-----------------------Fichero: letra_B-----------------------B-----------------------Fichero: fichero_eco-----------------------Esto es unaprueba de redireccion

IV.2.7. Funciones de posicionamiento

istream & seekg (int desp);istream & seekg (int desp, int origen);ostream & seekp (int desp);ostream & seekp (int desp, int origen);

Establece la posición actual del fichero sobre el que se aplica.

1. Con un parámetro (desp) se efectúa un posicionamiento absoluto(desp bytes) desde el principio del fichero.

2. Con dos parámetros, el posicionamiento es relativo respecto alorigen, que puede ser:

Gestión de E/S. FicherosFicheros. Introducción → Funciones de posicionamiento 326

ios::beg : inicio del fichero,

ios::cur : posición actual,

ios::end : fín del fichero.

int tellg ();int tellp ();

Devuelve la posición actual en un fichero de entrada(tellg()) o salida (tellp()).

// Fichero: reves.cpp#include <fstream>#include <cstdlib>using namespace std;

int main (int argc, char **argv){

ifstream fi;char c;

if (argc != 2) {cerr << "Error: Num. de params. erroneo\n";cerr << "Uso: " << argv[0]<< " <fichE>\n";exit (1);

}fi.open (argv[1]);if (!fi) {

cerr << "Error: no puedo abrir " << argv[1] << endl;exit (1);

}

Page 170: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Funciones de posicionamiento 327

fi.seekg ( 0, ios::end); // Colocar la finalfi.seekg (-1, ios::cur); // Retroceder 1

while (fi.tellg() > 0) {c = fi.get();cout.put(c);fi.seekg (-2, ios::cur); // Retroceder 2

}c = fi.get(); // Leer el primerocout.put(c); // Escribir el primero

fi.close ();return (0);

}

% cat fichero_ecoEsto es unaprueba de redireccion% reves fichero_eco

noiccerider ed abeurpanu se otsE%

// Fichero: tamanio3.cpp#include <fstream>#include <cstdlib>#include <string>#include <iomanip>using namespace std;

int tam_file (char *nombre);

Gestión de E/S. FicherosFicheros. Introducción → Funciones de posicionamiento 328

int main (int argc, char **argv){

if (argc != 2) {cerr << "Error: Num. de params. erroneo\n";cerr << "Uso: " << argv[0]<< " <fich>\n";exit (1);

}int tam = tam_file (argv[1]);

cout.setf (ios::fixed);cout << "\nFichero: " << argv[1] << setw(10) << tam << " bytes, ";cout << setprecision(2) << setw(8) << tam/1024.0 << " Kb.\n\n";

return (0);}/************************************************/int tam_file (char *nombre){

ifstream fi;

fi.open (nombre);if (!fi) {

cerr << "Error: no puedo abrir " << nombre << endl;exit (1);

}fi.seekg ( 0, ios::end); // Colocar la finalint tam = fi.tellg();fi.close ();

return (tam);}/************************************************/

Page 171: Metodología de la Programación

Gestión de E/S. FicherosFicheros. Introducción → Funciones de posicionamiento 329

Esta función se puede sobrecargar:

/************************************************/int tam_file (string & nombre){

ifstream fi;

fi.open (nombre.c_str());if (!fi) {

cerr << "Error: no puedo abrir " << nombre << endl;exit (1);

}fi.seekg ( 0, ios::end); // Colocar la final

int tam = fi.tellg();

fi.close ();

return (tam);}/************************************************/

y se llama:

string nombre;......nombre = argv[1];

tam = tam_file (nombre);......

Page 172: Metodología de la Programación

PRÁCTICAS

Curso: 2011/2012 Clase: Primero - Grupo: B

Page 173: Metodología de la Programación

�������������� ������������ �� ������������� ����������� �� ���� ��� �� �������� ������ ���������������������������� � �� � � � ������� � �� � ����� �� � � ���� � � �� � �� �������� !� ����� ��������������� ���� �������� ������"����� � ����� � ������ � �� � � �� � �� � � � � ����#�� � �� � ������ ������� $ %! � ���"�� � �� � �������� � �������� � �������� ��������� �� �&������� ��! � �� �������� �"�����������������%�� � '����� � �� � ��������� � ��� � ����� � �� � �� � ����������������� ����������� ���������#������������ ������ ������� �������� �������(�������%��������)�����������**������ � *������%� � +,���� � �� *�'������ � �� � - ��� � �� � �������� ���������������

����������� ��������

������������ �������������������� �������������������������������������������� �����

��������� ����� ������� ������������ ������ ���������������� ����������� ������������� ���

�� ��� ����!� � �

�� ��� ��������"����������#�$������� ��%����� ������� ��&�'�(��� ) *

.

���� �� ����� ���

����������� ������������������������������������������������������������������������������������������������������������������������������������������ ����

����������������������������������������������������������������������������������������������������������������������������������������� ����������������

��������������������������������������������������������������������������������������������������������������� ����������������������������������������������������������������������������������������������������������������������������������������������������������������� ������������

������������������������������������������������������������������������������������������������������������������� ���������������������������

����������������������������� ������������������������������������������������������������������������������������������������ ���������!�������������� ������"������������������������������������������������������������������������������������������������ ���������������������������!�������������#��������$��������������������������������������������������������������������������������������������� ������������������������%

�������������������������������������������������������������������������������������������������������������������������� ���������������������&

����'(��������������������������������������������������������������������������������������������������������������������������� �������������������&�������)����*�����'(�������������������������������������������������������������������������������������������������������� ��������&�������)�����������+�������������������������������������������������������������������������������������� ������������������������)������������������������������������������������������������������������������������������������������������������������ ���������������,�������������"���������#+����������������������������������������������������������������������������������������� ��������������-�.����������'(���������������������������������������������������������������������������������������������������� �����������������������/�����'(������������#+���������������������0�������������������������������� �������������������������������

�������1��������������������������������������������������������������������������������������������������������������������� ��������������������������%����2�������#���������������� ������������������������������������������������������������������������������������������������������ ���

�-�2�����+���������'3/4���0��������������������������������������������������������������������������������������������������������������� ���

-������"���� ��5��"�6�������������������������������������������������������������������������������������������������������������������� ���������-���7�����������������'3/4���0������������������������������������������������������������������������������� ��������������������������

������������ ����'3/4���0������������������������������������������������������������������������������������������������������� ���������������-

����)����*���� ����������������*��#������������� ������������������������������������������������������������ �������������������(�������������������������������������������������������������������������������������������������������������������������������������� ���

�������)������������������������������������������������������������������������������������������������������������������������ �������������������+��������������������#����8�������������������������������������������������������������� ������������������������!�������2�������#������������������������������������������������������������������������������������������������������������������������� ��%��������������������*�������������9����������������������������������������������������������������� ���������������������������%

����:������ ������9����������������������������������������������������������������������������������������������������������������� �������%����)����*���� ����������#����������������������������������������������������������������������������������������������������� ����������%��-�/���8�#�����;���<���������� ����/+�������������������������������������������������������������� ����������������������������=

���-���������� ������������ ���������������������������������������������������������������������������������������������� �������������&���-���(���������#������������������������������������������������������������������������������������������ ����������������������������-���:������ ������������������������������������������������������������������������������������������������ ����������������������������-������������ ��>�������������������������������������������������������������������������������������������������� ���������������������-

�!�7�*������������������������������������������������������������������������������������������������������������������������� ������������������

!���:����#����������9����������������������������������������������������������������������������������������������������������� �������

�%�7�*����������������������?��������������������������������������������������������������������������������������� ������������������������!

%���2�����+���������'3/4���0�������������������������������������������������������������������������������������������������� �������!

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

Page 174: Metodología de la Programación

5�*��������� 6

����������������� ��#���� ����� � �+��� ��*��� �������� �#��������� 9� ���#���� �� ��������� � ��������#���������'3/4���0@���9��������������� ���������� �����0����"����������������������#���

7���� � � � ��#�����@ � �� � ���"������� � $���� � ��*��� � ������������ � ��+�� � �� � 5#�� � ���06��)�������#����@����������� ��������"�������?�#������#����#��������������>�9�����������"����������� �����9������9����#������������������������������#��<

� �����<��������������#+�������A������7����� �� �������#���������"������������ ���������B��"��������==��������*����C���#�����5����� �6���������#�@��������@��������������D����#;��+;����������*�����*���������������������"���$��D���@�������������������� � � � ���*��#�� � �� � ������ � � ��� � ������� � �� � �����#�@ � > � ����#����� � ���������#������

� ����<��������������>�����9�����������������=%���������$������:����#��@�>�9������� ��#� �+8���"� �� ������ � � � �����#� �������"� ��#�����@ ��#����� �� �����������������D������+����� *���#����@�����������#���������C������A�����>��������8������$����#�������9�������#���#������

� ���������< �E�������C�� ����� � ����������A��������������������>��� ����>�������:����#���

7����#����@ �#�$��*�����$�+�����5���06�����������������+��C��$�+��� ���5'3/4���06 >� 9�����0������������A����#���� ����A�����9�@������C�����@���������*�������������������

� ����� �!�"�< /��������+�� ����'3/4���0��������9����9�����;�+����������������#� �������"� '3/4���0 > 9� "� ���#��F�� � ����� #�$�� ������������ 9��� � ���#�� � ����� � �� � �����#� � �������"�@ � ��#� � ���� � ��� � ��9���� � ���#;�����@��������������������9������*�;����@������#���*����������+�����������@�������������0���@ ����

���� � ��#���� � �� � ��*����� � ���#�����#���� � �� � �� � ������@ � �� � ���#��� � ����� � ����#������ � �C���� > � � *���#���� ��� � �������#����� �� �� ����� ���@ � > � �� � ��*�� �� � ������������ � ��'3/4���0�����������������������#��������

(��������@������� �����������@���>������������������������������+;�������������������������������@���#���������������������� ���������#����������C����� ������ ��� @��0������������*������� ��� *���������� ��� @�>����#��������� ������������� ���������������������9���������#�����*���������>������������������������������

(�� ����� � ���@ �� � �� � ����� � �- � �� ���������� ���*��� � ��������C������ �� � ��� ������+�������'3/4���0@ � #������� � 9� � �� � �� � ����� � � � � �� � ����>�� � ��� � ��������� � ������#��������������������������������� ���:�������+���������������������?���@������������������������������������������#���������������+�� ��9��������;������������)�#���8�#���@��������>�������������� ����/+��@���������������>��������������

.����#����@ � �� � �F��� � ��*��� � ������� � ����������� � ��+�� � �� � ���� � � � ��������� � � �������#��@ � ��C � ��#� ��*��� � ���������� � � � �����?� � ���� � �#����� � ��� � ��������� � � � �������#�����

� ����� ��� ������������8���� �������9�"��!������ �����������! �� �������'��������������������������"���� ����

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

.��� � ������� :

����������������� ���� �� �� � ��������"� � ��#�����#����� #���"� 9� ���#��� *���� ��� ���� ����#� � ���#������� � (��� � ���� � ��#������ � �� � �����#��� �@ � �� � ��������� � �� � ���� � ����������������#�*�?������9���������������������������������9�F����#���#�*�?������

������������� ��� ��������

/�������������;���#����������"��������������������� �9��*�������+�����#��#���8�� �)������������� ����������#��� ��#������ � ���� � �� � �#+�� � ������ � (��� � ���� � �������+�� ���� ����@ �0���� �� ��+��� �������4��������� ����������������������� ��������+�����������������#���������+�����+�������9��$����9�����#�"�������������"����:�#�"�#����� �� $���� �� ����� �������� � $���� �� �0������ �������#��������?����*��������@���C@������������������9��������������������������������*��������#���"����������*���C���������������+������������9���������������������������������������$�>����� �>�������+�������������4�����������

��������*��������#���"�������9�#��������9� �� �������� ��� ������ #;� ��*��������"��� � � � ���� � �� � ����#��� � ��� � ������������"� � 9� � ��� � �������� � �� � �������#���� � �� ���� ���; ��#����� ���"������������@�����������������������#������#������ � �����#��� � � �� � �#+�� � �������2�������������"������ *���@���������������"�� � �� � �� � ����� � � �������������������?������� � ������� � �� � �8� � � � *���@����#��� � ������ � �����1� � � /� � �������������������������������������8�����������������*���������������������������

)�� ����� �� �"�� �� ��������� /� ������������������������#���������#C��#��� � �����#��� � � 9� � �� � ���������� � $���� ����� ��������> ����������+��9�����������-�� >��&=��+>���� �2����������#�@���������������,���+����@�B�������@�:������������������� � > � � +>��� � ��� � ������ � ����; � �������������,0B0:0��+>����

���������� � �!�� ������

(��������������������������@�?�����+������������������������+�����7�9��?���������������� ������"� �� $��D���@ �� ����������� ��+�� 9? ���� � ���� ����#�� ����� #��������@����������#����@������������������������ ������'3/4���0�

�����������������������#���������#������ ����������������>��������������#����������C��������������#���������������������������"�����������@���#�������8�#���<

� ��;�����<7���������<7�=���>� 7

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

*�� ������5; 3 �� �����

*�� ������.;�� "������������ ��������

Page 175: Metodología de la Programación

.��� � ������� ?

� �2�������*�����2��"������������� ���7B7��7"�����B������*>�7����$#�#��� ��E����$����� ���#;��$�+�����$�����$������������#����'������#����@���� �������+�����������������������������������������>@�����������������@�����������������������#;0�#��������������#�������>������"� ��������#��������#������������������#��������������"�����������#�������������9�F�����������������8#���� �9�����"�����������������>�9���������������"�#��������������� �������9��9���#���9�������,�����������#;���0�������$�����$������������#����+�������+�8��������

� :7B7 �:�����G7B7 �����������������9�����;������>�������2�@�>��9�����#>�+������>�#;���;����

� �:7B7���0������G:7B7 ��������"����������:7B7����������������������0�������

� :):���:#����)�#�����:>���#���������� �����������������9�����#�������������������> � ����� � ����� � � � ��������"��� � �� �#;� � �;��� � > � � �#;� � ����� � 9� � �2� � ��9�@�*������#����@ ��� ��������"�� :):� ��� #�$� #;� ����� ��� �� 9� �� �� ��������"����������9������#?�������

� /:� �/��"����� :����� �� � �� �� �������� ����� 9� ���#��� �� ����0� � ���������"���#>��"�����@���������������������0�������

)��� � �������#�� � � � �����#� � '3/4���0@ �� � ����#���+�� � ������ � �� � �*�� � ��� � �����������;��� ��������� ��@���������#���������0����� "�������������������#����������"���������#��#��#;9�����(��������@������#���9���������#+������������������������������� ���������#+�����������������������>�����A�����9������#�������������

(�� ��8�#���@ ������ ��� ���������"�� ��2��������� ���� ��� ���#+�� ����� ����� ������ ��� ������#����������������#�������� �2�@ ����� ������������������"�����������#����2�@ ����� ��������#������������*������������>������������������"� ��?�����H�����8�#�����������������������#+�������@����@����@����� 9��������������������������������"���:):��

7�9� �� ��#+�� �� ��������"� �� ���� ���*��� �� ���� � � � ��������@ �� ����+�� 9� ���A������� ������#������ ���� ����� ���#�������� ���� ��"����� �#���"��� ��� ���� �������@������ � �� � ������� � � � ��������� � � �� � �����#� � ����#�� � "�� � �;��� � ��� � ��� � ��#+�������*������(����8�#���@������������#��������9��������;���������������0����0���������������:�����G7B7�9�����;��*��������������������#+��������> ������7�#;�@���������������������������"������#�����#����������$�������������/:�@���������#�����*����������#������"�����������

(������������������#+������������������������������������ ����#�����#�����@�����������#��'3/4���0�>��������������#����8����������������� �<

����� �������� ��

�;� ��������"��"���#�����+����������#��>��#������#�����*������������������"�������������#+����

� 1�������� ����������!��������������� �����������'�#������������ �� �!� ����� � ������� ��� ��������� �-$+$��)������!�� ��� ����"����� ������ ���������������� �

� $����� ��������� ����� �������������������� ����� ���������������

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

6��� �������� ��� � �� ���� @

�"������������ ��� �������������� ����� ��� ������ �� ������� � ��#�����#����� +������� ���"��@ ��� �� 9� ��������������������������������������� ���������������"������������������������@�>����������� �� ������ � ����� ���#���� � ���� �����������"� � �C���� � ������������ �2� ����� � ���#�@ �����������������������"����������������#�����#��������������#�������A����#�����$�>���������������������C������7�*���������������������������������������������<

� (��#���� �� ��������� � � "����� �����#�� �������"��� �� ���#�� �� 9� ��� �����#�������������������� ��������� ����������

� �� �� +��� ���#� ��� �� ������� � ���� �� ��������� � �� �����#� �������"� > ������������������������ >������������� ���������#�������������������������2����������#�@������������������#����������� ����"���� �����#��������������������#����������@ �� $�>�9� ����� ������������������

� B������ �"����� ������������@ � �� � �� �� ������ ��8� �� ������ ��������"� ���� � ���9����#���"� �"���@ ����� � �� ���� �#�������� � �� ������� �@ ���� @ ��� ����� �� �� "��;����������

��� ������������ �������������������"�� ��� ����� �>@ �*������#����@ ��� ��������� ����������#������#;0�#�����������������������7��������������������� �������������#�����������������#�������

�����*��������������@���������A����#���������������������������#��#;0�#����������������������@��������9���������+���9��������������������������#����������"��@���� "��@����#;���������������������������� �@������������� ��9��$�#�� �+�"���@����������#�����0�����������*��������#���� �>����������������"�����������������������#��������� ��� *��������������� ���0�������������������#���������������8�#���������������0����������D���D� @�������*������"�������������������� *������������9������+�"���

)��������#���������"� #����������������������������������������������������#���)��������*�������#������������������������#+��������(����8�#���@�I���D�����*���������������� ��������+������5�����������6<�������#����������� ��������#��)@������*���2@����������9�����C������+�����#+��������������� �

'3/4���0������������� ������������)�����������"�������������������#����������������� ���$��� �������� ����� �� ��������� /dev� �� ���������<

� ������������"����2��������#���hdX@�����X��������������a@ �b@ �c@ ��� ��7�����#���������2��#������������������������a@�������#����2�������"�����b@������*����2��#����������c�>������*����2�������"�����d��(����8�#���@�:������#�����������2����������*�������� > ��#� #������@ �������� ?��� �� ������� �� �� �����#� ��#� /dev/hdc�

� ������������"���:):���� ���#���sdX@�>�����"��X��������������/dev/sda@ /dev/sdb@���� �

� ��� � ��������"�� � :����� � 7B7 � ���� � �������� � ��#� � �2� � �/dev/hda@ �/dev/hdb@ � ���@�/dev/hde@���� �����#��:):���/dev/sda@���� �

� ��� ��������)242J2�����������������#���2������#��:):��� ������������9���0����������������#+ ����- ���������������"�@����#���/dev/cdrom�

- ���������� �������� ������� �����������"��������"��� �����������������&��'�������-���������� �� ���� !� ��%�������� %���������8���� �������9���������� �(��� �'�A���< �

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

Page 176: Metodología de la Programación

6��� �������� ��� � �� ���� B

� �����9������������#� �/dev/fd��������������9���0����������������#+ ��������������������"� ���#�� /dev/floppy�

7�"����@���������#���������"���������������������#���� �@�#��������������$����9��������������"�����������������#����������#�8�����$�@���������#������� ���#������������������������(����8�#���@����������#����9����������2�����:):���������"?���(��������#���"�@�� �"���� ����������� �9� �� ����� � �2�� ��� �9� ���� ��8�#��� � �� ������������C� � ���#�����/dev/hda ��������� ��#��������������������"��:):������*������2���>������������#�����"����#��/dev/sda ��B������� �������������������������>����*����������������A�������������#��

(��� �����*�� ��� �������� ����������� � � ����@ �� �F�� � �A#��� �� ��#+��� (���8�#���@�������#����������� �����#�����������#���������2��#�������������#��/dev/hda1������������ � ������� � � ���#���� � �� � ��*�� ���� � :):� � ���; �/dev/sdb3@ � ����� � ��� � ������������� *�������#����������#�������������������-�

�"������#$%�&#��� ��$����% ����'

������#����������9��$�>������������������������&@������&@��������& �������������#������������������������ ������������� ���#> �#���������>��9�����?�������#�����<

� �����+���� ��������������������+�������������������� ������� ����������� ���#�������>��0������������������9���0�������*�� �9��$�>������������ :������������#��� �������������������C�������(��������������� ������+���*�����"����������@���#�������8�#��� �����������������������#�����@�����������������+��>�9?�������������#�������$��������������

� /����9�F�����*��#�����#������*�����+��������� �9�����#��������������������9����������#���������"��������*A����������*��#��9�����#���@������8�#���@����*�����������������������#����������"������������*��#��������*������#�#��������������H:� ����������������������

"�� ��������� �����

)��������#�� "�����������������@��� ������#���������"������������8���������9������������@ � ������ ���#�� ����� �������� �����#�� �� ��������� ������������ (�� �� �����@ ��������������������@�������#����9��$�#������������������������������������������;���������#� ��������"� �9� �����#�� � �������� �� *���#����@ ��� �9� ��� � �����9� ��� � �����#���������� �� �� ���*� > �8���� � �� � �*� 9� $�> �� �� ���@ ���; ���� � �*� �� �����*��������������������#���������"���������3��#��#����@����� �*�������������<

�� 2����#������;����� ���������� ������"�� �: ������������������������������������������#��������#������"��

�� /���"������������@������*��������#��������������$��������� ��>�������*�����#�#������������������+���������������"�����*��#�����*����9����+���0����#������ #������+� ����*��@ � � � � "��@ ��� � �����#���������"�� �/�� �"�� ����*�����$� ����*��#�@ � ������������������������������9����#���������8��������

� ���0*C-�D0� ��*����C����- ��E����������������� ������������������������� ����������� ��� ���� ������� �FC(�"�� �������! � ���� � ��� � �� � ! � ��������� � �� � ���� � '���������� ��� ������� �� �� �� �������������������������!�� %�������������� �����'������� ����������� ���������� � ��������� � ������������������������������������������ ������(0F!�����������������#��������������������������������!� ���� '��������������������������#��� �����������

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

6��� �������� ��� � �� ���� G

(��#���#������������ �*��������*��#��������������������������9�������#����������������#�� �� �� ���� � ��� *������� � �����9� ��#� ���H � '�+@ ������� �� �� #�>�� ������������+�������'3/4���0�����������*��#������������@������8�#���@����������� ����������#���������"��9� �����������������������������#��A���������������;���������������#�����;����*��������������+���������*���������������9��

�"�"�������� ����� � �( ���

/���"���9����������������$��$������������������@�>�����#����������������������������#���� �������������������#�������������(����������������������+������@�$�#���������� � #� "�#�� ����#������ >���*���������� �����

B��*�#������������9������������ ���������������������#���#�������#����������������+>�����������*A�����������*������� ���:����#+��*�@���������#���+�����#���������*������������������� ��#������������������������$���@����9���������������#+��@���*�����������������#��� �������#��8��;�9���������;�+���������������@�����

/�������#�������$��������������������9�����#��������������������������������@���������#��� � ���$���� ����� �� � ��9�#� � 9� � ��� � � #� � �� � �+�� � ��*������ � ��� � ��������� � � � ���������� �� ��;����#����@ ��� � �����#��*���������� �������������#�����#�������"��?��������+��9��������������#�F��������8�#�������&���+>��� �9������������������������+���@�>���*����;������������$�����>������������

�0����� #���� � �����#�� � ���$����� (�� �8�#���@ �� +������� ��#��� �� �� �����#����#�����.7B��.����7����������B�+�� @�������������#�����9��������������������������#�����+��� � �� � �� � �0��������@ � �� � ��#����� �� � �� � ������� �@ � � � �� � ��+�� � � � C���� � �� � �� � 9� � �����#�����������+��9������������!�����������������$������#�����������������@���C���#������#+���>��������������������+������������������*����C���#����#����9������9?�$�>��������+��9��������������$�>������$���@���������������@�������;�"��C�@����� ��7�#;�@�������������������*���@��������+������;�������������������#��������#�$�����#���������@���C �9� ��� �$��� �������������������� ������#��%< �J.7B@ �.7B��@ �3B.:@ �,(.:@ ��0��@ ��0��@�������.:@ � ����� � (�� � �8�#���@ � �0�� � �� � ���� � ��*������ � ��� � ��������� � � � ;�+�� � +�������+���������7J���� �*����������#������+�����#��$����.7B�

�� � �����#���������"� ���@ � �� �*��� �#���@ � ����������� ��� � �����#� �� � ���$����@ � >� �9�����#����������������������������������+������������������������:����#+��*�@����������������������C������ � � � ��� � �����#�� �� � ���$�"�� � $���� �9� ���� � �����#� ��������"� � ���*� � �����������������������������������I���D�������*���"��������� .7B�� 3B.:�#��������9��'3/4���0�����������0������0���#�>��������#������7�#;�@����'3/4���0�����������������.7B=���������+�8�#��������������0���C+�����/:������9��������K �

3���0�������������� ���������������������#��������$�"���>������#����������"����2��$��$�@�� � #��#� � �����#� � �������"� � �� � ����� � � � *�������� � �������� � �����#�� � � � ���$�"��� � :����#+��*�@ �� �#�������� ����� �� ����� ��� ��������C������ � ��� �� � ?����� (�� �8�#���@���������������������������� �����������#��'3/4���0���+����������#��.7B@��������������C���*��������������������������������$�"���>������������������8�#���@�����������+������������������������������������$�"� ��7�C@����$�+��������������'3/4���0���+����0��@�9��

! �� ��� ���� ��������� ����������� � ����� � �� �����������%������������������������������������� �����!�������H��������������� ����� �����&���� �������H����������� ���

% ��;��� �<7���������<7�- ���>��>������

= -��������� ���� ����� �I$+5@� �I$+6.! �� � �&��������������� ������ ��� ���� � ���H� ������������������� ������� � ����������H� �������"����� ���"��H� �"������I$+5@�

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

Page 177: Metodología de la Programación

6��� �������� ��� � �� ���� J

���;���������#��������F��������?��

������#����������������������@��������#����@��������������������������������*���������������@�����������������#�������$��������*����������#������#����������?��������������������9��$�>����#�������������������>��9�@�+;����#����@����9�����$�������������������������������9����*���������������������������

7�9��������#���������������#����������?������������������#��� ����#������@��������+���9������������� �����+��������C����#����������#��#���:������������*�����������������#����<

� F�������������������A����#����������������������������9� �������� ��������#��� ����+������������������+��9���������@�#���;�������������#����+�����3���������������������������������+��9�@��������9�������������*�����������C����#�����������������B���������#������;���@��A�����C�������+�����������������������������

� 1������� �7�#;���� ����������� � �� ��������� ��� ������#���� ���$����@ ��� �$��� ������������+��9������+��9��+������������������������8�#���@������+����������������� � �� � +��9� � ����� � ���� � � � ���#���� � �� �#�$� �#;� � �����@ � ��9� �*�������� � ���+�������C�����������������������#��������>@�������������@��#��������������� ������������

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

:�(��'����� �� ������� 5K

�)�#�� ����������������� ��0����� #���� � ���*��#�� ���� ����� � #������� ��� ����������� � � ���� ���'������#����@���� ���*��#�������������� ������� �����#����������"������������������*��������������*��#�� ���������@����#����@�������������������������������������������������� ����������������������� �"�#����������������+����������"��C������+���������9�@���9��>�����*��������@��������#���������"����������*��#��������������#������9����������������������#>�+;�����>�������#����������"��������9��������������#���������������������

:� >� ������#�� � � ���� ��� ����D��� � ����@ > 9���#�� #������� ��� ����������� ������������9��>�����C�#��@���������������������*��#���9�����������"����������������������� � �����#�� ��������"�� � ��� �#���� ��� ��� � ���� �� � ��� � �����#�� �� ���������� � > ��� ���*���������+������ � '3/4���0 � 2�� � ��� #;� �������� ��� (�������� ��*�� �����D������������������������������I���D� �>�'(����������D��������+��������+�� ��9������8�������+��������#���'3/4���0 ��7�*���������+���������'3/4���0�>������>���'(�������#��$����#������+;�������������������������8�#����/+�� �

������������� ������"�#����������������������������*��#��'(����@�>��9���������+��������+�� �@�������������������������9����������#�����������������+8���"��@�>���������������������� #A�������������+������ � '3/4���0�

�)����*��� �

'(������'��#����������������� ���������*��#����+���9�����#��� � #������� � ��� � �������� � � � ����������� � � � ������������������������������>����������+������ �����@����#�������� � > #�"�� ������������ � ��� ������ � ��� ������9�������������

(����������������*��#������������������������������������"��#���� � ���*A� � �����#� � �������"�� � : �� � $�> � 9�������*�������#�*����:H�������;*����D�+�������>�����&@�*��+����������)2�H��> ����������������������������)2�H���7��������������)2�H������8�����;����"���� ��+;���� � �� � �����#� � '3/4���0 � >@ � � ��������� �@ ����8�����;�'(��������*���� ��(����$������������#��������$� �$��$���� �� � ��� �"�������� &���- �> �&����� �B�#+�?���� �����+�� ��8����� �'(���� ��������9���������#��'3/4���0�����������#�������7�#;�@���������*��#����#+�?���������>���������������>�����#;���#+����������#���:>���#�������)2��@ 9��������#;��9�������8������$����#�������9�����#�������������� ����������#��������� ����������#����>������������������"����������� � �

7���������� ��"�#�����"������8�#���@������������@�����������#����������������*��#���������������"�� �������������� ������������#�����#�����"��C���)���������������������������>���-�����������8�#������#�������� �����������>��������������

�)�������� +��������*��� �

B�������������������������������������������#��A���������� �����������������������������

�� �������������� ����� �������

�� ������������������ ��

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

*�� ������6;�*��������)�����

Page 178: Metodología de la Programación

:�(��'����� �� ������� 55

�����*���� � � �� � �����#� � '3/4���0 � 9� � �� � "� � � � �������� � �� � ������ � �8�#��� � $�#�������������� ��� �������� 5L"���6@ ���*�8� 5:�����$6@ ������ 59D���>4���#��6@ ������� �5�&��0!�%6�>���������5��6�+�������������*������������������������������������������������������������ ��

�������+���9�@�������������$��D��������������@�$�>��9��#����������*��������������������������������@����9���������������#;�����������"��������������� �����������;#��������"C����(�����"��������+��#��@����#;��������������������������#������"C���J�:7��������������� ������#������������%&&0�&&� ��&��0!�%�����%� ����+��������������������� �

/���"��������*������������������@�������*����������#���������"���'3/4���0 �>�����8�����������*��#��'(�������������������������������*��#��������#����9������#���9��$��������������������������������������9��"�#��������+�8������9����������������$� ��/���"��������������@ ���� �� ������ �����#������ �� ���������@ �"�#������������������ ��*�;��������������������#��#���"���#������������������������9��$�>�>������������9���A��������$�����*���������*���������� �����������������������"�#�������������������������������������

�� � �� � ��*�� �-� "�#�� � � � �8�#��� � �� � �� � 9� � �� �#������ � ����� � ���� � ������ � E��� � �� � ��������*���� �������9�������#����������8�#����9��"�#�����"�������������� ��

(��� ���� �8�#��� "�#�� � ��� � ���� �2� �������� �� ���#�� ����� > �� #�� #��������������������"��������������#� ��������>���������������������-�'�����

�� �0� �������������� ��D���� ����� ����E� ������ ��������.6K � � !����'�������������� �!�"����������������� �����,�������5KJ�� � �

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

*�� ������:;�1��'������������)�����

:�(��'����� �� ������� 5.

�)������� ������� ��,���� �������� ��� ��#$%

(�����#�����@�"���#���� #�������������+�������������������������(�����9�������������;���#�����#�����"��C�@��������+����A������0������3��#��#������������+���������0�����@�>��9��������������������������*A�������#��>���������������9������@�������������0�������#�������������+��#��������������� �����"�#�����������*������(��#��������������#�������������+������9��9���#������+�8�� >������������ ������������#���5(������ ��GM�3�"�6��7�����#�����������"����������9�����#������������������ ��

:���������������������"��������� ������$�+����������������+��@�������*��#��������������;����#;����#�����������"�������������$�������

�)���"��� ���������������� �

/���"���������������+���"�#�����������������������������������������I���D���(�������������������#������������������*������������>�����#�����+���5(������ ��GM�3�"�6�������+�� �������� 53�"�6 �� �� ����� ������� ��9���� � �� �� "������ 9� ������� $�#�� � ������������������������$��������� �@���#����������������#�F�@������������������ ������#����@��0�����@�� *��� �����������#�������$�����9��"�������8����3B.:@�.7B@��0��@����� ��B�#+�?�����#�� ��� �� ��� � ����@ *�;����#����@ �� �� ����� ������� � �� "������@ ������ ����#�F�����������*���!�"�#���� #����������������#����������� ��9�����;��������3B.:�

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

*�� ������@;�1���������������������������� �����(0F�

*�� ������?;�)���������)�����������

Page 179: Metodología de la Programación

:�(��'����� �� ������� 56

�� � �� � �������� � �'(���� � "�#�� � 9� � �� � �� � ���� � �������� � ����#�� � �� � ��"� � ;���� � ��������������� 9� "�#�� $������ �� ������ ������ ��#�����@ ���� 9� �� "�� ������� ���� �������������������$������:����#+��*�@������9�#��*�;�����������������������9�����$�������+����� ��������������"�����������������������9��9���C�������������?��������������������������������������(����8�#���@���������*���!����#���"���9��>�����$���������������� ���#����������� ����=@�=�'��@�#��������9��9����-����'����������*����

7���������� ������#����� ��*���������� �@�9�����;��������.7B������*�� �% ��(��������@�����������#�� ��������������� 9���A�����;����������������@�>�"��"�#�����������������������������������B�������������� ��"�#���9�����$����������������������������������������

�)���)�-�� ���� �������������,��

(��� �$���� �������"�� � ���� � ��� ������������ ����������@ ���#�� �������� � ��� � ��#+��� �9��$�#�����#������#�����������������������������+�� ��$������9��������������������������������������*���=�����������������������������������������+�� ��>���������������#������������� ������ �#������������������������9��#�������� �����+������������������#����������?���������������9��������C�����#������� ��

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

*�� ������B;�1����������������������������+I-�

*�� ������G;�1������������� ��������������I$+6.�

:�(��'����� �� ������� 5:

�)���.�/���!������*��� �

7� ���#���� � ���� � ������� � � "�#�� � 9� � >� � �� � 9���������������������������(�����������������������������#���� �� �������� � > ����������#�� �� ���� � 5��+���6@ �� ��#��A�9��������������������������+�� � ����$�������� ����+�������������������������������������+�� ����8���������������������������$����������������

�)���0���������*��� ����������,�������������� �� ��� �� �

'(��������#�������#�������� ���������+�����������������������������������������9��$�>��� ��������������� �#����$���!�"��������$�!������!���%�$������&��������!�'�����������(�!(����� �!)�$��������������'$���������������$��!����������'���*�!�!�"�������!(��� ���

(���+��#�����?����������������� ��#;����#A������������9�����������������'3/4���0��������#����"���������������< �>�������� ����������������#���I���D� �> 9�������F����'3/4���0��������������9������������I���D��

H+"��#����@�������#�������� �����$�������+��1��������������#���������@�������������>����#����� � �� � ���� � ��#����� � ��� � �� � ���������@ � � � �������� � ��� � ���� � �#+�� � �����#����������"������ ������8�#���@�"�#�����������������������������������'3/4���0���������������������������������I���D�� �+�!����'��%����������'$����!��%�&��������!�'������(�!�� �� �!)�$ �� �������� �'$������ ���� �� !�'�� ���

)�#����#�� �� ��"� � ��������� ��� �)2�� �'(���� �> � ��������� ��� � �������� �B��� � ��������*���� ����'(�����"�#���9������#������������������ ���������������<����3B.:������ �9� ��������� ������#��I���D��>������.7B���9��������#�� ������*���� ������ ����������#+�?������I���D� ��7#+����������������������#������������#��������#��������2�<�

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

*�� ������J;�$������� ���� �������� �

*�� ������5K;�-��������)�����

Page 180: Metodología de la Programación

:�(��'����� �� ������� 5?

��������>������������������"�#����� ������*��#������#�����������#�F����������@���������� � 9������� �� �� �����> ���������������� �� ��� �� � ����� �"�� ��*�� �� �

�� ������� ���������� ������������������� ��5+���6���������*�������9��?��� ����� ������� ������"���� ������ ���� �#����� �� ���� ��� ������� �I���D��������� � ������ � ��;����������"���#���� #� ���#�����#+��������#�����

3�������+8���"���������������������*������ �����������<

�� (������ ���������������#��I���D��>������������������3B.: ��7���0�#��#�������'��

�� (������ � � ���� � ��#������ � ���� � ���� � ���+�8�#�� � ��� � I���D� � �.7B�� ��7���0�#��#���� �� �'�� ����� �������� � � ��#+�?� ���C� � ��� ��� ���� �3B.:����� � ������������ � �����+������ � � �'3/4���0 ��� � ����� � ����� � ����"��� � ��� �# ��� � 9�����#����������>������+�����������������������#�������$������(���������@���������������#���� ������������������>��������� ����������������������.7B�������"����8�����9������'3/4���0����#����������>�#�������������������������"����8�����9������� �������� � �.7B�� ��� ���� �����+��� �#�$�� �� � ��� ���������C������ ��"������ �9������������������#��3B.:����0����(�������@��������#���+���������.7B�����#����������������#+�������'3/4���0@�>������#������������+�8��$�+�����

�� (������ ����������������'3/4���0���0�� � �7���0�#��#�������'���2�+�#����8��������� ��#�F� �������� � �� �����+�� � 9� "�>�#�� � �������� > � ��������������� � 9� � ����������#��� � /�� � ��������� � � +;���� � �����>��� � +�����������������������������#A� ���������������#;������ ���'���:������������������������������� �� ����#���� 9� ���� ������� � ���*� �� #���� �& '� ���� �������� #;��������������������������������������������������#��

�� (������ � � ���� � ��#������ � ���� � ���� � ���+�8�#�� � ��� � '3/4���0 � ��0�� ��7���0�#��#�������'���7���*���9��$���#�������I���D�@�������#������������� ���������#���������������������������������#����������#���+��������������>��9����@�������*A��#���"�@��+�#����������������������#�@����$��;�������9����9�#�����������<���*��;����������$C���������#���#��������������� �������������� ��

-� (������ �����D��������'3/4���0���D�� �������������� ���������#�����9�����*������#�F� � �� � �+�� � � � �� � #�#���� � ���������� � �� � ������ � �8�#��� � ����#�� � ����������0�#��#�������'��������������� �������������������������#����#��#�#��������������#+����#�#�����"����� �������������������9���8����#������"��;����#����������#�#����������������I���D����#+�?�����#�#��������������#+��@����������*�������������������������� �@ � �� ����������� ���$���������� �'3/4���0���#+�?����������������������$���@�������������#������������������� ��������������

�������� ����+�������+����������#��������� *�����������#>�����"������7�*����"�����������I���D� ��0�*�� �9� ����� � �����#� ����? � �������� ��� � �� ����#��� �������� � � > �9� �?��� �������#�����������������8�#����"�#�����������������������#�������������������#� ���#������>�����

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

*�� ������55;�)���� ����� ����������������������;��� �������� � ���� ����A���< �

:�(��'����� �� ������� 5@

�����������#��� *�����

(���� 9� ��� �� ����������� � I���D� >� �0�����@ �� 9� $���#�� ��� ����� ���; $��������������#;����9�F���>����������������������2����������#���8�#�������������������������������������������

)�#����#�� � $������ � #;� � ��9�F� � �� � ������� � � 3B.:� � (��� � ���� � �� � #����#�� � >�����������#�� � 5(������ � � GM � ���#��������4��"��6� � �� � �� � "������ � 9� � ������� � ����������� �����*�#��������"����#�F����������������������#���"�����������*�� �����B���������������� ��9�������������+����������*���������������

:��$�>����������������*��������������@���#+�?��������+���#�"����� ������� ������ ������������ (�� �8�#���@ �� 9���?��#�� ����� ��������� � .7B�������������� �������3B.:@�������#�� � #;� � 9� � #������� � � �� � �� � #��A5(������ � GM ���#��������4��"��6� 7 �� "��9� � ���#�� ��#+��� � � � ��#�F�@ � ��#+�?�����#�� �#�"���� � > � ������� ��� ����� ��������������������������#���"�����������*������

7�9� � ���� � ������� � � ��� � �������������������@ � �+�#�� � ����� � �� � ����� � 9� � �������#�� ���������� � �� ������������������>�� � ���� � �� � �����@ � ���#�� � ���"���� � 9� � �������#� � ��� � #;� � �����@ � >� � 9� � �� � ����#����8�������D���D����+���������#����������� ���������+���������������� ��������;� ���������+������� @������������������*�� �������������@�>��9����9����;����������#��������������+�����+��������*������(��������@�������������� ��.7B������"������������������������#����������"��@��������������������������������+��� ������ ��

/�� "���9��$�#����8�����������������������+���>�����#�� �F����������"������������������� ���8�� �'3/4���0� �:��$�����*���9�������$�#�����������"����������������������8�#�����������������A������������������9������*��������*�����#�������#�������$�����3B.:�� .7B@ ���*���#�� � �����#� � ���$���� ��#����+�� ��� '3/4���0 ��0��@ �0��@ ��� � ��������������������#��������0���

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

*�� ������5.;�1��������������H����������������+I-�

*�� ������56;�(������ �����������

Page 181: Metodología de la Programación

:�(��'����� �� ������� 5B

B�����F������������������������ �@��A������9�������#;�������F���@ ������������� ������ ���8����������+����������������������2�+�#������������������� ���0���������������������������������+���>@�������������@�������#������������������� *���������������������'3/4���0�>�������D�� ��(��C�#���$�+������������������*������� ����������������������������#������>�� *�������������A�������������� � 9� �����#������� �����#���������I���D���������� ���������#����������� ��9�@���#;�@��+���������#���� ����������*����-����#��������������� ���������������� ���0������

�� � �� � ����� � ����$� � � � �� � ��*�� ��-� ���#�� � "�� � 9� � ���������� ���0��������*��������������������*���@�>��9�������#�� � ��#� � ���������� � � � ����� � ������������ � (�� � �����@��$��� ��+�#�������� � ��� ��� ���"�� ����������� ������ ��������

�� �����*������#�����#����������"����������������������������������� �������������� ���0���>����D��@���������"�#�����

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

*�� ������5:;�$H��������������������������6���������������

*�� ������5?;�1�����������������������������

*�� ����� 5@; 1������ �� ������� ������ �

:�(��'����� �� ������� 5G

(����9�����������#����������������*����������$�#�������������+������+�� ����57������6���������� �� ��� ��� ������#��� � > �� ������ � �������� ��� ��#+���� 2����� �� ����������#���"�������+���������������9?�������9��"������������������#�#��������*����! �

'(�������#+�?�����������*��������������+���������#�����#������������"��������������*���+������ ������������������������������(����8�#���@����#����������;�����;����������� ������"�����*����% ��

������������ � ����������������#�����#;����������������*��#���9�����������������������������#����������"��@��������"�����$�>�9��$�������#����#������:�����������#����������� ������#������������I���D���>��A�����$�#������������'3/4���0 @������+���������������� ������"��

)�� ��1

������������������������������9���������+�� ����'3/4���0�����������������@�>�9���� � �������� � ����� � � � ��� � $����#������ � +;����� � �� � �����#�� � (��#��� � ����� � > � ������������������@ � ���� � �� � ���#��� � ��#+��� � �� � �������� � � � � ��#�F� � � � ��� �#��#��� � 7�#;�@�

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

*�� ������5B;���������� ��� ��� ���������� � �����������������

*�� ������5G;�(�����������������������������

Page 182: Metodología de la Programación

:�(��'����� �� ������� 5J

���������� #�� ���������>������ #�� *�;���� ��:�����9��"�#�����$���������������������"� ���� ��� ������� � #������� �� 9� $�+C� �� ?�@ �� �� +��� ���� �< �;��� >���������

������#��#;����#�������������1�����8���������������#����*#����������#+�������������������9������#����������������(����8�#���@����"�#��������+�8����������������������#��<

�����������

7� ��#����� � �� � �8���� � �� �#����� � � � ���#�� � �� � �� � 9� � �������#�� � �� � ���� � � 9������#���������������� #;������"����������������*������<

� ����������������� ����#������"�� � )����������"��������� ��

� ����������������� �������������� �� � �������������+���� ������������������

� J��������������������� �*������������ � ��� � �� � � � ��� � ����+��� � ����� � �������� ��

� )�#+������ �������������#�������$������������� �� ������� ��

� ����������#��A����>�����������������������������+����

� �����+�� � �� � ��+�� �� ������������ �> � �����������*��#��

.�������������*��+���������#+����

������������$���!�"�������(���������������"��������� ���������������������<

� ����������������� ������#��������0����� �

� ����A#������������� �������� �

� ���9�������� ������������#�������:������#���5�����6���#���������������������$�>�����������������*����

� );������� � ��#�F������������+� � �(������������ � ��#�F�@ � ���#;���;��� ���������+���N�#(������#�������A#����>�(�������������9���������������#���$�+�������O���+>�����O @���*�+>������ ���'�*�+>�����' �

(����8�#���@�"�#��������������������� �����#������������#��� ���-'+<

! ����� "� � � ����#� �

! ��������� �

� �$������

��������������� �"�%&#

'������ �������"�%&#��

(���� �������� "�%��&&� ������� �#�

)�����������������

*��� �������� � +��,� � +��,�- � +��,�. "�%��&&� ������� ��&&#� +/0

)��������"�������$��������������������������������������������� ��

�!���������$���!�"�������(��� #���������������� ����#������"����#�������������� �����(����8�#���@ ������#������ �� ������� ��9��$�#�������������� �������������� ��������#��� ������#��<

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

:�(��'����� �� ������� .K

! �����"�� �����#��

'������ �������"�%&#��

,������� ����� $���!�������$���(����"���������9��$�#���������+�������������� ������#����� �������� ��$�9��#�����������+�����#�������������������<

! �����"�� �����#��

1����������2/23-4�2/2335&/3������

�//������65���� ����������&&���������

)����7��������� ��6�6/8/��72��/�2������

1�����4 �9����:��4� ���;�9�����

�������8�6�3&23�<6�25*���$

7����#����� #����� ����������� ���������<���#�F� �����@��A#������������������������@��A#��������������@ ���� �> �� ���������� ��#�����������+������� �� ��������� ��������������� ���(����������������<

� �����#+������� ������� ���4�"4��� @

� ����������"��������������������������9��������������� ������"� @

� ���9?�����������#�������� @

� ���9?������������+����&= @

� �����#�F� ���1���+>������%=�!�� @

� ���������������#�������$������%� @

� ����������� ����0�������������������#�������$���������0 �

�������$�� �������'������*�!(���������������������������#��������$�������������������#�$��@�����#;��$�+����������<

���GGM��.7B�� ���GGM��I=-�.7B�� !��GGM��3B.: %���GGM�����0��D�� %���GGM�����0

��' ��������$���������'�����*�!(���������:�@������8�#���@�����#�����#+��������������������#��� � ���$���� �� � �� �������� � ��������� � �9� ���� ������� ��� �� � ���� ����0 �� �3B.:@��8������#��<

! �����"�� �����#��

'������ ���������

=�$� ��"����*� ����� ���#�<

!���������������� �������� ��� <"='(9>?(9#

������� � �� � ����� � � �� � - � �!� �� � �.�� � (��� � 9� � ��� � ��#+��� � 9� � $�#�� � $��$� � �����������"��@ $�#�� � ��� �� �������� � .� ���� �������� � �����+� �� ��+�� � ����������� ����������>��������������8���� �������1����������������#������������ �@����#�����#+���������+�����������#������#�������9���������������C����#������������+���9��$�>�������#����������������

:� ����#��������������1������������������+�������������������8;�������#������+� �����*�����.���������#�� ����������� ��&�

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

Page 183: Metodología de la Programación

:�(��'����� �� ������� .5

)�" 2����� ������ � ��� ������

/���"�� 9��$�#����������������������@��������������������#������������"�����������������������������9������#��������'(����@���������#�������$�����������#��#�����*��#���:�������������$�#����������1�������9���������$����#��������#���� @��+�#���������#�������������#��#���

(��� �� ���#������ �� �� �������� � #1�� � �����*����� ���#�<

����%���� �������@�

2��� ��� �� �� ���� � �����#� � ���$���� ��0��@ �0��@ "���@ ����@ ��� > �������@� �� ����#+��������������� � 9��"�#��������#�������7�������#��������#����������������� ��%����� 9�������"���9�����#����@�"�����9�����$�>��������������������������������(����8�#���@����� ������#�������� ������� ������������0��0����?����������������������#�������$�����#;��$�+����������������������������'3/4���0 <

����%��$�5�������

����������#���������������� ��������#��"����������#�������$�������I���D��=-�9�������������������������"����0���������#�������"� <

����%�����������5

� *���#����@���������9����#������#1����+������������������9��$�#������������������������ �����������������#����������1�

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

?�3 ������� �� �������� ..

�.�2���,���� � � ����������� ���#��� 9� �+�#�� ����� �� 9? �����+�� �9���#�� � ���� � /�� � �����+�� � � �������� � �� � �� � �����#��������"� � 8��� ��� � �� � ���������� � � � � �������������)��9���������+�� ������>������$����#�������+;�����������������@ � ��#� � ��� ��#�������� � �)@ � )NN@ � ���� @����������*+@����� @�������������0����"�@����� @�������(����������@�?���������;����#���"���������9������#������*������������7�*�����������������������������������$�������#����������� �����<

� :�������$��D���������#���������9����������+�� �����>�������������������������������������"���������� � �������� � �� � ��� � �;*���� � D�+ � � � �����������"�� � �����+������ � ����� � ����� � ������ � ��$��D��� ��������@ ��9� ���� �� ����������������

� .������������������ ����������������@������������� �#> � �;����� �� � ��������@ � >� �9� ��� � ������� ����������� � � ���; � #> � ���#������� � ���� � ����� � ����#�������������������

� )����������9������������������ �9���������������� � �����+�� � � +���� � )��� � ���� � ��� � �����+�����������>��������������������#;������"������

�� �$���<44�����D���$���#4���0��$�P���*�*�Q�:�$�>������������������������������+�������9���0�����@�8������������������C�������>����C������������ ���:����*�������@��� #;� �������� ��� 2�+���@ .����@ �����"�@ :�� >/+�����������F�@���*�����#���������������A+������$���#������ � � � �����?� � ��� � �� � ����D��� � ��+�� � > � �� � $������������ ��*��� �����+������ �������� �� R��� � 7����C� ���#�"� '������0@ 9������������+�� ��+��������2�+����>����R�������0���#����$��������*�����0�

)��� ���������������>����������������������������#;����������@���#����������������������#;�����H���H�����@�������*��#����#�������� �����#;*�����B$��'�#���������"�*�����������������������.�����0�

�����������#���� � � � 9� � �� � �� � �����+�� � � �� � ����>� � �� � ����#���� � �������� �@����#�����0������������+��������F������"���������������������������������2�������������������+�� �@��� ������#������������������"�����9���������"�������(����8�#���@���������"�@�:���>�.���������������(�����,���(��1�*������*�#��� �#��������9�����2�+��� � �� � �� � �1*� � 7�9� � ��� � ��������@ � ��� � ������������ � #;� � �0������ � �� � ������������������ �#+�� ���#������>��������� ��S���#;�@������ ��#�����#�>��C�������������@���#+�?��������#������� �*��������������������������@ �������9�����+�+��#��������#�����#������������������������#��������������

2� ����9��� � ���#�@ ����� � ��� �"�� ��� �#;� 5������������6 ��� � ����� � >� �9�@ � ��� ���"��������+������ � ����>�� � ���*��#�� � 9�@ � � � ���"?� � � � �� � �������� � *�;����@ � ���#���� � ��������*���� � ��� � �����#��> � �� � ��������� � �� ���"�� ������������� �� ��� � ���#��+��������� #��� � ��������� � ����#�������0� � ��� ��������@ ������ ����*��#�� �+�����> ��� ������*������#;����#����������������������9������#���

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

Page 184: Metodología de la Programación

?�3 ������� �� �������� .6

.�� ���� ����3����4

7�#;�@����������+�� ������������������"�������������#���� ��������#��@�9���������������������������>��� "���� �����#�����5��"�6��E������������8������������#�����������)2���2J2�����������������������������������������������"����8������#�����#����<

� (��#�� � �#����� � � � ���+�8�� � ��� � '3/4���0 � � � ��#�����@ � ��� � ������� � �����������������������������#��������������������������"�����������9������"���9���������#�� � �� � �����#� � ����#�� � ��� � ����+��� � �����*�������� � ������������� � 9��$�>�#���$��$�����9���������������������������#����������$��������*��������������*A��#�����0���C+�����#����9�������������"� �

� (��#������+������"���� ��5��"�6�����������������+������������"�����@������8�#���@������� � � � ������������ � ���� � ������� � ��������"�� � � � �� � ��� � *��� � �� � ������� � �����*��#���9�������������������

���"���� ��5��"�6����#;��������������8���� ��>��9����������������#����#���������������������������� ��� �)2�� �2J2 �9���� �#�$��#;� � ����� �9���� �������� @ ���� � �� �9������������#���������������������+�8�����������

�.���5������� ���������������

�� � ���� � ����� � �� � ������ � ��*��� � � � ��� � ������������ � #;� � ����"����� � 9� � �+��� � �������������"�� � �� #�>��C� � �� *���� ���� ������ � �������� : �� �� $�� ������9������9����������+��������+�� ��>����$����#�������9�������#���������

���� �� ��������

H���H�������I�����@��#�����@�2��D@ ����@)���

:��� � ���#;���� � 9� � ����>� � ��������� � � ��0���@ � ������ � ���������������@ $�8� � �;����@ +��� � ���� > ��*���$����#���������#���#����������������������������������9�"������������������H������>���� ���� ������#�����

B$��'�#� (��*��#��������9������*�;������*�;������������������� ���#���� �($���:$�����)�����($���(�����

��1�����H���H������2��D0��*

(��*��#������+8��"������������#���������)�����2��D �

:���+� (��*��#����������� ���#�9����� ������#����� ������������(�*���1�����(+���$���

LG��0�#�H���"�'3/(���

(��*��#�� � 9� � ���#���� � $���� � �;����� � #���#;����� � > � *�;����������C���������������0�����H���"�������#�����������������+�

O�+LG)2G�����

(��*��#��������*��+���)242J2�

7#��'��#:1>��'��#�#�����*

�����8��C���������;���@�J��(@�"��������������@����

��������.�����0H����O��9����

3�"�*�����������������

��������B$���+�� )������������ �����

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

?�3 ������� �� �������� .:

���� �� ��������

O#����"������

T�����(��3"7#�>�

��������D�+��D>��D>* �

L##��#���OL���7����>'���

��������������������>�"C�����������������(��*��#����������� ����#���

O�"���������������

�2� ���������������������D����

@�*+ 2������������*��#���

��B�L@��>L ����0����������D������������������ ������#������ ��>L�����������IS:�IS'����������0�

�#���@�1���@�*���@�"� ������������0���

7���+��������0��

�������������#���������

7�#;�@ � #�$�� � � � ����� � ������������ � �0����� � ���� � #A������� � ��������#�� � �I���D�@�'3/4���0@ ���H:@����� ��������9����������"����������������9�������#+������������#��'3/4���0������������0����"�#��������#;�����

�� �$���<44�����$�#����0����� $�> � �� � ����� � � � ������������ � ���� � ���0 � 8��� � ��� � ����9�"������� ���I���D��

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

Page 185: Metodología de la Programación

@�*� ��������� �������� .?

�0������������ ��������)������������ �����+������ ��*�� ����� �������� �� �� ��������� �<

� )����*���� ������*�������������������������������#�����#��>������$�������

� 7���������� ������+������������������������������A��������$��$��$� �>����������9?�������� ��"�#��������������'3/4���0� ����������������#�����$����������+����������������@���9��������*��#��9�����������������������+�����������������������������#��� � #������� � ��� � ���� � �0�������� � �� ����������� � 9� � �� � ���#��������� � ���������8�+������$�+���$��$�����"��#���������������������8�#��������'(���� �>��9C���#��������� ����������� ���9? ������� � ����#�� �������� '3/4���0�

� �����*��������������������9?������������������9�����������D����"�#��������������

� .����#����@����"������������@���������*������*���������������������������#����������#� � ��� � ���;#����� � � � ����0� � � � �� � ��@ � ����� � ��"�� � ������@ � ���"����� 9��9���#���9����������������������#�@������

������*��#��� ��������� ���������������������������������"����������������������������������#������9��$�*� �� ��������������*�;������������������� ������#����������@�������"��������+��#�����������������������"C���������8�#����%&&0�&& ��7�"����@��+�����9������� ��������� ������������ ���� �� ���8��� � "C�� � �� #������@ �� ���*��#� � ��������� �����������������#�����0������*����& ��������������������?�����@������������#���������������������#���*�;����������#�����0���

������� ���#�����"���#����8�#���� ��� ��� ��������� ��������� � �� � ��������� ������*���������+������� E����������"��������*���#���������������>���������������"�����������������������#��#�������+�� ��

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

*�� ������5J;�)������ ���������"������-� ��5K�5� �����������6�K�

@�*� ��������� �������� .@

�0������ +������������ �����+������ ���������

�������*��#���9���>������������������ ����������#����������������������������������"������������������*����������������� ������#;��$�+��������$������������)2���2J2@��������#+�?� � �� � ����+�� � �������� � ��� � �� � �����#� � � � ���"?� � � �� � �� � �.B(@ � ,BB( � � � :�� � ������������������#�*����:H����)2������*���������� �������������

/���"���9�����$������������ ������"������������@�>����$�������������������*���� ����������@ �� ����� ���*���� ����� ����� ��#� �� ���#� � �� ���� $������ �� �� 9� ����#���������

�0���*� �������� ������

��������������������������#;���#�������������������������������� ���,�#������������9?�����������������#���������>�� #���+�����*�����������������������#���7�#;�@�$�+�;�9��������������*�������������9��

�0������� ���������������� �

�� ����� ������ ��+�#�� ������ �� �#������� � �� � ��+�� �� ������������ � � � ��� ������ �9� �$�>���������������$�+��������9���������*��#���9���������>������������������ ��������#�����#������������������0�������������������������������"������������������+���<��������#���������#+��� �����+����������������@�������#���������������#��� ��9��$�> ��#����������������������:���������#������������������#��� �@����#;��������+�������������"��#����������*��#� � ��#� �'(���� � ������ � ���� � >@ � �� � "�� � $��$�� � ��� � �����������@ � ������� � � � ������������ � ��'3/4���0�

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

*�� ������.K;�1����#��������� ������!������������!��������������6�K�

*�� ������.5;�+��������������� �

Page 186: Metodología de la Programación

@�*� ��������� �������� .B

�0���������,� � ���������������� ������6

B�������������������������@�> ����������������������������@�9������������������*���� ������� �������� ����� � #����8��

'3/4���0�����*��������������������"�������#�����#���������������������#�������$�����"����� A����� � ���� � �����#� ����� � �� � ��*������� � � 8��;�9��� � ���������� � � � ��������@��+���������>����$������)���������������������������������������������;������������#;�U������� ���������� ������������#������������C������� �>������#+�������56�

,���� � �$��� � $�#�� "���� � 9� '3/4���0 ������ � � � ��� � �������� � ��������"�� � ���� � �����#�������� ������$�@ ������$�@ ������ ������ ���#+����$��������������� �� �������������+�8����������������#�������$�����*��+������#����������56@�����������������������5���6�>����������������$����5��$�6@����� �����������$��������������������>�����#���������������������#���������"���������������#������������������9�����������������+�����*����������� )����9���#�����������������������#�����#�����@��+�#�������+���������������#����8�����������@�9��������#;��9��������������������+����������������#�������$�����*��+���

/���"�������+����������������#����8�@��������8����9C�������������>����$�������������@���������;��������������������9��$�#�������������� �����#��������$�������2���#���9������������;�5#�����6���������������+��������"?������*�������������������#����8� ���������#�������$�����*��+���

�� ���������@ �� �����#� �������"� �����; �������� �� �� ��� �>� ���� � #����8� ���;�������������������56��7���"��@����������������������$�+�;�������9��������������#���������������� ��������������#���(����8�#���@������������� ����������������#����������������������� � ��� �������� ������ �� �����#�� )�#� $�#�� "���� �����@ �� � ������������������ �����+� ��������� ���#������ ������ ������ �(�� � �� � �����@ �����+������#�� ���#���������#����8��������������������������� ���

�� � �� � ��*�� ���� "�#�� � � #� � 9�� � �� �����*���� � � �� � �� � �����+������ � ���������<������"� � ���������� � �� �#�� � *�;���� � > � '������0 � ��� �#�� � ��0�� � �,�#�� � ��� � ���������� ��������5��������������#��>�������/�������� ������� ���������

7�#;�@ �$�#�� � ������ �9� � ��� ������������ �� �I���D�������#������ ��� � ��� ����������������A��> �������A��������������������"��> ���������� ��!�> ���������� ��1 ���'������0� � ���� � ��*������ � 9� � ���� � ������#�� � ������ � �����#� �'3/4���0@ � �����#������������������������������*��#�����I���D�������"?�������������������(���������@�������������� ���� �.7B��@ �'3/4���0 ����#��� ������ �> �#���������� ������#+��@ ��� ��� �3B.:@ ������������� ����8���������

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

*�� ������..;�1��'���������� ����� ��������������(�������.KK@� �����������6�K�

@�*� ��������� �������� .G

�0���"�2����� ������

/���"������*�����������������#����8�@����"�����������#���������������� ������"�#��������8�� �� �����#� > � �� 9� �������� �� #�#���� � �������#+�� ��D�� � ��� ����������� �I���D������+��C������#�����������"��9��9���#���+��������������������:������#�������������'3/4���0���+������"���� �������������?��#��#�@��������+���9�����9���#���+���������������������������@��������9����#������+�#������#���������������� ��#��������+���� ���

�0���)������������ ��+ ������ ������7�

B��� � ���+�� � ���� � �����@ � �� � ���� � �������� � �� � ���*��#� � ���*���� � �� � ������ � ���� � ���;�����#��#���� � '�/� � � � ���H� � :� � ����#�� � ����� � � � �����9� � �� � ���� � I���D� � >�'3/4���0@��+�#����������9��������*����������������������������������*��#�����*�������� �������� ��#���������#;������� �$�>������ ������#��� ���������@ ��F��?����� �� ���#��A�9����������;����������������������@������#��9�����#������*�������9?������#������#������+�8���

�0�"�8 � ����� ���7� � �

�� ��*A��#�#���� ��� �������� �� � ��������� � ��� � �������� �9� ��� ���� ����*��� ���� � ������9���� �� � ������������ �9� �����#�� � ��������� ������ � ���*��#�� � ����� ������ � �*��������*A��� � ���� �� �(�� ��8�#���@ �$�> ���*��������� �9����� ����>��� ��� � 8�*��@ ����� �9���������� ����*��#�� � ����������� � ��� � �� � ��������� � � � ����D���@ � ����� �2�������� �� � ��������+�� �@�����#���$��������������� ��#;����#������������������

�����"� � ���#��� � $���� � �� � ������� � ������� � � *���� � � ���9���� � >@ � �� � �� � ����#��@����#�� $���� �� ������� � ���"��� � ��� �� � ��� ���*��#�� 9� 9���#�� �����������*����� �

3� ������������������������������#�#������������9�������#������������� ��������>��9�@��� "�� �������� �� �����#�@ ���#�� �*��*�� ��"�� ���*��#�� � +����� ��� 9� �� ��������������(�����������@�+�����C������$��������������� ��+;��������������������7��#����@����C�����"������� � �������� � ��� � *���� � � � ������������ � � � ��������� � > � � � $����#������ � �������*���� ����������#��

�0�)���� +������� ����� ��

(��� ���+��@�>���#+�?���������������������+�� �@�$�>�9�������*������*�������#����������������<

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

*�� ������.6;�-�������������"��� ������������ � �'����������������� ��������� �

Page 187: Metodología de la Programación

@�*� ��������� �������� .J

� ����������!�����������'������������������#������� ���������������������������9�����������"���*���������$��������9���������� �����������������#�� ���#>��#���������������������������������+�8����������@���������������������#��������� ������������ ��>������*���� ������������"�����������������@����� �

� �/�������������� ��������#�� �7�#;���� �����������@ ������ ������#���0�����;�� ���������� � ���#����� � 7� � #���� � �+��C�#�� � ����� � � � ����� � ���� � ������ � ���+�8��$�+����� 3������#��������+����F�����$������"���������@�>��9�����#���$����������"��������������������"�������#��'3/4���0�

� ���*�0���� � ���$�������� � B�#���� � �� � �#��������+�� � �����*��� � �$��� � ���� � ������������"��� �� ���� ����@ �����#�� ���� � � �F��� ��� �#�������� 9� ����#��@�����*�����������8���������@���������0����������;#+�����@�������8�����������@������

� 7���"�� � � � ������"�� ������!��� � ��� � ����'�� � ��� � ���"����� �� � ����������� � �������*��#���9������������8�����������*��������@��������������*�;����@�>��>��#��� �����*�����������*A������������������#��������������#��������������� ��������������������� (����8�#���@�$�+�;������"�����9�������������������������#����� ��������������� @������9��*��������������������������"����D�+��������9������#���9��������������������������"����D�+ @�������'������#����@��������"������������������9������+;������>���#;�@��9�������������������9�����9��$�>�#�����������������������������"����

� ��������������#���9����������#���������������������0�1*�!�������#�������(���������@��������#� '3/4���0@��� ��������@����������������$���������9�������#�����?���������� �� �������� �� #�� ��0�� 9� ���#��� �8����� ������������ ���� ��#����������� '3/4���0��2��������������������#��@ ������������������@ � ������������������*�;���� �9� ����#��� � ���+�8�� �����#�>�� ���#���� �:�� ��#+��*�@ �> ������ �9� � ���$�+��������9�����+�8�#�����������������*�;��������������&&V�������#��@���������������� � �� � ����+���� � � � ������� � ��$� � ������� � ���#;����#���� � �� � ��#����� � ����8���� ����������#��

� �!���� ���$�&����� ��������������H+��������"���"�����������������9�����9��$�#����������� �������������)2���2J2���������������9��$�>�#��������*�������"��#����������������������

0�. �� 6 ���� 9��: ���������� ��,����

������������� ��"�#������������������8�#������������������������ �< � ��������+�� ����'3/4���0 /+�������$��$��������*���?��������+�������#��������� ��>���������@���C���#�������������������������� ��>����

J�#���� �������9������������#�����+������#;9���@�����������������-&�'��@�9��>������� �������� I���D� L(�(���������� ����� A���� ������� � � ��� ��#�F��

���� � �� � (�!�� � ����% � �� � �'$����� � ����� �� � ��� � !�$�� � �� � ��0������ � �� � �����*��'�!�"� � �'$����� � &�� � $���� � �� � �� �'1&����� � ������ � 9� � "�#�� � � � �����������#+����#>��#���������@���#��������#�������� �������������������@������#��9�������*�������@ �������+���9���������������������������9�����C��

(���� �������� ���#�����2J2��������������� ��� �� � �#�*���+��G���&G"G��%�����@ �9��������������A���#�������+�� ��������+���������#�#���������������� �����������#���������?������� ����>��'3H��@�������������������+�8��9� ��������� ���������� ���������>�$����#�������#>�� #���������*����������� ������#�� �B�#+�?���������+������������������������+������ �9� ��� ����"�� �� �/+��@ � ��#���� �O+��@ �9� � ����>� ��� ����������� ������+�8��O2����

�� $��"��� � ��� � �� �� �������������C(�!�� ��� ��� � � ���� � �� ���"��� ������ ������� ��� �� ������L3���� ���������

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

@�*� ��������� �������� 6K

�0�.������!����������������

(������#������������������ �@��������#������2J2�������������)2�H��>�$���#���9����������#� �����9� ��� ?���� )��� �������@ �� ��� �������� �� #��A � �� ��*�� �����9���� ����������#��A $�#�������"���������� ��5���*�*�6��������������.�@������9������������������������ �������F��������$� �

(���������������������#�@�������#�>��C�������������@�+�����;�����������������������#�������� �@��� ����@ �� � 5������� � �������� /+��6� �� 2J2 �� � �� �������� ��� �� ��������� ������������@��������#+�?���������+���������������/+���>����������������"���� ����� �

/�� � "�� � ����������� � ���� � ���#�������� �@���������#�������������"���� ��������/+��@������#��9�����#������������ � ��������� � � ��#� ��� � �������� � #;����������#���(��������@�������*������A�������������#��>���*������� "����������+����� � 9� � ���+�8��� � )�#� � �8�#���@�#�����#�� �� ��*�� �-@ ��� $�#�������*�� � �� � #��A � 5:����#� � GM�7#��������� �6� �:� �����"�� �9� �� ����� #������ ��� �������� ��#��������� �@���9�����������������"�*�� � ��� � �� � ����� � � � �������� � ������������������������+�������

)�#� � ������ � �����?� � ���; � �� � ������������ �@ � ���C�#�� � ����������� � ������� � �������� �� #��A �#��������� ����#� � �� "� � �� � �� � ��*�� @ � � � ������������#���� � �� � �� � ����� � 5�������6 � 9�����;���+�� ��������������

(�����������@�>��������������#��#��#��A@����#���"���������� ��5����������������������'��#�6��'(���� @�9�����#�������������������������5�������6@������������>���������������������������������

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

*�� ������.:;�$����"����� ���3M3�

*�� ������.?;�$����"������������������ �������

Page 188: Metodología de la Programación

@�*� ��������� �������� 65

�0�.���*�������� ����� ������

�����#�� � �� � ����� � � � ����������� � ��'��#� ���� �������� �� ����������� ��������������������������� ��������#�������$�������������� ��9�����/+������'(����@ � 9� � >� � $�#�� � ��������� � ��������������������������������������������������������������*������

(��� � ���*�� � � � ���� � ������� � $�#������"�������+����� ��*������������<

�� ���#������������������� ����������9� �����+�� ��� ��� ����� �$������=��&�'���

�� )���� � �� � ��"� � ������� � � � � ��#�F� � � � '�� � ���� � �� � �D��� � ,�#�� � ����� � 9��������������������� ��5���0G�D��6�������#��A��������#�������$�����

�� )����������"��������� ������#�F���&�'����������0�� ��������������#��

�� )����������"��������� ������#�F��=�!&�'����������0�� �����������������������

�� �� � ��*�� ��!� �� ���������� � ��� �"������� �9� $�� � �� ����������� �� � �� � ���*� �� �������#�������������

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

*�� ������.B;�(��'������ ������������������� �

*�� ������.@;�)���������������� ���

@�*� ��������� �������� 6.

.����#����@ � ������#�� � ��� �#������������ � 9� � $�#�� � ������ > � �����#�� � �� � �������� ��'(�����

�0�.�"�8 � ����� ������ �

)����������������������������@������#���������*��#������������� �����������+������������5�������6����������������

7���������� �@�����#���9�������������*�������*�������#���������#�@���*� �@�$����>����$��>������+�� ���������� ����������*����%�������������������������������"��������9��$������������������������������� ��

�����*���������� ��������������� �������������������������������������������������@���������#���������*��������������#�����9������#�����������������������*����=��� ��������������������������9�����������

� *���#����@ � �������� � ����������#�� � �� � #?��� � #���� � >� � 9�@ � ���"��#����@ � $�#�������������� ��������������� '(����������������������������9�����������$+�?��#���$��$�@����C�#���$�+����+��������#��A���������������������*��@�>��9�����C��������������������#� ��#+��� �� ��#�F� � �� ������� � �0������� � ������� �� ���� ��+�� 9� $�> �� �� ������� � �� �$�> � ��� ����9��� � ����@ � ���#��� � ������� � �� � ���� � �� � ���� � �#����@ � 9� ��� � �������#��������� �����������������#���0����#�������#������#���

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

*�� ������.G; )����� �������� ����� �������

*�� ������.J;�(,�����������������

Page 189: Metodología de la Programación

@�*� ��������� �������� 66

2���?���������������� ������� ��#���� �> ����"����� ���� ��� ��������� �@ �����#��������"������ � #�������� � � ������������ �� ?��� ���#�� "�� ��� ����������� 9� >� $�+C�#����8�������'(�����������"����������������������#;����#�����������'(����@���9����������#�����#��������#��������������*����&����#�� "��������������������������9�@���#�����$�#�����������������@��������������(��������@�� ��������#���9���������9��9���#����"��������������������� ��

/�� "���9��$�#�� �������������������@�� ���������������������������*����������#��������������������������������������#���9�����������������������������#�����#���������'3/4���0@ �� �� ���*�� �� �����@ ���� 9� �� ����� � ��#+�� � ��������� W9� ���;"��C�G�����#��������������(��������@����"�� #�����@����#��������������������������������������������������������������������$������

�� � ��*���������� ���� �� � ��������� ����@ ���� � �����@ �����*�� ��� ���#+���������� ��������������� ���"�����#�������������������������������*���������#���"������ "�������

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

*�� ������6K;�)��������������� �������� �������

*�� ������65;�)��� ����������

@�*� ��������� �������� 6:

�������*���>� ����>�������#+�����������������#����8��9��$�#���������������������������������� �<

�� ������#����������� �����#����#������������������ ����� ����(���������@ ��������#������������� ����������@ ���9�� �� $�#���������#����#���������������+�� �����#+���#;���;��������������

�� �����*���������� ����������������;�������D����E����������������� ����������@�>��9� � �� � ����#�� � 9� � ������ � ���*A� � ���� � � � #����8�� � �� � �����#� � �� � �����*�����#;����#������������*�������������������#���������#+���

�� �� �� ������� ������� � �� ��� ����#�� �������� �� �����#�� (�� �����@ �� ���� �#����8�����56@��������9�����*��;�������������#�@�����>��������������������������#������������������

�� ���A���#��������� ���������;����������������������� �2���9��?��������������������������� ���+�8������ ��@�����������#��������������������#���������#����8����� � $��$� � � � 9� � ��� � ������ ���*�� � �� � ���� � �� � ���� � ��������� � �������� � ���#������#����� �� �����#�� (�� �8�#���@ �� 9���#�� �������� �� "���� � #;�#������� �/+��@ ����#�� � �������� ���� ��������� � �� � ������ �9� ��� �����#������#������������������ ���H+���"��9������������������$���������*�� ���� ���#��������� �� ����#������#����� � �����$� ������� ��

:� �������*� � ��� � �������� �9� ��������� ���#������� �� �#����8�@ � ���; � "�� �9� ��0��������*��� � ���������� � ����������� � (��C�#�� �������� � ������������� #;� � ��#���8������������������*�����������������������������������������������

/�� � "�� �9� ��#�� ���#� � ";���� � ��� ������ � � �#����8� � > � ����#�� � 57������6@ � �� � ����������������"����������"����������������� ��������#�������$�����������*���������#�� "������� � "������@ � ��� � �� � ������ � ��*��� � � � ��� � �������� � 9� � �� � $�� � ����������� � > � ����#�������������#;���#����������9�����"��������������

7�������#����@����������9�����*�������������9��'�/�������������;����������#�����������5���6@�;������������� ������#+������

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

*�� ������6.;�� �������� �����

Page 190: Metodología de la Programación

@�*� ��������� �������� 6?

�0�.�)�����������;�� ����

:������#���������������������������9� $�#�� �����������@ ���#������� �� �+�� ��5�������6 ���� �� �"�������������*�������

7 � ��������� � ���������; ��� �"�������������+����������*�����>������������#����8���9�������������������9���� "�� ���������� �� �� ��*�� �� ��������������#���8�#���������#�#���������������������"�������

)��� � �� � ��������� � � �� � $� � ��#������@ � >�����#�� � ��������� � �� � �����#� ����� ����� � �������(��� ����@ �� ��� �������� �� "������ � �� ��*����� � (�����#�� � ��+�� � 5��������� � �$���6� � )�#�����#�� � "�� � �� � �� � #����8� � 9� � �� � ���#��F�@��+�#�� �0����� �� 2J2 � ��������� � � /+�������9�����"��"����������������

.����#����@����?�������������@���������;���#��A���������� �@��������#���������������#��������������������������������/+��@��$�������������������� ����������������

�� �� ��*�� �- ���#�� "�� ��� �������� ����+������� ��� #;� ������������ ����������� ��� ���#���@������������������#��#�����/+��@�>����A���#�@�9���������������������9����������#��5I���D��L(�(����������6����"��#��������������

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

*�� ������66;�*� �������

*�� ������6?;�����;����&���������"���

*�� ������6:;�*� �����������������

B�$����� ��� ��� '���� 6@

�<�5�+������� ���� �� ��� ��� ���� ����� � �� ����� ��+�� ��*��� ��������� 9� �� ����� �������� �9����� 9� ������������������������� ���������#���'3/4���0�

<�� 8�� ����� �����7� ����

������������9�������#��#�������#��������@ ��� �#����@ ��������������#����������"�����������@ � ��#� � ��� � �8�#��� � ��*�� � "������� � � � ��������� � I���D� � ��I � > � ��*�� ��'3/4���0� ���#;�@���������� ��$�+��������������9�����������'3/4���0��������#����"��@����9�����*���>�����������������������I�>�9����#;��������� ����&&V�

:� ������ �� ������ �@ ��*���"����� ����+����������� �������� '3/4���0 �� ������ ����<

� ���#���� ��������#��������>�����������������������#�����#���������@������������ ������������#+��������#���������������������������������#������������������"�����������������#������������ �����#������#;����������������*������������<

�� (��������������������������*����������� ����#��'(��������������� :>���#�������)2 �

�� ����������I�

�� ���������'3/4���0�

����#�������� ������������������������I�>��9��?���������������#>���#�������������������7�������������@�����������������$����������������� �����I���+������������� �����������@������������������ ��9�������� �����������?���@�>��8��������������������� �������0�������������F����������"�����������������������#�������������������� �

(�� � ���� � ���@ � ���"���� � 9� �'3/4���0 � ��� � �� � ��*�� � �� � ���������� � >� � 9� � ����*���������������9��9������>���'�+������H ����#�����������������9��������9��#����������������+��������8�������I�

(�� ������@ �� �������#�� ���#��� '3/4���0 > ����� �I@ ���� A���#� ��������; ��������*�������������9�� ����#������'�+������H @ �9����������� �����8���������*A�������#��9�����"���� �������� ��������������� ���������9��������� �9��5+���� '3/4���06����� 9�@ ��#���#����@ �� �*�����> �� #������� ����� �� ������

� /��� � ��*A� � ���*��#� � ��#� � '(���� � ���� � ���#�������� � ��� � ����������� � 9� � >������#��������I�>�$���� � ����� ����� � ��� �� �'3/4���0� �7 ���������� � � �������#���'3/4���0� ��������� �����;�#;�����������9�������������@�>��9���"���#�������������I������������������

7�9��������������#���������������� ��������#�����I�>����?��'3/4���0@���#+�?���� � ��� � $���� � �� � ��"?�� � �� � ���+��#� � �� � 9� � ���� � $�+�� � �������� ��I@ � �� � �������� � �������������������������*A��#��A���������*�����������#��9������#�����������>���#���������8���������I��������� ����@�$�+�C��9������������� �*�������������9��9��$+�?��#����������������'3/4���0��(���������*����������#+�?��$�>�"��������#���������#;� �����������������������������2J2�����������+�� ����'3/4���0�9�����*�#������������>���������������#������������7�"����������������*������� �������C�������������������������*�����������9��

:��������������+�� �������������������+�����$�+�C��9���������������#������������������2J2 ���*�����>���������@ �#����#����@��� �*�������������9���H�+���@������"?�����2J2@��������������������� ��9������#�����������������>���������$����#��������������*���� �������"��"�����������������*�������������������������;�����*������9������#��������>�����������+�� ��

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

Page 191: Metodología de la Programación

G�$����� �������� �� ���, 6B

�=�5�+������� ���� � � ��� �>�������������������� ��

(;*������:>���#�������)2@��������#�����0�+;��������������8�������������������9�����#�����������������������#������#�������������������������#�������������������@ � �������� � �����#�� � ������ � � � ��*��� � ����� � � � ������@ � �������� � +��1�� � �������������@�����

����������� ������$���������

(;*��� � 9� � �������� � � � ������ � � � ������������ � ��+���� � �� � #�>�� � ����� � � � ��������������������0���������"��������������I���D��>�'3/4���0��7�#;�@�����������������������������@ ������+����9�"�������������#����������D������#�������

������������������ �� ������������������ ��

�������������+������������������

������ ����� ������������������������&5������$����

����������������� ����'3/4���0��/+�� ���������������������� ��>�)�������

�=���2���,���� � � ���������

���������� ������� �����$����B��������7:9

(;*��������������������;�������#��� ����+�����;�����#��������9���������+�� ����'3/4���0��0��������

����������������� � ���������������%���� �

(;*�����D�+�����������+�� ��/+������*�?��>����������� �

����������������� �� ����������������%��� ��

(;*�����D�+�����������+�� ��O+������*�?��>����������� @����"����������/+���9�����O2������*�����'��#����#��*��������"��������

������������������� � ����������� ���������

����������� ���$%��� �� ����������� ��������

��������������������� �� ����������� �������

���������� ������ ���%������$ ����������� �����

/�����(��%��#�0�������$������������1�������2�3����1���� �������1�����������*��$��4������ ��������������

����������� ����������� �������� ���� ��

������������������������������ ����� ������� ������������(�� ��� ����!� � � *

���������������� ��������� �����������������������

��� �� ����� �� � ��� �+ ����,�� �������� � �-,�� ��� � ��,� �� . ����,� ���� � ��

��!������������� ���"� �� �

� # �����$ ������,���������������/�������� ��,� ���� �� �� ������ � ������� ������������� ����

� �����$ ������$���������0 ���� ��,� �� � ���������� ���

� ��$%�������!�����$�$���� ������� ��� ����� ������ ��� ��,� +������ ��� ��,� ��� � +��������������,���� ��,� ���� � , 1���� ���� �/��� � /�� �

�� ����0 � � ����,���� �,� + ���2� �1 � ,���� ������ �/������� � ���� ����� ��,� �

����� ���� ������������������ ��� ��������,����������������� �����������3����� �����

���������������� ��������������������������� ������� ������������ �������������������� ��� ����������� ��������

��������������������������,������4����� ��(http://creativecommons.org/licenses/by-nc-sa/2.5/es*

�%

Page 192: Metodología de la Programación

Introduccion al Sistema Operativo LinuxMetodologıa de la Programacion II

Departamento de Ciencias de la Computacion e I.A.E. T. Si Ingenierıa Informatica

Universidad de Granada

Objetivo de este documento

El objetivo de este documento no es el de ensenarel SO UNIX/Linux, sino el de proporcionar, sobrela base de los conocimientos de que se disponensobre MSDOS/Windows, el nivel de conocimientoadecuado para el normal desarrollo de las practicasde Metodologıa de la Programacion II. Para obtenerinformacion adicional, consultar la documentacionque se referencia al final de este documento.

0

Page 193: Metodología de la Programación

Indice

1. ¿Que es Linux? 21.1. Historia de UNIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.2. Historia de Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.3. Distribuciones de Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.4. Caracterısticas de Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

1.4.1. Multiusuario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.4.2. Multitarea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

1.5. Linux y Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2. Manejo basico de Linux 52.1. Arranque, login y cierre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.2. El arranque en el aula de practicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62.3. La shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62.4. El sistema de ficheros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2.4.1. Ordenes basicas de directorios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72.4.2. Permisos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82.4.3. El directorio home . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92.4.4. El directorio / . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92.4.5. Otros directorios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

2.5. Multitarea basica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

3. La Interfaz Grafica de Usuario (KDE) 133.1. Conceptos basicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133.2. Algunas aplicaciones en KDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

3.2.1. El navegador de disco . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143.2.2. Un editor de textos: kwrite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153.2.3. Netscape . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153.2.4. StarOffice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

4. Ordenes de UNIX 194.1. Ordenes basicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194.2. Ordenes basicas sobre directorios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204.3. Ordenes basicas sobre ficheros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214.4. Ordenes de gestion de permisos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224.5. Ordenes del sistema de ficheros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224.6. Ordenes de gestion de multitarea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

5. Mas informacion 235.1. Documentacion dentro del SO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235.2. Documentacion en Internet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235.3. Revistas disponibles en la biblioteca de la Universidad de Granada . . . . . . . . . . . . . 245.4. Libros disponibles en la biblioteca de la Universidad de Granada . . . . . . . . . . . . . . 24

1

1. ¿Que es Linux?

Linux es un sistema operativo de la familia UNIX que se ejecuta en PCs domesticos, ademas de enotras plataformas hardware, y es totalmente gratuito.

1.1. Historia de UNIX

El primer sistema operativo UNIX fue desarrollado en los laboratorios AT&T Bell de estados Unidosa finales de los anos sesenta y no pretendıa ser un sistema operativo (SO) comercial sino que se habıadesarrollado con el objetivo de proporcionar un entorno de programacion altamente productivo a ungrupo de expertos programadores.

Debido a sus caracterısticas y prestaciones, los departamentos de informatica de algunas universi-dades estadounidenses se interesaron por este SO y comenzaron a utilizarlo intensamente gracias aque AT&T puso el codigo a disposicion de instituciones educativas. Esto provoco una gran extensiondel UNIX, al que algunas universidades fueron anadiendo caracterısticas propias y creando sus propiasversiones. Aunque los laboratorios AT&T eran los propietarios de la version principal de UNIX (SystemV) surgieron tambien otros “dialectos” del sistema UNIX principal como son: Berkeley BSD (creado enla Universidad de Berkeley en California), POSIX (una evolucion de UNIX al amparo de la sociedadIEEE) o X/OPEN (el estandar europeo de UNIX muy relacionado con POSIX).

1.2. Historia de Linux

Linux aparecio a principios de los 90 inspirado en una pequena version de UNIX llamada MINIXy fue implementado por Linus Torvalds, un estudiante de informatica de la Universidad de Helsinki(Finlandia). Aquella era una version muy reducida que ha ido creciendo con los anos gracias a lasaportaciones de numerosos equipos de programadores a traves de Internet hasta llegar a lo que hoy seconoce. Actualmente, se podrıa decir que Linux es una reimplementacion de POSIX con extensionesde BSD y de System V, que incorpora todas las caracterısticas de un verdadero sistema operativocompetitivo: multitarea real, memoria virtual, comunicacion por redes, amplio soporte de dispositivos,etc. y que presenta la ventaja de su caracter libre (no creado ni poseıdo por ninguna empresa) y de quesu codigo fuente esta disponible y es gratuito.

1.3. Distribuciones de Linux

Sobre la base del trabajo de Linus Torvalds, que diseno el nucleo de Linux, se empezo a extender eluso de este SO a traves de internet al que se le iban anadiendo el resto de aplicaciones y utilidades. Deesta forma, en unos casos se empaquetaba el nucleo de Linux con una implementacion determinadade estas aplicaciones y en otros casos se empaquetaba con otras implementaciones de las mismasaplicaciones o incluso con otras aplicaciones. Cada uno de estos paquetes, que consta del nucleo y delresto de aplicaciones y utilidades de Linux, es lo que se conoce como una distribucion. Existen muchasdistribuciones, disponibles a traves de internet o en CDs que se reparten con revistas especializadaso a traves de compra directa, de entre las cuales, las mas conocidas son: RedHat, Debian, Slackware,SuSe, Mandrake o Corel Linux.

En principio, lo que se comenta en este documento es generico de Linux y es comun a todas lasdistribuciones, aunque si surgiese algo especıfico de una distribucion u otra se introducira una notaaclarativa.

1.4. Caracterısticas de Linux

Una de las principales caracterısticas que se pueden encontrar en Linux es que es un SO multitareay multiusuario.

2

Page 194: Metodología de la Programación

1.4.1. Multiusuario

En algunos SO esta previsto que un mismo ordenador sea utilizado por varias personas y permite lacreacion de perfiles de usuarios, en los que se almacenan sus preferencias y opciones de configuracionde cada usuario. En el caso de Windows 9X, todo el ordenador es un recurso compartido, desde laimpresora hasta los ficheros que contenga el (los) disco(s) duro(s) y, aunque tenga definidos variosusuarios, solo uno puede utilizar el ordenador en cada momento. Sin embargo, en el caso de UNIXes un SO multiusuario real. Esto significa que no todo el ordenador se puede compartir por todossus usuarios; algunos de ellos tendran acceso a unas partes y otros tendran acceso a otras partes.Normalmente, los dispositivos del ordenador son compartidos por todos los usuarios y los ficheros delos discos pueden ser privados o compartidos. Ademas varios usuarios pueden utilizar el ordenadorsimultaneamente.

Para implementar los mecanismos de seguridad UNIX se basa en dos conceptos. Por un lado en laidentificacion de cada usuario o grupo de usuarios con un nombre que se asocia con cada fichero delsistema de ficheros (discos duros, CD-ROM o diskettes) y que describe quien es el usuario que posee elfichero y a que grupo pertenece. Por otro lado, para cada fichero se reservan 9 indicadores, agrupadosde tres en tres que definen que operaciones se pueden realizar sobre ese fichero. Estos indicadorespueden ser una ‘r’, que indica que se pueden realizar operaciones de lectura, una ‘w’ que indica que sepueden realizar operaciones de escritura y que se tiene capacidad de borrar el fichero y una ‘x’ que indi-ca que se pueden realizar operaciones de ejecucion. Los primeros tres indicadores hacen referencia alusuario que posee el fichero, los siguientes tres hacen referencia al grupo de usuarios al que perteneceel dueno del fichero y los tres ultimos hacen referencia al resto de usuarios del ordenador. Para el casode directorios, el significado de los permisos ‘rwx’ es ligeramente distinto y se comentara mas adelanteen la seccion 2.4.2.

De esta forma, con estos dos mecanismos, para cada fichero se almacena que usuario es su dueno,a que grupo pertenece, que operaciones puede hacer el dueno, que operaciones pueden hacer loscompaneros de grupo del dueno y que operaciones pueden hacer el resto de usuarios. Por ejemplo,considerese la descripcion de los ficheros que aparece en la Figura 1

u g o uid gid fecha ficherorwx r-- --- user1 group1 Apr 4 14:00 /home/user1/file1rw- rw- r-- user2 group1 Feb 3 10:00 /home/user2/file2r-x r-x r-x user3 group2 Jun 3 1:00 /home/user3/file3

Figura 1: Ejemplos de derechos de acceso. u: derechos del dueno, g: derechos del grupo, o: derechosdel resto de usuarios, uid: identificador del dueno, gid: identificador del grupo del dueno, fecha: fechade la ultima modificacion

En esta figura se puede ver que el fichero file1 tiene todos los derechos para su dueno (user1),que user2 puede leer este fichero pero user 3 no. Con respecto a file2 se puede ver que su dueno(user2) puede leerlo y borrarlo, pero no ejecutarlo, que user1 tambien puede leerlo y borrarlo y queuser3 solo puede leerlo. Con respecto a file3, su dueno (user3) puede leerlo y ejecutarlo, pero nopuede borrarlo y lo mismo pueden hacer con el user2 y user 1 y cualquier usuario del ordenador.

En todo sistema UNIX existe un usuario especial, el administrador del sistema, al que el SO le otorgapermisos para hacer cualquier cosa en el sistema. Este usuario, cuyo nombre siempre es root, es elencargado de todos los temas de configuracion y administracion del sistema.

3

Ejemplo

En los ordenadores personales, en los que el propio usuario posee lascontrasenas de root y las suyas propias, es conveniente utilizar para eltrabajo habitual la identificacion personal y dejar la identificacion comoroot solamente para cuestiones de instalacion y/o administracion pues,dado que root tiene siempre todos los derechos, los errores que se pu-diesen cometer podrıan llegar a ser catastroficos, mientras que utilizandola identificacion personal, el impacto de estos errores es siempre menor.

Ademas de esto, UNIX tambien permite personalizar el sistema y definir distintas preferencias paracada usuario sin que los cambios en un perfil afecten al resto de perfiles.

1.4.2. Multitarea

Algunos ordenadores pueden ejecutar varios programas a la vez porque tienen mas de un proce-sador. Sin embargo, la mayorıa de los ordenadores tiene un unico procesador por lo que solo puedenejecutar un programa a la vez. Sin embargo, a pesar de esto, existen algunos sistemas operativos comoUNIX y, en parte Windows 9X, que permiten alternar el uso del unico procesador entre todos los pro-gramas que se esten ejecutando y, aunque solo se ejecuta uno cada vez, dado que se van alternandomuy rapidamente, da la impresion de que todos ellos se ejecutan simultaneamente. A esto se le conocecomo multitarea. UNIX es un SO multitarea real, tal y como se vera mas adelante, y ofrece total controlsobre todos los programas que se esten ejecutando en un mismo momento y la ejecucion de uno deellos no afecta al normal desarrollo de los demas. Esto no ocurre en muchos SO de la familia Windows,en los que el control de estos programas no es total y donde el “cuelgue” de uno de ellos puede dejar“colgados” a los demas.

1.5. Linux y Windows

A la hora de utilizar Linux, siempre surge la necesidad de comparar ¿en que se diferencia Linuxde lo que ya tenemos instalado, normalmente alguna de las variantes de Windows? Algunas de lasdiferencias mas significativas son las siguientes.

1. Ninguna de las versiones de Windows 9X es realmente multiusuario pues solamente soportaperfiles de usuario y no existe una gestion mınima de derechos de accesos al sistema de ficheros.Solo Windows NT y sus derivados (Windows 2000, XP) son realmente multiusuario.

2. Ninguna de las versiones de Windows 9X permite a varios usuarios simultaneamente ejecutarprocesos en una unica CPU.

3. Ninguna de las versiones de Windows 9X implementa una multitarea real, aunque lo parezca, estosolo esta conseguido en las versiones de Windows NT y sus derivados.

4. En todas las versiones de Windows 9X y algunas posteriores existe una gran confusion entre loque debe ser el nucleo del SO (soporte de dispositivos) y la interfaz grafica de ventanas, llegandoa darse el caso de que algunos dispositivos se reconocen sin mas en el arranque en la interfazgrafica (CDROM, tarjeta de sonido, raton) pero necesitan controladores (drivers) especıficos parael arranque en modo texto.

5. A pesar de estas diferencias es necesario reconocer que Windows y sus derivados estan profun-damente implantados a nivel mundial y son el sistema de referencia para muchos fabricantes dedispositivos. Esto hace que instalar los controladores para un dispositivo nuevo sea algo senci-llo si se dispone de Windows, pero puede convertirse en algo complicado si, por el contrario, se

4

Page 195: Metodología de la Programación

dispone de Linux 1. No obstante, hay que reconocer que este no es un problema de Linux, comotampoco lo es de Windows, sino de los propios fabricantes de dispositivos que no reconocen elpapel de Linux como SO competitivo a nivel mundial, aunque esta actitud esta cambiando.

2. Manejo basico de Linux

Una vez comprendido que es Linux, esta seccion se centra en su manejo y en la explotacion de suscaracterısticas.

2.1. Arranque, login y cierre

Una vez que ha arrancado la BIOS del ordenador, se ejecuta un programa cargador llamado LILO(LInux LOader). Este es un cargador muy versatil que reconoce practicamente cualquier SO que hayainstalado en el ordenador y permite arrancar con cualquiera de ellos.

En caso de haber elegido arrancar en Linux, a continuacion se carga el nucleo de Linux, se comprue-ba que hardware hay disponible y, en caso de que todo haya ido bien, se pasa el control a otro programa(init) que termina de cargar algunas partes del SO y deja el ordenador listo para ser utilizado (VerFigura 2).

Figura 2: Pantalla de Login de Linux. Sera necesario introducir el nombre de usuario y la contrasena

En este momento es necesario identificarse frente al ordenador proporcionando un nombre de usua-rio y una contrasena y se comienza una sesion de trabajo (que se comenta en la siguiente seccion).

Al igual que ocurre con otros SO, no es buena idea salir de Linux apagando directamente el ordena-dor pues se pueden perder algunos datos. Antes de poder apagar el ordenador es necesario salirse dela sesion de trabajo y salirse del SO. El fin de una sesion de trabajo se indica con la orden exit y paraterminar el SO y reiniciar el ordenador utilizaremos la combinacion de teclas Ctrl+Alt+Supr (existenotras formas de cerrar el SO, como son reboot, poweroff y halt que se comentaran mas adelante).

1Para saber si un determinado componente hardware es compatible con Linux se puede consultar la lista de com-patibilidad de hardware (Hardware Compatibility List o HCL) de cada distribucion disponible, en el caso de RedHat, enhttp://hardware.redhat.com/hcl/

5

Figura 3: Secuencia de funcionamiento de Linux

2.2. El arranque en el aula de practicas

En el aula de practicas el arranque es muy parecido. Tras la introduccion del nombre de usuario ycontrasena genericas de las aulas de practicas de la Universidad es necesario elegir un modo de arran-que en Linux y, despues la ultima version que se encuentre instalada. Una vez que se haya completadoel proceso de arranque de Linux, la pantalla de login es la misma que la comentada anteriormente.

2.3. La shell

Una sesion de trabajo comienza con el arranque de una shell, un programa del SO que se encargade hacer de interfaz entre el usuario y el propio SO, leyendo ordenes que este introduce, ordenandosu ejecucion y mostrandole los resultados obtenidos. Para ello, la shell del SO muestra una lınea conapariencia parecida a la siguiente, que se conoce como lınea de ordenes (en ingles command line oprompt)nombre-del-ordenador%

Se pueden escribir ordenes en esta lınea y pulsar la tecla [RETORNO] o [INTRO] para ejecutarlas. Esnecesario aclarar que en Linux, al igual que en todos los sistemas UNIX, se diferencia entre mayusculasy minusculas de forma que no es lo mismo la orden exit que la orden Exit ni el directorio tmp que eldirectorio Tmp.

Un mismo sistema Linux ofrece varias shells para que cada usuario trabaje con la que mas le gustesegun sus preferencias. Las mas conocidas son la C Shell (csh), y la Bourne Shell (bash) y tienendiferencias notables entre ellas, aunque lo que se explica en este documento es comun a ambas.

Una orden que es muy util a la hora de consultar el funcionamiento de otras ordenes, su sintaxis,etc, es la orden man

man ordenmuestra en pantalla la informacion de ayuda que el SO dispone de orden, su sintaxis, parametros, otrasordenes relacionadas, etc.

Ejemplo

turing% man exitMuestra la informacion de ayuda disponible para la orden exit

6

Page 196: Metodología de la Programación

Ejercicio

Revisar las ordenes basicas de la seccion 4.1 y probarlas en el aula depracticas

2.4. El sistema de ficheros

El sistema de ficheros de Linux es muy similar al de Windows 9X. Algunas de sus caracterısticasmas relevantes son las siguientes:

El nombre de un fichero puede tener hasta 255 caracteres y es conveniente no utilizar ninguno delos siguientes caracteres especiales

=|ˆ-’"‘*;[]()!&<>?

Se pueden utilizar numeros y letras pero es necesario distinguir entre letras minusculas y mayuscu-las.

El caracter separador de subdirectorios no es \ sino / .

Existen tres tipos de archivos

• Ficheros ordinarios.

• Directorios.

• Archivos de dispositivos, son archivos especiales que representan los dispositivos conecta-dos al ordenador de forma que escribir (leer) datos en estos ficheros significa enviar (recibir)datos a (desde) el correspondiente dispositivo.

2.4.1. Ordenes basicas de directorios

En la Seccion 4.2 se detallan las ordenes basicas sobre directorios, se puede ver que son absoluta-mente paralelas a las de MSDOS/Windows, solo que con una sintaxis algo diferente. Las especificacio-nes de rutas absolutas y rutas relativas son las mismas que en MSDOS/Windows con la diferencia deque el caracter separador de directorios no es \ sino / y de que en Linux no existen unidades como enMSDOS/Windows sino que todos los dispositivos son accesibles desde un unico arbol de directorios.

Ejercicio

Crear esta estructura de directorios en eldirectorio personal

Con respecto al manejo de ficheros, copiado, borrado, etc, la situacion es la misma. En la seccion4.3 se detallan las principales ordenes que tienen un significado paralelo a las de MSDOS/Windows.

7

Ejercicio

1. Buscar todos los ficheros cuyo nombre empiece por cron dentrodel directorio /var.

2. Copiar todos estos ficheros en el subdirectorio mp2/doc creadoanteriormente.

3. Mover aquellos que tengan extension .1 al directorio mp2/src.

4. Buscar todos los ficheros cuyo nombre empiece por message den-tro del directorio /var y guardar esta informacion en el ficheromp2/src/salida.txt.

5. Visualizar el contenido de este fichero.

6. Buscar en este ultimo fichero todas las ocurrencias de la cadenage y guardar la salida en el fichero mp2/salida.txt

7. Borrar todos los ficheros que se hayan creado con extension .txt

2.4.2. Permisos

Tal y como se ha comentado anteriormente, UNIX y Linux poseen un estricto sistema de control deacceso a los archivos, dado que un mismo ordenador, y su sistema de ficheros, puede ser compartidopor muchas personas. En estos sistemas operativos multiusuario es necesario diferenciar los ficherosque son de unas personas de los que son de otras (repasar seccion 1.4.1).

El permiso de lectura r sobre un fichero o directorio permite mostrar su contenido. El permiso deescritura de un fichero w permite escribir sobre el o borrarlo. En el caso de los directorios, el permiso deescritura permite crear ficheros directorios dentro de el. El permiso de ejecucion x permite ejecutar elprograma contenido en un fichero (suponiendo que contenga alguno). Como se puede ver, al contrariode lo que ocurre en MSDOS/Windows, para que un fichero sea ejecutable no es necesario asociarleuna determinada extension, sino asociarle un determinado permiso. En el caso de los directorios, elpermiso de ejecucion permite acceder al directorio.

No obstante el propietario de un fichero puede alterar los permisos que este tiene asociados paramodificar los privilegios que el resto de usuarios tienen sobre el, tanto los de su grupo como cual-quier otro. Incluso un usuario puede evitar que el mismo lo borre o modifique, algo que no sucede enMSDOS/Windows, provocando algun que otro desastre.

Ejemplo

turing% chmod a-x fichero

Quita el permiso de ejecucion del fichero a todo el mundo, incluido sudueno, en el ordenador llamado turing.turing% chmod g+w fichero

Da permiso de escritura a todos los miembros del grupo del dueno delfichero.

8

Page 197: Metodología de la Programación

Ejercicio

Consultar la seccion 4.4 y realizar los siguientes ejercicios.

1. Quitarle todos los permisos a los usuarios que no sean de vuestrogrupo a la estructura de directorios anterior.

2. Asignarle derechos de ejecucion a los miembros de vuestro grupoa los directorios bin y src.

2.4.3. El directorio home

Para cada usuario el directorio de referencia sera su directorio personal. Este es un directorio que,segun el administrador del sistema, puede estar colocado en diferentes partes del sistema de ficherospero que, en cualquier modo, indica un directorio que es propiedad del usuario y en el cual puedealmacenar toda la informacion privada que desee, pudiendo elegir compartir esta informacion con elresto de usuarios mediante las ordenes de cambio de permisos comentadas en la seccion 4.4. Estedirectorio personal se conoce como el directorio home del usuario.

Ejemplo

Para visualizar cual es el directorio home de un usuario se pueden utili-zar varios metodos.

1. turing% cd; pwd

Concatena la ejecucion de la orden cd sin argumentos, que realizaun cambio de directorio al directorio personal, y la orden pwd quemuestra el directorio actual.

2. turing% echo $HOME

Muestra el valor de la variable del sistema llamada HOME que esutilizada para este menester. A diferencia de la alternativa anterior,esta no modifica el directorio actual.

2.4.4. El directorio /

En UNIX y Linux, el sistema de ficheros siempre tiene una misma estructura homogenea indepen-dientemente de la configuracion hardware del ordenador, si tiene dos o mas discos duros, disquetera,CDROM, etc, como ocurre en MSDOS/Windows donde se les asocia a estos dispositivos una letra deunidad A:, D:, etc.

En el caso de Linux, todos los dispositivos de almacenamiento externo aparecen como subdirecto-rios, en alguna parte de un unico arbol de directorios, el sistema de ficheros, que se conoce como laraız del sistema de ficheros o /.

Ejemplo

Supongase un ordenador con dos discos duros y un CDROM. Enuna configuracion normal, el primer disco duro aparecera situado en/dev/hda, el segundo en /dev/hdb y el CDROM en /dev/cdrom.La unidad de diskettes normalmente aparece como /dev/fd0.¡Ojo!, Habitualmente no debe leerse ni escribirse directamente de estosdispositivos sino a traves de sus puntos de montaje.

9

No obstante, para poder utilizar uno de estos dispositivos de almacenamiento externo (discos duros,CDROM, diskettes) es necesario realizar una operacion de montaje. Esta operacion hace que cada unode estos dispositivos esten visibles en una parte determinada del arbol de directorios (ver ordenes demontaje en la seccion 4.5). Normalmente, los dispositivos de almacenamiento no extraibles son monta-dos por el propio SO en puntos predeterminados del sistema de ficheros. Sin embargo, los dispositivosextraibles como los diskettes o el CDROM deben ser montados y desmontados por el usuario o por elsistema en cada uso.

Ejemplo

Para poder utilizar un CDROM que se encuentre insertado en la unidad,es necesario montarlo en un directorio ya existente, que se encuentrevacıo y que no se este utilizando (no sea el directorio actual en unashell, por ejemplo). Para ello se utilizarıa la siguiente orden que montarıael CDROM en un directorio llamado Mi CDROM que cuelga del directoriopersonal del usuario.

turing% mount /dev/cdrom $HOME/Mi CDROM

El efecto de esta orden serıa que todo el arbol de directorios que cuelgadel CDROM aparece como subdirectorios del directorio en el que seha montado. Una vez que se ha terminado de utilizar hay que salir delsubarbol de directorios en que este montado el CDROM y desmontarlocon la orden

turing% umount $HOME/Mi CDROM

Nota: En lugar de $HOME se puede utilizar el sımbolo ∼ (AltGr+4)para referirse al directorio personal del usuario. Es mas, se puedehacer referencia al directorio personal de cualquier usuario como∼nombreusuario, p.ej., ∼ccia para hacer referencia al directoriopersonal del usuario ccia.

Ejemplo

En las distribuciones mas modernas aparecen dos directorios yacreados y listos para ser utilizados en estos casos: /mnt/cdrom y/mnt/floppy. En estos casos, existe un procedimiento de montajeabreviado que es el siguiente.turing% mount /mnt/cdrom

Ejercicio

1. Introducir un diskette y montarlo.

2. Copiar un fichero (el que sea) desde el diskette al directoriomp2/bin.

3. Desmontar el diskette.

10

Page 198: Metodología de la Programación

2.4.5. Otros directorios

En toda distribucion de UNIX/Linux suelen aparecer algunos directorios caracterısticos que se co-mentan brevemente a continuacion.

/ Es la unica raız del sistema de ficheros. En muchas ocasiones se conoce a este directorio comoROOT.

/bin Es el directorio donde residen algunas de las ordenes externas mas importantes del SO.

/dev Contiene ficheros del sistema representando todos los dispositivos que pueden estar fısicamenteinstalados en el ordenador.

/etc Este directorio esta reservado para los ficheros de configuracion del sistema. En este directoriono debe aparecer ningun fichero binario (programas).

/lib Contiene las bibliotecas necesarias para que se ejecuten los programas que residen en /bin (nolas bibliotecas de los programas de los usuarios).

/proc Contiene ficheros especiales que o bien reciben o envıan informacion al nucleo del sistema (Serecomienda no modificar el contenido de este directorio y sus ficheros).

/sbin Contiene programas que son unicamente accesibles al administrador del sistema, cuyo nombrede usuario es root. Tanto este directorio como al directorio /bin son imprescindibles para uncorrecto funcionamiento del sistema operativo. Si se mueven a otro lugar, se renombran o seborran, se crearıan serios problemas de arranque de Linux.

/usr Este es uno de los directorios mas importantes del sistema puesto que contiene la informacion delos programas de uso comun para todos los usuarios. Dentro de el podemos encontrar tambienlos directorios bin y lib que contienen, respectivamente, los ejecutables y bibliotecas de losprogramas instalados y que pueden utilizar todos los usuarios.

/home En caso de que exista este directorio, contendra los directorios personales de cada uno de losusuarios del sistema.

/mnt Un directorio auxiliar para realizar montajes.

2.5. Multitarea basica

En Linux se pueden ejecutar varias ordenes simultaneamente, como se ha comentado en la seccion1.4.2. Se dice que una orden se esta ejecutando en primer plano (foreground) cuando se ha ordenado suejecucion desde una shell y no se devolvera el control a la shell hasta que haya terminado la ejecucionde la orden. Se dice que una orden se esta ejecutando en segundo plano (background) cuando se haordenado su ejecucion desde una shell y esta vuelve a tomar el control inmediatamente despues sinesperar a que termine la orden (mientras tanto la orden continuara su ejecucion mostrando los mensajespertinentes, si es que muestra alguno). Para ejecutar una orden en segundo plano es necesario anadirleel sufijo & al final de la orden.

11

Ejemplo

turing% ls -laR >$HOME/salida.txtEsta orden muestra todos los ficheros que haya en el directorio actual,y los de todos sus subdirectorios, y guarda la salida en el fichero sa-lida.txt que situa en el directorio home del usuario. Hasta que notermina esta orden no se devuelve el control a la shell y no es posiblevolver a introducir una nueva orden.

turing% ls -laR >$HOME/salida.txt &Esta orden se ejecutara en segundo plano. Esto significa que inmediata-mente despues de introducir esta orden se devuelve el control a la shell,pudiendo seguir trabajando con otras ordenes. Mientras tanto, esta or-den se estara ejecutando “en paralelo” hasta que termine.

En cualquier momento se puede ver un listado de las ordenes que se esten ejecutando en back-ground y que no hayan terminado aun mediante la orden jobs.

Esta orden muestra una lista como la de la Figura 4. La columna de la izquierda muestra un numeroque es el identificador de la orden en segundo plano. En adelante se utilizara este numero para hacerreferencia a la orden correspondiente. Se puede ver que cuatro de las ordenes se encuentran eje-cutandose (Running) y que una de ellas (grep) se encuentra parada (Stopped). Esto podrıa debersea que la orden que esta paralizada necesita una operacion de entrada de datos desde el teclado y nopuede hacerla mientras esta en segundo plano, por ello el SO decide paralizarla temporalmente hastaque se pueda realizar esta operacion.

[1] Running xdvi -s 9 IntroLinux &[2] Running xfig &[3] Running acroread /mnt/cdrom/Mp2/Linux/Linux.pdf & (wd: ˜)[5] Running kruiser &[6] Stopped grep pepe

Figura 4: Salida de la orden jobs

Al contrario que ocurre en Windows, se tiene informacion detallada sobre las ordenes que se estenejecutando en segundo plano pudiendo tomar ciertas decisiones sobre ellos (ver seccion 4.6 para masdetalles).

Traer una orden a primer plano Si se quiere recuperar una orden que este en segundo plano, porejemplo para poder realizar una operacion de entrada de datos que la mantenga paralizada, o porcualquier otra razon, se utiliza la orden fg seguida del caracter % y del numero de identificacionde la orden. Por ejemplo fg%6.

Abortar una orden en primer plano Para abortar una orden en primer plano, se pulsa Ctrl+C.

Abortar una orden en segundo plano Si una orden se ha quedado “colgada” o no interesa que pro-siga su ejecucion, entonces se puede terminar “a la fuerza”. Para ello se utiliza la orden kill(matar) seguida del caracter % y del numero de identificacion de la orden.

Paralizar una orden en primer plano Si se esta ejecutando una orden en primer plano y se deseaparalizarla (porque tarda mucho o para hacer otra cosa mas urgente y se necesita acceder a lashell, por ejemplo) se pulsa Ctrl+Z.

Continuar una orden en segundo plano Para dejar que una orden paralizada pueda continuar en se-gundo plano se utiliza la orden bg seguida de % y del numero de identificacion de la orden. Al-gunas ordenes no se pueden continuar si el motivo de haberlas llevado a paralizarlas persiste(operacion de entrada desde el teclado).

12

Page 199: Metodología de la Programación

Llevar una orden de primer a segundo plano No hay una vıa directa, primero hay que paralizarla yluego hacerla continuar en segundo plano.

Ejercicio

1. Buscar todos los ficheros del sistema que empiecen por la secuen-cia varlo y guardar el resultado en mp2/doc/salida.txt.

2. Paralizar esta orden y continuarla en segundo plano.

3. Cuando esta orden haya terminado ejecutar grep pepe&.

4. La anterior orden se quedara paralizada. Matarla por la vıa rapida:-)

3. La Interfaz Grafica de Usuario (KDE)

3.1. Conceptos basicos

El entorno grafico habitual de los sistemas Unix se llama X Window. El sistema X Window se com-pone de dos partes principales: el servidor X y el programa para la gestion de las ventanas.

El servidor X es el programa que se encarga realmente de dibujar en la pantalla. Por el contrarioel gestor de ventanas, como su nombre indica, es el encargado de crear las ventanas y gestionar suapariencia.

Debido a este modelo, la apariencia de las aplicaciones varıa segun se use uno u otro gestor deventanas, entre los que destacan por su sencillez de uso los entornos GNOME y KDE. Al instalar Linuxel sistema puede preguntar si se desea arrancar Linux en modo texto o en modo grafico. Si se haseleccionado esta ultima opcion Linux arrancara directamente X Window; en caso contrario en la lıneade ordenes hay que escribir startx con lo cual se arranca el modo grafico.

El K Desktop Environment, mejor conocido como KDE es uno de los entornos de escritorio masconocidos y junto con el GNU Object Model Environment o GNOME son quizas los dos entornos masutilizados y en los se esta realizando mayor desarrollo. La razon de su exito radica en su facilidad deuso, su similitud con el entorno de Microsoft Windows, su funcionalidad y su gratuidad. Al arrancar KDEaparece el escritorio en el que se pueden encontrar elementos similares a los de otros entornos. Pordefecto la pantalla de KDE se divide en tres partes fundamentales:

Panel de KDE El panel de KDE tiene un papel parecido a la barra de tareas de Windows. Contieneaccesos directos a las aplicaciones mas empleadas ası como dos menus. El primer menu es elequivalente al menu Inicio de Windows, esto es el menu a traves del cual se pueden ejecutarlas aplicaciones. Al seleccionar este elemento se despliega un menu subdividido en distintascategorıas. KDE incluye una gran cantidad de utilidades que se integran con el entorno. Junto aeste aparece un segundo menu del KDE, en el menu de ventanas se puede acceder a todas lasventanas que esten abiertas en los distintos escritorios.

Escritorio Al contrario que otros entornos graficos, X Window permite organizar las ventanas en dis-tintos escritorios virtuales. Para cambiar de escritorio virtual se puede escoger uno de los cuatrobotones que aparecen en el panel. Justo encima del panel de KDE, aparece el escritorio, al igualque en Windows este elemento contiene iconos que permiten acceder a los elementos mas co-munes como las unidades de disco o la papelera.

Panel de ventanas Por ultimo en la parte superior del escritorio aparece otra barra, en la que apare-ceran botones por cada ventana que se cree. Las ventanas en el KDE tienen un aspecto similar alde las ventanas de Windows (al menos con el aspecto basico), pudiendo distinguir en ellas diver-sas partes: En la parte superior izquierda, aparece el icono de la aplicacion, seleccionando el cualaparece un menu con las opciones basicas de manipulacion de ventanas: minimizar, maximizar,cerrar; ası como otras no tan habituales como enviar la ventana a otros escritorio. Junto a el y enla parte superior central de la ventana se encuentra la barra de tıtulos de la ventana. Finalmente

13

en la parte superior derecha aparecen tres botones con las opciones de minimizar, maximizar ycerrar. Esta es la disposicion por defecto pero como se vera mas adelante esta disposicion puedeser adaptada a los gustos del usuario de una forma muy sencilla. Por debajo de este elemento seextiende la barra de menus y de herramientas y el area de trabajo de la aplicacion.

Al igual que en Windows, KDE permite cambiar el tamano de una ventana sin mas que acercarel raton a un borde de la misma. En esta posicion cambia el cursor, indicando en que direccionpodemos modificar el tamano de la ventana en esa posicion. Si se hace click sobre el borde y searrastra cambiara el tamano de la ventana.

3.2. Algunas aplicaciones en KDE

3.2.1. El navegador de disco

Al igual que el explorador de Windows, en KDE se puede encontrar un programa grafico que permitenavegar por el sistema de ficheros con una funcionalidad exactamente igual a la de Windows. Esteprograma aparecera en el escritorio con un icono parecido al siguiente

o bien se puede invocar desde la lınea de ordenes como konqueror. La apariencia de este programaes la mostrada en la Figura 5 y es muy sencilla de manejar.

Figura 5: El navegador de disco de KDE

14

Page 200: Metodología de la Programación

Ejercicio

1. Destruir la estructura de directorios que se habıa creado en ejerci-cios anteriores utilizando solamente el navegador de disco.

2. Volverla a construir utilizando solamente el navegador de disco.

3.2.2. Un editor de textos: kwrite

Existen numerosos editores de texto en Linux, algunos de ellos en modo texto (como vi) y otros deellos que funcionan en la interfaz grafica. Durante el desarrollo de esta asignatura se aconseja el uso deleditor kwrite que se puede encontrar en el panel de KDE, a traves de la lista de programas instalados,o bien introduciendo su nombre directamente en la lınea de ordenes. Es un editor sencillo que aportala suficiente funcionalidad como para escribir codigo en C/C++ (incluye por ejemplo el coloreado de lasintaxis).

Una pantalla de ejemplo de este programa aparece en la Figura 6 donde se pueden observar lostıpicos botones de la barra de herramientas de un editor como los utilizados en Windows.

3.2.3. Netscape

En cuanto a la navegacion por Internet, existen varios navegadores disponibles dependiendo de ladistribucion. En concreto hay una version del navegador de Netscape que funciona en Linux2 y ofreceexactamente la misma interfaz, tal y como se muestra en la Figura 7. Se puede acceder a este pro-grama desde el acceso directo que aparece en el escritorio, desde el panel de KDE o simplementeintroduciendo su nombre en minusculas (netscape) en la lınea de ordenes.

3.2.4. StarOffice

Finalmente, aunque no se incluye en todas las distribuciones, sobre todo algunas mas antiguas,existe una aplicacion muy similar al Office de Microsoft, pero que funciona en Linux integrando aplica-ciones como un procesador de textos, hoja de calculo, programa de presentaciones, etc. que se llamaStar Office, que se puede obtener gratuitamente y que tiene filtros para poder leer perfectamente losficheros de MS Office. Este programa se puede encontrar tambien a traves del panel de KDE o bienintroduciendo la orden soffice en la lınea de ordenes. La apariencia de la ventana principal es la queaparece en la Figura 8.

2Curiosamente fue en Linux donde aparecio la primera version de este navegador y mucho antes de que se conociese eltristemente famoso Internet Explorer.

15

Figura 6: El editor de texto kwrite

16

Page 201: Metodología de la Programación

Figura 7: La version de Linux del navegador Netscape es la misma que la version de Windows.

17

Figura 8: Ventana principal del programa Star Office desde el que se puede lanzar desde una hoja decalculo compatible con MS Excel a un procesador de texto compatible con MS Word pasando por unprograma de presentaciones compatible con MS. PowerPoint.

18

Page 202: Metodología de la Programación

4. Ordenes de UNIX

En esta seccion se muestran algunos detalles sobre el funcionamiento de las ordenes mas comunesde UNIX/Linux. No pretende ser un manual de referencia, sino que pretende ser un documento inicialque permita manejar con cierta soltura el SO. Las descripciones que se incluyen son, en algunos casosmınimas, debiendo recurrir a la hora de buscar mas informacion, a la ayuda del SO o a manualesespecıficos tales como los que se detallan en la seccion 5.

4.1. Ordenes basicas

exit Cierra una sesion de una shell.

halt Cierra el SO y bloquea el ordenador (segun la version puedeque lo apague).

poweroff Cierra el SO y apaga el ordenador.

reboot Cierra el SO y reinicia el ordenador.

passwd Cambia la contrasena del usuario.

man orden Muestra la ayuda disponible sobre la orden. Ordenes de manlas mismas que la orden more (seccion 4.3)

info Es una de las principales fuentes de informacion on-line sobrecualquier aspecto del SO.

echo [cadena] Muestra por pantalla la cadena que se pasa como argumento

En lo siguiente, se mostrara una breve descripcion de las ordenes mas comunes. Para mas informacion,consultar la ayuda que ofrece la orden man.

19

4.2. Ordenes basicas sobre directorios

pwd Muestra el directorio actual.

cd [dir] Cambia el directorio actual. dir puede ser una ruta absolutao relativa. Sin argumentos se cambia al directorio personal delusuario.

rmdir dir Borra el directorio (tiene que estar vacıo)

mkdir dir Crea el directorio especificado

ls [opciones][dir] Muestra el contenido del directorio especificado o, en caso deno especificar ninguno, el directorio actual. Admite sımboloscomodın como * y ? con el mismo significado que en MS-DOS/Windows. Principales opciones

-a Muestra todos los ficheros incluidos los ocultos (empie-zan con el caracter .)

-l Formato largo. Muestra toda la informacion disponiblesobre cada fichero: derechos, propietario, etc.

-R Recorre la estructura de directorios recursivamente.

20

Page 203: Metodología de la Programación

4.3. Ordenes basicas sobre ficheros

rm [opciones] archivo Borra el archivo. ¡Cuidado! En Linux no hay forma de recu-perar los archivos borrados. Principal opcion

-r borra archivos y directorios recursivamente. Usese conMUCHISIMO cuidado.

cp origen destino Copia el fichero origen en el destino. La casuıstica sobre lasespecificaciones de directorios y ficheros es la misma queen MSDOS/Windows. Se admiten sımbolos comodın. Noteseque, a diferencia de MSDOS/Windows, el destino es obligato-rio.

mv origen destino Mueve el fichero desde origen a destino. La casuıstica sobrelas especificaciones de directorios y ficheros es la misma quela de orden move de MSDOS/Windows. Se admiten sımboloscomodın. La orden mv tambien se usa para cambiar el nom-bre de los ficheros dando como destino el nuevo nombre delarchivo origen. En este caso no se admiten comodines.

redireccion de entradas y sali-das

Los sımbolos de redireccion de las entradas < y salidas > yel encauzamiento entre programas | tambien existen en Unixy tienen el mismo significado que en MSDOS/Windows.

more fichero Visualiza pagina a pagina el contenido del fichero. Algunasordenes de more

espacio Pagina siguiente.

b Pagina anterior.

retorno Lınea siguiente.

q Fin de la visualizacion.

grep regexp ficheros... Busca entre los ficheros especificados (puede haber mas deuno) aquellos que contengan una secuencia de caracteresque coincida con la expresion regular indicada como primerargumento y muestra las lıneas coincidentes en la pantalla.Esta orden no tiene equivalencia real en MSDOS/Windows.Esta es una orden muy completa y se recomienda consultar laayuda del SO.

find [dir] -name regexp Busca los archivos y directorios cuyo nombre coincida con laexpresion regular que aparece como segundo argumento. Elprimer argumento es el directorio desde el que se desea co-menzar la busqueda.

locate cadena Busca todas las entradas del sistema de ficheros que conten-gan, en alguna parte, la cadena especificada.

21

4.4. Ordenes de gestion de permisos

chmod [opc] modo ficheros Cambia los permisos de uno o mas ficheros segun el modo es-pecificado. El modo de permisos se especifica mediante unasecuencia de tres caracteres. El primer caracter es una u ,una g, una o o una a que hace referencia al usuario, a sugrupo, al resto de usuarios o a todos juntos respectivamente.El segundo caracter es un + o un - indicando que se conce-de o se quita el correspondiente permiso que se indica conel tercer caracter. Este puede ser una r, una w o una x paralos permisos de lectura, escritura y ejecucion respectivamen-te. Opciones

-R Propaga los cambios recursivamente a los subdirecto-rios.

chown [opc] usuario fichero El propietario del fichero pasa a ser el que se indica. Opciones

-R Propaga los cambios recursivamente a los subdirecto-rios.

chgrp [opc] grupo fichero El grupo al que pertenece el fichero pasa a ser el que se indi-ca. Opciones

-R Propaga los cambios recursivamente a los subdirecto-rios.

¡Cuidado! Aplicar cambios recursivamente puede resultarpeligroso. Usese con cuidado.

4.5. Ordenes del sistema de ficheros

mount [dispositivo] [dir] Monta el dispositivo especificado en el directorio. Cuando seejecuta sin argumentos muestra una lista de todos los dispo-sitivos que se encuentren montados en ese momento y el di-rectorio en el que se encuentran montados.

umount dir Desmonta el dispositivo que se encuentra montado en el di-rectorio.

22

Page 204: Metodología de la Programación

4.6. Ordenes de gestion de multitarea

Sufijo & Ejecuta una orden en segundo plano.

jobs Muestra la lista de ordenes en segundo plano.

bg identificador Continua la ejecucion en segundo plano de la tarea indicada

fg identificador Trae la orden indicada al primer plano.

kill [opc] identificador Mata la orden indicada. Opciones

-9 Para aquellas ordenes “recalcitrantes que no se quierenmorir” la opcion -9 procede con mayor intensidad paraabortar la orden.

Ctrl+Z Paraliza la orden que se este ejecutando en primer plano.

5. Mas informacion

5.1. Documentacion dentro del SO

1. Orden man

2. Orden info

3. En KDE, kdehelp (pulsar Alt+F2 y teclear informacion de ayuda).

4. El directorio /usr/share/doc contiene informacion de ayuda sobre algunos programas que sehayan instalado con posterioridad al SO.

5.2. Documentacion en Internet

1. Mucha documentacion en Linux

http://www.linux.com

http://www.linux.org

http://www.linuxdoc.org

2. Proyecto Linux en espanol (LuCAS). Gran cantidad de informacion en Espanol.

http://lucas.hispalinux.es/

3. Aprenda Linux como si estuviese en primero

http://mat21.etsii.upm.es/ayudainf/aprendainf/Linux/Linux.pdf

4. Otros

http://www.aebius.com/docs/spanish/guias/

http://www.linuxdoc.org

23

5.3. Revistas disponibles en la biblioteca de la Universidad de GranadaRegistro 1 de 2UBICACION BIBLIOTECA I. INFORMATICATITULO Linux actual.PUBLICAC Madrid : Prensa Tecnica , 1999,DESCRIPCION v: ; 30 cm + CD ROMs.DESCRIPCION mensual.MATERIA Linux (Sistema operativo de ordenadores) -- Revistas.AUTOR SEC Prensa Tecnica. Madrid ed.TITULO SEC Revista en castellano sobre el sistema operativo Linux.BIB UTIL # 0814590.ISBN 11389443.CDU 681.3.06.

Registro 2 de 2UBICACION BIBLIOTECA I. INFORMATICATITULO Linux Journal.PUBLICAC Madrid : Prensa Tecnica , 2000,DESCRIPCION v. ; 30 cm + CD ROMs.DESCRIPCION mensual.MATERIA Linux (Sistema operativo de ordenadores) -- Revistas.AUTOR SEC Prensa Tecnica. Madrid ed.TITULO SEC Revista mensual de la comunidad Linux.BIB UTIL # 0814604.ISBN 15757315.CDU 681.3.06.

5.4. Libros disponibles en la biblioteca de la Universidad de Granada

En la biblioteca de la Universidad existen mas de 100 libros relacionados con Linux. La mayorıade ellos estan disponibles en la biblioteca de la Escuela. En esta seccion solo mostramos los masrecientes, desde el ano 2000.

Registro 1 de 27UBICACION BIBLIOTECA I. INFORMATICAAUTOR Sanchez Andion, Fernando.TITULO El Kernel 2.4 de Linux / Fernando Sanchez Andion, Rocıo

Arango Munoz.PUBLICAC Madrid : Prentice Hall, 2003.DESCRIPCION XVII, 530 p. ; 24 cm.NOTA Incluye ındice.MATERIA Linux (Sistema operativo de ordenadores)AUTOR SEC Arango Munoz, Rocıo, coaut.ISBN 8420536105.DEP. LEGAL M 40745-2002.1 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) San

Registro 2 de 27UBICACION BIBLIOTECA I. INFORMATICAAUTOR Kolesnikov, Oleg.TITULO Guıa avanzada : redes privadas virtuales con Linux / Oleg

Kolesnilov, Brian Hatch ; traduccion Vox Populi.PUBLICAC Madrid [etc.] : Prentice Hall, 2003.DESCRIPCION XIX, 395 p. ; 24 cm.NOTA Glosario : p. 383-386.MATERIA Linux (Sistema operativo de ordenadores)MATERIA Redes de ordenador.MATERIA Medidas de seguridad.AUTOR SEC Vox Populi, trad.AUTOR SEC Hatch, Brian, coaut.ISBN 8420538442.DEP. LEGAL M 50767-2002.CDU 681.3.1 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) Kol

Registro 3 de 27UBICACION BIBLIOTECA I. INFORMATICAAUTOR Morrill, Daniel L.TITULO Configuracion de sistemas Linux / Daniel L. Morrill.PUBLICAC Madrid : Anaya Multimedia, 2003.DESCRIPCION 494 p. ; 23 cm + 1 CD-ROM.COLECCION Programacion.COLECCION Programacion (Anaya Multimedia)NOTA P. 462.MATERIA Linux (Sistema operativo de ordenadores)ISBN 8441514658.

24

Page 205: Metodología de la Programación

DEP. LEGAL M 49669-2002.CDU 681.3.2 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) Mor C

Registro 4 de 27UBICACION BIBLIOTECA I. INFORMATICAAUTOR Mancill, Tony.TITULO Linux routers / Tony Mancill ; traduccion Domingo Delgado

Medialdea.EDICION 2a ed.PUBLICAC Madrid [etc.] : Prentice Hall, 2003.DESCRIPCION XXVIII, 536 p. ; 25 cm.NOTA Glosario : p. 521.NOTA P. 529.MATERIA Linux (Sistema operativo de ordenadores)AUTOR SEC Delgado Medialdea, Domingo, trad.ISBN 8420536466.DEP. LEGAL M 48029-2002.CDU 681.3.1 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) Man

Registro 5 de 27UBICACION BIBLIOTECA I. INFORMATICAAUTOR Sarwar, Syed Mansoor.TITULO Linux : el libro de texto / Syed Mansoor Sarwar, Robert

Koretsky, Syed Aqeel Sarwar ; traduccion Jose Rafael GarcıaBermejo.

PUBLICAC Madrid [etc.] : Pearson Education, 2003.DESCRIPCION XX, 839 p. ; 24 cm.MATERIA Linux (Sistema operativo de ordenadores)AUTOR SEC Koretsky, Robert, coaut.AUTOR SEC Sarwar, Syed Aqeel, coaut.AUTOR SEC Garcıa-Bermejo, Jose Rafael, trad.ISBN 8478290605.CDU 681.3.1 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) Sar

Registro 6 de 27UBICACION BIBLIOTECA I. INFORMATICAAUTOR Mosberger, David.TITULO IA-64 Linux Kernel : design and implementation David

Mosberger, Stephane Eranian.PUBLICAC Upper Saddle River, NJ : Prentice Hall PTR , 2002,DESCRIPCION XXXIII, 522 p. : il. ; 25 cm.NOTA Glosario: p. 495-498.NOTA Bibliografıa: p. 499-504.MATERIA Diseno.MATERIA Linux (Sistema operativo de ordenadores)AUTOR SEC Eranian, Stephane coaut.BIB UTIL # 0886398.ISBN 0130610143.CDU 681.3.06.1 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) Mos

Registro 7 de 27UBICACION BIBLIOTECA I. INFORMATICATITULO Linux kernel programming : algorithms and structures of

version 2.4 / Michael Beck ... [et al.]EDICION Updated and extended 3rd ed.PUBLICAC London ; Boston : Addison-Wesley, 2002.DESCRIPCION XIV, 471 p. : il. ; 24 cm. + 1 CD-ROM.NOTA El CD-ROM contiene la version 2.4.4 del nucleo de Linux mas otros

programas y documentos.NOTA P. 449-453.MATERIA Linux (sistema operativo de ordenadores)MATERIA Ingenierıa del software.AUTOR SEC Beck, Michael coaut.ISBN 0201719754.CDU 681.3.1 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) lin2 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) lin CD-ROM

Registro 8 de 27UBICACION BIBLIOTECA CIENCIASAUTOR Negus, Christopher.TITULO Red Hat Linux 8 bible / Christopher Negus.PUBLICAC Indianapolis, IN : Wiley Pub., 2002.DESCRIPCION 1063 p. ; 24 cm. + 3 CD-ROMs (4 3/4 in.)MATERIA Linux (Sistema operativo de ordenadores)ISBN 0764549685.CDU 681.3.06.

25

1 > GENETICA (FCI) Genetica CONSULTA D2 > GENETICA (FCI) Genetica CD-ROM CONSULTA D3 > GENETICA (FCI) Genetica CONSULTA D

Registro 9 de 27UBICACION BIBLIOTECA I. INFORMATICAAUTOR Acero, Fernando.TITULO Manual de LinEx : (GNU/Linux) : guıa de referencia para

trabajar con este sistema operativo / [autores Fernando Acero,Luis Hontoria]

PUBLICAC Madrid : Edit-In, 2002.DESCRIPCION 447 p. : il. ; 23 cm + 1 CD-ROM.DESCRIPCION 447 p. : il. ; 23 cm + 1 CD-ROM.MATERIA Sistemas operativos.MATERIA Linux (Sistema operativo de ordenadores)AUTOR SEC Hontoria, Luis, coaut.ISBN 849546702X.DEP. LEGAL M 46351-2002.CDU 681.3.1 > BIBLIOTECA I. INFORMATI ESII/2 > BIBLIOTECA I. INFORMATI ESII/ CD-ROM

Registro 10 de 27UBICACION BIBLIOTECA I. INFORMATICAAUTOR Hatch, Brian.TITULO Hacking linux exponsed : linux security secrets and

solutions Brian Hatch, James Lee, George Kurtz.PUBLICAC New York : Osborne , cop. 2001,DESCRIPCION VIII, 566 p. ; 24 cm.MATERIA Medidas de seguridad.MATERIA Linux (Sistema operativo de ordenadores)MATERIA Internet (Red de ordenador)AUTOR SEC Lee, James, coaut.AUTOR SEC Kurtz, George, coaut.BIB UTIL # 0879036.ISBN 0072127732.CDU 681.3.06.1 > ARQUIT. TEC. COMP. (ESI Arquit. Tec. Comp..

Registro 11 de 27UBICACION BIBLIOTECA I. INFORMATICAAUTOR Toxen, Bob.TITULO Real world Linux security : intrusion prevention, detection,

and recovery Bob Toxen.PUBLICAC Upper Saddle River, NJ : Prentice Hall , 2001,DESCRIPCION XXX, 694 p. : il. ; 24 cm + 1 CD ROM.COLECCION Open source technology series.COLECCION Open source technology series (Prentice Hall PTR)MATERIA Linux (Sistema operativo de ordenadores)MATERIA Medidas de seguridad.BIB UTIL # 0839073.ISBN 0130281875.CDU 681.3.06.1 > CC. COMPUT. I.A. (ESII) Cien comp3 > LENG. SIST. INFOR. (ESI Leng. Sist. ---

Registro 12 de 27UBICACION BIBLIOTECA I. INFORMATICAAUTOR Shah, Steve.TITULO Manual de administracion de Linux Steve Shah ; traduccion

Fernando Elejalde Garcıa.PUBLICAC Madrid : Mac Graw Hill-Interamericana de Espana , cop. 2001,DESCRIPCION XXV, 546 p. : il. ; 24 cm + 1 CD ROM.MATERIA Linux (Sistema operativo de ordenadores)AUTOR SEC Elejalde Garcıa, Fernando trad.BIB UTIL # 0839909.ISBN 8448128923.DEP. LEGAL M-47342-2000.CDU 681.3.06.1 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) Sha2 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) Sha CD-ROM

Registro 13 de 27UBICACION BIBLIOTECA I. INFORMATICATITULO Linux : guıa de instalacion y administracion. Configuracion

y programacion de servidores de Internet e Intranet VicenteLopez Camacho [et al.]

PUBLICAC Madrid : Mac Graw Hill-Interamericana de Espana , cop. 2001,DESCRIPCION XXIII, 684 p. : il. ; 24 cm.NOTA Glosario: p. 673-676.MATERIA Linux (Sistema operativo de ordenadores)

26

Page 206: Metodología de la Programación

AUTOR SEC Lopez Camacho, Vicente.BIB UTIL # 0839912.ISBN 8448128915.DEP. LEGAL M-47903-2000.1 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) lin

Registro 14 de 27UBICACION BIBLIOTECA I. INFORMATICAAUTOR Gazo Cervero, Alfonso.TITULO Manual avanzado de Red Hat Linux 7 Alfonso Gazo Cervero,

Jose Luıs Gonzalez Sanchez.PUBLICAC Madrid : Anaya Multimedia , 2001,DESCRIPCION 416 p. : il. ; 23 cm + 1 CD ROM.MATERIA Linux (Sistema operativo de ordenadores)AUTOR SEC Gonzalez Sanchez, Jose Luis coaut.BIB UTIL # 0840774.ISBN 8441511330.DEP. LEGAL M-7952-2001.CDU 681.3.06.2 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) Gaz C PREST. NOR

Registro 15 de 27UBICACION BIBLIOTECA I. INFORMATICAAUTOR Leblanc, Dee Ann.TITULO La biblia de administracion de sistemas Linux Dee-Ann

LeBlanc.PUBLICAC Madrid : Anaya Multimedia , 2001,DESCRIPCION 864 p. : il. ; 23 cm + 1 CD ROM.MATERIA Linux (Sistema operativo de ordenadores)BIB UTIL # 0840805.ISBN 8441511268.DEP. LEGAL M-5229-2001.CDU 681.3.06.1 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) Leb2 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) Leb CD-ROM

Registro 16 de 27UBICACION BIBLIOTECA I. INFORMATICATITULO SuSe Linux 7.1 : professional [archivo de ordenador]EDICION 19 ed. act.PUBLICAC Nurnberg : Suse , 2001.DESCRIPCION 7 CD ROMs, 1 DVD, 2 disquetes + 4 manuales.NOTA Contiene: Instalacion, redes, conocimiento practico --

Configuracion -- Aplicaciones -- Quick Install manual.MATERIA Linux (Sistema operativo de ordenadores)BIB UTIL # 0841485.ISBN 3934678076.CDU 681.3.06.

22 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) sus 7 vers. 7-1

Registro 17 de 27UBICACION BIBLIOTECA I. INFORMATICAAUTOR Bovet, Daniel Pierre.TITULO Understanding the Linux kernel Daniel P- Bovet & Marco

Cesati.PUBLICAC Beijing [etc.] : O’Reilly , 2001.DESCRIPCION XVI, 684 p. : il. ; 24 cm.MATERIA Linux (Sistema operativo de ordenadores)AUTOR SEC Cesati, Marco coaut.BIB UTIL # 0845466.ISBN 0596000022.CDU 681.3.06.1 > ARQUIT. TEC. COMP. (ESI Arquit. Tec. Comp.2 > LENG. SIST. INFOR. (ESI Leng. Sist.

Registro 18 de 27UBICACION BIBLIOTECA I. INFORMATICA & BIBLIOTECA CIENCIASAUTOR Schenk, Thomas.TITULO Administracion de Red HAT Linux al descubierto Thomas

Schenk, [et al.]PUBLICAC Madrid [etc] : Pearson Education, 2001,DESCRIPCION XL, 1148 p. 25 cm + 1 CD ROM.MATERIA Linux (Sistema operativo de ordenadores)AUTOR SEC Barber, Derek coaut.BIB UTIL # 0845624.ISBN 8420531243.DEP. LEGAL M-10122-2001.CDU 681.3.06.1 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) Sch3 > BIBLIOTECA CIENCIAS FCI/681.3 ADM adm CD

27

4 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) Sch CD-ROM

Registro 19 de 27UBICACION BIBLIOTECA I. INFORMATICAAUTOR Pitts, David.TITULO Red Hat Linux 7 : a fondo David Pitts, Bill Ball y otros.PUBLICAC Madrid : Anaya Multimedia , 2001.DESCRIPCION 926 p. : il. ; 24 cm + 3 CD ROM.MATERIA Linux (Sistema operativo de ordenadores)AUTOR SEC Ball, Bill coaut.BIB UTIL # 0847128.ISBN 8441511497.DEP. LEGAL M-10415-2001.CDU 681.3.06.

4 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) Pit C vers.7

Registro 20 de 27UBICACION BIBLIOTECA CIENCIAS & BIBLIOTECA I. INFORMATICA & BIBLIOTECA

POLITECNICOAUTOR Negus, Christopher.TITULO La biblia de Red Hat Linux 7 : Christopher Negus.PUBLICAC Madrid : Anaya Multimedia, 2001.DESCRIPCION 990 p. ; 23 cm. + 3 CD.MATERIA Linux (Sistema operativo de ordenadores)BIB UTIL # 0848488.ISBN 8441511489.DEP. LEGAL M 10795-2001.CDU 681.3.CDU 681.3.06.1 > BIBLIOTECA CIENCIAS FCI/681.3 NEG bib3 > BIBLIOTECA CIENCIAS FCI/681.3 NEG bib CD4 > INGENIERIA CIVIL (BPOL) Ingen civil7 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) Neg C vers.7

Registro 21 de 27UBICACION BIBLIOTECA I. INFORMATICAAUTOR Raymond, Eric S.TITULO The Cathedral and the bazaar : musings on Linux and Open

Source by and accidental revolutionary Eric S. Raymond.PUBLICAC Beijing [etc.] : O’Reilly , 2001,DESCRIPCION XIV, 241 p. ; 23 cm.NOTA Bibliografıa: p. 225-235.MATERIA Internet (Red de ordenador)MATERIA Linux (Sistema operativo de ordenadores)BIB UTIL # 0849501.ISBN 0596001312.CDU 681.3.1 > CC. COMPUT. I.A. (ESII) Cien comp ---

Registro 22 de 27UBICACION BIBLIOTECA I. INFORMATICATITULO SuSE Linux 7.2 : professional [archivo de ordenador]PUBLICAC Nurnberg : Suse , 2001,DESCRIPCION 7 CDs, 1 DVD, 2 disquetes + 5 manuales.NOTA Contiene: Manual de referencia -- Configuracion --

Aplicaciones -- Quick install manual -- Manual de redes.MATERIA Linux (Sistema operativo de ordenadores)BIB UTIL # 0850390.CDU 681.3.06.

19 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) sus 7 vers. 7.2

Registro 23 de 27UBICACION BIBLIOTECA I. INFORMATICAAUTOR Maxwell, Steve.TITULO Red hat LINUX herramientas para la administracion de redes

Steve Maxwell ; traduccion, Gustavo Elıas Fonseca Bueno ;revision tecnica, Jaime Antonio Avila Mojica.

PUBLICAC Bogota [etc.] : Mac Graw-Hill , imp. 2001.DESCRIPCION XXVIII, 697 p. : il. ; 23 cm. + 2 CD-ROM.COLECCION MacGraw-Hill Tools Series Titles.NOTA Glosario: p. 659-668.MATERIA Redes de ordenador.MATERIA Linux (Sistema operativo de ordenadores)AUTOR SEC Avila Mojica, Jamir Antonio trad.AUTOR SEC Fonseca Bueno, Gustavo Elıas trad.BIB UTIL # 0856633.ISBN 9584102206.CDU 681.3.06.1 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) Max

28

Page 207: Metodología de la Programación

Registro 24 de 27UBICACION BIBLIOTECA I. INFORMATICAAUTOR Petersen, Richard.TITULO Linux : manual de referencia Richard Petersen ; traduccion

Vuelapluma.EDICION 2a ed.PUBLICAC Madrid [etc.] : Mac Graw-Hill Interamericana de Espana , 2001,DESCRIPCION XXXVI, 1306 p. 25 cm + 2 CD ROMs.MATERIA Linux (Sistema operativo de ordenadores)AUTOR SEC Vuelapluma, S. L. trad.BIB UTIL # 0860993.ISBN 8448131746.CDU 681.3.06.2 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) Pet3 > CC. COMPUT. I.A. (ESII) Cien. Comp./18

Registro 25 de 27UBICACION BIBLIOTECA I. INFORMATICAAUTOR Eyler, Pat.TITULO Redes LINUX con TCP/IP : guıa avanzada Pat Eyler ;

traduccion, traducciones Vox Populi.PUBLICAC Madrid [etc.] : Prentice Hall , D.L. 2001,DESCRIPCION XVI, 409 p. : il. ; 24 cm.NOTA Bibliografıa: p. 393-397.MATERIA Linux (Sistema operativo de ordenadores)MATERIA Redes de computacion.MATERIA TCP/IP (Protocolos de redes de computacion)AUTOR SEC Vox Populi trad.BIB UTIL # 0861248.ISBN 8420531561.DEP. LEGAL M-28419-2001.CDU 681.3.06.1 > BIBLIOTECA I. INFORMATI ESII/C.2 EYL red --- V

Registro 26 de 27UBICACION BIBLIOTECA I. INFORMATICAAUTOR Petersen, Richard.TITULO Fundamentos de programacion en Linux Richard Petersen ;

traduccion, Cecilia Avila de Baron ; revision tecnica, JoseAndres Martınez Silva.

PUBLICAC Bogota [etc.] : Osborne Mac Graw-Hill , cop. 2001,DESCRIPCION XXIII, 449 p. ; 24 cm.MATERIA Linux (Sistema operativo de ordenadores)AUTOR SEC Avila de Baron, Cecilia trad.AUTOR SEC Martınez Silva, Jose Andres trad.BIB UTIL # 0866095.ISBN 9584102303.CDU 681.3.06.1 > BIBLIOTECA I. INFORMATI ESII/D.4 (LIN) Pet ---

Registro 27 de 27UBICACION BIBLIOTECA I. INFORMATICAAUTOR Lombardo, John.TITULO Embedded Linux John Lombardo.PUBLICAC Indianapolis, Indiana : New Riders , 2001,DESCRIPCION XXVII, 192 p. ; 23 cm.MATERIA Linux (Sistema operativo de ordenadores)BIB UTIL # 0866500.ISBN 073570998X.CDU 681.3.06.1 > LENG. SIST. INFOR. (ESI Leng. Sist. Desp. A-12 ---

29 30

Page 208: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.

Practica 1. El modelo de compilacion

Francisco J. Cortijo Bon

Curso 2011-2012

Objetivos

1. Conocer los distintos tipos de ficheros que intervienen en el proceso de compilacion de programasen C++.

2. Conocer como se relacionan los diferentes tipos de ficheros que intervienen en el proceso decompilacion de programas en C++.

3. Conocer el programa gcc/g++ y saber como trabaja en las distintas etapas del proceso de gene-racion de un archivo ejecutable a partir de uno o mas ficheros fuente.

Indice

1. El modelo de compilacion en C++ 21.1. El preprocesador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.2. El compilador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41.3. El enlazador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41.4. Bibliotecas. El gestor de bibliotecas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2. g++ : el compilador de GNU para C++ 52.1. Un poco de historia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.2. Sintaxis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62.3. Opciones mas importantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

A. Introduccion al depurador DDD 10A.1. Conceptos basicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10A.2. Pantalla principal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10A.3. Ejecucion de un programa paso a paso . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11A.4. Inspeccion y modificacion de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11A.5. Inspeccion de la pila . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12A.6. Mantenimiento de sesiones de depuracion . . . . . . . . . . . . . . . . . . . . . . . . . . 13A.7. Reparacion del codigo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

B. El preprocesador de C++ 13B.1. Constantes simbolicas y macros funcionales . . . . . . . . . . . . . . . . . . . . . . . . . 14

B.1.1. Constantes simbolicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14B.1.2. Macros funcionales (con argumentos) . . . . . . . . . . . . . . . . . . . . . . . . . 15B.1.3. Eliminacion de constantes simbolicas . . . . . . . . . . . . . . . . . . . . . . . . . 15

B.2. Inclusion de ficheros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16B.2.1. Inclusion condicional de codigo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

1

Page 209: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 1 2

1. El modelo de compilacion en C++

En la figura 1 mostramos el esquema basico del proceso de compilacion de programas y creacionde bibliotecas en C++. En este grafico, indicamos mediante un rectangulo con esquinas redondeadaslos diferentes programas involucrados en estas tareas, mientras que los cilindros indican los tipos deficheros (con su extension habitual) que intervienen.

Compilador

Codigo fuentepreprocesado

Gestor debibliotecas

Codigo objeto(.o)

Ficheros de cabecera(.h)

Codigo objeto(.o)

Codigo fuente(.cpp)

Enlazador

Bibliotecas(.a)Bibliotecas

(.a)

Preprocesador

Codigoobjeto(.o)

Codigo ejecutable

Codigo objeto(.o)

(sin extensión)

Figura 1: Esquema del proceso de compilacion (generacion de programas ejecutables) en C++

Este esquema puede servirnos para enumerar las tareas de programacion habituales. La tarea mascomun es la generacion de un programa ejecutable. Como su nombre indica, es un fichero que contienecodigo directamente ejecutable. Este puede construirse de diversas formas:

1. A partir de un fichero con codigo fuente.

2. Enlazando ficheros con codigo objeto.

3. Enlazando el fichero con codigo objeto con una(s) biblioteca(s).

Las dos ultimas requieren que previamente se hayan construido los ficheros objeto (opcion 2) y losficheros de biblioteca (opcion 3). Como se puede comprobar en el esquema anterior, la creacion deestos tambien esta contemplada en el esquema. Ası, es posible generar unicamente ficheros objetopara:

1. Enlazarlos con otros y generar un ejecutable.

Exige que uno de los modulos objeto que se van a enlazar contenga la funcion main().

Esta forma de construir ejecutables es muy comun y usualmente los modulos objeto se borranuna vez se han usado para construir el ejecutable, ya que no tiene interes su permanencia.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 210: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 1 3

2. Incorporarlos a una biblioteca.

Una biblioteca, en la terminologıa de C++, sera es una coleccion de modulos objeto. Entre ellosexistira alguna relacion, que debe entenderse en un sentido amplio: si dos modulos objeto estanen la misma biblioteca, contendran funciones que trabajen sobre un mismo tema (por ejemplo,funciones de procesamiento de cadenas de caracteres).

Si el objetivo final es la creacion de un ejecutable, en ultima instancia uno o varios modulos objetode una biblioteca se enlazaran con un modulo objeto que contenga la funcion main().

Todos estos puntos se discutiran con mucho mas detalle posteriormente. Ahora, introducimos deforma muy general los conceptos y tecnicas mas importantes del proceso de compilacion en C++.

EjercicioEl orden es fundamental para el desarrollo y mantenimiento de programas. Y la premisa maselemental del orden es “un sitio para cada cosa y cada cosa en su sitio”.Hemos visto que en el proceso de desarrollo de software intervienen distintos tipos de fiche-ros. Cada tipo se guardara en un directorio especıfico:

src: contendra los ficheros fuente de C++ (.cpp)

include: contendra los ficheros de cabecera (.h)

obj: contendra los ficheros objeto (.o)

lib: contendra los ficheros de biblioteca (.a)

bin: contendra los ficheros ejecutables. Estos no tienen asociada ninguna extensionpredeterminada, sino que la capacidad de ejecucion es una propiedad del fichero.

En este ejercicio se trata de crear una estructura de directorios de manera que:

1. todos los directorios enumerados anteriormente sean hermanos

2. “cuelguen” de un directorio llamado MP, y

3. el directorio MP cuelgue de vuestro directorio personal (˜)

1.1. El preprocesador

El preprocesador (del ingles, preprocessor ) es una herramienta que filtra el codigo fuente antes deser compilado. El preprocesador acepta como entrada codigo fuente (.cpp) y se encarga de:

1. Eliminar los comentarios.

2. Interpretar y procesar las directivas de preprocesamiento. El preprocesador proporciona un con-junto de directivas que resultan una herramienta sumamente util al programador. Todas las direc-tivas comienzan siempre por el sımbolo #.

Dos de las directivas mas comunmente empleadas en C++ son #include y #define. En la sec-cion B tratamos con mas profundidad estas directivas y algunas otras mas complejas. En cualquiercaso, retomando el esquema mostrado en la figura 1 destacaremos que el preprocesador no genera unfichero de salida (en el sentido de que no se guarda el codigo fuente preprocesado). El codigo resultantese pasa directamente al compilador. Ası, aunque formalmente puden distinguirse las fases de preproce-sado y compilacion, en la practica el preprocesado se considera como la primera fase de la compilacion.Graficamente, en la figura 2 mostramos el esquema detallado de lo que se conoce comunmente porcompilacion.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 211: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 1 4

Codigo objeto(.o)

Ficheros de cabecera(.h)

CompiladorPreprocesador

Codigo fuentepreprocesado

CompilacionCodigo fuente

(.cpp)

Figura 2: Fase de compilacion

1.2. El compilador

El compilador (del ingles, compiler) analiza la sintaxis y la semantica del codigo fuente preprocesadoy lo traduce a un codigo objeto que se almacena en un archivo o modulo objeto (.o).

En el proceso de compilacion se realiza la traduccion del codigo fuente a codigo objeto pero no seresuelven las posibles referencias a objetos externos al archivo. Las referencias externas se refieren avariables y principalmmente a funciones que, aunque se utilizan en el archivo -y por tanto deben estardeclaradas- no se encuentran definidas en este, sino en otro archivo distinto. La declaracion servira alcompilador para comprobar que las referencias externas son sintacticamente correctas.

1.3. El enlazador

El enlazador (del ingles, linker) resuelve las referencias a objetos externos que se encuentran enun fichero fuente y genera un fichero ejecutble. Estas referencias son a objetos que se encuentran enotros modulos compilados, ya sea en forma de ficheros objeto o incorporados en alguna biblioteca (delingles, library).

1.4. Bibliotecas. El gestor de bibliotecas

C++ es un lenguaje muy reducido. Muchas de las posibilidades incorporadas en forma de funcionesen otros lenguajes, no se incluyen en el repertorio de instrucciones de C++. Por ejemplo, el lenguajeno incluye ninguna facilidad de entrada/salida, manipulacion de cadenas de caracteres, funciones ma-tematicas, etc. Esto no significa que C++ sea un lenguaje pobre. Todas estas funciones se incorporana traves de un amplio conjunto de bibliotecas que no forman parte, hablando propiamente, del lenguajede programacion.

No obstante, y afortunadamente, algunas bibliotecas se enlazan automaticamente al generar unprograma ejecutable, lo que induce al error de pensar que las funciones presentes en esas bibliotecasson propias del lenguaje C++. Otra cuestion es que se ha definido y estandarizado la llamada biblio-teca estandar de C++ (en realidad, bibliotecas) de forma que cualquier compilador que quiera tenerel “marchamo” de compatible con el estandard C++ debe asegurar que las funciones proporcionadasen esas bibliotecas se comportan de forma similar a como especifica el comite ISO/IEC para la estan-darizacion de C++ (http://www.open-std.org/jtc1/sc22/wg21/). A efectos practicos, las funciones de labiblioteca estandar pueden considerarse parte del lenguaje C++.

Aun teniendo en cuenta estas consideraciones, el conjunto de bibliotecas disponible y las funcionesincluidas en ellas pueden variar de un compilador a otro y el programador responsable debera asegu-rarse que cuando usa una funcion, esta forma parte de la biblioteca estandar: este es el procedimientomas seguro para construir programas transportables entre diferentes plataformas y compiladores.

Cualquier programador puede desarrollar sus propias bibliotecas de funciones y enriquecer de estamanera el lenguaje de una forma completamente estandarizada. En la figura 1 se muestra el procesode creacion y uso de bibliotecas propias. En esta figura se ilustra que una biblioteca es, en realidad,una “objetoteca”, si se nos permite el termino. De esta forma nos referimos a una biblioteca como a

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 212: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 1 5

una coleccion de modulos objeto. Estos modulos objeto contendran el codigo objeto correspondien-te a variables, constantes y funciones que pueden usarse por otros modulos si se enlazan de formaadecuada.

2. g++ : el compilador de GNU para C++

2.1. Un poco de historia

Fuente: wikipedia (http://es.wikipedia.org/wiki/GNU)El proyecto GNU fue iniciado por Richard Stallman con el objetivo de crear un sistema operativo

completamente libre: el sistema GNU.El 27 de septiembre de 1983 se anuncio publicamente el proyecto por primera vez en el grupo de

noticias net.unix-wizards. Al anuncio original, siguieron otros ensayos escritos por Richard Stallmancomo el “Manifiesto GNU”, que establecieron sus motivaciones para realizar el proyecto GNU, entre lasque destaca “volver al espıritu de cooperacion que prevalecio en los tiempos iniciales de la comunidadde usuarios de computadoras”.

GNU es un acronimo recursivo que significa GNU No es Unix (GNU is Not Unix). Puesto que eningles “gnu” (en espanol “nu”) se pronuncia igual que “new”, Richard Stallman recomienda pronunciar-lo “guh-noo”. En espanol, se recomienda pronunciarlo nu como el antılope africano o foneticamente;por ello, el termino mayoritariamente se deletrea (G-N-U) para su mejor comprension. En sus charlasRichard Stallman finalmente dice siempre ((Se puede pronunciar de cualquier forma, la unica pronun-ciacion erronea es decirle ‘linux’)).

UNIX es un Sistema Operativo no libre muy popular, porque esta basado en una arquitectura queha demostrado ser tecnicamente estable. El sistema GNU fue disenado para ser totalmente compatiblecon UNIX. El hecho de ser compatible con la arquitectura de UNIX implica que GNU este compuestode pequenas piezas individuales de software, muchas de las cuales ya estaban disponibles, comoel sistema de edicion de textos TeX y el sistema grafico X Window, que pudieron ser adaptados yreutilizados; otros en cambio tuvieron que ser reescritos.

Para asegurar que el software GNU permaneciera libre para que todos los usuarios pudieran “ejecu-tarlo, copiarlo, modificarlo y distribuirlo”, el proyecto debıa ser liberado bajo una licencia disenada paragarantizar esos derechos al tiempo que evitase restricciones posteriores de los mismos. La idea seconoce en Ingles como copyleft -’copia permitida’- (en clara oposicion a copyright -’derecho de copia’-),y esta contenida en la Licencia General Publica de GNU (GPL).

En 1985, Stallman creo la Free Software Foundation (FSF o Fundacion para el Software Libre) paraproveer soportes logısticos, legales y financieros al proyecto GNU. La FSF tambien contrato progra-madores para contribuir a GNU, aunque una porcion sustancial del desarrollo fue (y continua siendo)producida por voluntarios. A medida que GNU ganaba renombre, negocios interesados comenzaron acontribuir al desarrollo o comercializacion de productos GNU y el correspondiente soporte tecnico. En1990, el sistema GNU ya tenıa un editor de texto llamado Emacs, un exitoso compilador (GCC), y lamayor parte de las bibliotecas y utilidades que componen un sistema operativo UNIX tıpico. Pero faltabaun componente clave llamado nucleo (kernel en ingles).

En el manifiesto GNU, Stallman menciono que “un nucleo inicial existe, pero se necesitan muchosotros programas para emular Unix”. El se referıa a TRIX, que es un nucleo de llamadas remotas a pro-cedimientos, desarrollado por el MIT y cuyos autores decidieron que fuera libremente distribuido; TRIXera totalmente compatible con UNIX version 7. En diciembre de 1986 ya se habıa trabajado para modi-ficar este nucleo. Sin embargo, los programadores decidieron que no era inicialmente utilizable, debidoa que solamente funcionaba en “algunos equipos sumamente complicados y caros” razon por la cualdeberıa ser portado a otras arquitecturas antes de que se pudiera utilizar. Finalmente, en 1988, se deci-dio utilizar como base el nucleo Mach desarrollado en la CMU. Inicialmente, el nucleo recibio el nombrede Alix (ası se llamaba una novia de Stallman), pero por decision del programador Michael Bushnell fuerenombrado a Hurd. Desafortunadamente, debido a razones tecnicas y conflictos personales entre losprogramadores originales, el desarrollo de Hurd acabo estancandose.

En 1991, Linus Torvalds empezo a escribir el nucleo Linux y decidio distribuirlo bajo la licencia

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 213: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 1 6

GPL. Rapidamente, multiples programadores se unieron a Linus en el desarrollo, colaborando a travesde Internet y consiguiendo paulatinamente que Linux llegase a ser un nucleo compatible con UNIX. En1992, el nucleo Linux fue combinado con el sistema GNU, resultando en un sistema operativo libre ycompletamente funcional. El Sistema Operativo formado por esta combinacion es usualmente conocidocomo “GNU/Linux” o como una “distribucion Linux” y existen diversas variantes.

Tambien es frecuente hallar componentes de GNU instalados en un sistema UNIX no libre, en lugarde los programas originales para UNIX. Esto se debe a que muchos de los programas escritos porel proyecto GNU han demostrado ser de mayor calidad que sus versiones equivalentes de UNIX. Amenudo, estos componentes se conocen colectivamente como “herramientas GNU”. Muchos de losprogramas GNU han sido tambien transportados a otros sistemas operativos como Microsoft Windowsy Mac OS X.

GNU Compiler Collection (coleccion de compiladores GNU) es un conjunto de compiladores crea-dos por el proyecto GNU. GCC es software libre y lo distribuye la FSF bajo la licencia GPL.

Estos compiladores se consideran estandar para los sistemas operativos derivados de UNIX, decodigo abierto o tambien de propietarios, como Mac OS X. GCC requiere el conjunto de aplicacionesconocido como binutils para realizar tareas como identificar archivos objeto u obtener su tamano paracopiarlos, traducirlos o crear listas, enlazarlos, o quitarles sımbolos innecesarios.

Originalmente GCC significaba GNU C Compiler (compilador GNU para C), porque solo compilabael lenguaje C. Posteriormente se extendio para compilar C++, Fortran, Ada y otros.

g++ es el alias tradicional de GNU C++, un conjunto gratuito de compiladores de C++. Forma partedel GCC. En sistemas operativos GNU, gcc es el comando usado para ejecutar el compilador de C,mientras que g++ ejecuta el compilador de C++.

Otros programas del Proyecto GNU relacionados con nuestra materia son:

GNU ld: la implementacion de GNU del enlazador de Unix ld. Su nombre se forma a partir de lapalabra loader

Un enlazador es un programa que toma los ficheros de codigo objeto generado en los primerospasos del proceso de compilacion, la informacion de todos los recursos necesarios (biblioteca),quita aquellos recursos que no necesita, y enlaza el codigo objeto con su(s) biblioteca(s) y produceun fichero ejecutable. En el caso de los programas enlazados dinamicamente, el enlace entre elprograma ejecutable y las bibliotecas se realiza en tiempo de carga o ejecucion del programa.

GNU ar: la implementacion de GNU del archivador de Unix ar. Su nombre proviene de la palabraarchiver

Es una utilidad que mantiene grupos de ficheros como un unico fichero (basicamente, un empaque-tador-desempaquetador). Generalmente, se usa ar para crear y actualizar ficheros de bibliote-ca que utiliza el enlazador; sin embargo, se puede usar para crear archivos con cualquier otroproposito.

2.2. Sintaxis

La ejecucion de g++ sigue el siguiente patron sintactico:

g++ [ -opcion [argumento(s) opcion]] nombre fichero

donde:

Cada opcion va precedida por el signo - Algunas opciones no estan acompanadas de argumen-tos (por ejemplo, -c o -g) de ahı que argumento(s) opcion sea opcional.

En el caso de ir acompanadas de algun argumento, se especifican a continuacion de la opcion.Por ejemplo, la opcion -o saludo.o indica que el nombre del fichero resultado es saludo.o,la opcion -I /usr/include indica que se busquen los ficheros de cabecera en el directorio/usr/include, etc. Las opciones mas importantes se describen con detalle en la seccion 2.3.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 214: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 1 7

nombre fichero indica el fichero a procesar. Siempre debe especificarse.

El compilador interpreta por defecto que un fichero contiene codigo en un determinado formato(C, C++, fichero de cabecera, etc.) dependiendo de la extension del fichero. Las extensiones masimportantes que interpreta el compilador son las siguientes: .c (codigo fuente C), .h (fichero decabecera: este tipo de ficheros no se compilan ni se enlazan directamente, sino a traves de suinclusion en otros ficheros fuente), .cpp (codigo fuente C++).

Por defecto, el compilador realizara distintas tareas dependiendo del tipo de fichero que se leespecifique. Como es natural, existen opciones que especifican al compilador que realice soloaquellas etapas del proceso de compilacion que deseemos.

2.3. Opciones mas importantes

Las opciones mas frecuentemente empleadas son las siguientes:

-ansi considera unicamente codigo fuente escrito en C/C++ estandar y rechaza cualquier extension quepudiese tener conflictos con ese estandar.

-c realizar solamente el preprocesamiento y la compilacion de los ficheros fuentes. No se lleva acabo la etapa de enlazado.

Observe que estas acciones son las que corresponden a lo que se ha definido como com-pilacion. El hecho de tener que modificar el comportamiento de g++ con esta opcion para quesolo compile es indicativo de que el comportamiento por defecto de g++ no es -solo- compilarsino realizar el trabajo completo: compilar y enlazar para crear un ejecutable.

El programa enlazador proporcionado por GNU es ld. Sin embargo, no es usual llamar a esteprograma explıcitamente sino que este es invocado convenientemente por g++. Ası, vemos queg++ es mas que un compilador (formalmente hablando) ya que al llamar a g++ se proprocesa elcodigo fuente, se compila, e incluso se enlaza.

Ejercicio1. Crear el fichero saludo.cpp que imprima en la pantalla un mensaje de bienvenida (el

famoso ¡¡hola, mundo!!) y guardarlo en el directorio src.

2. Ejecutar la siguiente orden y observar e interpretar el resultado

g++ src/saludo.cpp

3. Ejecutar la siguiente orden y observar e interpretar el resultado

g++ -c src/saludo.cpp

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 215: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 1 8

-o fichero salida especifica el nombre del fichero de salida, resultado de la tarea solicitada al compi-lador.

Si no se especifica la opcion -o, el compilador generara un fichero y le asignara un nombre pordefecto (dependiendo del tipo de fichero que genere). Lo normal es que queramos asignarle unnombre determinado por nosotros, por lo que esta opcion siempre se empleara.

EjercicioEjecutar la siguiente orden y observar e interpretar el resultado. El diagrama de dependenciasse muestra en la figura 3.g++ -o bin/saludo src/saludo.cpp

Figura 3: Diagrama de dependencias para saludo

EjercicioEjecutar las siguientes ordenes y observar e interpretar el resultado. El diagrama de depen-dencias se muestra en la figura 4.

1. g++ -c -o obj/saludo.o src/saludo.cpp

2. g++ -o bin/saludo en dos pasos obj/saludo.o

Figura 4: Diagrama de dependencias para saludo en dos pasos

-W all Muestra todos los mensajes de advertencia del compilador.

-g Incluye en el ejecutable la informacion necesaria para poder trazarlo empleando un depurador.

-v Muestra con detalle en las ordenes ejecutadas por g++.

Ejercicio1. Ejecutar la siguiente orden y observar e interpretar el resultado

g++ -v -o bin/saludo src/saludo.cpp

2. Ejecutar la siguiente orden y observar e interpretar el resultado

g++ -Wall -v -o bin/saludo src/saludo.cpp

3. Ejecutar la siguiente orden y observar e interpretar el resultado, comparando el tamanodel fichero obtenido con el de saludo

g++ -g -o bin/saludo con g src/saludo.cpp

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 216: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 1 9

-I path especifica el directorio donde se encuentran los ficheros a incluir por la directiva #include.Se puede utilizar esta opcion varias veces para especificar distintos directorios.

EjercicioEjecutar la siguiente orden:

g++ -v -c -I/usr/local/include -o obj/saludo.o src/saludo.cpp

Observad como anade el directorio /usr/local/include a la lista de directorios en losque buscar los ficheros de cabecera. Si el fichero saludo.cpp incluyera un fichero de ca-becera que se encuentra en el directorio /usr/local/include, la orden anterior haceque g++ pueda encontrarlo para el preprocesador. Pueden incluirse cuantos directorios sedeseen, por ejemplo:

g++ -v -c -I/usr/local/include -I/include -o obj/saludo.osrc/saludo.cpp

-L path indica al enlazador el directorio donde se encuentran los ficheros de biblioteca. Como ocurrecon la opcion -I, se puede utilizar la opcion -L varias veces para especificar distintos directoriosde biblioteca.

1. Los ficheros de biblioteca que deben usarse se proporcionan a g++ con la opcion -lfichero.

2. Esta opcion hace que el enlazador busque en los directorios de bibliotecas (entre los queestan los especificados con -L) un fichero de biblioteca llamado libfichero.a y lo usa paraenlazarlo.

EjercicioEjecutar la siguiente orden:

g++ -v -o bin/saludo -L/usr/local/lib obj/saludo.o -lutils

Observe que se llama al enlazador para que enlace el objeto saludo.o con la bibliotecalibutils.a y obtenga el ejecutable saludo. Concretamente se busca el fichero de biblio-teca libutils.a en el directorio /usr/local/lib.

Copiar el fichero potencias.cpp en el directorio src y ejecutar las siguiente orden. Obser-var e interpretar los resultado

g++ -o bin/potencias src/potencias.cpp -lm

Ejecutar ahora la misma orden pero sin enlazar con la biblioteca matematica (libm.a). Ob-servara que funciona correctamente ¿porque? Ejecute la siguiente orden para interpretarlo:g++ -v -o bin/potencias src/potencias.cpp -lm

-D nombre[=cadena] define una constante simbolica llamada nombre con el valor cadena. Si no seespecifica el valor, nombre simplemente queda definida. cadena no puede contener blancos nitabuladores. Equivale a una linea #define al principio del fichero fuente, salvo que si se usa -D, elambito de la macrodefinicion incluye todos los ficheros especificados en la llamada al compilador.

-O Optimiza el tamano y la velocidad del codigo compilado. Existen varios niveles de optimizacioncada uno de los cuales proporciona un codigo menor y mas rapido a costa de emplear mastiempo de compilacion y memoria principal. Ordenadas de menor a mayor intensidad son: -O,-O1, -O2 y -O3. Existe una opcion adicional -Os orientada a optimizar exclusivamente el tamanodel codigo compilado (esta opcion no lleva a cabo ninguna optimizacion de velocidad que impliqueun aumento de codigo).

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 217: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 1 10

A. Introduccion al depurador DDD

A.1. Conceptos basicos

El programa ddd es, basicamente, una interfaz (front-end) separada que se puede utilizar con undepurador en lınea de ordenes. En el caso que concierne a este documento, ddd sera la interfaz de altonivel del depurador gdb.

Para poder utilizar el depurador es necesario compilar los ficheros fuente con la opcion -g. En otrocaso mostrara un mensaje de error. En cualquier caso, el depurador se invoca con la orden

ddd fichero-binario

A.2. Pantalla principal

La pantalla principal del depurador se muestra en la figura 5.a).

(a) (b)

Figura 5: Pantalla principal de ddd

En ella se pueden apreciar las siguientes partes.

1. Zona de menu y barra de herramientas. Con los componentes tıpicos de cualquier programa.

2. Zona de visualizacion de datos. En esta parte de la ventana se mostraran las variables que se ha-yan elegido y sus valores asociados. Si esta zona no estuviese visible, menu View - Data Window.

3. Zona de visualizacion de codigo fuente. Se muestra el codigo fuente que se esta depurando y lalınea por la que se esta ejecutando el programa. Si esta zona no estuviese visible, menu View -Source Window.

4. Zona de visualizacion de mensajes de gdb. Muestra los mensajes del verdadero depurador, eneste caso, gdb· Si esta zona no estuviese visible, menu View - Gdb Console.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 218: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 1 11

Sobre la ventala principal aparece una ventana flotante de herramientas que se muestra en la fi-gura 5.b) desde la que se pueden hacer, de forma simplificada, las mayorıa de las operaciones dedepuracion.

A.3. Ejecucion de un programa paso a paso

Una vez cargado un programa binario, se puede comenzar la ejecucion siguiendo cualquiera delos metodos mostrados en el cuadro 1. Hay que tener en cuenta que esta orden inicia la ejecuciondel programa de la misma forma que si se hubiese llamado desde la lınea de argumentos, de formaque, de no haber operaciones de entrada/salida desde el teclado, el programa comenzara a ejecutarsesin control directo desde el depurador hasta que termine, momento en el que devuelve el control aldepurador mostrando el siguiente mensaje

(gdb) Program exited normallyEn cualquier momento se puede terminar la ejecucion de un programa mediante distintas formas,

la mas rapida es mediante la orden kill (ver cuadro 1). Tambien se pueden pasar argumentos a lafuncion main desde la ventana que aparece en la figura 6.

Figura 6: Ventana para pasar argumentos a main

Para comenzar a ejecutar un programa bajo control del depurador es conveniente colocar un puntode ruptura1 en la primera lınea ejecutable del codigo. Una vez colocado este punto de ruptura se puedecomenzar la ejecucion del programa paso a paso segun lo mostrado en el cuadro 1 y teniendo encuenta que ddd senala la lınea de codigo activa con una pequena flecha verde a la izquierda de la lınea

. ddd tambien muestra la salida de la ejecucion del programa en una ventana independiente (DDD:Execution window). Si esta ventana no estuviese visible, entonces puede mostrarse pulsando enmenu Program - Run in execution window.

A.4. Inspeccion y modificacion de datos

ddd, como cualquier depurador, permite inspeccionar los valores asociados a cualquier variable ymodificar sus valores. Se puede visualizar datos temporalmente, de forma que solo se visualizan sus

1Un punto de ruptura (abreviadamente PR) es una marca en una lınea de codigo ejecutable de forma que su ejecucion siemprese interrumpe antes de ejecutar esta lınea, pasando el control al depurador. ddd visualiza esta marca como una pequena senal

de STOP .

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 219: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 1 12

valores durante un tiempo limitado, o permanentemente en la ventana de datos (watch, de forma quesus valores se visualicen durante toda la ejecucion (ver cuadro 1). Es necesario aclarar que solo sepuede visualizar el valor de una variable cuando la lınea de ejecucion activa se encuentre en un ambitoen el que sea visible esta variable. Asımismo, ddd permite modificar, en tiempo de ejecucion, los valoresasociados a cualquier variable de un programa, bien desde la ventana del codigo, bien desde la ventanade visualizacion de datos.

A.5. Inspeccion de la pila

Durante el proceso de ejecucion de un programa se suceden llamadas a modulos que se van alma-cenando en la pila. ddd ofrece la posibilidad de inspeccionar el estado de esta pila y analizar que lla-madas se estan resolviendo en un momendo dado de la ejecucion de un programa (ver cuadro 1).

Accion Menu Teclas Barra herra-mientas

Otro

Comenzar la ejecucion Program -Run

F2 Run

Matar el programa Program - Kill F4 KillPoner un PR - - Break Pinchar derecho - Set

breakpointQuitar un PR - - - Pinchar derecho sobre

STOP - Disable Break-point

Paso a Paso (sı llamadas) Program -Step

F5 Step

Paso a Paso (no llamadas) Program -Next

F6 Next

Continuar indefinidamente Program -Continue

F9 Cont

Continuar hasta el cursor Program -Until

F7 Until Pinchar derecho - Conti-nue Until Here

Continuar hasta el final de lafuncion actual

Program - Fi-nish

F8 Finish

Mostrar temporalmente el valorde una variable

Escribir sunombre en(): - BotonPrint

- - Situar raton sobre cual-quier ocurrencia

Mostrar permanentemente elvalor de una variable (ventanade datos)

Escribir sunombre en(): - BotonDisplay

- - Pinchar derecho sobrecualquier ocurrencia -Display

Borrar una variable de la ven-tana de datos

- - - Pinchar derecho sobre vi-sualizacion - Undisplay

Cambiar el valor de una varia-ble

Pinchar so-bre variable(en ventanade datos ocodigo) -Boton Set

- - Pinchar derecho sobre vi-sualizacion - Set value

Cuadro 1: Principales acciones del programa ddd y las formas mas comunes de invocarlas

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 220: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 1 13

Figura 7: Ventana que muestra el estado de la pilla de llamadas a modulos

A.6. Mantenimiento de sesiones de depuracion

Una vez que se cierra el programa ddd se pierde toda la informacion sobre PR, visualizacion per-manente de datos, etc, que se hubiese configurado a lo largo de una sesion de depuracion. Para evi-tar volver a introducir toda esta informacion, ddd permite grabar sesiones de depuracion a traves delmenu principal (opciones de sesiones). Cuando se graba una sesion de depuracion se graba exclusi-vamente la configuracion de depuracion, en ningun caso se puede volver a restaurar la ejecucion de unprograma antiguo con sus valores de memoria, etc.

A.7. Reparacion del codigo

Durante una sesion con ddd es normal que sea necesario modificar el codigo para reparar algunerror detectado. En este caso es necesario mantener bien actualizada la version del programa que seencuentra cargada. Para ello lo mejor es interrumpir la ejecucion del programa, recompilar los modulosque fuese necesario y recargarlo para continuar la depuracion.

B. El preprocesador de C++

Recordemos que el preprocesamiento es la primera etapa del proceso de compilacion de programasC++. El preprocesador es una herramienta que filtra el codigo fuente antes de ser compilado. Aceptacomo entrada codigo fuente y se encarga de:

1. Eliminar los comentarios.

2. Interpretar y procesar las directivas de preprocesamiento. El preprocesador proporciona un con-junto de directivas que resultan una herramienta sumamente util al programador. Todas las direc-tivas comienzan siempre por el sımbolo #.

#include: Sustituye la lınea por el contenido del fichero especificado.Por ejemplo, #include <iostream> incluye el fichero iostream.h, que contiene decla-raciones de tipos y funciones de entrada/salida de la biblioteca estandar de C++. La inclusionimplica que todo el contenido del fichero incluıdo sustituye a la lınea #include.Los nombres de los ficheros de cabecera heredados de C comienzan por la letra c, y se inclu-yen usando la misma sintaxis. Por ejemplo: #include <cstring>,#include<cstdlib>,. . .

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 221: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 1 14

#define: Define una constante (identificador) simbolico.Sustituye las apariciones del identificador por el valor especificado, salvo si el identificadorse encuentra dentro de una constante de cadena de caracteres (entre comillas).Por ejemplo, #define MAX_SIZE 100 establece el valor de la constante simbolica MAX_SIZEa 100. En el programa se utilizara la constante simbolica y el preprocesador sustituye cadaaparacion de MAX_SIZE por el literal 100 (de tipo int).

El uso de las directivas de preprocesamiento proporciona varias ventajas:

1. Facilita el desarrollo del software.

2. Facilita la lectura de los programas.

3. Facilita la modificacion del software.

4. Ayuda a hacer el codigo C++ portable a diferentes arquitecturas.

5. Facilita el ocultamiento de informacion.

En este apendice veremos algunas de las directivas mas importantes del preprocesador de C++:

#define: Creacion de constantes simbolicas y macros funcionales.

#undef: Eliminacion de constantes simbolicas.

#include: Inclusion de ficheros.

#if (#else, #endif): Inclusion condicional de codigo.

B.1. Constantes simbolicas y macros funcionales

B.1.1. Constantes simbolicas

La directiva #define se puede emplear para definir constantes simbolicas de la siguiente forma:

#define identificador texto de sustitucion

El preprocesador sustituye todas las apariciones de identificador por el texto de sustitucion. Funcionade la misma manera que la utilidad “Busca y Sustituye” que tienen casi todos los editores de texto.La unica excepcion son las apariciones dentro de constantes de cadena de caracteres (delimitadasentre comillas), que no resultan afectadas por la directiva #define. El ambito de la definicion de unaconstante simbolica se establece desde el punto en el que se define hasta el final del fichero fuente enel que se encuentra.Veamos algunos ejemplos sencillos.

#define TAMMAX 256

hace que sustituya todas las apariciones del identificador TAMMAX por la constantenumerica (entera) 256.

#define UTIL_VEC

simplemente define la constante simbolica UTIL_VEC, aunque sin asignarle ningun va-lor de sustitucion: se puede interpretar como una “bandera” (existe/no existe). Se sueleemplear para la inclusion condicional de codigo (ver seccion B.2.1 de este apendice).

#define begin {#define end }

para aquellos que odian poner llaves en el comienzo y final de un bloque y prefierenescribir begin..end.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 222: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 1 15

B.1.2. Macros funcionales (con argumentos)

Podemos tambien definir macros funcionales (con argumentos). Son como “pequenas funciones”pero con algunas diferencias:

1. Puesto que su implementacion se lleva a cabo a traves de una sustitucion de texto, su efecto enel programa no es el de las funciones tradicionales.

2. En general, las macros recursivas no funcionan.

3. En las macros funcionales el tipo de los argumentos es indiferente. Suponen una gran ventajacuando queremos hacer el mismo tratamiento a diferentes tipos de datos.

Las macros funcionales pueden ser problematicas para los programadores descuidados. Hemosde recordar que lo unico que hacen es realizar una sustitucion de texto. Por ejemplo, si definimos lasiguiente macro funcional:

#define DOBLE(x) x+x

y tenemos la sentencia

a = DOBLE(b) * c;

su expansion sera la siguiente: a = b + b * c; Ahora bien, puesto que el operador * tiene mayorprecedencia que +, tenemos que la anterior expansion se interpreta, realmente, como a = b + (b * c);lo que probablemente no coincide con nuestras intenciones iniciales. La forma de “reforzar” la definicionde DOBLE() es la siguiente

#define DOBLE(x) ((x)+(x))

con lo que garantizamos la evaluacion de los operandos antes de aplicarle la operacion de suma. Eneste caso, la sentencia anterior (a = DOBLE(b) * c) se expande a

a = ((b) + (b)) * c;

con lo que se avalua la suma antes del producto.Veamos ahora algunos ejemplos adicionales.

#define MAX(A,B) ((A)>(B)?(A):(B))

La ventaja de esta definicion de la “funcion” maximo es que podemos emplearla paracualquier tipo para el que este definido un orden (si esta definido el operador >)

#define DIFABS(A,B) ((A)>(B)?((A)-(B)):((B)-(A)))

Calcula la diferencia absoluta entre dos operandos.

B.1.3. Eliminacion de constantes simbolicas

La directiva: #undef identificador anula una definicion previa del identificador especificado. Es pre-ciso anular la definicion de un identificador para asignarle un nuevo valor con un nuevo #define.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 223: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 1 16

B.2. Inclusion de ficheros

La directiva #include hace que se incluya el contenido del fichero especificado en la posicionen la que se encuentra la directiva. Se emplean casi siempre para realizar la inclusion de ficheros decabecera de otros modulos y/o bibliotecas. El nombre del fichero puede especificarse de dos formas:

#include <fichero>

#include "fichero"

La unica diferencia es que <fichero> indica que el fichero se encuentra en alguno de los directorios deficheros de cabecera del sistema o entre los especificados como directorios de ficheros de cabecera(opcion -I del compilador: ver seccion 2.3), mientras que "fichero" indica que se encuentra en eldirectorio donde se esta realizando la compilacion. Ası,

#include <iostream>

incluye el contenido del fichero de cabecera que contiene los prototipos de las funciones de entra-da/salida de la biblioteca estandar de C++. Busca el fichero entre los directorios de ficheros de cabeceradel sistema.

B.2.1. Inclusion condicional de codigo

La directiva #if evalua una expresion constante entera. Se emplea para incluir codigo de formaselectiva, dependiendo del valor de condiciones evaluadas en tiempo de compilacion (en concreto,durante el preprocesamiento). Veamos algunos ejemplos.

#if ENTERO == LARGOtypedef long mitipo;

#elsetypedef int mitipo;

#endif

Si la constante simbolica ENTERO tiene el valor LARGO se crea un alias para el tipo long llamadomitipo. En otro caso, mitipo es un alias para el tipo int.

La clausula #else es opcional, aunque siempre hay que terminar con #endif. Podemos encadenaruna serie de #if - #else - #if empleando la directiva #elif (resumen de la secuencia #else - #if):

#if SISTEMA == SYSV#define CABECERA "sysv.h"

#elif SISTEMA == LINUX#define CABECERA "linux.h"

#elif SISTEMA == MSDOS#define CABECERA "dos.h"

#else#define CABECERA "generico.h"

#endif

#include CABECERA

De esta forma, estamos seguros de que incluiremos el fichero de cabecera apropiado al sistema enel que estemos compilando. Por supuesto, debemos especificar de alguna forma el valor de la constanteSISTEMA (por ejemplo, usando macros en la llamada al compilador, como indicamos en la seccion 2.3).

Podemos emplear el predicado: defined(identificador) para comprobar la existencia del identifi-cador especificado. Este existira si previamente se ha utilizado en una macrodefinicion (siguiendo a laclausula #define). Este predicado se suele usar en su forma resumida (columna derecha):

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 224: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 1 17

#if defined(identificador) #ifdef(identificador)#if !defined(identificador) #ifndef(identificador)

Su utilizacion esta aconsejada para prevenir la inclusion repetida de un fichero de cabecera en unmismo fichero fuente. Aunque pueda parecer que esto no ocurre a menudo ya que a nadie se le ocurreescribir, por ejemplo, en el mismo fichero:

#include "cabecera1.h"#include "cabecera1.h"

sı puede ocurrir lo siguiente:

#include "cabecera1.h"#include "cabecera2.h"

y que cabecera2.h incluya, a su vez, a cabecera1.h (una inclusion “transitiva”). El resultado es queel contenido de cabecera1.h se copia dos veces, dando lugar a errores por definicion multiple. Estose puede evitar protegiendo el contenido del fichero de cabecera de la siguiente forma:

#ifndef (HDR)#define HDR

Resto del contenido del fichero de cabecera

#endif

En este ejemplo, la constante simbolica HDR se emplea como testigo, para evitar que nuestro ficherode cabecera se incluya varias veces en el programa que lo usa. De esta forma, cuando se incluye laprimera vez, la constante HDR no esta definida, por lo que la evaluacion de #ifndef(HDR) es cierta,se define y se procesa (incluye) el resto del fichero de cabecera. Cuando se intenta incluir de nuevo,como HDR ya esta definida la evaluacion de #ifndef (HDR) es falsa y el preprocesador salta a lalınea siguiente al predicado #endif. Si no hay nada tras este predicado el resultado es que no incluyenada.

Todos los ficheros de cabecera que acompanan a los ficheros de la biblioteca estandar tienen unprologo de este estilo.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 225: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 1 18

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 226: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.

Practica 2. El programa make y los ficheros makefile

Francisco J. Cortijo Bon

Curso 2011-2012

Objetivos

1. Ser conscientes de la dificultad de mantener proyectos complejos (con multiples ficheros y depen-dencias) si no se utilizan herramientas especıficas.

2. Conocer el funcionamiento de la orden make.

3. Conocer la sintaxis de los ficheros makefile y como son interpretados por make.

Indice

1. El programa make 201.1. Sintaxis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211.2. Opciones mas importantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211.3. Funcionamiento de make . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

2. Ficheros makefile 222.1. Comentarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222.2. Reglas. Reglas explıcitas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222.3. Ordenes. Prefijos de ordenes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242.4. Destinos Simbolicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252.5. Destinos .PHONY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252.6. Macros en ficheros makefile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262.7. Macros predefinidas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

A. Sustituciones en macros 28

B. Macros como parametros en la llamada a make 28

C. Reglas implıcitas 29C.1. Reglas implıcitas patron . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30C.2. Reglas patron estaticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

D. Directivas condicionales en ficheros makefile 31

19

Page 227: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 2 20

La gestion y mantenimiento del software durante el proceso de desarrollo puede ser una tarea arduasi este se estructura en diferentes ficheros fuente y se utilizan, ademas, funciones ya incorporadas enficheros de biblioteca. Durante el proceso de desarrollo se modifica frecuentemente el sotware y lasmodificaciones incorporadas pueden afectar a otros modulos: la modificacion de una funcion en unmodulo afecta necesariamente a los modulos que usan dicha funcion, que deben actualizarse. Estasmodificaciones deben propagarse a los modulos que dependen de aquellos que han sido modificados,de forma que el programa ejecutable final refleje las modificaciones introducidas.

Esta cascada de modificaciones afectara forzosamente al programa ejecutable final. Si esta se-cuencia de modificaciones no se realiza de forma ordenada y metodica podemos encontrarnos con unprograma ejecutable que no considera las modificaciones introducidas. Este problema es tanto masacusado cuanto mayor sea la complejidad del proyecto software, lo que implica unos complejos diagra-mas de dependencias entre los modulos implicados, haciendo tedioso y propenso a errores el procesode propagacion hacia el programa ejecutable de las actualizaciones introducidas.

La utilidad make proporciona los mecanismos adecuados para la gestion de proyectos software. Estautilidad mecaniza muchas de las etapas de desarrollo y mantenimiento de un programa, proporcionandomecanismos simples para obtener versiones actualizadas de los programas, por complicado que seael diagrama de dependencias entre modulos asociado al proyecto. Esto se logra proporcionando a lautilidad make la secuencia de mandatos que crean ciertos archivos, y la lista de archivos que necesitanotros archivos (lista de dependencias) para ser actualizados antes de que se hagan dichas operaciones.Una vez especificadas las dependencias entre los distintos modulos del proyecto, cualquier cambio enuno de ellos provocara la creacion de una nueva version de los modulos dependientes de aquel quese modifica, reduciendo al mınimo necesario e imprescindible el numero de modulos a recompilar paracrear un nuevo fichero ejecutable.

La utilizacion de la orden make exige la creacion previa de un fichero de descripcion llamado generi-camente makefile, que contiene las ordenes que debe ejecutar make, ası como las dependenciasentre los distintos modulos del proyecto. Este archivo de descripcion es un fichero de texto.

La sintaxis del fichero makefile varıa ligeramente de un sistema a otro, al igual que la sintaxisde make, si bien las lıneas basicas son similares y la comprension y dominio de ambos en un sistemahace que el aprendizaje para otro sistema sea una tarea trivial. Esta vision de generalidad es la quenos impulsa a estudiar esta utilidad y descartemos el uso de gestores de proyectos como los que pro-porcionan los entornos de programacion integrados. En esta seccion nos centraremos en la descripcionde la utilidad make y en la sintaxis de los ficheros makefile de GNU.

Resumiendo, el uso de la utilidad make conjuntamente con los ficheros makefile proporcionan elmecanismo para realizar una gestion inteligente, sencilla y precisa de un proyecto software, ya quepermite:

1. Una forma sencilla de especificar la dependencia entre los modulos de un proyecto software,

2. La recompilacion unicamente de los modulos que han de actualizarse,

3. Obtener siempre la version ultima que refleja las modificaciones realizadas, y

4. Un mecanismo casi estandar de gestion de proyectos software, independiente de la plataforma enla que se desarrolla.

1. El programa make

La utilidad make utiliza las reglas descritas en el fichero makefile para determinar que ficheros hade construir y como construirlos.

Examinando las listas de dependencia determina que ficheros ha de reconstruir. El criterio es muysimple, se comparan fechas y horas: si el fichero fuente es mas reciente que el fichero destino, re-construye el destino. Este sencillo mecanismo (suponiendo que se ha especificado correctamente ladependencia entre modulos) hace posible mantener siempre actualizada la ultima version.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 228: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 2 21

1.1. Sintaxis

La sintaxis de la llamada al programa make es la siguiente:

make [opciones] [destino(s)]]

donde:

cada opcion va precedida por un signo - o una barra inclinada /. En la seccion 1.2 enumeramoslas opciones mas importantes.

destino indica el destino que debe crear. Generalmente se trata del fichero que debe crear oactualizar, estando especificado en el fichero makefile el procedimiento de creacion/actualizaciondel mismo (seccion 2.3). Una explicacion detallada de los destinos puede encontrarse en lassecciones 2.2 y 2.4.

Observese que tanto las opciones como los destinos son opcionales, por lo que podrıa ejecutarsemake sin mas. El efecto de esta ejecucion, ası como el funcionamiento detallado de make cuando seespecifican destinos se explica en la seccion 1.3.

1.2. Opciones mas importantes

Las opciones mas frecuentemente empleadas son las siguientes:

-h o --help Proporciona ayuda acerca de make.

-f fichero. Utilizaremos esta opcion si se proporciona a make un nombre de fichero distinto del demakefile o Makefile. Se toma el fichero llamado fichero como el fichero makefile.

-n , --just-print, --dry-run o --recon: Muestra las instrucciones que ejecutarıa la utilidadmake, pero no los ejecuta. Sirve para verificar la correccion de un fichero makefile.

-p , --print-data-base: Muestra las reglas y macros asociadas al fichero makefile, incluidas laspredefinidas.

1.3. Funcionamiento de make

El funcionamiento de la utilidad make es el siguiente:

1. En primer lugar, busca el fichero makefile que debe interpretar. Si se ha especificado la opcion-f fichero, busca ese fichero. Si no, busca en el directorio actual un fichero llamado makefileo Makefile. En cualquier caso, si lo encuentra, lo interpreta; si no, da un mensaje de error ytermina.

2. Intenta construir el(los) destino(s) especificado(s). Si no se proporciona ningun destino, intentaconstruir solamente el primer destino que aparece en el fichero makefile. Para construir un des-tino es posible que deba construir antes otros destinos si el destino especificado depende deotros que no estan construidos. Para saber que destinos debe construir comprueba las listas dedependencias. Esta reaccion en cadena se llama dependencia encadenada.

3. Si en cualquier paso falla al construir algun destino, se detiene la ejecucion, muestra un mensajede error y borra el destino que estaba construyendo.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 229: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 2 22

2. Ficheros makefile

Un fichero makefile contiene las ordenes que debe ejecutar la utilidad make, ası como las depen-dencias entre los distintos modulos del proyecto. Este archivo de descripcion es un fichero de texto.

Los elementos que pueden incluirse en un fichero makefile son los siguientes:

1. Comentarios.

2. Reglas explıcitas.

3. Ordenes.

4. Destinos simbolicos.

2.1. Comentarios

Los comentarios tienen como objeto clarificar el contenido del fichero makefile. Una lınea del co-mentario tiene en su primera columna el sımbolo #. Los comentarios tienen el ambito de una lınea.

EjercicioCrear un fichero llamado makefile con el siguiente contenido:

# Fichero: makefile# Construye el ejecutable saludo a partir de saludo.cppbin/saludo : src/saludo.cpp

g++ src/saludo.cpp -o bin/saludo

Se incluyen dos lıneas de comentario al principio del fichero makefile que indican las tareasque realizara la utilidad make.Si el fichero makefile se encuentra en el directorio actual, para realizar las acciones en elindicadas tan solo habra que ejecutar la orden:% makeya que el fichero makefile se llama makefile. El mismo efecto hubieramos obtenido ejecu-tando la orden:% make -f makefile

2.2. Reglas. Reglas explıcitas

Las reglas constituyen el mecanismo por el que se indica a la utilidad make los destinos (objetivos),las listas de dependencias y como construir los destinos. Como puede deducirse, son la parte funda-mental de un fichero makefile. Las reglas que instruyen a make son de dos tipos: explıcitas e implıcitasy se definen de la siguiente forma:

Las reglas explıcitas dan instrucciones a make para que construya los ficheros especificados.

Las reglas implıcitas dan instrucciones generales que make sigue cuando no puede encontraruna regla explıcita.

El formato habitual de una regla explıcita es el siguiente:

objetivo: lista de dependenciaorden(es)

donde:

El objetivo identifica la regla e indica el fichero a crear.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 230: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 2 23

La lista de dependencia especifica los ficheros de los que depende objetivo. Esta lista contienelos nombres de los ficheros separados por espacios en blanco.

Si alguno de los ficheros especificados en esta lista se ha modificado, se busca una regla que con-tenga a ese fichero como destino y se construye. Una vez se han construido las ultimas versionesde los ficheros especificados en lista de dependencia se construye objetivo.

Las orden(es) son ordenes validas para el sistema operativo en el que se ejecute la utilidad make.Pueden incluirse varias instrucciones en una regla, cada uno en una lınea distinta. Usualmenteestas instrucciones sirven para construir el objetivo (en esta asignatura, habitualmente son lla-madas al compilador g++), aunque no tiene porque ser ası.

MUY IMPORTANTE: Cada lınea de ordenes empezara con un TABULADOR. Si no es ası, makemostrara un error y no continuara procesando el fichero makefile.

EjercicioEn el ejemplo anterior (fichero makefile) encontramos una unica regla:

bin/saludo : src/saludo.cppg++ src/saludo.cpp -o bin/saludo

que indica que para construir el objetivo saludo se requiere la existencia de saludo.cpp(saludo depende de saludo.cpp). Esta dependencia se esquematiza en el diagrama dedependencias mostrado en la figura 1. Finalmente, el destino se construye ejecutando laorden:

g++ src/saludo.cpp -o bin/saludo

que compila el fichero saludo.cpp generando un fichero objeto temporal y lo enlaza con lasbibliotecas adecuadas para generar finalmente saludo.

1. Ejecutar las siguientes ordenes e interpretar el resultado:

% make

% make -f makefile

% make bin/saludo

% make -f makefile bin/saludo

2. Antes de volver a ejecutar make con las cuatro variantes enumeradas anteriormente,modificar el fichero saludo.cpp. Interpretar el resultado.

3. Probar la orden touch sobre saludo.cpp y volver a ejecutar make. Interpretar elresultado.

Figura 1: Diagrama de dependencias para saludo

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 231: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 2 24

EjercicioA partir del diagrama de dependencias mostrado en la figura 2 construir el fichero makefilellamado makefile2.mak.Ejecutar las siguientes ordenes e interpretar el resultado:

% make -f makefile2.mak bin/saludo

% make -f makefile2.mak

Figura 2: Diagrama de dependencias para makefile2.mak

2.3. Ordenes. Prefijos de ordenes

Como se indico anteriormente, se puede incluir cualquier orden valida del sistema operativo en elque se ejecute la utilidad make. Pueden incluirse cuantas ordenes se requieran como parte de unaregla, cada una en una lınea distinta, y como nota importante, recordamos que es imprescindible quecada lınea empiece con un tabulador para que make interprete correctamente el fichero makefile.

Las ordenes pueden ir precedidas por prefijos. Los mas importantes son:

@ Desactivar el eco durante la ejecucion de esa orden.

- Ignorar los errores que puede producir la orden a la que precede.

EjercicioCopiar el fichero makefile3.mak en vuestro directorio de trabajo.En este fichero makefile se especifican dos ordenes en cada una de las reglas, entre ellasuna para mostrar un mensaje en pantalla (echo), indicando que accion se desencadena encada caso. Las ordenes echo van precedidos por el prefijo @ en el fichero makefile paraindicar que debe desactivarse el eco durante la ejecucion de esa instruccion.

1. Ejecutar make sobre este fichero makefile e interpretar el resultado.

2. Poner el prefijo @ en la llamada a g++ y volver a ejecutar make.

3. Eliminar los prefijos y volver a ejecutar make.

EjercicioUsando como base makefile3.mak anadir (al final) la siguiente regla, y guardar el nuevocontenido en el fichero makefile4.mak:# Esta regla especifica un destino sin lista de dependenciaclean :

@echo Borrando ficheros objetorm obj/*.o

Esta nueva regla, cuyo destino es clean no tiene asociada una lista de dependencia. Laconstruccion del destino clean no requiere la construccion de otro destino previo ya que laconstruccion de ese destino no depende de nada. Para ello bastara ejecutar:

% make -f makefile4.mak clean

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 232: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 2 25

2.4. Destinos Simbolicos

Un destino simbolico se especifica en un fichero makefile en la primera lınea operativa del mismo.En su sintaxis se asemeja a la especificacion de una regla, con la diferencia que no tiene asociadaninguna orden. El formato es el siguiente:

destino simbolico: lista de destinos

donde:

destino simbolico es el nombre del destino simbolico. El nombre particular no tiene ningunaimportancia, como se deducira de nuestra explicacion.

lista de destinos especifica los destinos que se construiran cuando se invoque a make.

La finalidad de incluir un destino simbolico en un fichero makefile es la de que se construyan variosdestinos sin necesidad de invocar a make tantas veces como destinos se desee construir.

Al estar en la primera lınea operativa del fichero makefile, la utilidad make intentara construir eldestino simbolico. Para ello, examinara la lista de dependencia (llamada ahora lista de destinos) yconstruira cada uno de los destinos de esta lista: debe existir una regla para cada uno de los des-tinos. Finalmente, intentara construir el destino simbolico y como no habra ninguna instruccion quele indique a make como ha de construirlo no hara nada mas. Pero el objetivo esta cumplido: se hanconstruido varios destinos con una sola ejecucion de make. Observese como el nombre dado al destinosimbolico no tiene importancia.

EjercicioConstruir el fichero makefile5.mak con un destino simbolico llamado todo que cree losejecutables saludo y unico. Ejecutar:

1. % make -f makefile5.mak todo

2. % make -f makefile5.mak

EjercicioAnadir el destino clean a la lista de dependencia del destino simbolico todo, ası como laregla asociada.Anadir un destino llamado salva a la lista de dependencia del destino simbolico todo,ası como la regla asociada:

salva : saludo unicoecho Creando directorio resultadomkdir resultadoecho Moviendo los ejecutables al directorio resultadomove $ˆ resultado

En la ultima orden asociada a la ultima regla se hace uso de la macro $ˆ que se sustituyepor todos los nombres de los ficheros de la lista de dependencias. O sea, make interpreta laorden anterior como:

move saludo unico resultado

2.5. Destinos .PHONY

Si en un fichero makefile apareciera una regla:

clean :@echo Borrando ficheros objetorm obj/*.o

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 233: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 2 26

y hubiera un fichero llamado clean, la ejecucion de la orden:

make clean

no funcionara como esta previsto (no borrara los ficheros) puesto que el destino clean no tiene ningunadependencia y existe el fichero clean. Ası, make supone que no tiene que volver a generar el ficheroclean con la orden asociada a esta regla, pues el fichero clean esta actualizado, y no ejecutarıala orden que borra los ficheros de extension .o. Una forma de solucionarlo es declarar este tipo dedestinos como falsos (phony) usando .PHONY de la siguiente forma:

.PHONY : cleanEsta regla la podemos poner en cualquier parte del fichero makefile, aunque normalmente se coloca

antes de la regla clean. Haciendo esto, al ejecutar la orden

make clean

todo funcionara bien, aunque exista un fichero llamado clean. Observar que tambien serıa convenientehacer lo mismo para el caso del destino simbolico saludos en los ejemplos anteriores.

2.6. Macros en ficheros makefile

Una macro o variable MAKE es una cadena que se expande cuando se usa en un fichero makefile.Las macros permiten crear ficheros makefile genericos o plantilla que se adaptan a diferentes pro-

yectos software. Una macro puede representar listas de nombres de ficheros, opciones del compilador,programas a ejecutar, directorios donde buscar los ficheros fuente, directorios donde escribir la salida,etc. Puede verse como una version mas potente que la directiva #define de C++, pero aplicada aficheros makefile.La sintaxis de definicion de macros en un fichero makefile es la siguiente:

NombreMacro = texto a expandir

donde:

NombreMacro es el nombre de la macro. Es sensible a las mayusculas y no puede contenerespacios en blanco. La costumbre es utilizar nombres en mayuscula.

texto a expandir es una cadena que puede contener cualquier caracter alfanumerico, de puntua-cion o espacios en blanco

Para definir una macro llamada, por ejemplo, OBJ que representa a la cadena ˜/MP/obj se espe-cificara de la siguiente manera:

OBJ = ˜/MP/obj

Si esta lınea se incluye en el fichero makefile, cuando make encuentra la construccion $(OBJ) enel, sustituye dicha construccion por ˜/MP/obj. Cada macro debe estar en una lınea separada en unfichero makefile y se situan, normalmente, al principio de este. Si make encuentra mas de una definicionpara el mismo nombre (no es habitual), la nueva definicion reemplaza a la antigua.

La expansion de la macro se hace recursivamente. O sea, que si la macro contiene referencias aotras macros, estas referencias seran expandidas tambien. Veamos un ejemplo. Podemos definir unamacro para cada uno de los directorios de trabajo:

SRC = srcBIN = binOBJ = objINCLUDE = includeLIB = lib

Si el fichero makefile esta situado en la misma carpeta que los directorios, y en el fichero aparece:

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 234: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 2 27

$(BIN)/saludo: $(SRC)/saludo.cppg++ -o $(BIN)/saludo $(SRC)/saludo.cpp

se sustituye por:

bin/saludo: src/saludo.cppg++ -o bin/saludo src/saludo.cpp

¿y si el fichero makefile estuviera en una carpeta distinta? Podrıa anadirse una macro (la primera):

HOMEDIR = /home/users/app/new/MP

y se modifican las anteriores por:

SRC = $(HOMEDIR)/srcBIN = $(HOMEDIR)/binOBJ = $(HOMEDIR)/objINCLUDE = $(HOMEDIR)/includeLIB = $(HOMEDIR)/lib

Ahora, la regla anterior se sustituye por:

/home/users/app/new/MP/bin/saludo: /home/users/app/new/MP/saludo.cppg++ -o /home/users/app/new/MP/saludo /home/users/app/new/MP/saludo.cpp

Si los directorios se situaran en otra carpeta bastara con cambiar la macro HOMEDIR. En nuestro casopodrıamos escribir:

HOMEDIR = ˜/MP

EjercicioModificar el fichero makefile5.mak para que incluya las macros referentes a los directoriosque hemos enumerado anteriormente.

2.7. Macros predefinidas

Las macros predefinidas utilizadas habitualmente en ficheros makefile son las que enumeramos acontinuacion:

$@ Nombre del fichero destino de la regla.$< Nombre de la primera dependencia de la regla.$ˆ Equivale a todas las dependencias de la regla, con un espacio entre ellas.$? Equivale a las dependencias de la regla mas nuevas que el destino, con un espacio entre ellas.

EjercicioModificar el fichero makefile5.mak de manera que se muestren los valores de las macrospredefinidas $@ , $<, $ˆ, y $? en las reglas que generan algun fichero como resultado.Usad la orden @echo

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 235: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 2 28

A. Sustituciones en macros

La utilidad make permite sustituir caracteres temporalmente en una macro previamente definida. Lasintaxis de la sustitucion en macros es la siguiente:

$(NombreMacro:TextoOriginal = TextoNuevo)

que se interpreta como: sustituir en la cadena asociada a NombreMacro todas las apariciones deTextoOriginal por TextoNuevo. Es importante resaltar que:

1. No se permiten espacios en blanco antes o despues de los dos puntos.

2. No se redefine la macro NombreMacro, se trata de una sustitucion temporal, por lo que Nombre-Macro mantiene el valor dado en su definicion.

Por ejemplo, dada una macro llamada FUENTE definida como:

FUENTES = f1.cpp f2.cpp f3.cpp

se pueden sustituir temporalmente los caracteres .cpp por .o escribiendo $(FUENTES:.cpp=.o)que da como resultado f1.o f2.o f3.o. El valor de la macro FUENTES no se modifica, ya que lasustitucion es temporal.

B. Macros como parametros en la llamada a make

Ademas de las opciones basicas indicadas en la seccion 1.2, hay una opcion que permite especificarel valor de una constante simbolica que se emplea en un fichero makefile en la llamada a make en lugarde especificar su valor en el fichero makefile.

El mecanismo de sustitucion es similar al expuesto anteriormente, salvo que ahora make no buscael valor de la macro en el fichero makefile. La sintaxis de la llamada a make con macros es la siguiente:

make NombreMacro[=cadena] [opciones...] [destino(s)]]

NombreMacro[=cadena] define la constante simbolica NombreMacro con el valor espe-cificado (si lo hubiera) despues del signo =. Si cadena contiene espacios, sera necesarioencerrar cadena entre comillas.

Si NombreMacro tambien esta definida dentro del fichero makefile, se ignorara la definiciondel fichero.

El uso de macros en llamadas a make permite la construccion de ficheros makefile genericos, yaque el mismo fichero puede utilizarse para diferentes tareas que se deciden en el momento de invocara make con el valor apropiado de la macro.

EjercicioModificar el fichero makefile ppal 2 para que el resultado (el ejecutable ppal 2) lo guardeen un directorio cuyo nombre completo (camino absoluto, desde la raiz /) se indica comoparametro al fichero makefile con una macro llamada DESTDIR.Importante: Como el directorio puede no existir, crearlo en el propio fichero makefile.

1. Ejecutar make sobre este fichero especificando el directorio destino apropiadamente.

2. ¿Que ocurre si se vuelve a ejecutar la orden anterior?

3. Modificar apropiadamente el fichero makefile ppal 2 para evitar el error.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 236: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 2 29

EjercicioModificar el fichero makefile ppal 2 para que el resultado (el ejecutable ppal 2) lo guardeen un directorio cuyo nombre completo (camino absoluto, desde la raiz /) se indica comoparametro al fichero makefile con una macro llamada DESTDIR.Importante: Como el directorio puede no existir, crearlo en el propio fichero makefile.

1. Ejecutar make sobre este fichero especificando el directorio destino apropiadamente.

2. ¿Que ocurre si se vuelve a ejecutar la orden anterior?

3. Modificar apropiadamente el fichero makefile ppal 2 para evitar el error.

EjercicioExtender el makefile anterior con una opcion para incluir informacion de depuracion o no.

C. Reglas implıcitas

En los ficheros makefile aparecen, en la mayorıa de los casos, reglas que se parecen mucho. Enlos ejercicios anteriores se puede ver, por ejemplo, que las reglas que generan los ficheros objeto sonidenticas, solo se diferencian en los nombres de los ficheros que manipulan.

Las reglas implıcitas son reglas que make interpreta para actualizar destinos sin tener que escribirlasdentro del fichero makefile. De otra forma: si no se especifica una regla explıcita para construir undestino, se utilizara una regla implıcita (que no hay que escribir).

Existe un catalogo de reglas implıcitas predefinidas que pueden usarse para distintos lenguajesde programacion (ver http://www.gnu.org/software/make/manual/make.html#Implicit-Rules) .El que make elija una u otra dependera del nombre y extension de los ficheros. Por ejemplo, para el caso que nosinteresa, compilacion de programas en C++, existe una regla implıcita que dice como obtener el fichero objeto (.o)a partir del fichero fuente (.cpp). Esa regla se usa cuando no existe una regla explıcita que diga como construirese modulo objeto. En tal caso se ejecutara la siguiente orden para construir el modulo objeto cuando el ficherofuente sea modificado:

$(CXX) -c $(CPPFLAGS) $(CXXFLAGS)Las reglas implıcitas que usa make utilizan una serie de macros predefinidas, tales como las del caso anterior

(CXX, CPPFLAGS y CXXFLAGS). Para mas informacion verhttp://www.gnu.org/software/make/manual/make.html#Implicit-Variables

El valor de estas macros pueden ser definidas:

1. Dentro del fichero makefile,

2. A traves de argumentos pasados a make, o

3. Con valores predefinidos. Por ejemplo,

CXX: Programa para compilar programas en C++; Por defecto: g++.

CPPFLAGS: Modificadores extra para el preprocesador de C. El valor por defecto es la cadena vacıa.

CXXFLAGS: Modificadores extra para el compilador de C++. El valor por defecto es la cadena vacıa.

Si deseamos que make use reglas implıcitas, en el fichero makefile escribiremos la regla sin ninguna orden. Esposible anadir nuevas dependencias a la regla.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 237: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 2 30

EjercicioUsar como base makefile ppal 2 y copiarlo en makefile ppal 3, modificando la regla que crea elejecutable para que este se llame ppal 3.

1. Eliminar las reglas que crean los ficheros objeto y ejecutar make.

2. Forzar la dependencia de los modulos objeto respecto a los ficheros de cabecera (.h) adecua-dos para que cuando se modifique algun fichero de cabecera se ejecute la regla implıcita queactualiza el o los ficheros objeto necesarios, y finalmente el ejecutable.Nota: Los ficheros de cabecera se encuentran en un subdirectorio del directorio MP llama-do include. Modificar la variable CXXFLAGS con el valor -I$(INCLUDE) (se expandera a-I./include para cada ejecucion de la regla implıcita).

a) Modificar (touch) adicion.cpp y ejecutar make. Observad que instrucciones se ejecutany en que orden.

b) Modificar (touch) adicion.h y ejecutar make. Observad que instrucciones se ejecutan yen que orden.

Otra regla que puede usarse es la regla implıcita que permite enlazar el programa. La siguiente regla:$(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)

se interpreta como sigue: n se construira a partir de n.o usando el enlazador (ld). Esta regla funciona correc-tamente para programas con un solo fichero fuente aunque tambien funcionarcorrectamente en programas conmultiples ficheros objeto si uno de los cuales tiene el mismo nombre que el ejecutable.

EjercicioCopiar ppal 2.cpp en ppal 4.cppUsar como base makefile ppal 3 y copiarlo en makefile ppal 4,Eliminar la orden en la regla que crea el ejecutable manteniendo la lista de dependencia y ejecutarmake.

C.1. Reglas implıcitas patronLas reglas implıcitas patron pueden ser utilizadas por el usuario para definir nuevas reglas implıcitas en un

fichero makefile. Tambien pueden ser utilizadas para redefinir las reglas implıcitas que proporciona make paraadaptarlas a nuestras necesidades. Una regla patron es parecida a una regla normal, pero el destino de la reglacontiene el caracter % en alguna parte (solo una vez). Este destino constituye entonces un patron para emparejarnombres de ficheros.

Por ejemplo el destino %.o empareja a todos los ficheros con extension .o. Una regla patron %.o:%.cpp dicecomo construir cualquier fichero .o a partir del fichero .cpp correspondiente. En una regla patron podemos tenervarias dependencias que tambien pueden contener el caracter %. Por ejemplo:

%.o : %.cpp %.h comun.hg++ -c $< -o $@

significa que cada fichero .o debe volver a construirse cuando se modifique el .cpp o el .h correspondiente, obien comun.h. Una reglas patron del tipo %.o:%.cpp puede simplificarse escribiendo .cpp.o:La regla implıcita patron predefinida para compilar ficheros .cpp y obtener ficheros .o es la siguiente:

%.o : %.cpp$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) $< -o $@

Esta regla podrıa ser redefinida en nuestro fichero makefile escribiendo esta regla con el mismo destino ydependencias, pero modificando las ordenes a nuestra conveniencia. Si queremos que make ignore una reglaimplıcita podemos escribir una regla patron con el mismo destino y dependencias que la regla implıcita predefinida,y sin ninguna orden asociada.

IMPORTANTE: Una regla regla implıcita patron puede aplicarse a cualquier destino que se empareja con su patron,pero solo se aplicara cuando el destino no tiene ordenes que lo construya mediante otra regla distinta, y solo cuandopuededan encontrase las dependecias. Cuando se puede aplicar mas de una regla implıcita, solo se aplicara unade ellas: la eleccion depende del orden de las reglas.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 238: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 2 31

C.2. Reglas patron estaticasLas reglas patron estaticas son otro tipo de reglas que se pueden utilizar en ficheros makefile y que son muy

parecidas en su funcionamiento a las reglas implıcitas patron. Estas reglas no se consideran implıcitas, pero alser muy parecidas en funcionamiento a las reglas patron implıcitas, las exponemos en esta seccion. El formato deestas reglas es el siguiente:

destino(s): patron de destino : patrones de dependenciaorden(es)

donde:

La lista destinos especifica a que destinos se aplicara la regla. Esta es la principal diferencia con las reglaspatron implıcitas. Ahora la regla se aplica unicamente a la lista de destinos, mientras que en las implıcitas seintenta aplicar a todos los que se emparejan con el patron destino. Los destinos pueden contener caracterescomodın como * y ?

El patron de destino y los patrones de dependencia dicen como calcular las dependencias para cada destino.

Veamos un pequeno ejemplo que muestra como obtener los ficheros f1.o y f2.o.

OBJETOS = f1.o f2.o

$(OBJETOS): %.o: %.cppg++ -c $(CFLAGS) $< -o $@

En este ejemplo, la regla solo se aplica a los ficheros f1.cpp y f2.cpp. Si existen otros ficheros con extension.cpp, esta regla no se aplicara ya que no se han incluido en la lista destinos.

D. Directivas condicionales en ficheros makefileLas directivas condicionales se parecen a las directivas condicionales del preprocesador de C++. Permiten a

make dirigir el flujo de procesamiento en un fichero makefile a un bloque u otro dependiendo del resultado de laevaluacion de una condicion, evaluada con una directiva condicional.

Para mas informacion ver http://www.gnu.org/software/make/manual/make.html#Conditionals

La sintaxis de un condicional simple sin else serıa la siguiente:directiva condicional

texto (si el resultado es verdad)endif

La sintaxis para un condicional con parte else serıa:directiva condicional

texto (si el resultado es verdad)else

texto (si el resultado es falso)endif

Las directivas condicionales para ficheros makefile son las siguientes:ifdef macro: Actua como la directiva #ifdef de C++ pero con macros en lugar de directivas #define.ifndef macro: Actua como la directiva #ifndef de C++ pero con macros, en lugar de directivas #define.ifeq (arg1,arg2) o ifeq ’arg1’ ’arg2’ o ifeq "arg1" "arg2" oifeq "arg1" ’arg2’ o ifeq ’arg1’ "arg2"

Devuelve verdad si los dos argumentos expandidos son iguales.

ifneq (arg1,arg2) o ifneq ’arg1’ ’arg2’ o ifneq "arg1" "arg2" oifneq "arg1" ’arg2’ o ifneq ’arg1’ "arg2"

Devuelve verdad si los dos argumentos expandidos son distintos

else

Actua como un else de C++.

endif

Termina una declaracion ifdef, ifndef ifeq o ifneq.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 239: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 2 32

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 240: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.

Practica 3. Compilacion separada.Gestion y uso de bibliotecas.

El programa ar

Francisco J. Cortijo Bon

Curso 2011-2012

Objetivos

1. Conocer las ventajas de la modularizacion

2. Saber como organizar un proyecto software en distintos ficheros, como se relacionan y como segestionan usando un fichero makefile.

3. Entender el concepto de biblioteca en programacion.

4. Conocer el funcionamiento de la orden ar.

5. Saber como enlazar ficheros de biblioteca.

6. Apender a gestionar y enlazar bibliotecas en ficheros makefile.

Indice

1. La modularizacion del software en C++ 341.1. Introduccion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341.2. Ventajas de la modularizacion del software . . . . . . . . . . . . . . . . . . . . . . . . . . 341.3. Como dividir un programa en varios ficheros . . . . . . . . . . . . . . . . . . . . . . . . . 341.4. Organizacion de los ficheros fuente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

2. Bibliotecas 382.1. Tipos de bibliotecas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392.2. Estructura de una biblioteca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

3. El programa ar 42

4. g++, make y ar trabajando conjuntamente 434.1. Creacion de la biblioteca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434.2. Enlazar con una biblioteca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

5. Ejercicios 45

33

Page 241: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 3 34

1. La modularizacion del software en C++

1.1. Introduccion

Cuando se escriben programas medianos o grandes resulta sumamente recomendable (por no de-cir obligado) dividirlos en diferentes modulos fuente. Este enfoque proporciona muchas e importantesventajas, aunque complica en cierta medida la tarea de compilacion.

Basicamente, lo que se hara sera dividir nuestro programa fuente en varios ficheros. Estos ficherosse compilaran por separado, obteniendo diferentes ficheros objeto. Una vez obtenidos, los modulosobjeto se pueden, si se desea, reunir para formar bibliotecas. Para obtener el programa ejecutable, seenlazara el modulo objeto que contiene la funcion main() con varios modulos objeto y/o bibliotecas.

1.2. Ventajas de la modularizacion del software

1. Los modulos contendran de forma natural conjuntos de funciones relacionadas desde un puntode vista logico.

2. Resulta facil aplicar un enfoque orientado a objetos. Cada objeto (tipo de dato abstracto) se agrupaen un modulo junto con las operaciones del tipo definido.

3. El programa puede ser desarrollado por un equipo de programadores de forma comoda. Cada pro-gramador puede trabajar en distintos aspectos del programa, localizados en diferentes modulos.pueden reusarse en otros programas, reduciendo el tiempo y coste del desarrollo del software.

4. La compilacion de los modulos se puede realizar por separado. Cuando un modulo esta valida-do y compilado no sera preciso recompilarlo. Ademas, cuando haya que modificar el programa,solo tendremos que recompilar los ficheros fuente alterados por la modificacion. La utilidad makesera muy util para esta tarea.

5. El ocultamiento de informacion puede conseguirse con la modularizacion. El usuario de un moduloobjeto o de una biblioteca de modulos desconoce los detalles de implementacion de las funcio-nes y objetos definidos en estos. Mediante el uso de ficheros de cabecera proporcionaremos lainterface necesaria para poder usar estas funciones y objetos.

1.3. Como dividir un programa en varios ficheros

Cuando se divide un programa en varios ficheros, cada uno de ellos contendra una o mas funciones.Solo uno de estos ficheros contendra la funcion main(). Los programadores normalmente comienzana disenar un programa dividiendo el problema en subtareas que resulten mas manejables. Cada unade estas tareas se implementara como una o mas funciones. Normalmente, todas las funciones de unasubtarea residen en un fichero fuente.

Por ejemplo, cuando se realice la implementacion de tipos de datos abstractos definidos por elprogramador, lo normal sera incluir todas las funciones que acceden al tipo definido en el mismo fichero.Esto supone varias ventajas importantes:

1. La estructura de datos se puede utilizar de forma sencilla en otros programas.

2. Las funciones relacionadas se almacenan juntas.

3. Cualquier cambio posterior en la estructura de datos, requiere que se modifique y recompile elmınimo numero de ficheros y solo los imprescindibles.

Cuando las funciones de un modulo invocan objetos o funciones que se encuentran definidos enotros modulos, necesitan alguna informacion acerca de como realizar estas llamadas. El compiladorrequiere que se proporcionen declaraciones de funciones y/o objetos definidos en otros modulos. Lamejor forma de hacerlo (y, probablemente, la unica razonable) es mediante la creacion de ficheros de

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 242: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 3 35

cabecera (.h), que contienen las declaraciones de las funciones definidas en el fichero .cpp corres-pondiente. De esta forma, cuando un modulo requiera invocar funciones definidas en otros modulos,bastara con que se inserte una lınea #include del fichero de cabecera apropiado.

1.4. Organizacion de los ficheros fuente

Los ficheros fuente que componen nuestros programas deben estar organizados en un cierto orden.Normalmente sera el siguiente:

1. Una primera parte formada por una serie de constantes simbolicas en lıneas #define, una seriede lıneas #include para incluir ficheros de cabecera y redefiniciones (typedef) de los tipos dedatos que se van a tratar.

2. La declaracion de variables externas y su inicializacion, si es el caso. Se recuerda que, en general,no es recomendable su uso.

3. Una serie de funciones.

El orden de los elementos es importante, ya que en el lenguaje C++, cualquier objeto debe estardeclarado antes de que sea usado, y en particular, las funciones deben declararse antes de que serealice cualquier llamada a ellas. Se nos presentan dos posibilidades:

1. Que la definicion de la funcion se encuentre en el mismo fichero en el que se realiza lallamada. En este caso,

a) se situa la definicion de la funcion antes de la llamada (esta es una solucion raramenteempleada por los programadores),

b) se puede incluir una linea de declaracion (prototipo) al principio del fichero, con lo que ladefinicion se puede situar en cualquier punto del fichero, incluso despues de las llamadas aesta.

2. Que la definicion de la funcion se encuentre en otro fichero diferente al que contiene lallamada. En este caso es preciso incluir al principio del mismo una lınea de declaracion (prototipo)de la funcion en el fichero que contiene las llamadas a esta. Normalmente se realiza incluyendo(mediante la directiva de preprocesamiento #include) el fichero de cabecera asociado al moduloque contiene la definicion de la funcion.

Cuando modularizamos nuestros programas, hemos de hacer un uso adecuado de los ficherosde cabecera asociados a los modulos que estamos desarrollando. Ademas, los ficheros de cabe-cera tambien son utiles para contener las declaraciones de tipos, funciones y otros objetos quenecesitemos compartir entre varios de nuestros modulos.

Ası pues, a la hora de crear el fichero de cabecera asociado a un modulo debemos tener encuenta que objetos del modulo van a ser compartidos o invocados desde otros modulos (publi-cos) y cuales seran estrictamente privados al modulo: en el fichero de cabecera pondremos,unicamente, los publicos.

Recordar: En C++, todos los objetos deben estar declarados y definidos antes de ser usados.

Ejercicio

Copiar el fichero unico.cpp en vuestro directorio de trabajo. Generar el ejecutable unico.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 243: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 3 36

Figura 1: Diagrama de dependencias para construir ppal 1

EjercicioOrganizar el codigo fuente en distintos ficheros de manera que separaremos la declaracion yla definicion de las funciones. Guardar cada fichero en la carpeta adecuada.

Los ficheros involucrados y sus dependencias se muestran en la figura 1. Con mas detalle:

1. El fichero (ppal 1.cpp) contendra la funcion main()

2. El codigo asociado a las funciones se organiza en dos ficheros: uno contiene las decla-raciones (opers.h) y otro las definiciones (opers.cpp)

Realizar las siguientes tareas:

1. Generar el objeto ppal 1.o a partir de ppal 1.cpp

2. Generar el objeto opers.o a partir de opers.o

3. Generar el ejecutable ppal 1 a partir de los dos modulos objeto generados.

EjercicioEscribir un fichero llamado makefile ppal 1 para generar el ejecutable ppal 1, siguiendoel diagrama de dependencia mostrado en la figura 1.

Usad macros para especificar los directorios de trabajo.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 244: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 3 37

Figura 2: Diagrama de dependencias para construir ppal 2

EjercicioContinuaremos distribuyendo el codigo fuente en distintos ficheros, siguiendo el esquemaindicado en la figura 2.

1. El fichero (ppal 2.cpp) contendra la funcion main()

2. El codigo asociado a las funciones se organiza en cuatro ficheros organizados en paresdeclaracion-definicion:

a) El primer par (adicion.h y adicion.cpp) contiene las funciones suma() yresta()

b) El segundo (producto.h y producto.cpp) contiene las funcionesmultiplica() y divide()

Realizar las siguientes tareas:

1. Generar el objeto ppal 2.o a partir de ppal 2.cpp

2. Generar los objetos adicion.o y producto.o

3. Generar el ejecutable ppal 2 a partir de los tres modulos objeto generados.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 245: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 3 38

EjercicioModificar la funcion divide() de producto.cpp de manera que procese adecuadamentela excepcion que se genera cuando hay una division por cero.

1. Analizar que modulos deben recompilarse para generar un nuevo ejecutable, actualiza-do con la modificacion propuesta.

2. Volver a generar el ejecutable ppal 2

EjercicioEscribir un fichero llamado makefile ppal 2 para generar el ejecutable ppal 2, siguiendoel diagrama de dependencia mostrado en la figura 2.

Usad macros para especificar los directorios de trabajo.

2. Bibliotecas

En la practica de la programacion se crean conjuntos de funciones utiles para muy diferentes progra-mas: funciones de depuracion de entradas, funciones de presentacion de datos, funciones de calculo,etc. Si cualquiera de esas funciones quisiera usarse en un nuevo programa, la practica de “Copiar y Pe-gar” el trozo de codigo correspondiente a la funcion deseada no resulta, a la larga, una buena solucion,ya que,

1. El tamano total del codigo fuente de los programas se incrementa innecesariamente y es redun-dante.

2. Si se hace necesaria una actualizacion del codigo de una funcion es preciso modificar TODOSlos programas que usan esta funcion, lo que llevara a utilizar diferentes versiones de la mismafuncion si el control no es muy estricto o a un esfuerzo considerable para mantener la coherenciadel software.

En cualquier caso, esta practica llevara irremediablemente en un medio/largo plazo a una situacioninsostenible. La solucion obvia consiste en agrupar estas funciones usadas frecuentemente en modulosde biblioteca, llamados comunmente bibliotecas.

Una biblioteca contiene codigo objeto que puede ser enlazado con el codigo objeto de un moduloque usa una funcion de esa biblioteca.

De esta forma tan solo existe una version de cada funcion por lo que la actualizacion de una funcionimplicara unicamente recompilar el modulo donde esta esa funcion y los modulos que usan esa funcion,sin necesidad de modificar nada mas (siempre que no se modifique la cabecera de la funcion, y comoconsecuencia, la llamada a esta, claro esta). Si ademas nuestros proyectos se matienen medianteficheros makefile el esfuerzo de mantenimiento y recompilacion se reduce drasticamente.

Esta modularidad redunda en un mantenimiento mas eficiente del software y en una disminuciondel tamano de los ficheros fuente, ya que tan solo incluiran la llamada a las funciones de biblioteca, yno su definicion.

Vulgarmente se emplea el termino librerıa para referirse a una biblioteca, por la similitud con eloriginal ingles library. En terminos formales, la acepcion correcta es biblioteca, porque es la traduccioncorrecta de library, mientras que el termino ingles para librerıa es bookstore o book shop. Tambienes habitual referirse a ella con el termino de origen anglosajon toolkit (conjunto, equipo, maletın, caja,estuche, juego (kit) de herramientas).

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 246: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 3 39

2.1. Tipos de bibliotecas

Bibliotecas estaticas

La direccion real, las referencias para saltos y otras llamadas a las funciones de las bibliotecas sealmacenan en una direccion relativa o simbolica, que no puede resolverse hasta que todo el codigo esasignado a direcciones estaticas finales.

El enlazador resuelve todas las direcciones no resueltas convirtiendolas en direcciones fijas, o re-localizables desde una base comun. El enlace estatico da como resultado un archivo ejecutable contodos los sımbolos y modulos respectivos incluidos en dicho archivo. Este proceso se realiza antes dela ejecucion del programa y debe repetirse cada vez que alguno de los modulos es recompilado.

La ventaja de este tipo de enlace es que hace que un programa no dependa de ninguna biblioteca(puesto que las enlazo al compilar), haciendo mas facil su distribucion.

Bibliotecas dinamicas

Enlace dinamico significa que los modulos de una biblioteca son cargadas en un programa en tiempode ejecucion, en lugar de ser enlazadas en tiempo de compilacion, y se mantienen como archivosindependientes separados del fichero ejecutable del programa principal.

El enlazador realiza una mınima cantidad de trabajo en tiempo de compilacion, registra que modulosde la biblioteca necesita el programa y el ındice de nombres de los modulos en la biblioteca.

Algunos sistemas operativos solo pueden enlazar una biblioteca en tiempo de carga, antes de queel proceso comience su ejecucion, otros son capaces de esperar hasta despues de que el procesohaya empezado a ejecutarse y enlazar la biblioteca solo cuando efectivamente se hace referencia a ella(es decir, en tiempo de ejecucion). Esto ultimo se denomina retraso de carga”. En cualquier caso, esabiblioteca es una biblioteca enlazada dinamicamente.

2.2. Estructura de una biblioteca

Una biblioteca se estructura internamente como un conjunto de modulos objeto. Cada uno deestos modulos sera el resultado de la compilacion de un fichero de codigo fuente que puede conteneruna o varias funciones.

La extension por defecto de los ficheros de biblioteca es .a y se acostumbra a que su nombre em-piece por el prefijo lib. Ası, por ejemplo, si hablamos de la biblioteca ejemplo el fichero asociado sellamara libejemplo.a

Veamos, con un ejemplo, como se estructura una biblioteca. La biblioteca libejemplo.a contiene10 funciones. Los casos extremos en la construccion de esta biblioteca serıan:

1. Esta formada por un unico fichero objeto (por ejemplo, funcs.o) que es el resultado de la com-pilacion de un fichero fuente (funcs.cpp). Este caso se ilustra en la figura 3.

Figura 3: Construccion de una biblioteca a partir de un unico modulo objeto (caso 1)

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 247: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 3 40

// funcs.cpp// Contiene la definicion de 10 funciones//

int funcion_1 (int a, int b){

...........}

char *funcion_2 (char *s, char *t){

...........}

...........

int funcion_10 (char *s, int x){

...........}

2. Esta formada por 10 ficheros objeto (por ejemplo, fun01.o, . . ., fun10.o) resultado de la com-pilacion de 10 ficheros fuente (por ejemplo, fun01.cpp, . . ., fun10.cpp) que contienen, cadauno, la definicion de una unica funcion. Este caso se ilustra en las figuras 4 y 5.

Figura 4: Varios modulos fuente (caso 2)

Figura 5: Construccion de una biblioteca a partir de varios modulos objeto (caso 2)

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 248: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 3 41

Para generar un fichero ejecutable que utiliza una funcion de una biblioteca, el enlazador enlaza elmodulo objeto que contiene la funcion main() con el modulo objeto (completo) de la bibliotecadonde se encuentra la funcion utilizada. De esta forma, en el ejecutable solo se incluiran los modulosobjeto que contienen alguna funcion llamada por el programa.

Por ejemplo, supongamos que ppal.cpp contiene la funcion main(). Esta funcion usa la funcionfuncion_2() de la biblioteca libejemplo.a. Independientemente de la estructura de la biblioteca,ppal.cpp se escribira de la siguiente forma:

#include "ejemplo.h" // prototipos de las funciones de "libejemplo.a"

int main (void){

......cad1 = funcion_2 (cad2, cad3);......

}

Como regla general cada biblioteca llevara asociado un fichero de cabecera que contendra losprototipos de las funciones que se ofrecen en la biblioteca (funciones publicas). Este fichero decabecera actua de interface entre las funciones de la biblioteca y los programas que la usan.

En nuestro ejemplo, independientemente de la estructura interna de la biblioteca, esta ofrece 10funciones cuyos prototipo se encuentran declarados en ejemplo.h.

Para la eleccion de la estructura optima de la biblioteca hay que recordar que la parte de la biblio-teca que se enlaza al codigo objeto de la funcion main() es el modulo objeto completo en el que seencuentra la funcion de biblioteca usada. En la figura 6 mostramos como se construye un ejecutable apartir de un modulo objeto (ppal.o) que contiene la funcion main() y una biblioteca (libejemplo.a).

Figura 6: Construccion de un ejecutable que usa una funcion de biblioteca. Caso 1: biblioteca formadapor un modulo objeto. Caso 2: biblioteca formada por 10 modulos objeto

Sobre esta figura, distinguimos dos situaciones diferentes dependiendo de como se construye labiblioteca. En ambos casos el fichero objeto que se enlazara con la biblioteca (con mas precision, conel modulo objeto adecuado de la biblioteca) se construye de la misma forma: el programa que usa unafuncion de biblioteca no conoce (ni le importa) como se ha construıdo la biblioteca.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 249: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 3 42

Caso 1: El modulo objeto ppal.o se enlaza con el modulo objeto funcs.o (extraido de la biblio-teca libejemplo.a) para generar el ejecutable prog_1. El modulo funcs.o contiene el codigoobjeto de todas las funciones, por lo que se enlaza mucho codigo que no se usa.

Caso 2: El modulo objeto ppal.o se enlaza con el modulo objeto fun02.o (extraido de la bi-blioteca libejemplo.a) para generar el ejecutable prog_2. El modulo fun02.o contiene uni-camente el codigo objeto de la funcion que se usa, por lo que se enlaza el codigo estrictamentenecesario.

En cualquier caso, como usuario de la biblioteca se actua de la misma manera en ambas situaciones:enlaza el modulo objeto que conntiene la funcion main() con la biblioteca.Como disenador de la biblioteca sı debemos tener en cuenta la estructura que vamos a adoptar paraesta. La idea basica es conocida: si las bibliotecas estan formadas por modulos objeto con muchasfunciones cada una, los tamanos de los ejecutables seran muy grandes. En cambio, si las bibliotecasestan formadas por modulos objeto con pocas funciones cada una, los tamanos de los ejecutablesseran mas pequenos1.

3. El programa ar

El programa gestor de bibliotecas de GNU es ar. Con este programa es posible crear y modificarbibliotecas existentes: anadir nuevos modulos objeto, eliminar modulos objeto o reemplazarlos por otrosmas recientes. La sintaxis de la llamada a ar es:

ar [-]operacion [modificadores ] biblioteca [modulos objeto]

donde:

operacion indica la tarea que se desea realizar sobre la biblioteca. Estas pueden ser:

r Adicion o reemplazo. Reemplaza el modulo objeto de la biblioteca por la nueva version. Si elmodulo no se encuentra en la biblioteca, se anade a la misma. Si se emplea, ademas, el mo-dificador v, ar imprimira una lınea por cada modulo anadido o reemplazado, especificandoel nombre del modulo y las letras a o r, respectivamente.

d Borrado. Elimina un modulo de la biblioteca.

x Extraccion. Crea el fichero objeto cuyo nombre se especifica y copia su contenido de labiblioteca. La biblioteca queda inalterada.Si no se especifica ningun nombre, se extraen todos los ficheros de la biblioteca.

t Listado. Proporciona una lista especificando los modulos que componen la biblioteca.

modificadores: Se pueden anadir a las operaciones, modificando de alguna manera el comporta-miento por defecto de la operacion. Los mas importantes (y casi siempre se utilizan) son:

s Indexacion. Actualiza o crea (si no existıa previamente) el ındice de los modulos que compo-nen la biblioteca. Es necesario que la biblioteca tenga un ındice para que el enlazador sepacomo enlazarla. Este modificador puede emplearse acompanando a una operacion o por sisolo.

v Verbose. Muestra informacion sobre la operacion realizada.

biblioteca es el nombre de la biblioteca a crear o modificar.

modulos objeto es la lista de ficheros objeto que se van a anadir, eliminar, actualizar, etc. en labiblioteca.

Los siguientes ejercicios ayudaran a entender el funcionamiento de las distintas opciones de ar.

1Estas afirmaciones suponen que las funciones son equiparables en tamano, obviamente

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 250: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 3 43

EjercicioRepetir los siguientes ejemplos:

1. Crear la biblioteca libprueba.a a partir del modulo objeto oper.o.

ar -rvs lib/libprueba.a obj/oper.o

2. Mostrar los modulos que la componen.

ar -tv lib/libprueba.a

Ejercicio1. Anadir los modulos adicion.o y producto.o a la biblioteca libprueba.a.

ar -rvs lib/libprueba.a obj/adicion.o obj/producto.o

2. Mostrar los modulos que la componen.

ar -tv lib/libprueba.a

Ejercicio1. Extraer el modulo adicion.o de la biblioteca libprueba.a.

ar -xvs lib/libprueba.a adicion.o

2. Mostrar los modulos que la componen.

ar -tv lib/libprueba.a

3. Mostrar el directorio actual.

Ejercicio1. Borrar el modulo producto.o de la biblioteca libprueba.a.

ar -dvs lib/libprueba.a producto.o

2. Mostrar los modulos que la componen.

ar -tv lib/libprueba.a

3. Mostrar el directorio actual.

4. g++, make y ar trabajando conjuntamente

Como hemos senalado, ar es un programa general que empaqueta/desempaqueta ficheros en/desdearchivos, de manera similar a como hacen otros programas como zip, rar, tar, etc. (una lista amplia pue-de encontrarse en http://es.wikipedia.org/wiki/Anexo:Archivadores de ficheros).

Nuestro interes es aprender como puede emplearse una biblioteca para la generacion de un ejecu-table, y como escribir las dependencias en ficheros makefile para poder automatizar todo el proceso decreacion/actualizacion con la orden make.

4.1. Creacion de la biblioteca

Emplearemos una regla para la construccion de la biblioteca.

1. El objetivo sera la biblioteca a construir.

2. La lista de dependencias estara formada por los modulos objeto que constituiran la biblioteca.

Para los dos casos estudiados en la seccion 2.2 escribirıamos:

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 251: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 3 44

1. Caso 1.

lib/libejemplo.a : obj/funcs.oar -rvs /libejemplo.a obj/funcs.o

2. Caso 2.

lib/libejemplo.a : obj/fun01.o obj/fun02.o obj/fun03.o obj/fun04.o\obj/fun05.o obj/fun06.o obj/fun07.o obj/fun08.o\obj/fun09.o obj/fun10.o

ar -rvs lib/libejemplo.a obj/fun01.o obj/fun02.o obj/fun03.o\obj/fun04.o obj/fun05.o obj/fun06.o obj/fun07.o\obj/fun08.o obj/fun09.o obj/fun10.o

(La barra simple invertida (\) es muy util para dividir en varias lıneas ordenes muy largas ya quepermite continuar escribiendo en una nueva lınea la misma orden)

Evidentemente, resulta aconsejable escribir de manera mas compacta y generalizable esta regla:

MODS_EJEMPLO = obj/fun01.o obj/fun02.o obj/fun03.o obj/fun04.o\obj/fun05.o obj/fun06.o obj/fun07.o obj/fun08.o\obj/fun09.o obj/fun10.o

......lib/libejemplo.a : $(MODS_EJEMPLO)

ar -rvs lib/libejemplo.a $(MODS_EJEMPLO)

4.2. Enlazar con una biblioteca

El enlace lo realiza g++, llamando al enlazador ld. Extenderemos la regla que genera el ejecutable:

1. El objetivo es el mismo: generar el ejecutable.

2. La lista de dependencias incluira ahora a la biblioteca que se va a enlazar.

3. La orden debe especificar:

a) El directorio donde buscar la biblioteca (opcion -L)Recordemos que la opcion -Lpath indica al enlazador el directorio donde se encuentran losficheros de biblioteca. Se puede utilizar la opcion -L varias veces para especificar distintosdirectorios de biblioteca.

b) El nombre (resumido) de la biblioteca (opcion -l).Los ficheros de biblioteca se proporcionan a g++ de manera resumida, escribiendo -lnombrepara referirnos al fichero de biblioteca libnombre.a El enlazador busca en los directoriosde bibliotecas (entre los que estan los especificados con -L) un fichero de biblioteca llamadolibnombre.a y lo usa para enlazarlo.

Para los dos casos estudiados en la seccion 2.2 escribirıamos:

1. Caso 1.

bin/prog_1 : obj/ppal.o lib/libejemplo.ag++ -o bin/prog_1 obj/ppal.o -L./lib -lejemplo

2. Caso 2.

bin/prog_2 : obj/ppal.o lib/libejemplo.ag++ -o bin/prog_2 obj/ppal.o -L./lib -lejemplo

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 252: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 3 45

5. Ejercicios

Para poder realizar los ejercicios propuestos es necesario disponer de los ficheros:

ppal 1.cpp, ppal 2.cpp, opers.cpp, adicion.cpp y producto.cpp

Usaremos un nuevo fichero fuente, ppal.cpp, que sera una copia de ppal 1.cpp

opers.h, adicion.h y producto.h

makefile ppal 1 y makefile ppal 2

En todos los ejercicios debe poder diferenciar claramente los dos actores que pueden intervenir enel proceso:

1. El creador de la biblioteca

2. El usuario de la bibilioteca

aunque sea la misma persona (en este caso, usted) quien realice las dos tareas. Esta distincion esfundamental cuando se maneje los ficheros de cabecera: puede llegar a manejar dos ficheros exacta-mente iguales aunque con nombre diferentes. Uno de ellos sera empleado por el creador de la bibliotecay una vez construida la biblioteca, proporcionara otro fichero de cabecera que sirva de interface de labiblioteca a los usuarios de la misma.

Ejercicio

Utilizar como base makefile ppal 1 y construir el fichero makefile llamadomakefile 1lib 1mod que implementa el diagrama de la figura 7

Figura 7: Construccion de un ejecutable que usa funciones de biblioteca (1). Una biblioteca formada porun modulo objeto que implementa cuatro funciones.

En este caso tenemos una biblioteca formada por un unico modulo objeto. Todas las funciones estandefinidas en ese modulo objeto. Observe que el ejecutable sera exactamente igual que el que llamamosanteriormente ppal 1 (ver figura 3 de la practica 2). Explique por que.

El fichero de cabecera opers 1mod.h asociado a la biblioteca libopers 1mod.a podrıa tener elmismo contenido que el que se emplea para construir la biblioteca.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 253: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 3 46

Ejercicio

Utilizar como base makefile ppal 2 y construir el fichero makefile llamadomakefile 1lib 2mod que implementa el diagrama de la figura 8

Figura 8: Construccion de un ejecutable que usa funciones de biblioteca (2). Una biblioteca formada pordos modulos objeto que implementan dos funciones cada uno de ellos.

En este caso tenemos una biblioteca formada por dos modulos objeto. Cada uno define dos funcio-nes. Observe que el ejecutable sera exactamente igual que el que llamamos anteriormente ppal 2 (verfigura 4 de la practica 2). Explique por que.

El fichero de cabecera opers 2mod.h asociado a la biblioteca libopers 2mod.a podrıa tener elmismo contenido que opers 1mod.h (ejercicio anterior) si se pretende ofrecer la misma funcionalidad.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 254: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 3 47

Ejercicio

Construir el fichero makefile llamado makefile 1lib 4mod. El fichero makefile implementael diagrama de dependencias mostrado en la figura 9 En este caso tenemos una bibliotecaformada por cuatro modulos objeto, y cada uno define una unica funcion.

Como trabajo previo debera crear los ficheros fuente suma.cpp, resta.cpp,multiplica.cpp y divide.cpp. Observe que no se han considerado ficheros de cabece-ra para cada uno de estos ¿por que?

Figura 9: Construccion de un ejecutable que usa funciones de biblioteca (3). Una biblioteca formada porcuatro modulos objeto, y cada uno define una unica funcion.

El fichero de cabecera opers 4mod.h asociado a la biblioteca libopers 4mod.a podrıa tener elmismo contenido que opers 2mod.h y opers 1mod.h (ejercicios anteriores) si se pretende ofrecer lamisma funcionalidad.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 255: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 3 48

Ejercicio

Construir el fichero makefile llamado makefile 2lib 2mod. El fichero makefile implementael diagrama de dependencias mostrado en la figura 10

Observad que el ejecutable resultante debe ser exactamente igual que el anterior ¿por que?

En este caso tenemos dos bibliotecas (libadic 2mod.a y libproducto 2mod.a) con sus fi-cheros de cabecera asociados (adic 2mod.h y producto 2mod.h). Cada una de las bibliotecasesta compuesta de dos modulos objeto, y cada uno define dos funciones.

Figura 10: Construccion de un ejecutable que usa funciones de biblioteca (4). Dos bibliotecas formadascada una por dos modulos objeto, y cada uno define dos funciones.

Ejercicio

1. Tomar nota de los tamanos de los ejecutables ppal 1lib 1mod, ppal 1lib 2mod,ppal 1lib 4mod y ppal 2lib 2mod.

2. Editar el fichero ppal.cpp y comentar la lınea que llama a la funcion suma().

3. Volver a construir los ejecutables ppal 1lib 1mod, ppal 1lib 2mod,ppal 1lib 4mod y ppal 2lib 2mod.

4. Anotar los tamanos de los ejecutables, compararlos con los anteriores y discutir.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 256: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 3 49

EjercicioEn la Relacion de problemas I (punteros) propusimos escribir unas funciones para la gestionde cadenas clasicas de caracteres.Los prototipos de las funciones son:

int longitud cadena (const char * cadena);bool es palindromo (const char * cad);int comparar cadenas (const char * cad1, const char * cad2);char * copiar cadena (char * cad1, const char * cad2);char * encadenar cadena (char * cad1, const char * cad2);

1. Encapsular estas funciones en una biblioteca llamada libmiscadenas.a y escribir unmodulo llamado demo cadenas.cpp que contenga unicamente una funcion main() yque use las cuatro funciones.

No olvide escribir el fichero de cabecera asociado a la biblioteca, y llamarlemiscadenas.h

2. Escribir un fichero makefile para generar la biblioteca y el ejecutable.

3. Anadir a la biblioteca la funcion propuesta para extraer una subcadena, con prototipo

char * subcadena (char * cad1, const char * cad2, int p, int l);

4. Editar demo cadenas.cpp para que use la nueva funcion.

5. Volver a generar el ejecutable.

6. ¿Que puede decirse del fichero de cabecera asociado a la biblioteca?

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 257: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 3 50

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 258: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.

Practica 4. Gestion de memoria dinamica (I).Resolucion de la Relacion de Problemas II.

Francisco J. Cortijo Bon

Marzo de 2012

Objetivos

1. Reservar memoria en el heap y liberarla.

2. Gestionar estructuras tipo lista.

3. Gestionar vectores dinamicos

4. Seguir profundizando en la compilacion separada de programas.

.

Se trabajara sobre la Relacion de Problemas II: Memoria dinamica. Los problemas propuestos enesta relacion se han organizado en orden creciente de dificultad y tiempo de resolucion. Proponemosorganizar la resolucion de los problemas en dos bloques:

1. En el primero (ejercicios 1 a 7) se trabaja sobre estructuras dinamicas lineales simples (listas yvectores dinamicos). Este sera el trabajo a desarrollar en esta practica.

2. En el segundo (ejercicios 8 a 10) se trabaja con estructuras mas complicadas (matrices bidimen-sionales y listas con informacion compleja)

Trabajo a realizar

* Ejercicios obligatorios:

Se entregaran en la fecha, hora, lugar y siguiendo el procedimiento que se anunciara en la paginaweb de la asignatura y/o correo electronico.

Los ejercicios obligatorios son: 1, 2, 3, 4 y 5.

* Ejercicios opcionales:

Opcionalmente podra entregarse el ejercicio 6.

* Trabajo a realizar en el aula de practicas:

Mientras los companeros defienden los ejercicios entregados, los demas deben trabajar en laresolucion del ejercicio 7.

Recomendamos pensar en la solucion a los ejercicios usando clases.

51

Page 259: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 4 52

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 260: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.

Practica 5. Gestion de memoria dinamica (II).Resolucion de la Relacion de Problemas II.

Francisco J. Cortijo Bon

Marzo de 2012

Objetivos

1. Seguir practicando con la reserva y liberacion de memoria en el heap.

2. Gestionar estructuras dinamicas bidimensionales (tipo matriz).

3. Gestionar estructuras de datos con informacion compleja.

4. Seguir profundizando en la compilacion separada de programas.

.

Se trabajara sobre la Relacion de Problemas II: Memoria dinamica. Los problemas propuestosen esta relacion se han organizado en orden creciente de dificultad y tiempo de resolucion. Hemosorganizado la resolucion de los problemas en dos bloques:

1. En el primero (ejercicios 1 a 7) se trabaja sobre estructuras dinamicas lineales simples (listas yvectores dinamicos). Estos ejercicios se resolvieron en la practica 4.

2. En el segundo (ejercicios 8 a 10) se trabaja con estructuras mas complicadas (matrices bidimen-sionales y listas con informacion compleja). Este sera el trabajo a desarrollar en esta practica.

Trabajo a realizar

* Ejercicios obligatorios:

Se entregaran en la fecha, hora, lugar y siguiendo el procedimiento que se anunciara en la paginaweb de la asignatura y/o correo electronico.

Los ejercicios obligatorios son: 8 y 9 (apartado a).

* Ejercicios opcionales:

Opcionalmente podran entregarse los apartados b y c del ejercicio 9.

* Trabajo a realizar en el aula de practicas:

Mientras los companeros defienden los ejercicios entregados, los demas deben trabajar en laresolucion del ejercicio 10.

Recomendamos pensar en la solucion a los ejercicios usando clases.

53

Page 261: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 5 54

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 262: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.

Practica 10. Gestion de E/S. Ficheros (I).Resolucion de la Relacion de Ejercicios V.

Francisco J. Cortijo Bon

Curso 2011-2012

Objetivos

1. Comprender como se realiza realmente la E/S en C++ mediante flujos.

2. Practicar con operadores y metodos sobre flujos de E/S.

3. Usar la redireccion de E/S para leer y/o escribir de/en ficheros de texto

4. Usar algunas de las clases desarrolladas en anteriores precticas.

5. Construir programas que reciben argumentos desde la lınea de ordenes.

Los ficheros, en esta practica, se gestionaran indirectamente, por redireccion de E/S. Al ejecutar losprogramas, la redireccion de salida hara que se cree un fichero de texto y la redireccion de la entradahara que se tomen los datos de un fichero de texto.

Trabajo a realizar

Se trabajara sobre la relacion de problemas V: Gestion de E/S. Ficheros (I).

1. Realizar en casa los ejercicios 1, 2, 3, 4 y 5. Estos ejercicios son sencillos (algunos puedensolucionarse casi directamente a partir de los apuntes) y deben servir para adquirir destreza.

2. Los ejercicios 6, 7, 8 y 9 estan muy relacionados. Proponemos su realizacion en esta sesion depracticas. No hay ningun inconveniente si se hacen previamente.

3. Los programas a escribir en los ejercicios 10 y 11 reciben valores suministrados en la lınea deordenes. Proponemos su realizacion en esta sesion de practicas. No hay ningun inconveniente sise hacen previamente.

Al finalizar la sesion de practicas se construira un unico fichero zip (ficheros1.zip) que con-tendra los ficheros .cpp, .h y makefile, convenientemente distribuidos en las carpetas necesarias. Alextraerse los ficheros contenidos en este fichero zip deben crearse las carpetas y copiarse correctamen-te, para que al ejecutar make se generen los ficheros objeto, bibliotecas (si procede) y los ejecutables.

65

Page 263: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.

Practica 10. Gestion de E/S. Ficheros (II).Resolucion de la Relacion de Ejercicios VI.

Francisco J. Cortijo Bon

Curso 2011-2012

Objetivos

1. Usar programas que reciben argumentos desde la lınea de ordenes.

2. Usar algunas de las clases desarrolladas en anteriores practicas.

3. Comprender como se establece la comunicacion entre los programas y los ficheros de datosmediante flujos, particularmente con los objetos de fstream.

4. Practicar con las funciones de control del estado del flujo, en particular con la funcion eof() ysaber usarla correctamente.

5. Entender las diferencias entre flujos de texto y flujos binarios, practicar con ambos y saber elegirque tipo de procesamiento es el mas adecuado.

6. Saber como pueden combinarse los datos almacenados en diferentes ficheros para resolver con-sultas que requieran datos almacenados en mas de un fichero.

En esta practica los ficheros se gestionaran directamente, asociando flujos a ficheros, sin emplearla redireccion de E/S.

La practica totalidad de los ejercicios tomaran los valores de los argumentos de la lınea de ordenes,por lo que recomendamos revisar este apartado antes de resolver los ejercicios. Se debera comprobarque el numero de argumentos es correcto, ası como la existencia de los ficheros necesarios para suejecucion.

Nota: Es muy importante que se respeten las restricciones indicadas en los ejercicios para su reso-lucion, ya que de otra manera no se adquiriran las destrezas esperadas.

Trabajo a realizar

Se trabajara sobre la Relacion de Problemas VI: Gestion de E/S. Ficheros (II).

* Ejercicios obligatorios:

• Realizar en casa los ejercicios 1, 2, 3, 4 y 5. Estos ejercicios son los mas sencillos ya queprocesan unicamente ficheros de texto. Estos ejercicios deben servir para adquirir la destrezamınima necesaria para resolver los ejercicios mas complicados.Con la resolucion de estos ejercicios se cubren los objetivos propuestos en esta practica,excepto el objetivo 5.

• Realizar en casa los ejercicios 6, 7 y 8. El objetivo de estos es procesar ficheros binarios,con lo que se cubre el objetivo 5.

63

Page 264: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Practica 10 64

* Trabajo a realizar en el aula de practicas:

Mientras los companeros defienden los ejercicios entregados, los demas deben trabajar en laresolucion de los ejercicios 9 y 10. Evidentemente, no hay ningun inconveniente si se hacenpreviamente.

* Ejercicios opcionales:

• Los ejercicios 11, 12, 13 y 14 estan relacionados. Tienen un nivel de dificultad alto y enparticular el ejercicio 14 no podra resolverse hasta que se termine el tema IV.Encontrara muy utiles los programas que hay que construir.

• Los ejercicios 15, 16 y 17 consisten en reescribir tres ordenes de Unix/Linux. Los ejercicios 15y 16 son muy sencillos, mientras que el 17 resultara mas complejo si se resuelve respetandotodas las restricciones que se indican.

• El ejercicio 18 es un tıpico ejemplo en el que intervienen varios ficheros de datos, y en estecaso, en formato binario. En cualquier caso, con cierta disciplina, no resultara difıcil.

• En el ejercicio 19 interviene un solo fichero, en el que los registros tienen longitud variabley los datos se almacenan en binario. Las operaciones que deben realizarse requieren unprocesamiento muy cuidadoso, que hacen que se pueda etiquetar como difıcil.

• Finalmente, el ejercicio 20 es un ejercicio sencillo, pero que al igual que ocurre con el ejercicio14, solo podra resolverse al finalizar el tema.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 265: Metodología de la Programación

PROBLEMAS

Curso: 2011/2012 Clase: Primero - Grupo: B

Page 266: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.Relacion de Problemas I: Punteros

1. Describir la salida de los siguientes programas:

2. Represente graficamente la disposicion en memoria de las variables del programa mostrado en la figura 1, eindique lo que escribe la ultima sentencia de salida.

3. Declare una variable v como un vector de 1000 enteros. Escriba un trozo de codigo que recorra el vector ymodifique todos los enteros negativos cambiandolos de signo.

No se permite usar el operador [], es decir, el recorrido se efecuara usando aritmetica de punteros y el bucle secontrolara mediante un contador entero.

Nota: Para inicializar aleatoriamente el vector con valores enteros entre -50 y 50, por ejemplo, puede emplearseel siguiente fragmento de codigo:

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 267: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.

Figura 1: Codigo asociado al problema 2

#include <cstdlib>

#include <ctime>

...

const int MY_MAX_RAND = 50; // Queremos valores -50<=n<=50

time_t t;

...

srand ((int) time(&t)); // Inicializa el generador con el reloj del sistema

...

for int (i=0; i<1000; i++)

v[i] = (rand() % ((2*MY_MAX_RAND)+1)) - MY_MAX_RAND;

Acerca de srand(), rand() y time(): http://www.cplusplus.com

4. Modifique el codigo del problema 3 para controlar el final del bucle con un puntero a la posicion siguiente a laultima.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 268: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.

5. Con estas declaracciones:

const int Max = 100;

float v1 [Max] = {2, 3, 8, 22, 44, 88, 99, 100, 101, 255, 665};

float v2 [Max] = {1, 3, 4, 5, 6, 25, 87, 89, 99, 100, 500, 1000};

float res [2*Max];

int tam_v1=11, tam_v2=12; // 0 <= tam_v1, tam_v2 < Max

int tam_res = tam_v1+tam_v2; // 0 <= tam_res < 2*Max

Nota: Observad que v1 y v2 almacenan valores ordenados de menor a mayor.

Escribir un trozo de codigo para mezclar, de manera ordenada, los valores de v1 y v2 en el vector res.

No se debe usar el operador [], es decir, se debe resolver usando aritmetica de punteros.

6. Consideremos un vector v de numeros reales de tamano n. Supongamos que se desea dividir el vector en dossecciones: la primera contendra a todos los elementos menores o iguales al primero y la otra, los mayor.

Para ello, proponemos un algoritmo que consiste en:

Colocamos un puntero al principio del vector y lo adelantamos mientras el elemento apuntado sea menor oigual que el primero.

Colocamos un puntero al final del vector y lo atrasamos mientras el elemento apuntado sea mayor que elprimero.

Si los punteros no se han cruzado, es que se han encontrado dos elementos “mal colocados”. Los intercam-biamos y volvemos a empezar.

Este algoritmo acabara cuando los dos punteros se crucen, habiendo quedado todos los elementos ordenadossegun el criterio inicial.

Escriba un trozo de codigo que declare una constante (n) con valor 20 y un vector de reales con ese tamano, lorellene con numeros aleatorios entre 0 y 100 y lo reorganice usando el algoritmo antes descrito.

7. Las cadenas de caracteres representan un ejemplo clasico en el uso de punteros. La cadena almacena un numeroindeterminado de caracteres (para los ejercicios basatara un valor siempre menor que 100) delimitados al finalpor el caracter nulo (’\0’).

Escriba un trozo de codigo que localice la posicion del primer caracter espacio (’ ’) en una cadena de caracteres“clasica”.

La cadena debe recorrerse usando aritmetica de punteros y sin usar ningun entero. El programa debe indicar suposicion (0: primer caracter, 1: segundo caracter, etc.).

Nota: Usar la funcion getline() para la lectura de la cadena (Cuidado: usar el metodo publico de istream

sobre cin, o sea cin.getline()). Ver http://www.cplusplus.com/reference/iostream/istream/getline/

8. Consideremos una cadena de caracteres “clasica”. Escriba un trozo de codigo que lea una cadena y la imprimapero saltandose la primera palabra, evitando escribirla caracter a caracter.

Considere que puede haber una o mas palabras, y si hay mas de una palabra, estan separadas por espacios enblanco.

9. Implemente las siguientes funciones sobre cadenas de caracteres “clasicas”:

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 269: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.

a) Funcion longitud_cadena. Devuelve un entero con la longitud (numero de caracteres sin contar el nulo)de la cadena.

b) Funcion comparar_cadenas. Compara dos cadenas. Devuelve un valor negativo si la primera es mas “pe-quena”, positivo si es mas “grande” y cero si son “iguales”.

c) Funcion copiar_cadena. Copia una cadena de caracteres en otra. El resultado es el primer argumento.

d) Funcion encadenar_cadena. Anade una cadena de caracteres al final de otra. El resultado es el primerargumento.

Se supone que hay suficiente memoria en las cadenas de destino y no es necesario pasar el tamano de las cadenas(recordad que el caracter nulo delimita el final de la cadena).

10. Escriba una funcion a la que le damos una cadena de caracteres, una posicion de inicio p y una longitud l. Comoresultado, devuelve una subcadena que comienza en p y que tiene longitud l.

Nota: Si la longitud es demasiado grande (se sale de la cadena original), se devolvera una cadena de menortamano. No se debe usar el operador [], es decir, se debe resolver mediante aritmetica de punteros.

11. Se desea una funcion que reciba un vector de numeros enteros junto con su longitud y que devuelva un punteroal elemento mayor.

Escriba dos versiones:

a) Devuelve el resultado como resultado de la funcion (return).

b) Devuelve el resultado a traves de un parametro (funcion void).

Considere la siguiente declaracon:

int vector [100];

int usados; // 0 <= usados < 100

Haga uso de la primera funcion para mostrar en la salida estandar:

a) El elemento mayor del vector.

b) El elemento mayor de la primera mitad.

c) El elemento mayor de la segunda mitad.

12. Escriba una funcion que reciba como entrada un vector de numeros junto con su longitud y que nos devuelva unvector de punteros a los elementos del vector de entrada de forma que los elementos apuntados por dicho vectorde punteros esten ordenados (vease figura 2).

Note que el vector de punteros debe ser un parametro de la funcion, y estar reservado previamente a la llamadacon un tamano, al menos, igual al del vector.

Una vez escrita la funcion, considere la siguiente declaracion:

int vec [1000];

int *ptr [1000];

y escriba un trozo de codigo que, haciendo uso de la funcion, permita:

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 270: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.

Figura 2: Resultado de ordenar el vector de punteros

a) Ordenando punteros, mostrar los elementos del vector, ordenados.

b) Ordenando punteros, mostrar los elementos de la segunda mitad del vector, ordenados.

sin modificar el vector de datos vec.

13. Represente graficamente la disposicion en memoria de las variables del programa mostrado en la figura 3, eindique lo que escribe la ultima sentencia de salida. Tenga en cuenta que el operador -> tiene mas prioridad queel operador *.

14. Considere las figuras 4, 5 y 6. Se presentan graficamente un conjunto de estructuras de datos. Se puede observarque las matrices se representan indicando los ındices y las estructuras indicando los nombres de los campos.

Escriba los trozos de codigo que corresponden a su creacion.

Nota: No se debe usar memoria dinamica (para cada caso se incluye el nombre de las variables necesarias).

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 271: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.

Figura 3: Codigo asociado al problema 13

Figura 4: Estructuras complejas (1)

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 272: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.

Figura 5: Estructuras complejas (2)

Figura 6: Estructuras complejas (3)

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 273: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Problemas. 7

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.

Relacion de Problemas II: Memoria dinamica

1. Escriba un programa para que lea una secuencia con un numero indefinido de valores double hasta que seintroduzca un valor negativo. Estos valores (excepto el ultimo, el negativo) los almacenara en una estructura deceldas enlazadas (una lista) y despues mostara los valores almacenados.

Escribir un programa para solucionar este problema, con dos funciones:

a) Una para leer y almacenar los valores.

b) Otra para mostrarlos.

2. Ampliar el problema 1 de manera que una vez leıdos los datos realice unos calculos sobre los datos almacenadosen la lista. Se pide que se escriban tres funciones para calcular:

a) el numero de celdas enlazadas.

b) la media de los datos almacenados.

c) la varianza de los datos almacenados.

3. Utilizando como base el problema 1, escribir un programa que lea una secuencia de valores, los almacene en unalista e indique si la secuencia esta ordenada. Escribir una funcion para determinar si la secuencia esta ordenada.

4. Considere una secuencia de datos almacenada en una lista. Implemente una funcion para ordenar la secuenciaempleando el metodo de ordenacion por seleccion.

5. Considere una secuencia ordenada de datos almacenada en una lista.

a) Implemente una funcion para insertar un nuevo dato en su posicion correcta.

b) Implemente una funcion para, dado un dato, eliminar la celda que lo contiene.

6. Considere dos secuencias de datos ordenadas almacenadas en sendas listas. Implemente una funcion paramezclar ordenadamente las dos secuencias en una nueva, de forma que las dos listas originales se queden vacıas

tras realizar la mezcla y la lista resultante contenga todos los datos.

Como puede observar, se trata de una variante del algoritmo mergesort ya que ahora se exige la modificacion delas secuencias originales: en esta version los datos se “mueven” hacia la lista resultante en lugar de copiarlos.

Nota: No es preciso (ni se permite) realizar ninguna operacion de reserva ni liberacion de memoria.

7. Deseamos guardar un numero indefinido de valores double para poder procesarlos posteriormente. Resuelvael problema almacenando los datos en un vector dinamico que vaya creciendo conforme necesite espacio paraalmacernar un nuevo valor.

Escribir tres funciones diferentes, de manera que el problema se pueda resolver con cualquiera de ellas. Lasfunciones se diferencian en la manera en que hacen crecer el vector dinamico, aumentando su capacidad cuandono haya espacio para almacernar un nuevo valor, ampliandolo:

a) en una casilla

b) en bloques de tamano n

c) duplicando su tamano

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 274: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Problemas. 8

Nota: Reservar inicialmente 5 casillas.

Para la resolucion de este ejercicio proponemos dos programas diferentes.

1) El primero tomara los valores a insertar en el vector dinamico directamente del teclado.

2) El segundo tomara los valores a insertar desde una lista.

Intentar que el almacenamiento en el vector dinamico (procesamiento) sea lo mas independiente posible de laentrada de datos.

8. Supongamos que para definir matrices bidimensionales dinamicas usamos una estructura como la que apareceen la figura 4(tipo Matriz2D-1). En los apuntes de clase se detalla como crear y liberar esta estructura.

Nota: Recuerde que los modulos que procesan estructuras de este tipo necesitan recibir como parametros elnumero de filas y columnas de la matriz.

0

1

2

3

4

0 1 2 3 4 cols−1

matriz

fils−1

0 1 2 3 4 cols−1

0 1 2 3 4 cols−1

Figura 4: Tipo Matriz2D1: datos guardados en filas independientes

a) Construir un modulo que lea del teclado fils×cols valores y los copie en la matriz.

b) Construir un modulo que muestre los valores guardados en la matriz.

c) Construir un modulo que reciba una matriz de ese tipo, cree y devuelva una copia.

d) Construir un modulo que extraiga una submatriz de una matriz bidimensional Matriz2D-1. Como argu-mento de la funcion se introduce desde que fila y columna y hasta que fila y columna se debe realizar lacopia de la matriz original. La submatriz devuelta es una nueva matriz.

e) Construir un modulo que elimine una fila de una matriz bidimensional Matriz2D-1. Obviamente, no sepermiten “huecos” (filas vacıas).

f ) Construir un modulo como el anterior, pero que en vez de eliminar una fila, elimine una columna.

g) Construir un modulo que devuelva la traspuesta de una matriz. La matriz devuelta es una nueva matriz.

h) Construir un modulo que reciba una matriz y la modifique, de tal manera que “invierta” las filas: la primerasera la ultima, la segunda la penultima, y ası sucesivamente.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 275: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Problemas. 9

9. Supongamos que ahora decidimos utilizar una forma diferente para representar las matrices bidimensionalesdinamicas a la que se propone en el ejercicio 8. En este caso, usaremos una estructura semejante a la que apareceen la figura 5 (tipo Matriz2D-2). En los apuntes de clase se detalla como crear y liberar esta estructura.

Nota: Recuerde que los modulos que procesan estructuras de este tipo necesitan recibir como parametros elnumero de filas y columnas de la matriz.

1 filaa

matriz

0

1

2

3

4

fils−1

0 1

a2 fila n−esima fila

fils*cols−12 x cols−1cols−1

Figura 5: Tipo Matriz2D2: datos guardados en una sola fila

a) Reescribir todos los modulos propuestos en el ejercicio 8 usando esta nueva representacion.

b) Construir un modulo que dada una matriz bidimensional dinamica Matriz2D-1 realice una copia de lamisma en una matriz bidimensional dinamica Matriz2D-2 y la devuelva.

c) Desarrollar un modulo que realice el paso inverso, convertir de Matriz2D-2 a Matriz2D-1 y devoleverla.

10. Se desea desarrollar una estructura de datos que permita representar de forma general diversas figuras poligonales.Cada figura poligonal se puede representar como un conjunto de puntos en el plano unidos por segmentos derectas entre cada dos puntos adyacentes. Por esta razon se propone la representacion mostrada en la figura 6.

Ası, un polıgono se representa como una secuencia circular y ordenada de nodos enlazados. Por ejemplo, eltriangulo de puntos (2,0),(4,0) y (3,l) se representa como se indica en la figura 6.

Figura 6: Representacion de un polıgono y un ejemplo (un triangulo)

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 276: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Problemas. 10

Teniendo en cuenta esta representacion, responder a las siguientes cuestiones:

a) Implementar un modulo que permita iniciar y “rellenar” una variable de tipo Poligono proporcionandoleun vector de datos de tipo Punto2D y el numero de puntos que debe emplear para iniciar el polıgono.

b) Desarrollar un modulo que permita liberar la memoria reservada por una variable Poligono.

c) Construir un modulo que determine el numero de lados que contiene la figura almacenada en una variablede tipo Poligono.

d) Suponiendo que existe una funcion llamada PintaRecta (Punto2D pl, Punto2D p2) que pinta una rectaentre los dos puntos que se le pasan como argumentos, construir un modulo que permita pintar la figuraque representa una determinada variable Poligono.

e) Sabiendo que una variable Poligono almacena un cuadrado, implementar un modulo que devuelva los dostriangulos que resultan de unir mediante una recta la esquina inferior izquierda del cuadrado con su esquinasuperior derecha (figura 7.A).

f ) Construir un modulo que a partir de una variable Poligono que representa a un triangulo devuelva eltriangulo formado por los puntos medios de las rectas del triangulo original (figura 7.B).

g) Desarrollar un modulo que permita construir un polıgono regular de n lados inscrito en una circunferenciade radio r y centro (x,y) (figura 7.C).

Figura 7: A y B) Calculo de algunos triangulos. C) Construccion de un polıgono inscrito en una circunferencia

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 277: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Problemas. 11

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.

Relacion de Problemas III: Clases (I)

Los ejercicios propuestos tienen como finalidad que el alumno practique con los constructores y destructor de unaclase, ası como con metodos sencillos de acceso y manipulacion de la clase.

Todos los ejercicios deben estar completamente implementados y modularizados. Significa que debe existir, paracada clase:

Un fichero .h con las declaraciones.

Un fichero .cpp con las definiciones.

Ademas, debe implementarse un fichero .cpp con la funcion main() que contenga ejemplos sobre el uso de la clase.Finalmente, tambien debe escribirse un fichero makefile para generar el ejecutable. Podrıa usarse incluso un unico

fichero makefile para generar todos los ejecutables de esta relacion.

1. Implementar la clase Racional para trabajar con numeros fraccionarios de la forma a/b donde a y b son numerosenteros.

Proponer una representacion para la clase e implementar los siguientes metodos:

a) Constructor sin argumentos, que inicia un numero racional con valor cero.

b) Constructor que crea un racional a partir de un numero entero.

c) Constructor que crea un racional a partir de dos enteros: el primero sera el numerador y el segundo eldenominador.

d) Destructor (si procede).

e) Metodos para leer/escribir el valor del numerador/denominador.

f ) Metodo para escribir de manera “natural” en la salida estandar un numero racional (separando numeradory denominador con una barra inclinada /)

2. Implementar la clase VectorDinamico para trabajar con vectores de enteros de tamano arbitrario, y no definidoa priori.

Proponer una representacion para la clase e implementar los siguientes metodos:

a) Constructor sin argumentos, que crea un vector dinamico vacıo.

b) Constructor con un argumento, que crea un vector dinamico con un numero de casillas indicado en elargumento. Inicia todas la casillas a cero.

c) Constructor con dos argumentos, que crea un vector dinamico con un numero de casillas indicado en elprimer argumento. Inicia todas la casillas al valor indicado en el segundo argumento.

d) Destructor.

e) Metodo (valor devuelto: bool) que consulta si el vector dimamico esta vacıo.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 278: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Problemas. 12

f ) Metodo para consultar el numero de casillas ocupadas.

g) Metodos para leer/escribir un valor.

h) Metodo para escribir el contenido del vector dinamico.

i) Metodo para redimensionar un vector dinamico. Recibira un solo argumento: el nuevo numero de casillas,que suponemos siempre sera mayor que el actual. El “nuevo” vector debe mantener los valores almacenadosanteriormente, en las mismas posiciones.

3. Implementar la clase Matriz2D-1 para elementos de tipo TipoBase. De acuerdo con TipoBase establecer el valornulo (0 si TipoBase es int, 0.0 si TipoBase es double o float, "" si TipoBase es string,. . . ).

Empleando la representacion basica conocida, se trata de implementar los siguientes metodos:

a) Constructor sin argumentos, que crea una matriz vacıa.

b) Constructor con un argumento, que crea una matriz cuadrada con el numero de filas y columnas indicadoen el argumento. Inicia todas las casillas al valor nulo.

c) Constructor con dos argumentos, que crea una matriz con el numero de filas indicado en el primer argumentoy con el numero de columnas indicado en el segundo argumento. Inicia todas las casillas al valor nulo

d) Constructor con tres argumentos, que crea una matriz con el numero de filas indicado en el primer argumentoy con el numero de columnas indicado en el segundo argumento. Ademas inicia todas las casillas de la matrizal valor especificado con el tercer argumento.

e) Destructor.

f ) Metodo (valor devuelto: bool) que consulta si la matriz esta vacıa.

g) Metodos para escribir/leer un valor. Responderan a los prototipos:

void PonValor (int fila, int col, TipoBase val);

TipoBase LeeValor (int fila, int col);

4. Implementar la clase Matriz2D-2 para elementos de tipo TipoBase.

Empleando la representacion basica conocida, se trata de implementar los mismos metodos que en el problema 3.

5. Implementar la clase Lista para trabajar con listas dinamicas (de tamano arbitrario, y no definido a priori,cuyos nodos residen en el heap) de datos de tipo TipoBase. De acuerdo con TipoBase establecer el valor nulo (0si TipoBase es int, 0.0 si TipoBase es double o float, "" si TipoBase es string,. . . ).

Proponer una representacion para la clase (basada en el almacenamiento de los nodos en memoria dinamica) eimplementar los siguientes metodos:

a) Constructor sin argumentos, que crea una lista vacıa.

b) Constructor con un argumento, que crea una lista con un numero de nodos indicado en el argumento. Iniciatodos los nodos de la lista al valor nulo.

c) Constructor con dos argumentos, que crea una lista con un numero de nodo indicado en el primer argumento.Inicia todos los nodos de la lista al valor indicado en el segundo argumento.

d) Destructor.

e) Metodo (valor devuelto: bool) que consulta si la lista esta vacıa.

f ) Metodo para consultar el numero de nodos de la lista.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 279: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Problemas. 13

g) Metodo para escribir el contenido de una lista.

h) Metodo para insertar un valor en la lista. Modifica la lista. Respondera al siguiente prototipo:

void Insertar (TipoBase val, int pos);

de manera que inserta un nuevo nodo en la lista con valor val en la posicion pos (1 para el primer nodo, 2para el segundo, etc.). La posicion seguira el siguiente convenio: pos indica el numero de orden que ocuparael nuevo nodo que se va a insertar.

Algunos ejemplos (si TipoBase es int):

Antes: < 6, 8, 4, 3, 2, 9 > Insertar (5, 2) Despues: < 6, 5, 8, 4, 3, 2, 9 >

Antes: < 6, 8, 4, 3, 2, 9 > Insertar (5, 6) Despues: < 6, 8, 4, 3, 2, 5, 9 >

Antes: < 6, 8, 4, 3, 2, 9 > Insertar (5, 7) Despues: < 6, 8, 4, 3, 2, 9, 5 >

Antes: < 6, 8, 4, 3, 2, 9 > Insertar (5, 1) Despues: < 5, 6, 8, 4, 3, 2, 9 >

i) Metodo para borrar un nodo en la lista. Respondera al siguiente prototipo:

void Borrar (int pos);

de manera que borra el nodo que ocupa la posicion pos (1 para el primer nodo, 2 para el segundo, etc.)

j ) Metodos para leer/escribir un valor.

TipoBase ObtenerValor (int pos);

void PonerValor (int pos, TipoBase val);

de tal manera que pos indica la posicion del nodo (1 para el primer nodo, 2 para el segundo, etc.)

6. Implementar la clase Pila.

Una pila es una estructura de datos que permite la gestion de problemas en los que la gestion se realiza empleandoun protocolo LIFO (last in f irst out).

Proponer una representacion para la clase (basada en el almacenamiento de los nodos en memoria dinamica) eimplementar los siguientes metodos:

a) Constructor sin argumentos, que crea una pila vacıa.

b) Destructor.

c) Metodo (valor devuelto: bool) que consulta si la pila esta vacıa.

d) Metodo para anadir un valor. La pila se modifica.

e) Metodo para sacar un valor. Obtiene (devuelve) el elemento extraıdo. La pila se modifica.

f ) Metodo para consultar que elemento esta en el tope de la pila. La pila no se modifica.

7. Implementar la clase Cola.

Una cola es una estructura de datos que permite la gestion de problemas en los que la gestion se realiza empleandoun protocolo FIFO (First in f irst out).

Proponer una representacion para la clase (basada en el almacenamiento de los nodos en memoria dinamica) eimplementar los siguientes metodos:

a) Constructor sin argumentos, que crea una cola vacıa.

b) Destructor.

c) Metodo (valor devuelto: bool) que consulta si la cola esta vacıa.

d) Metodo para anadir un valor. La cola se modifica.

e) Metodo para sacar un valor. Obtiene (devuelve) el elemento extraıdo. La cola se modifica.

f ) Metodo para consultar que elemento esta en la cabecera de la cola. La cola no se modifica.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 280: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Problemas. 14

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 281: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Problemas. 15

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.

Relacion de Problemas IV: Clases (II)

Los ejercicios propuestos tienen como finalidad que el alumno practique con:

el constructor de copia y la sobrecarga del operador de asignacion, empleando codigo reutilizable,

la sobrecarga de los operadores [] y ()

la sobrecarga de operadores relacionales

la sobrecarga de operadores aritmeticos

la sobrecarga de operadores sobre flujos

Muchos de estos ejercicios amplıan las clases disenadas e implementadas como solucion a los ejercicios propuestosen la Relacion de Problemas III (Clases I). En cualquier caso, todos los ejercicios deben estar completamente

implementados y modularizados continuando y complementando el trabajo ya realizado.

1. Ampliar la clase Racional con los siguientes metodos:

a) Sobregargar los operadores unarios + y -.

b) Sobregargar los operadores aritmeticos binarios +, -, * y / para poder operar entre dos racionales y racionalescon enteros (en cualquier orden).

c) Sobregargar los operadores aritmeticos binarios +=, -=, *= y /=.

d) Sobregargar los operadores relacionales binarios ==, !=, >, < , >= y <= para poder comparar racionales conracionales y racionales con enteros (en cualquier orden).

e) Sobreescribir los operadores << y >> para insertar un numero racional en un flujo y extraer un numeroracional de un flujo. La insercion/extraccion se realizara de la siguiente manera. Si r es un dato de la claseRacional:

Si r contiene el valor 3/5, la instrucion cout << r mostrara 3/5

La ejecucion de cin >> r hara que se lea una cadena de caracteres y se procese adecuadamente paraaislar el numerador y el denominador (usar como referencia-seprador el caracter /). La cadena no puedecontener espacios en blanco.Por ejemplo, cuando el usuario escriba 3/5 se procesara esa palabra y r tomara el valor 3/5.

2. Ampliar la clase VectorDinamico de datos de tipo TipoBase con los siguientes metodos:

a) Constructor de copia y sobrecarga del operador de asignacion, empleando codigo reutilizable. Reescribir eldestructor en base a esta estrategia.

b) Sobregargar el operador [] para que sirva de operador de acceso a los elementos del vector dinamico ypueda actuar tanto como lvalue como rvalue.

c) Sobregargar los operadores relacionales binarios == y != para comparar dos vectores dinamicos. Dos vectoresseran iguales si tienen el mismo numero de casillas ocupadas y los contenidos son iguales y en las mismasposiciones.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 282: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Problemas. 16

d) Sobregargar los operadores relacionales binarios >, <, >= y <= para poder comparar dos vectores dinamicos.Usar un criterio similar al que se sigue en la comparacion de dos cadenas de caracteres clasicas.

e) Considerar una implementacion nueva para redimensionar un vector dinamico: emplear los operadoresbinarios +, -, += y -= de manera que, por ejemplo:

Si v es un VectorDinamico, la instruccion v = v+1 crea un VectorDinamico con una casilla mas que v, lorellena a partir de este y lo devuelve; a continuacion se asigna a v. Si v es un VectorDinamico, la instruccionVectorDinamico v2 = v+1 crea un vector dinamico con una casilla mas que v, lo rellena a partir de v y lodevuelve; a continuacion se se crea v2 a partir del vector dinamico ası construido.

Si v es un VectorDinamico, la instruccion v -= 10 crea un VectorDinamico con 10 casillas menos quev, lo rellena a partir de este (descartando las 10 ultimas) y lo devuelve; a continuacion se asigna a v.Se sobreentiende que antes de realizar esta operacion estamos seguros que el numero de casillas ocupadas

seguira siendo menor o igual que el numero maximo de casillas disponibles que tendremos despues de lareduccion.

f ) Sobreescribir los operadores << y >> para leer/escribir un vector dinamico.

Notas:

Para la implementacion del operador >> leera una secuencia indefinida de valores, hasta que se introduz-ca el valor *. Los valores se leeran en una cadena de caracteres, y solo se convertiran al tipo TipoBase

cuando se verifique que son validos para su almacenamiento (no se ha introducido el terminador (*)).

Los valores siempre se guardaran al final.

3. Ampliar la clase Matriz2D-1 con los siguientes metodos:

a) Constructor de copia y sobrecarga del operador de asignacion, empleando codigo reutilizable. Reescribir eldestructor en base a esta estrategia.

b) Una sobrecarga alternativa del operador de asignacion, que recibe como argumento un dato de tipo TipoBasee inicia toda la matriz al valor especificado.

c) Sobregargar el operador () para que sirva de operador de acceso a los elementos de la matriz dinamica ypueda actuar tanto como lvalue como rvalue.

d) Sobregargar los operadores unarios + y -.

e) Sobregargar los operadores relacionales binarios == y != para comparar dos matrices dinamicas: seran igualessi tienen el mismo numero de filas y columnas, y los contenidos son iguales y en las mismas posiciones.

f ) Sobreescribir el operador << para mostrar el contenido de una matriz dinamica.

4. Ampliar la clase Matriz2D-2.

Empleando la representacion basica conocida, se trata de implementar los mismos metodos que en el problema 3.

5. Ampliar la clase Lista de datos de tipo TipoBase con los siguientes metodos:

a) Constructor de copia y sobrecarga del operador de asignacion, empleando codigo reutilizable. Reescribir eldestructor en base a esta estrategia.

b) Sobregargar el operador [] para que sirva de operador de acceso a los elementos de la lista y pueda actuartanto como lvalue como rvalue. El ındice hace referencia a la posicion, de tal manera que 1 indica el primernodo, 2 el segundo, etc.)

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 283: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Problemas. 17

c) Sobreescribir los operadores << y >> para leer/escribir una lista.

Notas:

Para la implementacion del operador >> leera una secuencia indefinida de valores, hasta que se introduz-ca el valor *. Los valores se leeran en una cadena de caracteres, y solo se convertiran al tipo TipoBase

cuando se verifique que son validos para su almacenamiento (no se ha introducido el terminador (*)).

Los valores siempre se guardaran al final.

6. Ampliar la clase Pila de datos de tipo TipoBase con los siguientes metodos:

a) Constructor de copia y sobrecarga del operador de asignacion, empleando codigo reutilizable. Reescribir eldestructor en base a esta estrategia.

b) Sobreescribir el operador <<.

7. Ampliar la clase Cola de datos de tipo TipoBase con los siguientes metodos:

a) Constructor de copia y sobrecarga del operador de asignacion, empleando codigo reutilizable. Reescribir eldestructor en base a esta estrategia.

b) Sobreescribir el operador <<.

8. Implementa una clase Conjunto que permita manipular un conjunto de elementos de tipo TipoBase.

Para la representacion interna de los datos usar una lista de celdas enlazadas. El orden de los elementos no esimportante desde un punto de vista teorico, pero aconsejamos que se mantengan los elementos ordenados parafacilitar la implementacion de los metodos de la clase.

La clase Conjunto debe contener, al menos, las siguientes operaciones:

a) Constructor sin argumentos: crea un conjunto vacıo.

b) Constructor con un argumento de tipo TipoBase: crea un conjunto con un unico elemento (el proporcionadocomo argumento).

c) Constructor de copia (empleando codigo reutilizable).

d) Destructor (empleando codigo reutilizable).

e) Metodo que consulta si el conjunto esta vacıo.

f ) Sobrecarga del operador de asignacion (empleando codigo reutilizable).

g) Metodo que nos diga cuantos elementos tiene el conjunto.

h) Metodo que reciba un dato de tipo TipoBase y consulte si pertence al conjunto.

i) Sobreescribir los operadores << y >> para leer/escribir un Conjunto.

Notas:

Para la implementacion del operador >> leera una secuencia indefinida de valores, hasta que se introduz-ca el valor *. Los valores se leeran en una cadena de caracteres, y solo se convertiran al tipo TipoBase

cuando se verifique que son validos para su almacenamiento (no se ha introducido el terminador (*)).

Evidentemente, no se permiten elementos repetidos.

j ) Metodo que devuelva un VectorDinamico con todos los elementos del conjunto.

k) Sobregargar los operadores relacionales binarios == y != para comparar dos conjuntos. Dos conjuntos seraniguales si tienen el mismo numero de elementos y los mismos valores (independientemente de su posicion).

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 284: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Problemas. 18

l) Sobreescribir el operador binario + para calcular la union de dos conjuntos. Respondera a las siguientessituaciones:

Si A y B son datos de tipo Conjunto, A+B sera otro dato de tipo Conjunto y contendra A ∪B

Si A es un dato de tipo Conjunto y a es un dato de tipo TipoBase, A+a sera un dato de tipo Conjunto

y contendra A ∪ {a}

Si A es un dato de tipo Conjunto y a es un dato de tipo TipoBase, a+A sera un dato de tipo Conjunto

y contendra {a} ∪A

m) Sobreescribir el operador binario - para calcular la diferencia de dos conjuntos. Respondera a las siguientessituaciones:

Si A y B son datos de tipo Conjunto, A-B sera otro dato de tipo Conjunto y contendra A−B, o sea, elresultado de quitar de A los elementos que estan en B.

Si A es un dato de tipo Conjunto y a es un dato de tipo TipoBase, A-a sera un dato de tipo Conjunto

y contendra A− {a}, o sea, el resultado de eleminar del conjunto A el elemento a.

n) Sobreescribir el operador binario * para calcular la interseccion de dos conjuntos. Respondera a las si-guientes situaciones:

Si A y B son datos de tipo Conjunto, A*B sera otro dato de tipo Conjunto y contendra A ∩B

Si A es un dato de tipo Conjunto y a es un dato de tipo TipoBase, A*a sera un dato de tipo Conjunto

y contendra A ∩ {a}

Si A es un dato de tipo Conjunto y a es un dato de tipo TipoBase, a*A sera un dato de tipo Conjunto

y contendra {a} ∩A

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 285: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Problemas. 15

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.

Relacion de Problemas IV: Clases (II)

Los ejercicios propuestos tienen como finalidad que el alumno practique con:

el constructor de copia y la sobrecarga del operador de asignacion, empleando codigo reutilizable,

la sobrecarga de los operadores [] y ()

la sobrecarga de operadores relacionales

la sobrecarga de operadores aritmeticos

la sobrecarga de operadores sobre flujos

Muchos de estos ejercicios amplıan las clases disenadas e implementadas como solucion a los ejercicios propuestosen la Relacion de Problemas III (Clases I). En cualquier caso, todos los ejercicios deben estar completamente

implementados y modularizados continuando y complementando el trabajo ya realizado.

1. Ampliar la clase Racional con los siguientes metodos:

a) Sobregargar los operadores unarios + y -.

b) Sobregargar los operadores aritmeticos binarios +, -, * y / para poder operar entre dos racionales y racionalescon enteros (en cualquier orden).

c) Sobregargar los operadores aritmeticos binarios +=, -=, *= y /=.

d) Sobregargar los operadores relacionales binarios ==, !=, >, < , >= y <= para poder comparar racionales conracionales y racionales con enteros (en cualquier orden).

e) Sobreescribir los operadores << y >> para insertar un numero racional en un flujo y extraer un numeroracional de un flujo. La insercion/extraccion se realizara de la siguiente manera. Si r es un dato de la claseRacional:

Si r contiene el valor 3/5, la instrucion cout << r mostrara 3/5

La ejecucion de cin >> r hara que se lea una cadena de caracteres y se procese adecuadamente paraaislar el numerador y el denominador (usar como referencia-seprador el caracter /). La cadena no puedecontener espacios en blanco.Por ejemplo, cuando el usuario escriba 3/5 se procesara esa palabra y r tomara el valor 3/5.

2. Ampliar la clase VectorDinamico de datos de tipo TipoBase con los siguientes metodos:

a) Constructor de copia y sobrecarga del operador de asignacion, empleando codigo reutilizable. Reescribir eldestructor en base a esta estrategia.

b) Sobregargar el operador [] para que sirva de operador de acceso a los elementos del vector dinamico ypueda actuar tanto como lvalue como rvalue.

c) Sobregargar los operadores relacionales binarios == y != para comparar dos vectores dinamicos. Dos vectoresseran iguales si tienen el mismo numero de casillas ocupadas y los contenidos son iguales y en las mismasposiciones.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 286: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Problemas. 16

d) Sobregargar los operadores relacionales binarios >, <, >= y <= para poder comparar dos vectores dinamicos.Usar un criterio similar al que se sigue en la comparacion de dos cadenas de caracteres clasicas.

e) Considerar una implementacion nueva para redimensionar un vector dinamico: emplear los operadoresbinarios +, -, += y -= de manera que, por ejemplo:

Si v es un VectorDinamico, la instruccion v = v+1 crea un VectorDinamico con una casilla mas que v, lorellena a partir de este y lo devuelve; a continuacion se asigna a v. Si v es un VectorDinamico, la instruccionVectorDinamico v2 = v+1 crea un vector dinamico con una casilla mas que v, lo rellena a partir de v y lodevuelve; a continuacion se se crea v2 a partir del vector dinamico ası construido.

Si v es un VectorDinamico, la instruccion v -= 10 crea un VectorDinamico con 10 casillas menos quev, lo rellena a partir de este (descartando las 10 ultimas) y lo devuelve; a continuacion se asigna a v.Se sobreentiende que antes de realizar esta operacion estamos seguros que el numero de casillas ocupadas

seguira siendo menor o igual que el numero maximo de casillas disponibles que tendremos despues de lareduccion.

f ) Sobreescribir los operadores << y >> para leer/escribir un vector dinamico.

Notas:

Para la implementacion del operador >> leera una secuencia indefinida de valores, hasta que se introduz-ca el valor *. Los valores se leeran en una cadena de caracteres, y solo se convertiran al tipo TipoBase

cuando se verifique que son validos para su almacenamiento (no se ha introducido el terminador (*)).

Los valores siempre se guardaran al final.

3. Ampliar la clase Matriz2D-1 con los siguientes metodos:

a) Constructor de copia y sobrecarga del operador de asignacion, empleando codigo reutilizable. Reescribir eldestructor en base a esta estrategia.

b) Una sobrecarga alternativa del operador de asignacion, que recibe como argumento un dato de tipo TipoBasee inicia toda la matriz al valor especificado.

c) Sobregargar el operador () para que sirva de operador de acceso a los elementos de la matriz dinamica ypueda actuar tanto como lvalue como rvalue.

d) Sobregargar los operadores unarios + y -.

e) Sobregargar los operadores relacionales binarios == y != para comparar dos matrices dinamicas: seran igualessi tienen el mismo numero de filas y columnas, y los contenidos son iguales y en las mismas posiciones.

f ) Sobreescribir el operador << para mostrar el contenido de una matriz dinamica.

4. Ampliar la clase Matriz2D-2.

Empleando la representacion basica conocida, se trata de implementar los mismos metodos que en el problema 3.

5. Ampliar la clase Lista de datos de tipo TipoBase con los siguientes metodos:

a) Constructor de copia y sobrecarga del operador de asignacion, empleando codigo reutilizable. Reescribir eldestructor en base a esta estrategia.

b) Sobregargar el operador [] para que sirva de operador de acceso a los elementos de la lista y pueda actuartanto como lvalue como rvalue. El ındice hace referencia a la posicion, de tal manera que 1 indica el primernodo, 2 el segundo, etc.)

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 287: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Problemas. 17

c) Sobreescribir los operadores << y >> para leer/escribir una lista.

Notas:

Para la implementacion del operador >> leera una secuencia indefinida de valores, hasta que se introduz-ca el valor *. Los valores se leeran en una cadena de caracteres, y solo se convertiran al tipo TipoBase

cuando se verifique que son validos para su almacenamiento (no se ha introducido el terminador (*)).

Los valores siempre se guardaran al final.

6. Ampliar la clase Pila de datos de tipo TipoBase con los siguientes metodos:

a) Constructor de copia y sobrecarga del operador de asignacion, empleando codigo reutilizable. Reescribir eldestructor en base a esta estrategia.

b) Sobreescribir el operador <<.

7. Ampliar la clase Cola de datos de tipo TipoBase con los siguientes metodos:

a) Constructor de copia y sobrecarga del operador de asignacion, empleando codigo reutilizable. Reescribir eldestructor en base a esta estrategia.

b) Sobreescribir el operador <<.

8. Implementa una clase Conjunto que permita manipular un conjunto de elementos de tipo TipoBase.

Para la representacion interna de los datos usar una lista de celdas enlazadas. El orden de los elementos no esimportante desde un punto de vista teorico, pero aconsejamos que se mantengan los elementos ordenados parafacilitar la implementacion de los metodos de la clase.

La clase Conjunto debe contener, al menos, las siguientes operaciones:

a) Constructor sin argumentos: crea un conjunto vacıo.

b) Constructor con un argumento de tipo TipoBase: crea un conjunto con un unico elemento (el proporcionadocomo argumento).

c) Constructor de copia (empleando codigo reutilizable).

d) Destructor (empleando codigo reutilizable).

e) Metodo que consulta si el conjunto esta vacıo.

f ) Sobrecarga del operador de asignacion (empleando codigo reutilizable).

g) Metodo que nos diga cuantos elementos tiene el conjunto.

h) Metodo que reciba un dato de tipo TipoBase y consulte si pertence al conjunto.

i) Sobreescribir los operadores << y >> para leer/escribir un Conjunto.

Notas:

Para la implementacion del operador >> leera una secuencia indefinida de valores, hasta que se introduz-ca el valor *. Los valores se leeran en una cadena de caracteres, y solo se convertiran al tipo TipoBase

cuando se verifique que son validos para su almacenamiento (no se ha introducido el terminador (*)).

Evidentemente, no se permiten elementos repetidos.

j ) Metodo que devuelva un VectorDinamico con todos los elementos del conjunto.

k) Sobregargar los operadores relacionales binarios == y != para comparar dos conjuntos. Dos conjuntos seraniguales si tienen el mismo numero de elementos y los mismos valores (independientemente de su posicion).

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 288: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Problemas. 18

l) Sobreescribir el operador binario + para calcular la union de dos conjuntos. Respondera a las siguientessituaciones:

Si A y B son datos de tipo Conjunto, A+B sera otro dato de tipo Conjunto y contendra A ∪B

Si A es un dato de tipo Conjunto y a es un dato de tipo TipoBase, A+a sera un dato de tipo Conjunto

y contendra A ∪ {a}

Si A es un dato de tipo Conjunto y a es un dato de tipo TipoBase, a+A sera un dato de tipo Conjunto

y contendra {a} ∪A

m) Sobreescribir el operador binario - para calcular la diferencia de dos conjuntos. Respondera a las siguientessituaciones:

Si A y B son datos de tipo Conjunto, A-B sera otro dato de tipo Conjunto y contendra A−B, o sea, elresultado de quitar de A los elementos que estan en B.

Si A es un dato de tipo Conjunto y a es un dato de tipo TipoBase, A-a sera un dato de tipo Conjunto

y contendra A− {a}, o sea, el resultado de eleminar del conjunto A el elemento a.

n) Sobreescribir el operador binario * para calcular la interseccion de dos conjuntos. Respondera a las si-guientes situaciones:

Si A y B son datos de tipo Conjunto, A*B sera otro dato de tipo Conjunto y contendra A ∩B

Si A es un dato de tipo Conjunto y a es un dato de tipo TipoBase, A*a sera un dato de tipo Conjunto

y contendra A ∩ {a}

Si A es un dato de tipo Conjunto y a es un dato de tipo TipoBase, a*A sera un dato de tipo Conjunto

y contendra {a} ∩A

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 289: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.Relacion de Problemas V: Gestion de E/S. Ficheros (I)

1. Escribir un programa que lea una secuencia indefinida de caracteres de la entrada estandar (terminada por EOF)y los copie literalmente en la salida estandar.

2. Escribir un programa que lea una secuencia indefinida de caracteres de la entrada estandar (terminada por EOF)y los copie en la salida estandar, exceptuando las vocales.

3. Escribir un programa que lea una secuencia indefinida de caracteres de la entrada estandar (terminada por EOF)y muestre en la salida estandar el numero total de caracteres leidos.

4. Escribir un programa que lea una secuencia indefinida de caracteres de la entrada estandar (terminada por EOF)y muestre en la salida estandar el numero de lıneas no vacıas que hay en esa secuencia.

Nota: Se entendera que una lınea es vacıa si contiene unicamente el caracter ’\n’

5. Escribir un programa que lea una secuencia indefinida de caracteres de la entrada estandar (terminada por EOF)y copie en la salida estandar las lıneas que no comiencen por el caracter #

6. Escribir un programa que lea una serie indefinida de numeros enteros de la entrada estandar (terminada porEOF) y los copie, en el mismo orden, en la salida estandar.

En la secuencia de entrada se pueden usar espacios, tabuladores o saltos de lıneas (en cualquier numero ycombinacion) para separar dos numeros enteros consecutivos.

En la secuencia de salida se separan dos enteros consecutivos con un salto de lınea.

7. Escribir un programa que lea una serie indefinida de numeros enteros de la entrada estandar (terminada porEOF) y los copie, en orden inverso, en la salida estandar.

En la secuencia de entrada se pueden usar espacios, tabuladores o saltos de lıneas (en cualquier numero ycombinacion) para separar dos numeros enteros consecutivos.

En la secuencia de salida se separan dos enteros consecutivos con un salto de lınea.

Usar un objeto Pila para invertir la secuencia.

8. Escribir un programa que lea una serie indefinida de numeros enteros de la entrada estandar (terminada porEOF) y los copie, en el mismo orden, en la salida estandar.

En la secuencia de entrada, dos numeros consecutivos estan separados por el caracter *.

En la secuencia de salida se separan dos enteros consecutivos con un salto de lınea.

9. Escribir un programa que lea un fichero como los generados en los problemas 6, 7 y 8 y que muestre en la salidaestandar la suma de todos esos numeros.

10. Escribir un programa que lea una secuencia indefinida de caracteres de la entrada estandar (terminada por EOF)y reciba como argumento desde la lınea de ordenes un dato de tipo char. El programa mostrara en la salidaestandar el numero de caracteres leidos de la entrada estandar iguales al argumento suministrado.

Por ejemplo: cuenta_letra a < ElQuijote.txt mostrara el numero de caracteres a que hay en ElQuijote.txt

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 290: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.

11. Escribir un programa que lea una secuencia indefinida de caracteres de la entrada estandar (terminada por EOF)y reciba como argumento desde la lınea de ordenes un dato de tipo int.

El programa mostrara en la salida estandar el numero de palabras leidas de la entrada estandar cuya longitudsea igual al argumento suministrado.

Por ejemplo: cuenta_palabras 10 < ElQuijote.txtmostrara el numero de palabras que hay en ElQuijote.txtque tienen 10 caracteres.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 291: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Problemas. 21

Grado en Ingenierıa Informatica. Metodologıa de la Programacion.

Relacion de Problemas VI: Gestion de E/S. Ficheros (II)

1. Escribir un programa que reciba los nombres de dos ficheros de texto de la lınea de ordenes. El programa crearaun fichero (cuyo nombre se especifica en el segundo argumento) a partir de un fichero existente (cuyo nombre seespecifica en el primer argumento) copiando su contenido y anadiendo al principio de cada lınea, su numero.

2. Escribir un programa similar a diff para comparar dos ficheros de texto. El programa imprimira el numerode la primera lınea en la que difieren y el contenido de estas. Por ejemplo, la ejecucion de diff Fich1 Fich2

producira como resultado:

( 20) Fich1: en formato binario. Estos ficheros son especialmente adecuados para

Fich2: en formato binario. Estos ficheros, aunque no son legibles, son especialmente

si las 19 primeras lıneas de Fich1 y Fich2 son identicas, y la primera diferencia se encuentra en la lınea 20.

Nota: Este programa puede ser util para comprobar si despues de encriptar y desencriptar un fichero (proble-ma 4), obtenemos un fichero identico al original.

3. Escribir un programa que reciba como parametros tres nombres de ficheros de texto. Los dos primeros ficheroscontienen numeros reales y estan ordenados. El programa tomara los datos de esos ficheros y los ira copiandoordenadamente en el tercer fichero, de forma que al finalizar este tambien ordenado.

4. Escribir un programa que permita encriptar y desencriptar el contenido de un fichero de texto. Para encriptar

sustituiremos cada letra (mayusculas y minusculas) por la letra que esta p posiciones mas adelante en el alfa-beto (para las ultimas letras ciclamos el alfabeto). Los caracteres que no sean letras se quedaran igual. Paradesencriptar la sustitucion sera a la inversa. La llamada al programa se realizara con este esquema:

codifica <ficheroE> <ficheroS> <p> <tipo>

donde:

<ficheroE> y <ficheroS> son los nombres de los ficheros de entrada y salida, respectivamente

<p> es el numero entero positivo que se aplica para codificar/descodificar cada uno de los caracteres.

<tipo> es una cadena de caracteres que puede valer: enc para encriptar y desenc para desencriptar.

5. Un fichero de texto contiene numeros enteros que se disponen en lıneas y en cada lınea estan separados porespacios en blanco. Todas las lıneas tienen el mismo numero de elementos.

Se trata de escribir un constructor para las clases Matriz2D_1 y Matriz2D_2 que reciba el nombre de un ficherocon la estructura descrita y rellene las casillas de la matriz con los datos contenidos en el fichero. Se sobreentiendeque los datos estan guardados por filas en el fichero.

Las restricciones que se imponen, y que se deben cumplir en la resolucion son:

a) El fichero solo puede ser leıdo una unica vez, y no pueden copiarse completo en memoria.

b) Se desconoce a priori el numero de lıneas del fichero.

c) Las lıneas del fichero tiene una longitud indeterminada, aunque nunca mayor de 500.

d) El numero de datos de cada lınea es indeterminado, aunque este es comun para todas las lıneas.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 292: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Problemas. 22

e) No puede emplearse una matriz con un numero de filas “tentativo” sino que la matriz ocupara en cadamomento el espacio estrictamente necesario y los datos se copiaran conforme se lean cada una de las filas.

El numero de lıneas de datos del fichero debe coincidir con el numero de filas de la matriz, y el numero de

elementos de cada fila con el numero de columnas.

Nota: Es posible que sea necesario anadir un nuevo metodo a las clases Matriz2D_1 y Matriz2D_2 que permitaredimensionar la matriz, anadiendo una nueva fila.

6. Se dispone de ficheros de texto que contienen un numero indeterminado de lıneas, cada una de ellas con los datoscorrespondientes a una serie de grupos de valores reales.

Por ejemplo, una lınea de entrada podrıa ser la siguiente:

3 2 3.1 0.4 5 1.0 1.0 1.0 1.0 1.0 2 5.2 4.7

donde puede observar que se distinguen tres grupos de datos (indicado por el primer numero de la lınea) y cadagrupo empieza por un valor entero (2, 5 y 2) seguido por tantos valores reales como indique el valor entero queencabeza cada grupo:

3 2 3.1 0.4 5 1.0 1.0 1.0 1.0 1.0 2 5.2 4.7

Escribir un programa que escriba en la salida estandar una lınea de resultado por cada lınea de entrada, y encada lınea mostrara las sumas de los valores de cada grupo que la componen.

Por ejemplo, en el caso anterior, deberıa escribir:

3.5 5.0 9.9

El programa se ejecutara desde la lınea de ordenes y permitira:

a) Llamarlo sin ningun argumento. En este caso, los datos de entrada se leeran desde la entrada estandar.

b) Llamarlo con un argumento. El argumento corresponde al nombre del archivo con las lıneas de entrada.

Las restricciones que se imponen, y que se deben cumplir en la resolucion son:

a) El fichero solo puede ser leıdo una unica vez, y no pueden copiarse completo en memoria.

b) Se desconoce a priori el numero de lıneas del fichero.

c) Las lıneas del fichero tiene una longitud indeterminada, aunque nunca mayor de 500.

7. Escriba dos programas para transformar ficheros con datos correspondientes a una serie de grupos de valoresreales (como estan descritos en el problema 6), para transformar entre formato binario y texto:

a) Un programa que transforme un fichero de texto a binario:

text2bin <FichText> <FichBin>

b) Un programa que transforme un fichero de binario a texto:

bin2text <FichBin> <FichText>

Debe optimizarse el uso de los recursos, y por tanto, se aplican las restricciones enumeradas en el problema 6.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 293: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Problemas. 23

8. Escribir un programa que reciba el nombre de dos ficheros. El programa copiara, en el mismo orden, los numerosque contiene el fichero de entrada en el fichero de salida.

El primer fichero (entrada) contiene una serie indefinida de numeros enteros:

• Es un fichero de texto.

• Se pueden usar espacios, tabuladores o saltos de lıneas (en cualquier numero y combinacion) paraseparar dos numeros enteros consecutivos.

El segundo fichero (salida) es un fichero binario.

El programa leera los numeros y los copiara de uno en uno.

9. Escribir un programa con las mismas caracterısticas que las descritas en el problema 8 pero que escriba en elfichero de salida bloques de 512 bytes.

10. Escribir un programa que lea un fichero binario como los generados en los problemas 8 y 9 y que muestre en lasalida estandar la suma de todos esos numeros. Para la lectura se empleara un buffer de 512 bytes.

11. Construir un programa que divida un fichero de texto en diferentes ficheros indicando como argumentos el nombredel fichero original y el maximo numero de lıneas que contendra cada fichero resultante.

Se creara un fichero de control que contendra con los datos necesario para la reconstruccion del fichero original.

Por ejemplo, si Fichero contiene 1600 lıneas, la ejecucion de parte_lineas Fichero 500 genera como resultadolos ficheros Fichero_1, Fichero_2, Fichero_3 y Fichero_4. Los tres primeros contienen 500 lıneas de Ficheroy el ultimo, las 100 restantes. Se creara un fichero oculto llamado .Fichero.ctrl que contendra (formato texto,en dos lıneas separadas): nombre del fichero original y numero de ficheros resultantes de la particion.

Nota: Utilizad cadenas para construir los nombres de los ficheros resultantes.

12. Construir un programa que divida un fichero de cualquier tipo en diferentes ficheros, indicando como argumentosel nombre del fichero original y el maximo numero de bytes que contendra cada fichero resultante.

Por ejemplo, si el tamano de Fichero es 1800 bytes, la ejecucion de parte_bytes Fichero 500 genera comoresultado los ficheros Fichero_1, Fichero_2, Fichero_3 y Fichero_4. Los tres primeros contienen 500 bytesde Fichero y el ultimo, los 300 restantes. Se creara un fichero oculto llamado .Fichero.ctrl que contendra(formato texto, en dos lıneas separadas): nombre del fichero original y numero de ficheros resultantes de laparticion.

Nota: Utilizad cadenas para construir los nombres de los ficheros resultantes.

13. Construir un programa que reconstruya un fichero a partir de una serie de ficheros que contienen sus “partes”.Los ficheros que pueden emplearse como origen se han creado con los programas descritos en los problemas 11y 12 y por ese motivo se emplara el fichero de control creado por esos programas.

Por ejemplo, la ejecucion de reconstruye Fichero genera como resultado Fichero. Usara .Fichero.ctrl paraconocer los ficheros que debe usar y el orden en que se debe hacer la reconstruccion.

Nota: Utilizad cadenas para construir los nombres de los ficheros que intervienen.

14. Repetir los problemas 11, 12 y 13 usando la clase stringstream para componer los nombres de los ficheros.

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 294: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Problemas. 24

15. Escribir un programa similar a grep que busque una cadena en una serie de ficheros de texto. La cadena a buscary los ficheros en los que buscar se proporcionan en la lınea de ordenes. Por ejemplo:

busca Olga fich1 fich2 fich3

busca la cadena Olga en los ficheros fich1, fich2 y fich3.

Cada vez que encuentre la cadena buscada, debe indicar el fichero en el que es localizada, el numero de lınea yla lınea completa que la contiene. Un ejemplo de salida de este programa es:

fich1 (lınea 33): Mi amiga Olga ha aprobado MP aunque no se

fich3 (lınea 2): ya se lo dije ayer a Pepe, pero ni caso

fich3 (lınea 242): finalmente, Olga se puso a estudiar

Las restricciones que se imponen, y que se deben cumplir en la resolucion son:

a) El numero de ficheros que se pueden proporcionar es ilimitado.

b) Cada uno de los ficheros solo puede ser leıdo una unica vez, y no pueden copiarse completos en memoria.

c) Se desconoce a priori el numero de lıneas de los ficheros.

d) Las lıneas de los ficheros tienen una longitud indeterminada, aunque nunca mayor de 500.

16. Implementar un programa que similar a head que muestre las primeras lıneas de un fichero de texto.

Por ejemplo, la ejecucion de cabecera 15 reconstruye.cpp mostrara las primeras 15 lıneas del fichero detexto reconstruye.cpp

Se aplican las mismas restricciones que las indicadas en el problema 15(excepto la primera, evidentemente).

17. Implementar un programa que similar a tail que muestre las ultimas lıneas de un fichero de texto.

Por ejemplo, la ejecucion de final 15 reconstruye.cpp mostrara las ultimas 15 lıneas del fichero de textoreconstruye.cpp

Se aplican las mismas restricciones que las indicadas en el problema 15 (excepto la primera, evidentemente).

18. Una empresa de distribucion mantiene la informacion acerca de sus vendedores, productos y ventas en ficherosinformaticos. Los ficheros almacenan la informacion en formato binario y la estructura de los registros es:

Fichero Vendedores:

RegVendedor : CodVendedor (unsigned char), Nombre (50*char) y CodZona (unsigned char).

Fichero Articulos:

RegArticulo : CodArticulo (10*char), Descripcion (30*char) y PVP (float).

Fichero Ventas:

RegVenta : NumFactura (int), CodVendedor (unsigned char), CodArticulo (10*char) y Unidades (int).

Se supone que el fichero Ventas contiene las ventas realizadas en un mes.

Se trata de realizar programas para:

a) Mostrar el total (numero de ventas y cantidad total de ventas) de las ventas realizadas por un vendedor,dado su codigo (CodVendedor).

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 295: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Problemas. 25

b) Pedir una cantidad y crear un fichero (binario) llamado VendedoresVIP cuyos registros tengan la siguienteestructura:

RegVendedorVIP : CodVendedor (unsigned char), CodZona (unsigned char), TotalVentas (float).

donde TotalVentas es la cantidad total de ventas realizadas por el vendedor.

El fichero VendedoresVIP tendra unicamente los registros de los vendedores cuyo total de ventas sea superiora la cantidad leıda.

19. Algunos ficheros se identifican mediante una“cabecera”especial, como los archivos PGM que tienen en la posicioncero los caracteres P5. Este tipo de ficheros, y las marcas que los identifican son los que se gestionaran en esteproblema.

Un fichero de descripciones es un fichero binario que almacena las distintas marcas que identifican a tipos deficheros, ası como informacion acerca de donde se ubican en los archivos.

Los registros del fichero Descripciones tienen longitud variable y su formato es el siguiente:

RegDescripcion : PosInicioMarca (int), LongMarca (int), Marca (LongMarca*char) y Comentario (100*char)

Un ejemplo (en forma tabular) de los contenidos de este archivo podrıa ser:

0 2 P5 Imagen PGM0 2 P6 Imagen PPM10 8 DAT CIEN Datos Cientıficos

Donde podemos ver que si un archivo tiene la cadena “DAT CIEN” (8 caracteres) a partir de la posicion 10 delarchivo, se trata de un archivo de tipo “Datos Cientıficos”.

Las tareas a realizar son:

a) Escribir una funcion (Insertar) para anadir descripciones.

La funcion recibira el nombre de un archivo de descripciones junto con una nueva entrada (un dato de tipoRegDescripcion) y anadira esa entrada a dicho archivo (creandolo si es necesario).

b) Implementar una funcion (TipoArchivo) que determine el tipo de un fichero.

La funcion recibira el nombre del fichero del que queremos averiguar si tipo junto con el nombre delarchivo de descripciones. Como resultado devuelve una cadena con el comentario asociado, o la cadena Tipo

desconocido si no se ha localizado su tipo.

c) Escribir un programa que, usando la funcion del apartado anterior, reciba de la lınea de ordenes el nombrede un archivo y escriba en la salida estandar la descripcion (comentario) asociado a su tipo. Tenga en cuentalos posibles casos de error.

20. Hacer un programa que permita formar el nombre de un fichero de la forma: salidaXXX.Z.dat a partir de dosnumeros que recibe de la lınea de ordenes:

XXX es un numero de 3 dıgitos (se rellena con ceros a la izquierda si es necesario), y

Z es un numero con cualquier cantidad de dıgitos.

A continuacion se presentan varios ejemplos de ejecucion (nuestro programa se llamara componer):

componer 45 6 generarıa el nombre de fichero salida.045.6.dat

componer 5 67 generarıa el nombre de fichero salida.005.67.dat

Nota: usar la clase stringstream

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 296: Metodología de la Programación

Grado en Ingenierıa Informatica. Metodologıa de la Programacion. Problemas. 26

.Depto. de Ciencias de la Computacion e I.A. Universidad de Granada. Curso 2011-2012

Page 297: Metodología de la Programación

EXAMENES

Curso: 2011/2012 Clase: Primero - Grupo: B

Page 298: Metodología de la Programación

Metodologıa de la Programacion IIExamen de teorıa. 29 Junio 2006.

1. Considere una clase Imagen, de f filas por c columnas, que se representa como sigue:Donde puede observar que la estructura de datos

20 1 c−1

20 1 c−1

20 1 c−1

0

1

f−1

Imagconsiste en una lista de f celdas enlazadas en lasque se almacenan vectores de c elementos (valoresde 0 a 255) para cada una de las filas. Donde f esel numero de filas y c el numero de columnas.Existe una celda por cada fila, de forma que todala estructura cuelga de un unico puntero (Imag),que podrıa ser cero en caso de que la imageneste vacıa.La ultima celda contiene un cero en el campo quecorresponde al puntero siguiente.

a) (0.75 punto) Implemente el constructor por defecto (crea una imagen vacıa) y el destructor.b) (0.75 punto) Implemente el constructor de copias.c) (1 punto) Sobrecargue el operador de asignacion.d) (1 punto) Implemente dos funciones Set y Get que permitan modificar y acceder al contenido de una

posicion de la imagen, respectivamente. Las cabeceras deben ser:

void Imagen::Set(int f, int c, unsigned char dato);unsigned char Imagen::Get(int f, int c) const;

e) (1 punto) Sobrecargue los operadores == y != para poder comprobar la igualdad de dos imagenes.

2. (2 puntos) Considere la parte publica de la clase Imagen, en la que se incluyen las funciones Set y Get. Supongaque disponemos de una imagen en la que unicamente hay puntos con valores 0 y 255. En esa imagen, existe unaregion vacıa (valores 0) rodeada de valores 255. Escriba una funcion recursiva para que, a partir de una posicioncualquiera situada dentro de dicha region vacıa, rellene todas las posiciones de dicha region con el valor 128.En la siguiente figura se puede ver un ejemplo con una imagen inicial en la que hay una region vacıa delimitadapor puntos con valor 255. En la parte derecha vemos el resultado que debe producir el algoritmo.

= 255

= 128

= 0

= punto departida

Situación inicial Situación final

3. (2 puntos) Se dispone de ficheros de texto que contienen un numero indeterminado de lıneas, cada una de ellascon los datos correspondientes a una serie de valores reales. Un ejemplo es el siguiente:

3 3.1 0.0 2.15 1.0 1.0 1.0 1.0 1.02 5.2 4.7

donde puede observar que cada lınea contiene un valor entero seguido por tantos elementos como indique este.Escriba un programa que obtenga en la salida estandar los valores que corresponden a la sumatoria de cada fila.Por ejemplo, en el caso anterior, debera obtener los valores 5.2, 5 y 9.9. La forma de lanzar el programa desdela lınea de ordenes debe permitir:

a) Llamarlo sin ningun argumento. Los datos con las sumas a realizar se leeran desde la entrada estandar.b) Llamarlo con un argumento. El argumento corresponde al nombre del archivo con los datos a sumar.

4. Escriba dos programas para transformar ficheros con datos de sumatorias (pregunta anterior), para transformarentre formato binario y texto:

a) (0.75 punto) Un programa que transforme un fichero de texto a binario.b) (0.75 punto) Un programa que transforme un fichero de binario a texto.

Para ello, los programas recibiran, en la lınea de ordenes, dos argumentos con los nombres del fichero de entraday salida respectivamente. Tenga en cuenta que un fichero en formato binario contiene todos los datos de formaconsecutiva de la siguiente forma.

<n1(int)><dato_1(float)>...<dato_n1(float)><n2(int)><dato_1(float)>...<dato_n2(float)>...

Finalmente, no olvide que debe optimizar el uso de recursos, y por tanto, no se permiten soluciones en las quese tenga, por ejemplo, todo el fichero en memoria.

Duracion del examen: 3 horas.

Page 299: Metodología de la Programación

Metodologıa de la Programacion IIExamen de teorıa. Septiembre 2006.

1. (2 puntos) Escriba una funcion recursiva que obtenga el numero de repeticiones de cada vocal (5 valores enteros)en una cadena de caracteres.

2. (2 puntos) Considere la siguiente clase:

class Entero {int *v;

public:Entero (int i=0) { v= new int; *v=i; }~Entero () { delete v; }int Set(int i) { *v= i; }int Get() const { return *v; }

};

Realice las modificaciones que crea convenientes sobre la clase Entero para que el siguiente codigo funcionecorrectamente, describiendo brevemente la razon de dichos cambios.

Entero Doble(Entero e){ return e.Get()*2; }

int main(){ Entero x(5), y;y= Doble(x);cout << "Resultado: " << y << endl;

}

3. Se desea crear una clase Menu para simplificar el desarrollo de programas que usan menus en modo texto. Paraello, se propone la siguiente representacion:

class Menu {char *titulo; // Encabezado que damos al menu (0 si no existe)char **opc; // Cadenas que describen cada una de las opcionesint nopc; // Numero de opciones actualmente en el menu

public:...

};

a) (1.5 puntos) Escriba la implementacion de las funciones miembro correspondientes al constructor pordefecto (crea un menu vacıo), destructor, constructor de copias y operador de asignacion.

b) (1.25 puntos) Escriba tres funciones:SetTitulo que asigne un nuevo valor al tıtulo.GetNumeroOpciones que devuelva el numero de opciones que hay actualmente en el menu.AddOpcion que reciba una cadena de caracteres y la anada como una nueva opcion despues de la ultima.

c) (1 puntos) Sobrecargue los operadores << y >> para poder usar el menu para seleccionar una de lasopciones. Concretamente:

Sobrecargue el operador << para que podamos imprimir el menu. Un ejemplo de llamada podrıa sercout<<menu, que imprime en la salida estandar el tıtulo del menu seguido por cada una de las opciones(numerandolas, del 1 al numero de opciones, en lıneas distintas).Sobrecargue el operador >> para que podamos escoger una nueva opcion. La sintaxis de llamadasera menu>>entero, y provoca la solicitud de una opcion (como un numero del 1 al numero de op-ciones desde la entrada estandar) de entre las que incluye el menu.

d) (0.25 puntos) Complete el entorno Class, que hemos presentado en la pregunta, con la parte publicacorrespondiente.

4. (2 puntos) Escriba un programa alreves que recibe en la lınea de ordenes el nombre de un fichero, y escribe enla salida estandar el mismo flujo de caracteres, pero en orden inverso. Por ejemplo, si el archivo abecedario.txtcontiene los caracteres:

abcdefghijklmn~nopqrstuvwxyz

una posible ejecucion del programa obtendrıa lo que sigue:

% alreves abecedario.txtzyxwvutsrqpo~nnmlkjihgfedcba

El programa debe optimizar el uso de la memoria, y dado que el tamano del archivo puede ser muy grande, nose permite cargar todo el archivo de entrada.

Duracion del examen: 2 horas y 30 minutos.

Page 300: Metodología de la Programación

�������������� ����������������� ���������������� ���

!#"�$&%'"(!#%')+*#,-%'".!#"(/�01)+2�3546!879,%;:=<�>@?BADCE?(F8?BGIHKJL<�M6NIOPCE?&Q=REAESLGTCE?�NIU=V�U

WYX[Z N]\^REA_F8Ga`Kb�cedgf�h ijdgijkmlni5o�kIp9qro�k�s#t uYk&vni8s#o�vxwyt z{p|fIp{vxp~}�t ��o{�ep{v8��ijk�}��mw�}�t dgijkIwyt �Yk�i8wj�Bijh_qrvxpYsxl�p{h_s#�Yk���s#t�}��~s#�Ydg�|�ei8wyf_�Yk{��p}�i|�(ijk��Yijvy� X�� pgp{fIp{vnt ijkIs#t�p~}�i6}�t�sn����}�t ��o{���1h�pgfa��}�ijdg�mw�zYijv�ijk&i8w�lxp9�I�Yo�vxp��

��h�f�vn�{ln�{lnt fa�g}�i|h�p9qro�kIs#t uYk�vni8s#o�vxwyt z{p9}�ij�ai6wyijv�ijh�wyt �Yo�t ijkYlniY����I�K���B�����K�����m�{�� {¡B¢� Y��£n�B�{¤B¥I�m §¦�¨(���{¤B¥a�Y D©�¨����{¤B¥_�Y §���Kª�«wyt ijkI}�� £y¦�¨�©_« h�pYw�s#���Yvx}�ijk�pY}�pYw�}�i5h�p~i8wn¬mo�t kIpgwyo�f_ijvnt �Yv�t ­8¬mo�t ijvx}�p9® ���Kª ijh�p{kIsn���1}�ijh�s#oIpY}�vxpY}�� X¯�°a±n²_³�´�µ8¶Y·#¸1µº¹�¹�»º´�µK¼_·#½¿¾#»I·P¶KÀ�¹�´�µK¼_·#¸1µº¹P¶Y·¿Á Â�Ãn»�¼_Ä#ÀLÅK¼ÇÆ=ÈBɺÊ�Ë�ÌBͺÊaÌmÎ{Ï�ÌBÎmÐEÑ�ÒaÓ�Ô#Õ_Ó�ÔmÖYÌ#×_Ø^Ùg¾#»I·P¶KÀLÚ#»#Û#§»�¼�Ä#»IÂY¶K½nÂY¶Yµ½n·#ÁÜÁ ·#¼_µ+¶Y·gÄnµKÁ µK½6¼_·�Ý{½nµºÙÞÄ#»�ßYÂ&·�¹j¾#»�Àܼ_Âg¹�»º´�·#½�ÀLµK½6À à8¾#»�ÀL·#½n¶YÂ�á8ÀL·#¼_·~¶YÂY¶YÂ6´�µK½|Á Â+Äxµ8µK½n¶Y·#¼_ÂY¶YÂ�Ñ�Ò_Ó�ÔjÕ_Ó{Øâß+Ä#»�ßYµ+ÂK¼_Äxã�µ&·�¹IÖYÌj×'ä

å�XæZ�ç MÜè]\^REA_F8Ga`Kb;é'pY}�pYw�h�pYw�wyt �Yo�t ijkmlni8w�s#h�pYwyi8wj�

ê8ë8ì{íºí]î{ì8ïºðYñ#ò@óñ�ôKï¿ôKõ�ö9ômêI÷1øºø(ùºú8ûYü8ð{ý¿þKü¿õYñ8ë8ì{í]ÿ@ê8ýºë��8ûKô{ì{í�ºômíºñ��8ô{ü8þ§ê��{ì8ð����xû�÷����YëKñºê�������� ÷

ê8ë8ì{íºí��xûYì��Küjô óî{ì8ïºðYñ#ò ñxû�÷����YëKñºê�������� ÷

ê8ë8ì{íºí��mñ#þKüKýPóñ�ôKï¿ô=÷1øºø(ùºú8ûYü8ð{ý¿þKüTñxû����Küjô{ü{í�xûYì��Küjô�����÷����YëKñºê������ ÷� p�� Z VaMÜè@\^REA�F8Ga`Kb6cedgf�h ijdgijkYlni1ijh�s#�YkIw�lnvnoIs�ln�Yv5fa�Yv|}�i#qri8s�ln�I�=ijh�s#�YkIw�lnvnoIs�ln�Yv|}�i1s#�Yf�t�p���ijh��Yf_ijvxpY}��Yv'}�i�pYwyt �YkIpYs#t u{k�®]ijh}�i8w�lnvnoIs�ln�Yv�fIp{vxp9h�pgs#h�pYwyi ���Y�B�_��� X

� ��� Z U=MÜè&\^REA_F8G�b��j��w�k�i8s#i8wnp{vnt �|t dgf�h ijdgijkYlxp{vÞijhI�YfaijvxpY}��Yv�}�i;pYwyt �YkIpYs#t uYkgfIp{vxp5h�p6s#h�pYwyi�� ªa�m¢� K¡! #" p{­j�Yk�ih�p|vni8wyf�o�i8w�lxp X� s�� Z V(\^REA�F8Ga`Kbcedgf�h ijdgijkYlni6ijh��Yf_ijvxpY}��Yv�}�i6pYwyt �YkIpYs#t u{k+®+ijh=s#�YkIw�lnvnoIs�ln�Yv�}�i6s#�Yf�t�p~fIp{vxp9h�pgs#h�pYwyi%$ �K�� B� X� }!� Z U=MÜè§\^REA_F8G�b'&Bo�f_�Yk��mp�¬mo�i1h�p(s#h�pYwyi'$ �K�� B� k��]}�t�wyfa�Yk�i�}�i1o�k@s#�YkIw�lnvnoIsxlx�Yv|}�i�s#�Yf�t�p�t dgf�h ijdgijkYlxpY}�� X ��wns#vnt �Ip&o�kiy�eijdgf�h � � s#u�}�t �Y�9ijk)(+*,*-��ijk+ijh_¬mo�i;i8w�lxp9wyt lnoIpYs#t uYk�h h ijz{p{v/.�p|p6o�k+ijvnvn�Yv�ijk1lnt ijdgfa�g}�i'iy�eijs#oIs#t uYk+®gvxp{­j�Yk�iijh_dg�{lnt z{�}�i6}�t�sx���gijvnvn�Yv X

� i�� Z V&\^REA�F8G�b0&B�Y��vnijsjp{vn�Yo�iijh_�YfaijvxpY}��Yv��/*�fIp{vxp|h�p~s#h�pYwyi0$ �K�� B� X ��w�lni5�YfaijvxpY}��YvÞs#vni8p|o�k&kmo�ijzY�9z�t�}�i#�gp6fIp{vylnt v�}�i'o�kzBt�}�ij�g®+o�kIp~t d1p{�Yijk=��p21IpY}�t ijkI}��gh�p~t d1p{�Yijk�p{h_�IkIp{h�}�i|}�t�sx���gzBt�}�ij� X3�X,46587 9;:=<?>8@BADCFE (��YkIwyt�}�ijvniÞijhBlnt fa� ���Y���_��� }�i�h�p'f�vnij�Yo�kmlxp'p{kmlnijvnt �Yv X é;i8wyi8p{dg�mw^p21IpY}�t v�p{h�dgu�}�o�h��;qro�kIs#t �YkIp{h t�}�pY}9fIp{vxp;fa��}�ijvi8wns#vnt ��t v�ijk&�asn��ijvn�mw�®�h ijijv}�i8wn}�i5�asn��ijvn�mw�}�pKln�mw�}�i5i8w�lni5lnt fa� X�� p~i8wyfai8s#t �asjpYs#t uYk�}�i|}�t�sx���~�asx��ijvn�gi8w�h�pgwyt �Yo�t ijkmlniY�

� p��#G�t ijk�i5qr�Yvnd1pKln�~��t kIp{vnt � X� ���+��hEs#�YkYlnijk�t�}��1}�ijh��asx��ijvn�gi8w�ijh=wyt �Yo�t ijkmlniY�

t X é;�mw�ijkmlnijvn�mw�¬mo�i|t kI}�t�sjp{k&ijh=k�H�dgijvn��}Bi5�Ih�pYw�®&}�i|s#�Yh o�dgkIpYw�}�i|h�p~d1pKlnvnt ­ Xt t X�I s#�YkYlnt kBoIpYs#t uYk&zBt ijk�ijk+ln��}��mwÞh �mw�ijh ijdgijkmln�mw�}�i|h�p~d1pKlnvnt ­ X

cedgf�h ijdgijkYlni6h�pYwÞqro�kIs#t �Yk�i8w�dgt ijd9��vn�9� � ijijvy�;®g�e��wns#vnt ��t vy�'fIp{vxp9h�p~h i8s�lno�vxp~®+i8wns#vnt lno�vxp~}�i5o�kIp ���Y�B�_��� ijk�o�k+�asx��ijvn� XJ X6Z N@\^REA�F8Ga`KbLKkIp�p{f�h t�sjpYs#t uYk�t k�qr�YvndNMKlnt�sjp+ijk¿o�kIp&ijdgf�vnijwnp&}�i~lnvxp{kIwyf_�Yvylni8w;o�lnt h t ­8p&o�kIp+�IpYwyi1}�i1}�pKln�mw'ijk¿h�p&¬mo�iY�=ijkmlnvni�{lnvn�mwj�mlnt ijk�i|h �mw�wyt �Yo�t ijkmlni8wÞ�asn��ijvn�mwj��Y�{¡��Y¤_�º���{�� DO �0&Bi9lnvxpKlxp&}�i~o�k]�asx��ijvn�&}�igF8?m:�F8G¿ijk�ijh�¬mo�i~ijkPsjpY}�p�h . k�i8p&wyi~�YoIp{vx}�p1t k�qr�Yvnd1pYs#t uYk�wy�Y��vni9o�kPs#�YkI}�oIsxlx�Yv8�¬mo�i|wyi|ijk�s#o�ijkmlnvxp~ijk�i8w�lni5�Yvx}�ijk=�

(�u�}�t �Y�g}�i6s#�YkI}�oIs�ln�Yv � ijkmlnijvn�8�• P i8sx�Ipg}�i6p{h lxp~ijk�h�p~ijdgf�vni8wnp � sjpY}�ijkIpg}�iLQgsjp{vxpYs�lnijvni8wj�Bi#k�ijh�qr�Yvnd1pKln�g}�}�Rºdgd#RKpYp��• S �Yd9��vni5®&p{faijh h t�}��mw � sjpY}�ijkIpg}�i|sjp{vxpYs�lnijvni8w�}�i5h �Yk��Yt lnoI}�p{vn��t lnvxp{vytÜp��B�IpYw�lxp~ijh_�IkIp{h�}�i5h�pgh . k�i8p��

Page 301: Metodología de la Programación

OY Y�B�_�m�B�{�DODT#ªBªUTK�B� �V&Bi'lnvxpKlxp~}�i5o�k&�asn��ijvn�XW^SLAE<�HKSLG�ijk&ijh=¬mo�i|wyi5�YoIp{vx}�p6h�p~t k�qr�Yvnd1pYs#t uYk&}�i5h �mw�wyijvnzBt�s#t �mw�vni8p{h t ­8pY}��mw�fa�Yvh �mw;s#�YkI}�oIs�ln�Yvni8w;sjpY}�p1dgi8w �ZY X i X h �mw'wyijvnzBt�s#t �mw}�i~i8w�lni9dgi8w'wyi9�YoIp{vx}�p{k�ijk�ijh��asn��ijvn��[=?mH�\=S^]YSLGa`�_�U�`D_8V�U�� X (ÞpY}�p�wyijvnzBt�s#t �i8w�o�k��Yvno�fa�~qr�Yvnd1pY}�p9fa�Yv�h �mw�wyt �Yo�t ijkmlni8w�}�pKln�mwj��}�t�wyf�o�i8w�ln�mw�ijk&i8w�lni|�Yvx}�ijk=�

• S o�d X }�i|vnoBl�p � ijkYlnijvn�8�•

(�u�}�t �Y�g}�i6s#�YkI}�oIs�ln�Yv � ijkmlnijvn�8�• P i8sx�Ipgwnp{h t�}�p �^a sjp{vxpYs�lnijvni8wj��¬mo�i|s#�Yvnvni8wyf_�{kI}�ijk&p~h �mw�}D. �Yt ln�mw�}�i|h�p9qri8sx�Ipg}�}�Rºdgd#RKpYp��•

� �Yk��Yt lnoI}�}�i5h�p~vno�lxp���ijkcbBt h uYdgi#lnvn�mw �ed �mpKl��� p9ijdgf�vni8wnp6i8w�lBM~t kYlnijvni8wnpY}�p9ijk&�Y��lnijk�ijv�o�k&f�vn�Y�YvxpKd1p9}�i|s#�YkIwyo�h lxp9¬Bo�i5vni8s#t �Ip~s#�Ydg�gp{vn�Yo�dgijkYln�mw�}Bi5h�p~h . k�i8p~}�i5uYvx}�ijk�i8wh �mw^k��Yd9��vni8w�}�i�h �mwE�asx��ijvn�mw^®6ijhIs#u�}�t �Y�5}�i�o�k1s#�YkI}�oIs�ln�Yv�®~sjp{h�s#o�h i�®9d9o�i8w�lnvni�ijhEÄnÅ8¶KÀ Ýmµ1¶Y·'ÄxµK¼_¶K»IÄ�feµK½��a¼_µK¸1Ú#½n·ß~Âx´�·#ÁÜÁ ÀL¶YµK¹®�h �mw0gKÀÜÁ ÅK¸1·�f ½nµº¹Lfeµ�feÂKÁ ·�¹9¾#»I·6½y·xÂKÁ À à8Â&·�¹j·~ÄxµK¼_¶K»IÄ�feµK½ X��h=f�vn�Y�Yvxp{d1p9wyi5iy�ei8s#o�lxp{vBM���fa�Yv�iy�eijdgf�h �I�h �8¡ji�� �Y�{¡��Y¤_�º���{�� DOkOY Y�B�_�m�B�{�DODT�l8m!TDn�lon�p8qn�p8qD���{¡B¤I ��sr��{¡��jt{¡ku� 2vI�wq8x8l�y�¨/mszYªGEp{d9��t {jk�i8w�lBMTt kYlnijvni8wnpY}�pTi#kâ�{lnvn�Tf�vn�Y�Yvxp{d1pP¬mo�i]f�vn��}�o�­8sjpTs#�Ydg�@wnp{h t�}�pTo�kâh t�w�lxpY}��@s#�Ydgf�h i#ln�@ijkâijh'¬mo�i]fIp{vxp@s#pY}�ps#�YkI}�oIs�ln�Yv5wyigd9o�i8w�lnvni~o�k¿vni8wyo�dgijk¿}�igh �mw5wyijvnzBt�s#t �mw;vni8p{h t ­8pY}��mw;fa�Yv-{jh X ��w�lxp+t k�qr�Yvnd1pYs#t uYk¿wyig�Yo�p{vx}�p{vBM���pY}�ijdNMYwj�_ijk¿o�k�asn��ijvn�9}�i;F8?m:�F8G&}�ik��Yd9��vni �� jOº¤a�{���Y��� s#�Yk1ijh_wyt �Yo�t ijkmlni�qr�Yvnd1pKln�9}�ih . k�i8p��ÄnÅ8¶KÀ Ýmµ�¶Y·6ÄxµK¼_¶K»IÄ�feµK½��jgKÀÜÁ ÅK¸1·�f ½nµº¹|feµ�feÂKÁ ·�¹|¾#»I·½n·nÂKÁ À à8Â�·�¹j·~ÄnµK¼_¶K»IÄ�feµK½��=¼!}�¸�·#½yµ+¶Y·6á8ÀLÂ�Û#·�¹6½n·xÂKÁ À à8ÂY¶Yµº¹9®]¼_µK¸1Ú#½n·6ß+Âx´�·#ÁÜÁ ÀL¶YµK¹ X��h=f�vn�Y�Yvxp{d1p9wyi5iy�ei8s#o�lxp{vBM���fa�Yv�iy�eijdgf�h �I�h ����OK��� �Y�{¡��Y¤_�K���Y�� jO~OY Y�B�_�m���K�jO8T2l8mjTjn�ln�p8qkq8x8l�y�¨/mszYª�n�p8xD���{¡B¤a B�sr��{¡��jtK¡ku� �vI�l?n�mkq?n�l8p�¨/�szYª �8���K¤I�{¡��m¡����{¡��{�k���jª��{¡I ��~�B¢m¤��Y�Y Y���n8n���n��8��¨/p�zYª n��~�Y¤���Om�§�m¤I {¡��� DO��� Y¡I jOº�B���DOY�"(GIF8<=� ��kTh �mw|}��mw|f�vn�Y�YvxpKd1pYw'i8w�lBM&i���f�vni8wnp{dgijkmlnigf�vn�Y��t ��t�}���ijdgf�h i8p{v|i8w�lnvnoIs�lno�vxpYw|}�i�}�pKln�mw6pYwy��s#t�pY}�pYw5p�s#�Yh i8sjs#t �Yk�i8w� zYijs�ln�Yvni8wj��d1pKlnvnt�s#i8wj��h t�w�lxpYwj� XjXjX �9fIp{vxp~�Yo�p{vx}�p{v�ijk�dgijdg�Yvnt�p~h �mw�}�pKln�mw�h ijt�}��mw�}�i|h �mwÞ�asx��ijvn�mw XVI }�ijdNMYwj��}�ij�_i5dgt k�t dgt ­8p{vxwyiijh�k8H�dgijvn�1}�i6pYsjs#i8wy�mw�p~h �mwÞ�asn��ijvn�mw X

�&R�HK<j]YS^�aA�CE?8�Þ?m:=<�>@?BA��6N��EGIHK<�`YM

Page 302: Metodología de la Programación

Metodologıa de la Programacion II

I. Informatica - I.T.I. Sistemas - I.T.I Gestion. Septiembre de 2011.

El tiempo para realizar el examen es de 2:30 horas

1. Considere que tenemos almacenada una secuencia ordenada de numeros enteros en una lista de celdas enlazadasdefinidas con la siguiente estructura:

struct Celda {int dato; // Dato en la celda actualCelda *sig; // Puntero al siguiente elemento de la lista};

a) (1 punto) Defina una funcion que recibe un entero y una lista y modifica dicha lista ordenada insertando elentero en la posicion correspondiente.

b) (1 punto) Defina una funcion que recibe un entero y una lista y modifica dicha lista eliminando la primeraaparicion de ese entero en la lista.

Nota: tenga en cuenta que en ambas funciones se puede dar el caso de que la lista que se pasa este vacıa.

2. Se define una matriz bilineal simetrica como una matriz de n × n enteros en la que todos los elementossignificativos (distintos de un valor por defecto) estan situados en las 2 diagonales principales y tal que alrecorrer ambas diagonales en orden creciente de filas, presentan los mismos elementos. Un ejemplo de este tipode matrices es la matriz del ejemplo. Es una matriz 6× 6 de valores enteros y con el 0 como valor por defecto.

2 0 0 0 0 20 4 0 0 4 00 0 7 7 0 00 0 1 1 0 00 9 0 0 9 06 0 0 0 0 6

Se quiere construir la clase MatrizBS. Resuelva los siguientes problemas:

a) (1 punto) Definir la parte privada de la clase. Debe minimizarse el uso de memoria, guardando lo estricta-mente necesario, para lo que sera necesario usar memoria dinamica. Observe que no se deben guardar losn x n valores de la matriz, ya que serıan redundantes.

b) (1 punto) Implementar el constructor por defecto y el destructor. El constructor por defecto creara unamatriz de tamano 4 × 4, en la que los elementos de las dos diagonales principales seran todos 1 y el valorpor defecto sera 0.

c) (1 punto) Implementar un constructor que reciba tres valores: n (el numero de filas y columnas),un vectorde enteros que contiene n elementos correspondientes a los valores en las diagonales y, finalmente, el valorque corresponde a las posiciones fuera de las diagonales. Este ultimo sera un parametro opcional cuyo valorpor defecto sera cero.

d) (1 punto) Implemente la sobrecarga del operador de asignacion de la clase MatrizBS.

3. (2 puntos) Escribir un programa que reciba como parametros -en la lınea de ordenes- tres nombres de ficheros detexto. Los dos primeros ficheros contienen numeros reales ordenados en orden creciente y separados por espaciosen blanco. El programa tomara los datos de esos ficheros y los ira copiando ordenadamente (de forma creciente)en el tercer fichero, de forma que al finalizar tambien este ordenado.

4. (2 puntos) Implemente una funcion recursiva que permita calcular el termino n-esimo de la serie de los numerosde Catalan de acuerdo a la siguiente expresion:

Cn ={

1 si n = 02(2n−1)

n+1 Cn−1 si n > 0

Nota: Los primeros terminos de la serie, desde el 0-esimo, son 1, 1, 2, 5, 14, 42, 132, ...

Page 303: Metodología de la Programación

Metodologıa de la ProgramacionExamen de teorıa. Grado en Ingenierıa Informatica. Julio 2011.

1. (1.5 puntos) Supongamos que en la parte privada de la clase VectorDinamico tenemos definido:

int NumMaxElems; // Num. de casillas reservadas en vint NumOcupados; // Num. de casillas ocupadasint * v; // Acceso a los datos

de manera que mediante v se accede a los datos almacenados en el vector dinamico. Construir el metodo privado:

bool redimensionar (int nuevotam);

que cambia el numero de casillas reservadas (NumMaxElems) al valor dado por nuevotam. El nuevo tamano puedeser mayor o menor que el que tenıa, y el vector debe conservar todos los elementos que sean posibles al cambiarel tamano. Devuelve un valor booleano indicando si se han conservado todos los elementos “ocupados”.

2. Supongamos que tenemos una clase que denominamos Lista.El codigo que declara la estructura de datos, ası como un ejemplo con 5 elementos son:

0 1 2 3 4

50

nelemsprimeroelementos

1.0 4

siguiente

3.0 −1

elem siguiente

2.0 3

elem siguiente

7.0 1

elem siguiente

5.0 2

elem siguienteelem

<1.0, 5.0, 2.0, 7.0, 3.0>

Representa la lista (en orden):

struct dato {float elem;int siguiente

};class Lista {

private:dato *elementos;int primero;int nelems;

public:..............

};

donde el campo elem es el elemento de cada posicion de una lista de float, y siguiente es el ındice en el vectorelementos donde se encuentra el siguiente elemento de la lista (-1 si no hay mas elementos).Para este nuevo tipo de dato que almacena listas de elementos float, implemente los siguientes metodos:

a) (1 punto) El constructor de copia.b) (1 punto) El operador de asignacion.c) (1.5 puntos) El operador logico de igualdad ==. Dos listas son iguales si tienen el mismo numero de elementos

y estos estan dispuestos en el mismo orden logico (esto es, si al recorrerlas se obtiene la misma secuenciade valores).

d) (1 punto) Un metodo que recibe un nombre de archivo (a traves de un parametro de tipo cadena estiloC) y almacena la Lista en dicho fichero y en formato binario. El fichero esta compuesto por un int quecorresponde al numero de elementos de la lista (sea n este numero), seguido de otro int que indica el ındiceen el vector del primer elemento de la lista, y seguido finalmente por una secuencia de n parejas float-int.

e) (1.5 puntos) Un metodo que, dado el nombre de un archivo con el formato indicado en el punto anterior,cargue el contenido de la lista almacenada en dicho fichero.

3. (2.5 puntos) Escribir un programa similar a grep que busque una palabra en una serie de ficheros de texto. Lapalabra a buscar y los ficheros en los que buscar se proporcionan en la lınea de ordenes. Por ejemplo:

busca examen fich1 fich2 fich3

busca la palabra examen en los ficheros fich1, fich2 y fich3.Cada vez que encuentre la cadena buscada, debe indicar el fichero en el que se ha localizado, el numero de lınea,y la lınea completa que la contiene. Un ejemplo de salida de este programa es:

fich1 (lınea 33): El examen ha sido facilfich3 (lınea 2): ya te dije ayer que hoy era el examenfich3 (lınea 242): finalmente, el examen tiene tres preguntas

Las restricciones que se imponen, y que se deben cumplir en la resolucion son:

a) El numero de ficheros que se pueden proporcionar es ilimitado.b) Cada uno de los ficheros solo puede ser leıdo una unica vez, y no pueden copiarse completos en memoria.c) Se desconoce a priori el numero de lıneas de los ficheros.d) Las lıneas de los ficheros tienen una longitud indeterminada, aunque nunca mayor de 500.

Duracion del examen: 3 horas.