viernes, 26 de noviembre de 2010

cursos de programación( curso de c++)

UNIVERSIDADE DA CORUÑA
El lenguaje de programación C++
Fernando Bellas Permuy
fbellas@udc.es
http://www.tic.udc.es/~fbellas
Departamento de Tecnologías de la Información y las Comunicaciones (TIC)
Universidad de A Coruña
1
Introducción
• C++ extiende el lenguaje de programación C con conceptos de
Orientación a Objetos.
• Es un lenguaje compilado.
• Índice:
• Revisión del lenguaje C.
• Mejoras (no OO) introducidas por C++.
• Clases.
• La herramienta “make” en Unix.
• Herencia.
• Sobrecarga de operadores.
• Plantillas (templates).
• Excepciones.
• La librería estándar de C++.
• Bibliografía.
2
Nociones básicas de C (1)
• Tipos de datos básicos.
• Operadores aritméticos: =, +, -, %, /, ++, --, y variantes de =
• Variables: locales, globales.
Tipo Indentificador Ejemplo de valores Modificadores
Caracteres char 'a', '9', '#', 10 unsigned
Enteros int 23, -34, 0 long, short,
unsigned
Reales float 3, 3.0, 3e10
Reales (doble precisión)
double 3, 3.0, 3e600 long
“Booleans” int 0 (false), != 0 (true)
#include
float e; /* Variable global */
int main ()
{
float v, t; /* Variables locales */
v = 30; /* Velocidad */
t = 5; /* Tiempo */
e = v * t;
printf("Velocidad: %f\nTiempo: %f\n", v, t);
printf("Espacio recorrido: %f\n", e);
return 0;
}
3
Nociones básicas de C (y 2)
• Operadores ++, --, y variantes de =
• Entrada salida con printf/scanf y similares.
• Caracteres de control en printf, scanf: d, o, x, c, s, f, e, p.
• En C++ hay una alternativa mejor: los streams de entrada/salida.
i = 4;
j = 2 * (i++);
/* i = 5, j = 8 */
i = 4;
j = 2 * (++i);
/* i=5, j = 10 */
i = 4;
i %= 3; /* i = i % 3; */
i += 4; /* i = i + 4; */
/* i = 5 */
#include
int main ()
{
float v, t, e;
printf("Velocidad: ");
scanf("%f", &v);
printf("Tiempo: ");
scanf("%f", &t);
e = v * t;
printf("Velocidad: %5.2f; Tiempo: %5.2f; Espacio: %5.2f\n",v,t,e);
return 0;
}
4
Control de flujo (1)
• Operadores relacionales: >, >=, <, <=, ==, !=
• Operadores lógicos: &&, ||, !
• if.. else..
• switch-case-default
if (condición) {
<< sentencias >>
} else {
<< sentencias >>
}
switch (exp) {
case A:
<< instrucciones >>
break;
case B:
<< instrucciones >>
break;
...
default:
<< instrucciones por defecto >>
}
switch (letra) {
case 'a':
case 'e':
case 'i':
case 'o':
case 'u': printf("Es una vocal\n");
break;
case 'ñ': printf("Nuestra querida ñ\n");
break;
default: printf("Cualquier otro caracter");
}
5
Control de flujo (y 2)
• Bucle while
• Bucle do.. while
• Bucle for
Operadores de bit
• & (AND), | (OR), ~ (NOT), ^ (XOR), >> (shift right), << (shift
left).
while (condición) {
<< instrucciones >>
}
do {
<< instrucciones >>
} while (condición)
for (inic; cond; incr) {
<< instrucciones >>
}
for (i=1; i<=10; i++) {
printf(“%i\n“, d);
}
6
Estructuras de datos estáticas (1)
• Vectores.
• Registros o Estructuras.
• Uniones.
int vector[] = {1, 2, 3, 4, 5};
int vector2[5] = {1, 2, 3, 4, 5};
int matriz[10][10];
char matriz3[4][5][6];
int main ()
{
float matriz2[][3] = { {1, 2, 3}, {4, 5, 6} };
int i, j;
for (i=0; i<2; i++) {
for (j=0; j<3; j++) {
printf("%f\n", matriz2[i][j]);
}
}
return 0;
}
struct nombre {
Tipo1 campo1;
Tipo2 campo2;
...
TipoN campoN;
} variable;
struct TipoPunto {
int x;
int y;
} punto;
punto.x = 1;
punto.y = 2;
union Ejemplo {
char caracter;
int entero;
};
struct FiguraColoreada {
int color;
int tipoFigura;
union {
struct Esfera e;
struct Segmento s;
} figura;
}
7
Estructuras de datos estáticas (y 2)
• Tipos definidos por el usuario (typedef).
• Enumeraciones.
typedef unsigned char TipoByte;
typedef struct {
int x;
int y;
} TipoPunto;
enum Dia { Lunes, Martes, Miercoles, Jueves, Viernes, Sabado, Domingo};
8
Punteros (1)
• Un puntero es una variable cuyo contenido es una dirección
de memoria.
• Operadores: &, *, ->
• Ejemplos:
• Punteros y matrices.
int x;
int* px;
x = 1;
px = &x;
*px = 2; /* x = 2 */
TipoPunto* pPunto;
pPunto->x = 1;
pPunto->y = 2;
int i;
int v[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int* p;
for (i=0; i<10; i++) {
printf("%d\n", v[i]);
}
for (i=0, p=v; i<10; i++, p++) {
printf("%d\n", *p);
}
for (p=v; p != &(v[10]); p++) {
printf("%d\n", *p);
}
9
Punteros (y 2)
• Cadenas de caracteres: Vectores de caracteres terminados en 0
('\0').
#include
char* mensaje = "hola";
int main ()
{
char cadena[10];
char* p = cadena;
unsigned int longitud = 0;
puts(mensaje);
scanf("%9s", cadena);
while (*p != 0) {
longitud++;
p++;
}
printf("Longitud: %d\n", longitud);
return 0;
}
10
Funciones
• Un ejemplo.
• Paso de parámetros.
• La función main()
int Suma (int x, int y)
{
return x+y;
}
void Swap (int* a, int* b)
{
int temporal;
temporal = *a;
*a = *b;
*b = temporal;
}
int main ()
{
int x = 4;
int y = 5;
Swap(&x, &y);
/* x = 5, y = 4 */
}
int main (int argc, char* argv[], char* env[])
{
int i;
for (i = 0; i < argc; i++) puts(argv[i]);
for (i = 0; env[i]; i++) puts(env[i]);
return 0;
}
11
Ejercicio
#ifndef _Pila_
#define _Pila_
/* Tipos. */
typedef enum {Pila_OK, Pila_Error}
Pila_CodigoRetorno;
typedef struct Pila_Nodo {
int fElemento;
struct Pila_Nodo* fAnterior;
} Pila_Nodo;
typedef struct {
Pila_Nodo* fCima;
} Pila;
/* Funciones. */
Pila* Pila_Crear ();
Pila_CodigoRetorno Pila_Introducir (Pila* pila,
int elemento);
Pila_CodigoRetorno Pila_Sacar (Pila* pila,
int* elemento);
int Pila_EsVacia (Pila* pila);
void Pila_Destruir (Pila* pila);
#endif
12
Mejoras (no OO) introducidas por C++ (1)
• Referencias.
• Comentario de línea: //
• Constantes y declaraciones de variables.
• Tipos enumerados.
int val = 10;
int& ref = val;
int& ref2; // Error !
void Swap (int& x, int& y) {
int tmp = x;
x = y;
y = tmp;
}
int main () {
int x = 5; int y = 7;
Swap(x, y);
return 0;
}
const int LONGITUD = 4; // En C antiguo => #define LONGITUD 4
void f ()
{
int x;
x = 23;
cout << x << endl;
int y = 1;
cout << y << endl;
}
enum Color {rojo = 0, amarillo = 8, azul = 16};
13
Mejoras (no OO) introducidas por C++ (2)
• Sobrecarga de funciones (y operadores).
• Argumentos por defecto.
• Asignación de memoria dinámica => operadores new y
delete.
• Los prototipos de función son obligatorios.
• Se puede hacer inlining de funciones.
void print (int entero);
void print (const char* cadena);
void print (double real);
print(2);
print("hola");
print(1.0);
void print (int valor, int base=10);
void f()
{
print(31);
print(31, 10);
print(31, 16);
}
int* x = new int(2);
int* y = new int[10];
delete x;
delete []y;
inline void f (int i) { cout << i << endl; }
14
Mejoras (no OO) introducidas por C++ (y 3)
• Tipo bool.
• Posibles valores true (1) y false (0).
• Namespaces.
// Fichero de especificación.
namespace Libreria {
typedef enum {uno, dos, tres} Tipo;
double Funcion (const char* str);
}
// Fichero de implementación.
double Libreria::Funcion (const char* str) { /* ... */ }
// Uso.
double d = Libreria::Funcion(unaCadena);
using namespace Libreria;
using namespace Libreria::Funcion;
15
Clases (1)
• Ejemplo:
• Especificadores de acceso: private (por defecto), public y
protected.
• Constructores: constructor por defecto, constructor copia y
constructores adicionales.
class Fecha {
public:
void Establecer (unsigned int dia, unsigned mes,
unsigned int anho);
void Obtener (unsigned int& dia, unsigned int& mes,
unsigned int& anho) const;
void Imprimir ();
private:
unsigned int fDia, fMes, fAnho;
};
void Fecha::Obtener (unsigned int& dia, unsigned int& mes,
unsigned int& anho)
{
dia = fDia; mes = fMes; anho = fAnho;
}
class Fecha {
// ...
public:
Fecha (unsigned int dia, unsigned int mes,
unsigned int anho);
Fecha (const char* cadena);
Fecha (); // Constructor por defecto.
Fecha (const Fecha& fecha); // Constructor copia.
};
16
Clases (2)
• ... continuación del ejemplo.
• Destructor: ~NombreDeLaClase()
Fecha miCumple(19, 4, 1998);
Fecha miCumple2("19 Abril 1998");
Fecha miCumple3; // Constructor por defecto.
Fecha* miCumple4 = new Fecha(19, 4, 1998);
Fecha miCumple5 = miCumple2; // Inicialización (c. copia).
Fecha miCumple6;
miCumple6 = miCumple5; // Es una asignación.
void f (Fecha fecha);
f(miCumple);
void f(const Fecha& fecha);
f(miCumple);
class X {
public:
// ...
~X ();
};
{
X x;
X* x2 = new X;
X* x3 = new X[10];
delete x2;
delete []x3;
}
17
Clases (3)
• Puntero this.
• Miembros static.
class X {
public:
// ...
void Metodo (int i) { this-> i = i; }
private:
int i;
};
#include
using namespace std;
class Ejemplo {
public:
// ...
Ejemplo () { cuenta++; }
static int Cuantos () { return cuenta; }
private:
static int cuenta;
// ...
};
int Ejemplo::cuenta = 0;
int main ()
{
Ejemplo e1, e2;
cout << Ejemplo::Cuantos() << endl; // 2
return 0;
}
18
Clases (y 4)
• Clases utilidad (utility classes): todos los métodos/atributos
son static.
• Las clases utilidad evitan el uso de funciones globales.
• Especificador const en métodos.
• Funciones, métodos y clases amigas.
class LibreriaMatematica {
public:
static float Seno (float angulo);
static float Coseno (float angulo);
static float Tangente (float angulo);
// ...
};
float resultado = LibreriaMatematica::Seno(12.1);
class Ejemplo {
// ...
private:
int i;
friend void FuncionAmiga (Ejemplo& e);
friend void X::MetodoAmigo (Ejemplo& e);
friend Y;
};
void FuncionAmiga (Ejemplo& e)
{
cout << e.i << endl;
}
19
Ejercicio (1)
• Patrón de diseño (design pattern) “Iterador” (Iterator).
• Diagrama de clases.
• Diagrama de objetos.
IteradorListaD
Primero ()
Siguiente ()
Fin ()
Elemento ()
int fPosicion
ListaD* fLista
NodoListaD
PonerElemento (elemento)
ObtenerElemento ()
PonerSiguiente (siguiente)
ObtenerSiguiente ()
int fElemento
NodoListaD* fSiguiente
ListaD
CrearIterador ()
InsertarP (elemento)
InsertarF (elemento)
Longitud ()
Elemento (indice)
NodoListaD* fPrincipio
NodoListaD* fFinal
int fLongitud
nodoListaD1
fElemento (23)
fSiguiente
nodoListaD3
fElemento (7)
fSiguiente
nodoListaD2
fElemento (12)
fSiguiente
unaListaD
fLongitud (3)
fPrincipio
fFinal
unIteradorListaD
fPosición (1)
fLista
unIteradorListaD
fPosición (0)
fLista
20
Ejercicio (2)
#ifndef _ListaD_
#define _ListaD_
#include "NodoListaD.h"
class IteradorListaD;
class ListaD {
public:
ListaD ();
ListaD (const ListaD& lista);
~ListaD ();
const ListaD& operator = (const ListaD& lista);
public:
IteradorListaD* CrearIterador () const;
void InsertarP (int elemento);
void InsertarF (int elemento);
private:
int Longitud () const;
int Elemento (int indice) const;
friend IteradorListaD;
private:
void Destruir ();
void CopiarDesde (const ListaD& lista);
void Inicializar ();
private:
NodoListaD* fPrincipio;
NodoListaD* fFinal;
int fLongitud;
};
#endif
21
Ejercicio (3)
#ifndef _IteradorListaD_
#define _IteradorListaD_
#include "ListaD.h"
class IteradorListaD {
public:
IteradorListaD (ListaD* lista);
~IteradorListaD ();
public:
void Primero();
void Siguiente();
int Fin () const;
int Elemento () const;
private:
IteradorListaD (const IteradorListaD& iterador);
const IteradorListaD& operator= (
const IteradorListaD& iterador);
private:
int fPosicion;
ListaD* fLista;
};
#endif
22
Ejercicio (4)
#ifndef _NodoListaD_
#define _NodoListaD_
class NodoListaD {
public:
NodoListaD (int elemento, NodoListaD* siguiente);
~NodoListaD ();
void PonerElemento (int elemento);
int ObtenerElemento () const;
void PonerSiguiente (NodoListaD* siguiente);
NodoListaD* ObtenerSiguiente () const;
private:
NodoListaD (const NodoListaD& nodoListaD);
const NodoListaD& operator= (
const NodoListaD& nodoListaD);
private:
int fElemento;
NodoListaD* fSiguiente;
};
#endif
23
Ejercicio (y 5)
class ClasePrueba {
public:
void InsertarElementos (ListaD& lista);
void Listar (IteradorListaD& iterador);
};
void ClasePrueba::InsertarElementos (ListaD& lista)
{
for (int i = 0; i<10; i++) {
lista.InsertarF(i);
}
}
void ClasePrueba::Listar (IteradorListaD& iterador)
{
iterador.Primero();
cout << "Lista: " << endl;
while (!iterador.Fin()) {
cout << iterador.Elemento() << endl;
iterador.Siguiente();
}
}
int main ()
{
ClasePrueba prueba;
ListaD lista;
prueba.InsertarElementos(lista);
IteradorListaD* iterador = lista.CrearIterador();
prueba.Listar(*iterador);
delete iterador;
return 0;
}
24
La herramienta “make” en Unix (1)
• make es una herramienta que permite expresar dependencias
temporales entre ficheros mediante reglas.
• Cada regla puede llevar asociada una acción, que se ejecutará
si se cumple la regla.
• Las reglas se expresan en un fichero (Makefile).
• La utilidad más importante de make es la compilación de aplicaciones
(ej.: C, C++, etc.).
• Existen versiones para sistemas operativos distintos a Unix.
• No es una herramienta estándar.
• Existen herramientas que generan Makefiles automáticamente
a partir de un conjunto de ficheros C/C++ (por ejemplo).
• Invocación
• Si el fichero se llama Makefile => make
• En otro caso => make -f NombreFicheroMakefile
25
La herramienta “make” en Unix (2)
• Un primer Makefile (Makefile1) ...
Prueba: NodoListaD.o IteradorListaD.o ListaD.o Prueba.o
g++ -o Prueba NodoListaD.o IteradorListaD.o \
ListaD.o Prueba.o
NodoListaD.o: NodoListaD.cpp NodoListaD.h
g++ -c NodoListaD.cpp
IteradorListaD.o: IteradorListaD.cpp IteradorListaD.h \
ListaD.h
g++ -c IteradorListaD.cpp
ListaD.o: ListaD.cpp ListaD.h NodoListaD.h \
IteradorListaD.h
g++ -c ListaD.cpp
Prueba.o: Prueba.cpp ListaD.h IteradorListaD.h
g++ -c Prueba.cpp
clean:
rm -rf NodoListaD.o IteradorListaD.o ListaD.o \
Prueba.o Prueba *~
• A recordar:
• Reglas separadas al menos por una línea en blanco.
• La acción empieza con un tabulador.
• Invocaciones ...
• make -f Makefile1
• make -f Makefile1 clean
26
La herramienta “make” en Unix (3)
• Una primera mejora (variables) ...
# Variables.
OBJS = NodoListaD.o IteradorListaD.o ListaD.o Prueba.o
# Reglas.
Prueba: $(OBJS)
g++ -o Prueba $(OBJS)
NodoListaD.o: NodoListaD.cpp NodoListaD.h
g++ -c NodoListaD.cpp
IteradorListaD.o: IteradorListaD.cpp IteradorListaD.h \
ListaD.h
g++ -c IteradorListaD.cpp
ListaD.o: ListaD.cpp ListaD.h NodoListaD.h \
IteradorListaD.h
g++ -c ListaD.cpp
Prueba.o : Prueba.cpp ListaD.h IteradorListaD.h
g++ -c Prueba.cpp
clean:
rm -rf $(OBJS) Prueba *~
27
La herramienta “make” en Unix (4)
• Otra mejora más (reglas implícitas) ...
# Variables.
OBJS = NodoListaD.o IteradorListaD.o ListaD.o Prueba.o
# Reglas implicitas.
%.o: %.cpp
g++ -c $<
#.cpp.o:
# g++ -c $<
# Reglas.
Prueba: $(OBJS)
g++ -o Prueba $(OBJS)
NodoListaD.o: NodoListaD.h
IteradorListaD.o: IteradorListaD.h ListaD.h
ListaD.o: ListaD.h NodoListaD.h IteradorListaD.h
Prueba.o: ListaD.h IteradorListaD.h
clean:
rm -rf $(OBJS) Prueba *~
28
La herramienta “make” en Unix (5)
• Problemas de los anteriores Makefiles:
• Difíciles de mantener.
• Demasiadas recompilaciones (un cambio en un comentario en un
fichero cabecera ...).
• Relajando las dependencias ...
# Variables.
OBJS = NodoListaD.o IteradorListaD.o ListaD.o Prueba.o
# Reglas implicitas.
%.o: %.cpp
g++ -c $<
# Reglas.
Prueba: $(OBJS)
g++ -o Prueba $(OBJS)
clean:
rm -rf $(OBJS) Prueba *~
• El anterior Makefile puede tener algunos problemas de inconsistencias,
pero en general es un opción aconsejable.
29
La herramienta “make” en Unix (6)
• Cuando un proyecto está estructurado en varios directorios ...
• En el directorio Ejemplo3, el Makefile tiene el siguiente aspecto.
include ../EjemplosC++.incl
# OBJS
OBJS = NodoListaD.o ListaD.o IteradorListaD.o Prueba.o
Prueba: $(OBJS)
$(COMPILADOR) -o Prueba $(OBJS)
clean:
rm -rf $(OBJS) Prueba *~
• En el directorio padre => EjemplosC++.incl =>
# Compilador.
COMPILADOR = g++
# Compilación.
%.o: %.cpp
$(COMPILADOR) -c $<
30
La herramienta “make” en Unix (y 7)
• Cuando un proyecto está estructurado en varios directorios ...
(continuación)
• En el directorio padre existe un Makefile que recompila todo el software
...
all:
for i in Ejemplo*; \
do if [ -d $$i ]; then cd $$i; make; cd ..; fi; \
done
clean:
rm -f *~
for i in Ejemplo*; \
do if [ -d $$i ]; then cd $$i; make clean; cd ..; \
fi; done
31
Herencia (1)
• Un ejemplo:
• Tres tipos de herencia: public, protected y private.
#include
using namespace std;
class Persona {
public:
void Saluda () { cout << "Hola" << endl; }
};
class PersonaEducada : public Persona {
public:
void BuenosDias () { cout << "Buenos dias" << endl; }
};
int main () {
Persona a;
PersonaEducada b;
a.Saluda();
b.Saluda();
b.BuenosDias();
return 0;
}
class X {
public:
int a;
protected:
int b;
private:
int c;
};
class X2 : public X {
void f() {
cout << a; // OK, pública.
cout << b; // OK, protegida.
cout << c; // Error, privada en X.
};
};
32
Herencia (2)
• Constructores.
• Orden de llamada de constructores: primero los de las clases
base (de arriba hacia abajo), y luego los de los objetos miembro.
• Orden de llamada de los destructores: a la inversa que los constructores.
#include
using namespace std;
class X {
public:
X (int i) { cout << "Constructor X: " << i << endl; }
~X () { cout << "Destructor X" << endl; }
};
class Y : public X {
public:
Y (int i) : X(1), x(123) {
cout << "Constructor Y: " << i << endl; }
~Y () { cout << "Destructor Y" << endl; }
private:
X x;
};
int main ()
{
Y y(1);
return 0;
}
33
Herencia (3)
• Redefinición de métodos.
#include
using namespace std;
class Persona {
public:
void Habla () { cout << "Hace un día precioso" << endl; }
};
class Futbolero : public Persona {
public:
void Habla () { cout << "¿ A qué hora es el partido ?"
<< endl; }
};
class Pesado : public Persona {
public:
void Habla () {
Persona::Habla();
cout << "Recuerdo una vez que bla, bla, bla ..."
<< endl;
}
};
int main ()
{
Persona persona;
Futbolero futbolero;
Pesado pesado;
persona.Habla(); // Hace un día precioso
futbolero.Habla(); // ¿ A qué hora es el partido ?
pesado.Habla(); // Hace un día precioso
// Recuerdo una vez que bla, bla,
// bla ...
return 0;
}
34
Herencia (4)
• Métodos virtuales.
• El problema anterior se soluciona declarando Identificacion()
como virtual.
#include
using namespace std;
class Vehiculo {
public:
void Habla () { cout << "Soy un " << Identificacion()
<< endl; }
const char* Identificacion () { return "vehículo"; }
};
class Coche : public Vehiculo {
public:
const char* Identificacion () { return "coche"; }
};
class Barco : public Vehiculo {
public:
const char* Identificacion () { return "barco"; }
};
int main ()
{
Vehiculo vehiculo;
Coche coche;
Barco barco;
vehiculo.Habla(); // Soy un vehículo
coche.Habla(); // Soy un vehículo
barco.Habla(); // Soy un vehículo
return 0;
}
35
Herencia (5)
• ... es decir ...
• ¿ y qué ocurría con ?
• Se produce polimorfismo cuando se accede a la función virtual
con un objeto puntero (o referencia) de la clase base.
class Vehiculo {
public:
void Habla () { cout << "Soy un " << Identificacion()
<< endl; }
virtual const char* Identificacion () {
return "vehiculo"; }
};
Vehiculo vehiculo;
Coche coche;
vehiculo = coche;
vehiculo.Habla();
Vehiculo* vehiculo = new Vehiculo;
Coche* coche = new Coche;
Barco* barco = new Barco;
vehiculo->Habla(); // Soy un vehículo
coche->Habla(); // Soy un coche
barco->Habla(); // Soy un barco
Vehiculo* vehiculo2 = barco;
vehiculo2->Habla(); // Soy un barco
36
Herencia (6)
• ... continuación del ejemplo.
• Clases abstractas: no se pueden tener instancias de clases
abstractas. Su objetivo es definir una interfaz.
void f (const Vehiculo& vehiculo)
{
vehiculo.Habla();
}
int main ()
{
Coche coche;
f(coche); // Soy un coche
}
class Figura { // Clase abstracta
public:
virtual void Dibujar () = 0; // Virtual pura
virtual float Area () = 0; // Virtual pura
// ...
};
class Rectangulo : public Figura {
public:
virtual void Dibujar () { // ... }
virtual float Area () { // ... }
// ...
};
class ListaDeFiguras {
public:
void Insertar(Figura* figura);
void Dibujar();
// ...
};
37
Herencia (y 7)
• Herencia múltiple.
• Problemas de ambigüedad con la herencia múltiple.
class Vehiculo { ...};
class VehiculoTerrestre : public Vehiculo { ... };
class VehiculoMaritimo : public Vehiculo { ... };
class VehiculoAnfibio : public VehiculoTerrestre,
public VehiculoMaritimo
{ ... };
class X {
public:
void f ();
};
class Y {
public:
void f ();
};
class Z : public X, public Y {
public:
// ...
};
int main ()
{
Z z;
z.f(); // Ambigüedad !
z.X::f();
return 0;
}
38
Ejercicio (1)
• Patrón de diseño (design pattern): “Iterador” (Iterator).
Lista
CrearIterador ()
InsertarP (elemento)
InsertarF (elemento)
Iterador
Primero ()
Siguiente ()
Fin ()
Elemento ()
Cliente
ListaD
CrearIterador ()
InsertarP (elemento)
InsertarF (elemento)
Longitud ()
Elemento (indice)
NodoListaD* fPrincipio
NodoListaD* fFinal
int fLongitud
ListaE
CrearIterador ()
InsertarP (elemento)
InsertarF (elemento)
IteradorListaD
Primero ()
Siguiente ()
Fin ()
Elemento ()
int fPosicion
ListaD* fLista
IteradorIListaD
Primero ()
Siguiente ()
Fin ()
Elemento ()
int fPosicion
ListaD* fLista
39
Ejercicio (2)
#ifndef _Lista_
#define _Lista_
class Iterador;
class Lista {
public:
virtual ~Lista();
public:
virtual Iterador* CrearIterador () const = 0;
virtual void InsertarP (int elemento) = 0;
virtual void InsertarF (int elemento) = 0;
};
#endif
#ifndef _Iterador_
#define _Iterador_
class Iterador {
public:
virtual ~Iterador ();
public:
virtual void Primero () = 0;
virtual void Siguiente () = 0;
virtual int Fin () const = 0;
virtual int Elemento () const = 0;
};
#endif
40
Ejercicio (3)
#ifndef _ListaD_
#define _ListaD_
#include "NodoListaD.h"
#include "Lista.h"
class IteradorListaD;
class IteradorIListaD;
class ListaD : public Lista {
public:
ListaD ();
ListaD (const ListaD& lista);
virtual ~ListaD ();
const ListaD& operator = (const ListaD& lista);
public:
virtual Iterador* CrearIterador () const;
virtual void InsertarP (int elemento);
virtual void InsertarF (int Elemento);
private:
int Longitud () const;
int Elemento (int indice) const;
friend IteradorListaD;
friend IteradorIListaD;
private:
void Destruir ();
void CopiarDesde (const ListaD& lista);
void Inicializar ();
private:
NodoListaD* fPrincipio;
NodoListaD* fFinal;
int fLongitud;
};
#endif
41
Ejercicio (4)
#ifndef _IteradorListaD_
#define _IteradorListaD_
#include "ListaD.h"
#include "Iterador.h"
class IteradorListaD : public Iterador {
public:
IteradorListaD (ListaD* lista);
virtual ~IteradorListaD ();
public:
virtual void Primero();
virtual void Siguiente();
virtual int Fin () const;
virtual int Elemento () const;
private:
IteradorListaD (const IteradorListaD& iterador);
const IteradorListaD& operator= (
const IteradorListaD& iterador);
private:
int fPosicion;
ListaD* fLista;
};
#endif
42
Ejercicio (y 5)
class ClasePrueba {
public:
void InsertarElementos (Lista& lista);
void Listar (Iterador& iterador);
};
void ClasePrueba::InsertarElementos (Lista& lista)
{
for (int i = 0; i<10; i++) {
lista.InsertarF(i);
}
}
void ClasePrueba::Listar (Iterador& iterador)
{
iterador.Primero();
cout << "Lista: " << endl;
while (!iterador.Fin()) {
cout << iterador.Elemento() << endl;
iterador.Siguiente();
}
}
int main ()
{
ClasePrueba prueba;
ListaD lista;
prueba.InsertarElementos(lista);
Iterador* iterador1 = lista.CrearIterador();
prueba.Listar(*iterador1);
IteradorIListaD iterador2(&lista);
prueba.Listar(iterador2);
delete iterador1;
return 0;
}
43
Sobrecarga de operadores (1)
• Operadores que se pueden sobrecargar: +, -, *, /, %, ^, &, |, ~,
=, <, >, +=, -=, *=, /=, %=, ^=, &=, |=, <<, >>, <<=, >>=, ==,
!=, <=, >=, &&, ||, ++, --, ->, [], new, delete.
• Ejemplo:
class Complejo {
public:
Complejo (double real, double imag) {
fReal = real; fImag = imag;
}
Complejo operator+ (const Complejo& c) {
return Complejo(fReal+c.fReal, fImag+c.fImag);
}
Complejo operator++ () {
return Complejo(++fReal, ++fImag);
}
Complejo operator++ (int) {
return Complejo(fReal++, fImag++);
}
const Complejo& operator= (const Complejo& c) {
if (this != &c) {
fReal = c.fReal;
fImag = c.fImag;
}
return *this;
}
void Imprimir () {
cout << fReal << " " << fImag << endl;
}
private:
double fReal, fImag;
};
44
Sobrecarga de operadores (2)
• ... continuación del ejemplo.
• Otra forma de sobrecargar operadores: funciones globales.
Complejo c1(1, 1);
Complejo c2(2, 2);
Complejo c3(3, 3);
Complejo c4(5, 5);
c4 = c1 + ++c2 + c3++;
c4.Imprimir(); // fReal: 7; fImag: 7
c1 = c2 = c4;
c1.Imprimir(); // fReal: 7; fImag: 7
c1 = c2.operator+(c3);
c1.Imprimir(); // fReal: 11; fImag: 11
c1 = c2.operator++();
c1.Imprimir(); // fReal: 7; fImag: 7
c1 = c2.operator++(123);
c1.Imprimir(); // fReal: 131; fImag: 131
class Complejo {
public:
double DameReal () const { return fReal; }
double DameImag () const { return fImag; }
// ...
private:
double fReal, fImag;
};
45
Sobrecarga de operadores (3)
• ... continuación del ejemplo.
• Otra alternativa habría sido el uso de friends.
• Problema:
• Solución => Conversión de tipos + funciones globales.
Complejo operator+ (const Complejo& c1, const Complejo& c2)
{
return Complejo(c1.DameReal() + c2.DameReal(),
c1.DameImag() + c2.DameImag());
}
Complejo operator++ (const Complejo& c)
{
double real = c1.DameReal();
double imag = c1.DameImag();
return Complejo(++real, ++imag);
}
Complejo operator+ (Complejo& c, double d)
{
return Complejo(c.DameReal()+d, c.DameImag());
}
// ...
c3 = c3 + 1;
c3 = 1 + c3; // Error !
class Complejo {
public:
Complejo (double real, double imag=0) {
fReal = real; fImag = imag; }
// ...
};
46
Sobrecarga de operadores (y 4)
• Operador de conversión.
class X {
public:
// ...
operator int () { return i;}
private:
int i;
};
// ...
X x(4);
int i;
i = x;
47
Ejercicio
#ifndef _Vector_
#define _Vector_
#include
using namespace std;
class Vector {
public:
enum {kTamPorDefecto=10};
typedef int Elemento;
public:
Vector (unsigned int tamanho=Vector::kTamPorDefecto);
Vector (const Vector& vector);
~Vector ();
const Vector& operator= (const Vector& vector);
public:
Elemento& operator[] (unsigned int indice) const;
Vector operator+ (const Vector& vector) const;
Vector operator- (const Vector& vector) const;
Vector operator* (const Vector& vector) const;
Vector operator/ (const Vector& vector) const;
void Imprimir (ostream& salida) const;
unsigned int Tamanho () const;
private:
void CopiarDesde (const Vector& vector);
void Destruir ();
private:
unsigned int fTamanho;
Elemento* fDatos;
};
#endif
48
Plantillas (1)
• Definir una función que nos dé el mayor de dos números.
• Problema: ¿ y si queremos hacer lo mismo para otros tipos de
datos (inclusive clases definidas por nosotros) ?
• Solución: templates.
• Ahora es posible hacer ...
• Si se define una función no template con el mismo prototipo
que otra función template, tiene más prioridad la primera.
int DameElMayor (int x, int y)
{
if (x > y) {
return x;
} else {
return y;
}
}
template
Tipo DameElMayor (const Tipo& x, const Tipo& y)
{
if (x > y) {
return x;
} else {
return y;
}
}
double d1, d2, d3;
// ...
d3 = DameElMayor(d1, d2);
49
Plantillas (y 2)
• Las plantillas también se pueden aplicar a clases C++.
• Si se define una clase no template con la misma especificación
que otra clase template, tiene más prioridad la primera.
template
class Pila {
public:
// ...
void Insertar (const Elemento& elemento);
unsigned int Longitud () const;
private:
NodoPila* pila;
// ...
}
template
void Pila::Insertar (const Elemento& elemento)
{
// ...
}
template
unsigned int Pila::Longitud () const
{
// ...
}
class Pila pila;
50
Excepciones (1)
• Una excepción es una anomalía que sucede en un programa en
tiempo de ejecución.
• Idea general.
void FuncionA () throw (char*, ErrorRango, ErrorMemoria)
{
// ...
try {
// ...
FuncionB();
// ...
} catch (const char* cadena) {
// ...
} catch (const ErrorRango& err) {
// ...
} catch (const ErrorMemoria& err) {
// ...
} catch (...) {
throw;
}
}
void FuncionB () throw (char*, ErrorRango, ErrorMemoria)
{
// ...
if (error) {
throw ("No hay suficiente memoria");
}
// ...
}
51
Excepciones (2)
• Ejemplo:
class ExcepcionPila {
public:
enum Subcategoria { InsuficienteMemoria, EstaVacia,
_numeroDeSubCategorias};
public:
ExcepcionPila (Subcategoria s);
void Imprimir ();
private:
Subcategoria fSubcategoria;
static const char* fMensajes[_numeroDeSubCategorias];
};
const char* ExcepcionPila::fMensajes[
ExcepcionPila::_numeroDeSubCategorias] = {
"Insuficiente memoria", "Pila vacía"
};
ExcepcionPila::ExcepcionPila (Subcategoria s)
{
fSubcategoria = s;
}
void ExcepcionPila::Imprimir ()
{
cerr << fMensajes[fSubcategoria] << endl;
}
52
Excepciones (y 3)
• ... continuación del ejemplo.
• Si la excepción se captura, todos los objetos construidos en la
pila, se liberan automáticamente. Por tanto, es siempre recomendable
hacer uso del mecanismo de excepciones.
• Normalmente se define una jerarquía de excepciones.
template
void Pila::Insertar (const Elemento& elemento)
throw (ExcepcionPila)
{
// ...
if (noHayMemoria) {
throw ExcepcionPila(
ExcepcionPila::InsuficienteMemoria);
}
// ...
}
try {
pila.Insertar(elemento);
} catch (const ExcepcionPila& e) {
e.Imprimir();
} catch (...) {
cerr << "Excepción desconocida" << endl;
}
53
Ejercicio (1)
#ifndef _ExcepcionLibreria_
#define _ExcepcionLibreria_
class ExcepcionLibreria {
public:
virtual const char* DameElNombre() const;
};
class DivisionPorCero : public ExcepcionLibreria {
public:
virtual const char* DameElNombre() const;
};
class MemoriaInsuficiente : public ExcepcionLibreria {
public:
virtual const char* DameElNombre() const;
};
class IndiceFueraDeRango : public ExcepcionLibreria {
public:
virtual const char* DameElNombre() const;
};
class DistintaDimension : public ExcepcionLibreria {
public:
virtual const char* DameElNombre() const;
};
#endif
54
Ejercicio (y 2)
#ifndef _Vector_
#define _Vector_
#include
#include "ExcepcionLibreria.h"
using namespace std;
template
class Vector {
public:
enum {kTamPorDefecto=10};
public:
Vector (unsigned int tamanho=Vector::kTamPorDefecto);
// throw (MemoriaInsuficiente)
Vector (const Vector& vector);
// throw (MemoriaInsuficiente)
~Vector ();
const Vector& operator= (
const Vector& vector);
// throw (MemoriaInsuficiente)
public:
TipoElemento& operator[] (unsigned int indice) const;
// throw (IndiceFueraDeRango);
Vector operator+ (
const Vector& vector) const;
// throw (DistintaDimension)
Vector operator- (
const Vector& vector) const;
// throw (DistintaDimension)
Vector operator* (
const Vector& vector) const;
// throw (DistintaDimension)
Vector operator/ (
const Vector& vector) const;
// throw (DistintaDimension, DivisionPorCero);
void Imprimir (ostream& salida) const;
unsigned int Tamanho () const;
private:
void CopiarDesde (const Vector& vector);
// throw (MemoriaInsuficiente)
void Destruir ();
private:
unsigned int fTamanho;
TipoElemento* fDatos;
};
#include "Vector.cpp"
#endif
55
La librería estándar de C++
• Proporciona:
• string
• Entrada/salida por medio de streams
• Contenedores: vector, list, map, set, stack, queue, etc.
• Algoritmos: for_each, de comparación, de copia, operaciones
matemáticas, mezclado, de búsqueda, de ordenación, etc.
• Soporte análisis numérico: funciones matemáticas estándar, aritmética
de vectores, números complejos, etc.
• Es muy eficiente.
• Todos los componentes están definidos en el espacio de nombres
std.
• Ficheros cabecera.
• , , , , ,
, , , , etc.
• , y , etc. ya no forman parte
de la librería estándar C++, si bien, la mayor parte de los compiladores
siguen soportándolos (pero no son iguales que las versiones estándares).
• Obsérvese que no tiene nada que ver con .
• Para cada cabecera X.h de la librería estándar C, existe la cabecera
equivalente , que contiene las mismas definiciones en el espacio
de nombres std.
• , , , etc.
56
Strings
#include
#include
using namespace std;
int main ()
{
string str1;
string str2("Hola");
str1 = "Adios";
if (str1 > str2) {
cout << str1 << " es mayor que " << str2 << endl;
} if (str1 == str2) {
cout << str1 << " es igual a " << str2 << endl;
} else {
cout << str1 << " es menor que " << str2 << endl;
}
return 0;
}
57
Entrada/salida por medio de streams (1)
• Un stream es un flujo de datos (fichero, cadena de caracteres).
• La librería de streams proporciona las mismas funcionalidades
que la librería stdio, pero es orientada a objetos.
• Objetos predefinidos: cin, cout, cerr.
• Clase padre: ios.
• Clase ostream.
• Hereda de ios.
• Representa un stream de salida.
• La operación de salida se realiza usando el operador <<.
• Proporciona métodos para introducir datos en el stream.
• << está sobrecargado para los tipos básicos.
• << ha de aplicarse a un objeto de la clase ostream o de uno de sus hijos.
• << se puede sobrecargar para nuestros tipos (inclusive clases).
• Clase istream.
• Análoga a ostream para entrada.
• Ejemplo:
#include
#include
using namespace std;
int main ()
{
cout << "Hola" << endl;
double f = 12.3;
cout << f << endl;
cout << "Introduce un entero: ";
int i;
cin >> i;
cout << "Introduce una cadena de caracteres: ";
string cadena;
cin >> cadena;
cout << cadena << endl;
return 0;
}
58
Entrada/salida por medio de streams (2)
• Sobrecarga de operadores << y >>.
#include
using namespace std;
class Punto {
public:
Punto (float x=0, float y=0) { fX = x; fY = y; }
void PonerX (float x) { fX = x; }
void PonerY (float y) { fY = y; }
float ObtenerX () const { return fX; }
float ObtenerY () const { return fY; }
private:
float fX, fY;
};
istream& operator >> (istream& s, Punto& p)
{
float x, y;
s >> x >> y;
p.PonerX(x);
p.PonerY(y);
return s;
}
ostream& operator << (ostream& s, const Punto& p)
{
s << p.ObtenerX() << ' ' << p.ObtenerY() << endl;
return s;
}
int main ()
{
Punto p;
cout << "Introduce punto: ";
cin >> p;
cout << "Punto introducido: " << p;
return 0;
}
59
Entrada/salida por medio de streams (3)
• Clase ofstream.
• Hereda de ostream y está asociada a un fichero.
• Clase ifstream.
• Hereda de istream y está asociada a un fichero.
#include
#include
using namespace std;
int main ()
{
ofstream fichero("Salida.txt");
string mensaje("Hola y adiós");
double d = 12.3;
Punto punto(2, 3);
fichero << mensaje << endl;
fichero << d << endl;
fichero << punto << endl;
return 0;
}
#include
#include
using namespace std;
int main ()
{
ifstream fichero("Salida.txt");
string mensaje;
double d;
Punto punto;
getline(fichero, mensaje);
fichero >> d;
fichero >> punto;
cout << mensaje << endl;
cout << d << endl;
cout << punto << endl;
return 0;
}
60
Entrada/salida por medio de streams (4)
• Ejemplo: copia de ficheros.
// NOTA ACERCA DE PORTABILIDAD: Este ejemplo debería usar ios_base::out,
// ios_base::trunc, etc. en vez de ios::out, ios::trunc, etc., y hacer un
// #include (que define la clase ios_base). Se ha utilizado la
// segunda opción, dado que compila en casi cualquier compilador
// (ej.: GNU, MVC++), mientras que la segunda (la estándar) no (ej.: GNU).
#include
#include
#include
using namespace std;
int main (int argc, const char* argv[])
{
string nombrePrograma(argv[0]);
if (argc != 3) {
cerr << "Uso: " + nombrePrograma +
" ficheroOrigen ficheroDestino" << endl;
return -1;
}
string nombreFicheroOrigen(argv[1]);
string nombreFicheroDestino(argv[2]);
// Los streams siempre se pueden testear tal y como ilustra este
// ejemplo. Esto es posible, dado que se redefinen los operadores
// void* y !. El resultado es "true" si la operación anterior ha
// tenido éxito, y "false" en caso contrario. Además, se precisa
// abrir los streams en modo binario (por defecto se abren en modo
// texto) para que el código sea portable a sistemas operativos
// que tratan de manera diferente a los ficheros de texto y a los
// binarios (ej.: MS-Windows).
ifstream entrada(nombreFicheroOrigen.c_str(), ios::in | ios::binary);
if (!entrada) {
cerr << "No se puede abrir " + nombreFicheroOrigen << endl;
return -1;
}
61
Entrada/salida por medio de streams (5)
• Ejemplo: copia de ficheros (cont).
char caracter;
// No valdría "entrada >> caracter" porque con ">>" se saltan los
// espacios en blanco, fines de línea, etc. "entrada.get" devuelve
// el stream. En la última iteración, "entrada.get" intenta leer más
// allá del final del flujo, por lo que el operador void* devuelve
// "false" (porque la operación no ha tenido éxito).
while (entrada.get(caracter)) {
salida.put(caracter);
if (!salida) {
cerr << "Error escribiendo en " + nombreFicheroDestino <<
endl;
return -1;
}
}
// Si no se ha terminado de leer la entrada, es que ha habido un
// problema de lectura.
if (!entrada.eof()) {
cerr << "Error leyendo de " + nombreFicheroOrigen << endl;
return -1;
}
return 0;
}
62
Entrada/salida por medio de streams (6)
• Ejemplo: copia de ficheros (versión más eficiente).
// NOTA ACERCA DE PORTABILIDAD: Este ejemplo debería usar ios_base::out,
// ios_base::trunc, etc. en vez de ios::out, ios::trunc, etc., y hacer un
// #include (que define la clase ios_base). Se ha utilizado la
// segunda opción, dado que compila en casi cualquier compilador
// (ej.: GNU, MVC++), mientras que la segunda (la estándar) no (ej.: GNU).
#include
#include
#include
using namespace std;
int main (int argc, const char* argv[])
{
string nombrePrograma(argv[0]);
if (argc != 3) {
cerr << "Uso: " + nombrePrograma +
" ficheroOrigen ficheroDestino" << endl;
return -1;
}
string nombreFicheroOrigen(argv[1]);
string nombreFicheroDestino(argv[2]);
ifstream entrada(nombreFicheroOrigen.c_str(), ios::in | ios::binary);
if (!entrada) {
cerr << "No se puede abrir " + nombreFicheroOrigen << endl;
return -1;
}
ofstream salida(nombreFicheroDestino.c_str(), ios::out | ios::trunc |
ios::binary);
if (!salida) {
cerr << "No se puede escribir en " + nombreFicheroDestino <<
endl;
return -1;
}
63
Entrada/salida por medio de streams (7)
• Ejemplo: copia de ficheros (versión más eficiente, cont).
const unsigned int BUFFER_SIZE = 10000;
char buffer[BUFFER_SIZE];
while (entrada.read(buffer, BUFFER_SIZE)) {
salida.write(buffer, BUFFER_SIZE);
if (!salida) {
cerr << "Error escribiendo en " + nombreFicheroDestino <<
endl;
return -1;
}
}
if (!entrada.eof()) {
cerr << "Error leyendo de " + nombreFicheroOrigen << endl;
return -1;
}
// El anterior bucle termina cuando quedan menos caracteres que los
// que se pretenden leer ("read", al igual que "get", también devuelve
// el stream, y el operador void* devuelve "false" si no se han leído
// tantos caracteres como los especificados). "gcount" devuelve
// el número de caracteres que se han leído en la última operación
// de lectura.
salida.write(buffer, entrada.gcount());
if (!salida) {
cerr << "Error escribiendo en " + nombreFicheroDestino << endl;
return -1;
}
return 0;
}
64
Entrada/salida por medio de streams (y 8)
• Clase ostringstream.
• Hereda de ostream.
• Está asociada a un string.
• Ejemplo.
• Clase istringstream.
• Hereda de istream.
• Está asociada a una cadena de caracteres.
• Ejemplo.
#include
using namespace std;
int main ()
{
ostringstream s;
string mensaje("Hola");
double d = 12.3;
Punto punto(2, 3);
s << mensaje << ' ' << d << ' ';
s << punto;
cout << s.str() << endl;
return 0;
}
#include
using namespace std;
int main ()
{
string cadena("Hola 12.3 2 3");
istringstream s(cadena);
string mensaje;
double d;
Punto punto;
s >> mensaje >> d >> punto;
cout << mensaje << ' ' << d << ' ' << punto
<< endl;
return 0;
}
65
Contenedores (1)
• Contenedores de objetos de cualquier tipo.
• vector, list, map, set, stack, queue, etc.
• Son clases template (ej.: vector).
• Los elementos de un contenedor son copias de los objetos
insertados.
• El contenedor puede copiar elementos usando el constructor copia o
el operador de asignación.
• Por tanto, es conveniente definir ambos métodos para los tipos que
usemos con contenedores, con la semántica apropiada.
• Cuando la copia no es apropiada, el contenedor debería tener
punteros a objetos en vez de los objetos.
• Situación frecuente: se desea recorrer una lista de figuras (heredan
todos de un mismo tipo base y redefinen operaciones) e invocar una
operación polimórfica.
• Usar list y no list
.
66
Contenedores (2)
• Ejemplo de vector.
#include
#include
using namespace std;
int main ()
{
vector v(4);
v[0] = 1;
v[1] = 4;
v[2] = 9;
v[3] = 16; // 1 4 9 16
v.push_back(30); // El tamaño del vector aumenta.
for (int i=0; icout << v[i] << " ";
} // 1 4 9 16 30
cout << endl;
vector::iterator iterador = v.begin();
for (iterador = v.begin(); iterador != v.end(); iterador++) {
cout << *iterador << " ";
}
cout << endl;
// En el caso de "vector", el iterador es de acceso aleatorio,
// es decir, se le pueden sumar y restar enteros (aparte de usar los
// operadores ++, -- y * como en cualquier iterador).
iterador = v.begin() + 2; // Avanza al tercer elemento.
v.insert(iterador, 123); // 1 4 123 9 16 30(inserta antes del iterador)
for (iterador = v.begin(); iterador != v.end(); iterador++) {
*iterador = *iterador + 1;
} // 2 5 124 10 17 31
v.erase(v.begin()); // 5 124 10 17 31
for (iterador = v.begin(); iterador != v.end(); iterador++) {
cout << *iterador << " ";
}
cout << endl;
return 0;
}
67
Contenedores (3)
• Ejemplo de list.
• Mejor que vector cuando las inserciones y borrados son frecuentes.
#include
#include
using namespace std;
int main ()
{
list lista;
lista.insert(lista.end(), 1);
lista.insert(lista.end(), 4);
lista.insert(lista.end(), 9);
lista.insert(lista.end(), 16); // 1 4 9 16
list::iterator iterador = lista.begin();
for (iterador = lista.begin(); iterador != lista.end(); iterador++) {
cout << *iterador << " ";
}
cout << endl;
// En el caso de "list", el iterador es bidreccional, y por tanto,
// no se le pueden sumar y restar enteros, pero sí usar las operaciones
// comunes a cualquier tipo de iterador: ++, -- y *.
iterador = lista.begin();
for (int i=0; i<2; i++) { // Avanza al tercer elemento.
iterador++;
}
lista.insert(iterador, 123); // 1 4 123 9 16(inserta antes del iterador)
for (iterador = lista.begin(); iterador != lista.end(); iterador++) {
*iterador = *iterador + 1;
} // 2 5 124 10 17
lista.erase(lista.begin()); // 5 124 10 17
for (iterador = lista.begin(); iterador != lista.end(); iterador++) {
cout << *iterador << " ";
}
cout << endl;
return 0;
}
68
Contenedores (y 4)
• Ejemplo de map.
#include
#include
#include
using namespace std;
int main ()
{
typedef map MiMapa;
MiMapa mapa;
mapa["Celta"] = 70;
mapa["BarÇa"] = 40;
mapa["Depor"] = 80;
mapa["Compos"] = 75;
MiMapa::iterator i;
for (i = mapa.begin(); i != mapa.end(); i++) {
cout << ((*i).first) << ": " << (*i).second << "; ";
}
cout << endl;
i = mapa.find("Depor");
if (i != mapa.end()) { // Si existe
cout << "Depor: " << mapa["Depor"] << endl;
}
mapa.erase("BarÇa");
for (i = mapa.begin(); i != mapa.end(); i++) {
cout << ((*i).first) << ": " << (*i).second << "; ";
}
cout << endl;
return 0;
}
69
Algoritmos
• Ejemplo de sort.
#include
#include
#include
#include
using namespace std;
int main ()
{
vector years(5);
years[0] = 1990;
years[1] = 1980;
years[2] = 2000;
years[3] = 1970;
years[4] = 1960;
sort(years.begin(), years.end(), greater() );
vector::iterator i;
for (i=years.begin(); i != years.end(); i++) {
cout << *i << endl;
}
return 0;
}
70
Recursos
• Libros de C++.
• S. B. Lippman, J. Lajoie, C++ Primer, 3rd edition, Addison-Wesley, 1998.
• Bjarne Stroustrup. The C++ Programming Language, Longman Higher Education,
2000.
• James O. Coplien. Advanced C++: Programming Styles and Idioms, Addison-
Wesley, 1992.
• S. Meyers, Effective C++, 2nd edition, Addison-Wesley, 1997.
• D. R.Musser, G. J. Derge, A. Saini, A. Stepanov, STL Tutorial and Reference
Guide, 2nd edition, Addison-Wesley, 2001.
• Cetus links.
• Central site: http://www.cetus-links.org
• Mirror en España: http://zeus.uax.es/uax/oop
• Mi página web.
• http://www.tic.udc.es/~fbellas
• Transparencias, ejemplos, enunciado de la práctica, etc.

cursos de programación( lenguaje C++)

Universidad Austral de Chile
Facultad de Cs. de la Ingeniería
Instituto de Informatica
Apuntes de Clases
INFO 161 : El Lenguaje de Programación C++
Prof. Luis Alberto Alvarez González
Valdivia, Marzo de 1999.-
C++ Página i
Tabla de Contenidos
1. INTRODUCCIÓN 1
1.1. LENGUAJES DE COMPUTACIÓN. 1
1.1.1. HISTORIA DE LOS LENGUAJES 2
1.2. PARADIGMAS DE PROGRAMACIÓN 3
1.2.1. PROGRAMACIÓN POR PROCEDIMIENTO O PARADIGMA PROCEDURAL. 4
1.2.2. PROGRAMACIÓN MODULAR. 5
1.2.3. PROGRAMACIÓN ORIENTADA A OBJETOS (POO). 7
2. EL LENGUAJE C++ 9
2.1. INTRODUCCIÓN 9
2.1.1. VARIABLES Y ARITMÉTICA 9
2.1.2. TIPOS FUNDAMENTALES 10
2.1.3. ASIGNACIONES 10
2.1.4. PUNTEROS Y ARREGLOS 11
2.1.5. PRUEBAS Y CICLOS 12
2.2. FUNCIONES 13
2.2.1. PASO POR VALOR Y POR REFERENCIA 15
3. DECLARACIONES Y CONSTANTES 17
3.1. NOMBRES 22
3.2. TIPOS 22
3.2.1. TIPOS FUNDAMENTALES 23
3.2.2. CONVERSIÓN DE TIPOS. 23
3.2.3. TIPOS DERIVADOS. 24
4. PUNTEROS. 33
4.1. EXPRESIONES CON PUNTEROS 34
4.2. ARITMÉTICA DE PUNTEROS. 35
4.3. ARREGLO DE PUNTEROS 40
5. FUNCIONES 44
5.1. FORMA GENERAL DE UNA FUNCIÓN. 44
5.1.1. RETORNO DE VALORES. 46
5.2. REGLAS DE ALCANCE DE FUNCIONES 47
C++ Página ii
5.2.1. VARIABLES LOCALES. 47
5.2.2. PARÁMETROS FORMALES. 48
5.2.3. VARIABLES GLOBALES 49
5.3. ARGUMENTOS DE UNA FUNCIÓN. 50
5.3.1. CREANDO UNA LLAMADA POR REFERENCIA. 51
5.3.2. LLAMADO DE FUNCIONES CON ARREGLOS. 52
5.3.3. FUNCIONES QUE RETORNAN VALORES. 55
5.3.4. RETORNO DE PUNTEROS 56
6. ALGORITMOS DE ORDENAMIENTO 59
6.1. ORDENAMIENTO POR INTERCAMBIO 60
6.2. ORDENAMIENTO POR SELECCIÓN 62
6.3. ORDENAMIENTO POR INSERCIÓN 63
7. ESTRUCTURAS 64
7.1. REFERENCIANDO ELEMENTOS DE UNA ESTRUCTURA. 65
7.2. ARREGLO DE ESTRUCTURAS 66
7.3. PASO DE ESTRUCTURAS A FUNCIONES 77
7.3.1. PASO DE ELEMENTOS 77
7.3.2. PASO DE ESTRUCTURAS ENTERAS A FUNCIONES 78
8. ALGUNAS ESTRUCTURAS DE DATOS 82
8.1. COLAS 83
8.2. COLAS CIRCULARES 86
8.3. STACKS O PILAS. 89
8.4. LISTAS ENLAZADAS 94
BIBLIOGRAFÍA 96
LENGUAJES DE PROGRAMACIÓN
C++ Página 1
1. Introducción
1.1. Lenguajes de Computación.
· Lenguaje. Cualquier notación de representar algoritmos o
estructuras de datos es considerado un lenguaje.
· Pseudolenguajes. Notación informal, pero “entendible”.
· Lenguajes de Especificación. Para especificar como deben
hacerse un determinado sistema. Existen formales. Z,
TROLL, etc. Se estudian en Ingeniería de Software. No
son implementados en computador.
· Lenguajes de Programación de Computadores.
FORTRAN, COBOL, PASCAL, C, ADA, C++, Visual
Basic, etc.
LENGUAJES DE PROGRAMACIÓN
C++ Página 2
1.1.1. Historia de los Lenguajes
1950-55 Computadores
Primitivos.
Lenguaje de Máquina
Lenguaje Ensamblador.
Muy primitivos
números binarios o
hexadecimales.
mnemónicos.
1956-60 FORTRAN
ALGOL
COBOL
LISP
Formula TRANslation
ALGoritms Language
COmmon Bussines
Oriented Language.
LISt Processing.
1961-65 SNOBOL
APL
1966-70 PL/I
SIMULA
BASIC
1971-75 Pascal
1976-80 Ada
C
Prolog
1981. C++, Smalltalk.
1990 Visual Basic, Visual
C++
LENGUAJES DE PROGRAMACIÓN
C++ Página 3
1.2. Paradigmas de Programación
Los paradigma son estilos de programación.
· Programación por Procedimiento.
· Programación Modular
· Programación orientada a listas.
· Programación orientada a objetos.
Paradigma : Estilo o forma de programar. No depende del
lenguaje.
Existen lenguajes más aptos para un determinado paradigma.
Ejemplo,
Pascal para programación por procedimiento.
Lisp y Prolog, para manejo de listas.
Smaltalk, para POO.
Modula, para programación modular.
LENGUAJES DE PROGRAMACIÓN
C++ Página 4
1.2.1. Programación por procedimiento o
paradigma procedural.
¿ Que procedimientos se desean ?
=>
Elegir los mejores algoritmos.
Los lenguajes que apoyan este paradigma proporcionan
recursos para pasar argumentos a las funciones o
procedimientos y que entregan como resultado. Este tipo de
programación parte con FORTRAN, sigue ALGOL y ahora
Pascal y C.
Ejemplo
ordenar_lista(lista)
{
// codigo del procedimiento
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 5
1.2.2. Programación modular.
Modulo. Conjunto de procedimientos.
¿ Que módulos se necesitan ?
=>
Dividir el programa y que los
datos queden ocultos.
Muy común y usado en la construcción de grandes sistemas
de computación. El lenguaje Modula apoya directamente
este estilo de programación.
ejemplo en C. Un ejemplo clásico es el manejo de pilas, lo
que desde un punto modular se transforma en:
1. Ofrecer al usuario una interfaz para la pila. por
ejemplo funciones meter() y sacar()
2. Garantizar que se puede tener acceso a la pila a través
de una interfaz con el usuario.
3. Garantizar la inicialización de la pila
LENGUAJES DE PROGRAMACIÓN
C++ Página 6
ejemplo en C
// declaración de la interfaz para el
// modulo pila de caracteres.
void meter(char);
char sacar();
const int capacidad_pila = 100;
Suponiendo que la interfaz se encuentra en pila.h
#include “pila.h” // emplea la interfaz
static char v(capacidad_pila);// static significa
// global
static char* p=v; // al principio la pila
// esta vacía
void meter(char c)
{
// verifica si la pila tiene espacio y mete c
}
char sacar()
{
// verifica que no este vacia la pila y saca.
}
Note que el usuario, desde fuera del archivo/modulo tiene
acceso a la pila, puesto que las variables se declaran locales
respecto al módulo (static).
LENGUAJES DE PROGRAMACIÓN
C++ Página 7
1.2.3. Programación orientada a objetos (POO).
Supongamos que una figura cualquiera tiene color y esta
compuesta por puntos, de esta forma se define
class figura {
punto centro;
color col;
// ...
public :
punto donde() { return centro; }
void mover(punto hacia) { centro = hacia;
dibujar ();}
virtual void dibujar();
virtual void girar();
//...
};
void se usa con funciones que no retornan valor
virtual, se usa para funciones que virtualmente serán
usadas.
Algunas funciones generales
void girar_toda(figura v[ ], int tam, int angulo)
//
// girar “angulos” grados a todos los primeros “tam”
// miembros del arreglo v.
{
int i=0;
while (iv[i].girar(angulo);
i=i+1;
}
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 8
Como definir una figura específica:
class circulo : public figura {
int radio;
public:
void dibujar(){ /*... */ };
void girar(int) {}
};
Se dice que circulo es una “clase derivada” de la “clase
base” figura. Otra forma es decir que circulo es
una “subclase” y figura es una “superclase”.
¿ Que clases se desean ?
=>
Definir relaciones funciones y
relaciones entre clases
LENGUAJES DE PROGRAMACIÓN
C++ Página 9
2. El lenguaje C++
2.1. Introducción
Una mejor versión de C.
Programa y salidas
ejemplo
#include
int main()
{
cout << “Hola INFO 161 \n”;
}
#include Contiene las funciones de
E/S.
int le dice que la salida de la función main es entero, no
es necesario para main.
2.1.1. variables y aritmética
ejemplo
int pulgada;
LENGUAJES DE PROGRAMACIÓN
C++ Página 10
2.1.2. tipos fundamentales
enteros
char
short
int
long
punto flotante o reales
float
double
long double
operadores aritméticos
+
-
*
/
%
operadores de comparación
= =
!=
<
>
<=
>=
2.1.3. Asignaciones
double d;
int i;
short s;
//...
d=d+i;
i=s*i;
LENGUAJES DE PROGRAMACIÓN
C++ Página 11
2.1.4. Punteros y Arreglos
Ejemplo
char v[10]; // arreglo de 10 caracteres
char *p; // puntero a un caracter
v[10] tiene 10 elementos de v[0] a v[9]
p=&v[3] // apunta al cuarto
elemento
& es “dirección de “
LENGUAJES DE PROGRAMACIÓN
C++ Página 12
2.1.5. Pruebas y ciclos
Se escribirá un programa que convierta pulgadas a
centímetros y viceversa
#include
int main()
{
const float factor=2.54;
float x,pulg,cm;
char car=0;
cout << "ingrese longitud: ";
cin >> x; // leer número
cin >> car; // leer sufijo
if (car == 'p') { //pulgadas
pulg=x;
cm=x*factor;
}
else if (car=='c') { //centímetros
pulg=x/factor;
cm=x;
}
else
pulg=cm=0;
cout << pulg << " pulgadas = " << cm
<< " centímetros\n";
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 13
otra forma es reemplazar el if usando la instrucción case,
es decir :
switch(car) {
case 'p':
pulg=x;
cm=x*factor;
break;
case 'c':
pulg=x/factor;
cm=x;
break;
default:
pulg=cm=0;
break;
}
2.2. Funciones
ejemplo
extern float pot(float,int);
// pot() se define en otro lugar
int main()
{
for(int i=0; i<10; i++) cout <<
pot(2,i)<<‘\n’,
}
aquí el compilador convierte el 2 a float
LENGUAJES DE PROGRAMACIÓN
C++ Página 14
Una forma de definir pot podría ser
float pot(float x, int n)
{
switch(n) {
case 0: return 1;
case 1: return x;
default: return x*pot(x,n-1);
}
}
Se podrían definir dos funciones, una para enteros y otra
para reales con el mismo nombre en cuyo caso el compilador
elige la más apropiada,
ejemplo
int pot(int , int);
double pot(double, double);
//...
x=pot(2,10); // llamar a pot(int,int)
y=pot(2.0,10.0); // llamar a
pot(double,double)
esto se llama sobrecarga.
LENGUAJES DE PROGRAMACIÓN
C++ Página 15
2.2.1. Paso por valor y por referencia
por valor
void inter(int* p, int* q)
{
int t=*p;
*p=*q;
*q=t;
}
el operador * devuelve el valor del objeto al que apunta el
puntero. Para llamarla
void f(int i, int j)
{
inter(&i, &j);
}
Paso por referencia
void inter(int& r1, int& r2)
{
int t=r1;
r1=r2;
r2=t;
}
void g(int i, int j)
{
inter(i,j);
}
el int& significa una referencia a int y en este caso r1 y
r2 son variables sinónimos.
LENGUAJES DE PROGRAMACIÓN
C++ Página 16
Módulos
Un programa en casi simple se compone de varios módulos
que se compilan en forma independiente y la declaración
extern permite referenciar a una función u objeto definido
en otro modulo,
Otra forma es creando archivos encabezados (headers) en
cuyo caso se colocan al principio del programa y son .h
por ejemplo para usar sqrt() se debe incluir math.h
si los archivos a incluir se encuentran en el directorio
estándar se colocan entre paréntices angulares.
Si los archivos no están en el directorio estándar se encierran
entre comillas y eventualmente el path.
LENGUAJES DE PROGRAMACIÓN
C++ Página 17
3. Declaraciones y constantes
Se presentan los tipos fundamentales (char, int, float, etc.) y las
formas básicas de derivar nuevos tipos (funciones, arreglos, punteros
etc.)
Declaraciones.
Antes de usar un nombre se debe declararlo
Ejemplo
char car;
int cuenta = 1;
char* nombre = “Joel”;
struct complejo {float re, im;},
complejo varcom;
extern complejo sqrt(complejo);
extern int número_error;
typedef complejo punto;
float real(complejo* p) {return p->re; };
const double pi=4.1415926535897932385;
struct usuario;
template abs(T,a) {return a<0 ? -a:a;}
enum perro {Bulldog, Chihuahua, Terrier };
Las declaraciones pueden ser definiciones.
Las declaraciones pueden o no definir un valor por ejemplo,
char car;
complejo varcom;
no definen ningún valor
int cuenta = 1;
char* nombre = “Joel”;
struct complejo {float re, im;},
typedef complejo punto;
float real(complejo* p) {return p->re; };
templateabs(T,a) {return a<0 ? -a : a; }
LENGUAJES DE PROGRAMACIÓN
C++ Página 18
enum perro {Bulldog, Chihuahua, Terrier };
Las variables generalmente cambian su valor dentro del programa,
sin embargo otras se definen como constantes, es decir, su valor no
cambiará, por ejemplo,
const double pi=4.1415926535897932385;
Otras declaraciones no son definiciones, por ejemplo :
extern complejo sqrt(complejo);
extern int número_error;
struct usuario;
otras tipos de definiciones,
typedef complejo punto;
Permite que punto sea sinónimo de complejo; es decir
complejo varcom;
es equivalente a:
punto varcom;
templateabs(T,a) {return a<0 ? -a : a; }
permite que a abs se le ingrese el tipo como parámetro.
enum perro {Bulldog, Chihuahua, Terrier };
es otra forma de enumerar entero.
las variables no se pueden definir más de una ves, ejemplo
char car;
char car; // ¡ error !.
es este caso no hay error
extern char car;
extern char car;
LENGUAJES DE PROGRAMACIÓN
C++ Página 19
Porque es una declaración, la definición está en otro archivo.
Si en una declaración no concuerdan los tipo, se produce un error,
por ejemplo,
extern int número_error;
extern short número_error;
Alcance. (Variables Globales y locales)
Una declaración sólo es válida dentro del bloque. ejemplo
int x;
void f()
{
int x;
x=1;
{
int x;
x=2;
}
x=3;
}
int* p=&x;
La primera definición es válida para todo el programa, sin embargo
en los bloque siguientes se redefine x, y se hace válida para cada
bloque.
Se recomienda no usar variables globales u ocultas con nombre
como x o i, porque pueden llevar a confusión.
LENGUAJES DE PROGRAMACIÓN
C++ Página 20
Se puede usar el operador :: para referirse a variables globales.
ejemplo
int x;
void f2()
{
int x=1;
:: x=2;
}
OBSERVACIÓN :No existe la forma de usar un nombre local desde
el exterior,
Un error común es
void f(int x)
{
int x;
}
Tiempo de vida.
Una variable nace cuando se declara y muere cuando se termina el
bloque dentro del cual fue declarado.
Una forma de declarar nombre globales dentro de un bloque es
usando la palabra static y aunque se declare dentro de una
función que se invoca muchas veces, sólo se iniciará una vez.
LENGUAJES DE PROGRAMACIÓN
C++ Página 21
Ejemplo,
int a=1;
void f()
{
int b=1;
static int c=a;
cout << “a = “ << a++
<< “b = “ << b++
<< “c = “ << c++ << ‘\n’;
}
int main()
{
while (a<4) f();
}
produce las salida
a = 1 b =1 c = 1
a = 2 b =1 c = 2
a = 3 b =1 c = 3
LENGUAJES DE PROGRAMACIÓN
C++ Página 22
3.1. Nombres
· El primer caracter debe ser una letra. Se puede usar _.
· No hay restricciones de largo.
· No se pueden usar nombre claves.
Ejemplos de nombre válidos
hola universidad_austral_de_chile
INFO161 _Informatica ___
Ejemplo de nombres no válidos
012 universidad austral
$hola class num.cuenta else
3.2. Tipos
Todo identificador esta asociado a un tipo.
Ejemplo
int numero_error;
float real(complejo* p)
aquí numero_error es un entero (int).
· La función real debe ser invocada pasándole un puntero de
tipo complejo como argumento.
LENGUAJES DE PROGRAMACIÓN
C++ Página 23
· int y complejo son nombres de tipos.
Se puede saber la memoria que ocupa un tipo usando la
función sizeof(tipo)
Ejemplo.
int main() {
cout << “lo que ocupa un entero
son ”<}
3.2.1. Tipos fundamentales
Enteros Reales enteros sin signo enteros con
signo
char float unsigned char signed char
short int double unsigned short int signed short int
int long double unsigned int signed int
long int unsigned long int signed long int
3.2.2. Conversión de tipos.
Ejemplos
float f;
char* p;
//...
long ll=long(p);
int i=int(f);
int i1=256+255;
char car=i1; // car == 255
int i2=car; // i2 == ?
LENGUAJES DE PROGRAMACIÓN
C++ Página 24
3.2.3. Tipos Derivados.
A partir de los tipos fundamentales se puede derivar otros
tipos que son:
* puntero
& referencia
[ ] arreglo
( ) función
Ejemplos,
char* p[20];
void f(int);
i=*p; // usa el objeto al que apunta;
int (*p)[10];// puntero a un arreglo.
Void
Se comporta como un tipo fundamental, pero sirve para
indicar que una función no devuelve valor.
Ejemplos
void f();
void* pv;
LENGUAJES DE PROGRAMACIÓN
C++ Página 25
Punteros.
Se denota por T*, donde T es el tipo. Punteros a arreglos y
funciones con más complicados.
Ejemplos
int* i;
char** aac; // puntero a puntero char
int (*vp)[10]; // puntero a arreglo de 10 int
int (*fp)(char, char*)
// puntero a función que recibe como
// argumentos (char, char*) y devuelve
// un int
La operación fundamental de un puntero es la indirección, es
decir, hace referencia al objeto que apunta. Es un operación
unario.
Ejemplo
char c1=‘a’;
char*p = &c1; //p = dirección de c1
char c2=*p; // c2=c1;
Es posible hacer algunas operaciones con punteros.
Ejemplo
int strlen(char* p) {
int i=0;
while (*p++) i++;
return i;
}
otra forma es,
LENGUAJES DE PROGRAMACIÓN
C++ Página 26
int strlen(const char* p) {
char*q=p;
while (*q++);
return q-p-1;
}
Arreglos
Si T es un tipo T[n] es un arreglo de n elementos del tipo T.
Los elementos se indican de 0 a n-1
Ejemplo
float v[3];
int a[2][5]; //matriz
char* vpc[32];
//arreglo de 32 punteros a caracter
un programa para desplegar el valor entero de las letras
minúsculas podría ser
LENGUAJES DE PROGRAMACIÓN
C++ Página 27
#include
#include
char alfa[]=“abcdefghijklmnopqrestuvwxyz”;
main()
{
int n=strlen(alfa);
for(int i=0; ichar car=alfa[i]
cout<<‘\’’<<<“=“<<<“=0“<<<“=0x“<}
}
salida
‘a’ = 97 = 0141=0x61
.
.
· No es necesario especificar el tamaño del arreglo,
· oct() y hex() están declaradas en iostream.h
· strlen está declarada en string.h
· Un string de caracteres declarado como “abcd” termina
con 0.
otra forma de declarar arreglos es
int v1[]={1,2,3,4};
int v2[]={‘a’,’b’,’c’,’d’};
char v3[]={1,2,3,4};
char v4[ ]={‘a’,’b’,’c’,’d’};
LENGUAJES DE PROGRAMACIÓN
C++ Página 28
· v4 no termina con 0, ¡ cuidado!.
NOTA: Se recomiendo no especificar arreglo de caracteres
de la forma ante indicada.
· La coma (,) es un operador de secuencia,
Luego
int matriz[3,4]; // error
Lo correcto es
int matriz[3] [4];
nótese que se declara un arreglo de 4 elementos y cada
elemento a su vez es un arreglo de 3 elementos.
Ejemplo
char v[2] [5] = {
{ ‘a’,’b’,’c’,’d’,’e’},
{‘0’,’1’,’2’,’3’,’4’}
};
main() {
for(int i=0;i<2;i++) {
for(int j=0;j<5;j++)
cout<<“v[“<<cout<<‘\n’;
}
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 29
Punteros y arreglos
Los punteros y arreglos están íntimamente ligados
Ejemplo
int main() {
char alfa[]=“abcdefghijklmnopqretuvwxyz”;
char* p=alfa;
char car;
while(car=*p++)
cout<<<“=0”<}
También pudo haberse declarado como
char *p=&alfa[0];
Cual es el resultado de
main(){
char vc[10];
int vi[10];
char* pc=vc;
int* pi=vi;
cout<<“char* “<cout<<“int* “<}
que hubiese pasado si se hubiera escrito
cout<<“char* “<cout<<“int* “<LENGUAJES DE PROGRAMACIÓN
C++ Página 30
¡Cuidado no se pueden mezclar operaciones entre
punteros que apuntan a distintos arreglos !!.
ejemplo
int v1[10];
int v2[10];
int i=&v1[5]- &v1[3];
i=&v1[5]- &v2[3];
int* p=v2 + 2;
p=v2+2;
Estructuras
Un arreglo son varios elementos de un mismo tipo
Una estructura son varios elementos de distinto tipo
Ejemplo
struct domicilio {
char* nombre;
char* calle;
int* numero;
int* telefono;
}
Se puede accesar los elementos de un arreglo mediante
el operador punto (.)
Por ejemplo
domicilio la;
la.nombre=“Luis Alvarez”
la.numero=123;
LENGUAJES DE PROGRAMACIÓN
C++ Página 31
También se puede usar la notación para arreglos,
ejemplo
domicilio la={“Luis Alvarez”,”picarte”,3000,212121}
· Lo normal es que se tenga acceso a los elementos de
una estructura usando punteros.
· Los punteros a estructuras usan el operador ->
por ejemplo
void imprimir_domicilio(domicilio* p)
{
cout<nombre<<‘\n’
<calle<<‘\n’
<numero<<‘\n’
<teléfono<<‘\n’
}
Los objetos de una estructura se pueden asignar, pasar
como argumento de una función y devolverlos como
resultado
Ejemplo
domicilio actual;
domicilio fijar_actual(domicilio
siguiente)
{
domicilio previo=actual;
actual=siguiente;
return previo;
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 32
NOTA: Las operaciones == y != no están definidas.
En un arreglo los elementos ocupan posiciones de
memoria contiguas, de igual forma en los arreglos, sin
embargo, podrían haber problemas al tratar de hacer
sizeof().
El nombre de un tipo se puede usar inclusive en la
estructura, por ejemplo
struct dato {
dato* predecesor;
dato* sucesor;
};
No se puede declarar nuevos tipos para estructura sin
haber primero terminado de declarar, ejemplo,
struct dato {
dato predecesor; // ¡¡ error !!
dato sucesor;
};
Dos o mas estructuras se pueden referenciar entre si,
ejemplo
struct lista;
struct dato;
dato* pre;
dato* suc;
lista* miembro_de;
};
struct lista{
dato* cabeza;
};
LENGUAJES DE PROGRAMACIÓN
C++ Página 33
4. Punteros.
· Los punteros son direcciones.
· El puntero es una variable que contiene una dirección de
memoria.
· El puntero es una variable que apunta a otra.
Existen dos operadores especiales que son:
* : indica que la variable es un puntero
& : entrega la dirección del operando.
ejemplo
#include
main() {
int *direcc, cont, val;
cont=100;
direcc=&cont;
val= *direcc;
cout << val;
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 34
Otro ejemplo
#include
main() {
float x=10.1, y;
int *p;
p = &x;
y = *p;
cout << y;
}
4.1. Expresiones con Punteros
Asignación de Punteros.
Ejemplo
#include
main() {
int x;
int *p1, *p2;
p1=&x;
p2=p1;
cout << p2;
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 35
4.2. Aritmética de Punteros.
Los únicos operadores permitidos con punteros son + y -.
Si por ejemplo un puntero p a entero esta apuntado a la
dirección 0xABCDE y se realiza la siguiente operación
p++
quedará apuntando a la dirección ................
También se puede hacer operaciones del tipo p+n, por
ejemplo,
p+9
En este caso apuntará al noveno elemento, tomando como
base p.
Comparación de punteros.
Es posible comparar punteros. Por ejemplo
#include
main() {
int *p1, *p2;
cout << "P1,P2 = " <if (p1else cout << "P2 < P1\n";
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 36
Punteros y Arreglos
Ejemplo 1
#include
main() {
char str[]={'a','b','c','d','e','f','g',0}, *p1;
p1=str;
cout<< str[4]<<'\n';
cout<< *(p1+4);
}
Ejemplo 2
Versión arreglo
#include
#include
#include
main() {
char str[80];
cout <<" ingrese una palabra en mayúsculas ";
gets(str);
cout <<"\n palabra en minúsculas ";
for(int i=0;str[i];i++) cout << char(tolower(str[i]));
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 37
Versión punteros
#include
#include
#include
main() {
char str[80], *p;
cout <<" ingrese una palabra en mayúsculas ";
gets(str);
cout <<"\n palabra en minúsculas ";
p=str;
while(*p) cout << char(tolower(*p++));
}
Indexación de Punteros.
#include
main() {
int num[5]={1,2,3,4,5}, *p;
p=num;
for(int i=0;i<5;i++) cout << p[i]<< '\n';
}
NOTA: P[t] es idéntico a p+t.
LENGUAJES DE PROGRAMACIÓN
C++ Página 38
Un ejemplo de Stack. Crear un stack de tal manera
#include
int stack[50], *p1, *tope;
main() {
int valor;
p1=stack;
tope=stack;
cout<<"ingrese enteros >s que 0 al stack \n";
cout << " para sacarlos ingrese 0\n";
cout << " para terminar ingrese -1 \n";
do{
cin >> valor;
if(valor!=0) {
*p1=valor;
p1++;
}
else {
if(p1==tope)
cout<< "stack vacio";
else {
p1--;
cout<< *p1;
}
}
} while(valor!=-1);
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 39
Punteros y Strings
Un nombre de arreglo sin índice es un puntero al primer
elemento del arreglo.
#include
#include
main() {
char s1[80], s2[80];
char *p1, *p2;
p1=s1;
p2=s2;
cout << "ingrese dos palabras \n";
gets(s1);
gets(s2);
int flag=1;
while(*p1&&flag)
if(*p1-*p2) flag=0;
else {p1++; p2++;};
if(flag) cout << "iguales";
else cout <<"distintos";
}
Obteniendo la Dirección de un Elemento de un Arreglo
Un puntero puede inicializarce con la dirección de cualquier
elemento. Por ejemplo
p=&x[2];
LENGUAJES DE PROGRAMACIÓN
C++ Página 40
Ejemplo
#include
#include
main() {
char str[80], *p;
int i,t;
cout << "ingrese un string : ";
gets(str);
cout << "\n posición inicial y el tamaño ";
cout << "de un sub string (i,t) \n";
cin >> i;
cin >> t;
cout << "\n el resultado es \n";
p=&str[i];
for(int j=0;j}
4.3. Arreglo de Punteros
Se puede usar un arreglo de punteros a indicar otro tipo de
datos. Por ejemplo
int *x[10];
De esta forma se puede asignar una variable a uno de los
elementos de la siguiente forma
x[2]=&var;
Ahora var se puede usar como
*x[2]
LENGUAJES DE PROGRAMACIÓN
C++ Página 41
Ejemplo de arreglo de punteros.
#include
main() {
char *info161[]= {"Cárdenas Luis\n",
"Chávez Pamela\n",
"Coronado Moises\n",
"Díaz Rodrigo\n",
"Gallegos Walkiria\n",
"Kruze Ivan\n",
"Lizama Orlando\n",
"Loaiza Pablo\n",
"López Luis\n",
"López Diego\n"};
int i;
cout << "ingrese numero de lista =";
cin >> i;
cout << info161[i-1];
}
Punteros a Punteros.
Un arreglo de punteros es lo mismo que punteros punteros.
Un puntero a puntero es una forma de indirección múltiple.
LENGUAJES DE PROGRAMACIÓN
C++ Página 42
Indirección simple
Indirección múltiple.
Ejemplo
#include
main() {
int x, *p, **q;
x=10;
p=&x;
q=&p;
cout << **q;
}
Inicialización de Punteros.
¡¡¡ Antes de usar un puntero se debe inicializar. !!!
Después de declarar un puntero, se debe inicializar.
Dirección
Dirección Dirección
Valor
Valor
Puntero
Puntero Puntero
Variable
Variable
LENGUAJES DE PROGRAMACIÓN
C++ Página 43
Ejemplo,
#include
main() {
char *p="Hola. ¿ como estan ?";
while(*p)cout << *p++;
}
Problemas con punteros.
Típico.
(1)
main() {
int x, *p;
x=10;
*p=x;
}
(2)
main() {
int x, *p;
x=10;
p=x;
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 44
5. Funciones
5.1. Forma General de una Función.
Tipo nombre_función(lista de parámetros)
Declaración de parámetros
{
Cuerpo de la función
}
La sentencia return
Usos
· Salir de la función
· retornar valores.
Regreso desde una función.
Hay dos formas:
· Hasta que encuentra el }
· Hasta que encuentra return
LENGUAJES DE PROGRAMACIÓN
C++ Página 45
Ejemplo 1.
void pr_reverse(char *s) {
for(int t=strlen(s)-1;t+1;t--) cout<}
Ejemplo 2.
void potencia(float base, int exponente) {
if(exponente<0) {cout <<"no se calcular";
return ;
}
float i=1;
for(;exponente;exponente--) i=base*i;
cout<<" La respuesta es :"<}
Programas completos.
Programa 1
#include
#include
#include
void pr_reverse(char *s);
main() {
char str[80], *p; p=str;
cout<<"ingrese una frase : "; gets(str);
cout <<'\n';
pr_reverse(p);
}
void pr_reverse(char *s) {
for(int t=strlen(s)-1;t+1;t--) cout<}
LENGUAJES DE PROGRAMACIÓN
C++ Página 46
Programa 2.
#include
void potencia(float base, int exponente);
main() {
float x; int y;
cout<<"ingrese un número : "; cin >> x;
cout<<" ahora su exponente : ";cin >> y;
cout <<'\n';
potencia(x,y);
}
void potencia(float base, int exponente) {
if(exponente<0) {cout <<"no se calcular";
return ;
}
float i=1;
for(;exponente;exponente--) i=base*i;
cout<<" La respuesta es :"<}
5.1.1. Retorno de Valores.
Todas las funciones, excepto las void, retornan un valor.
· Una función puede ser asignada a un valor, por ejemplo
x=abs(y);
· o no ser asignada como swap(x,y);
LENGUAJES DE PROGRAMACIÓN
C++ Página 47
5.2. Reglas de Alcance de Funciones
Hay tres tipos de variables en funciones:
· Variables locales
· Parámetros formales
· Variables Globales.
5.2.1. Variables Locales.
Todas las variables declaradas dentro del bloque de la
función son locales.
Ejemplo
func1() {
int x=10;
}
func2() {
int x=-199;
}
Otro ejemplo
f() {
char ch;
cout<<“ ¿continua (s/n) ? :”;
if(ch==“s”) {
char s[80];
cout<<“ingrese el nombre :”;
gets(s);
almacenar(s);
}
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 48
Ventaja, se reserva memoria sólo si es necesario.
5.2.2. Parámetros Formales.
Si una función usa argumentos, estos deben estar asociados a
variables que acepten estos argumentos. Estas variables son
llamadas parámetros formales.
Los parámetros formales se comportan como variables
locales dentro de la función.
Ejemplo
#include
#include
int esta_en(char *s, char letra);
main() {
char str[80], c, *p; p=str;
cout<<"ingrese una frase : "; gets(str);
cout <<"\n ingrese un caracter :"; cin >> c;
cout << esta_en(p,c);
}
int esta_en(char *s, char letra){
while(*s)
f(*s==letra) return 1;
else s++;
return 0;
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 49
5.2.3. Variables Globales
Las variables globales son vistas en todo el programa y en
cada parte del programa.
Ejemplo
#include
void func1();
void func2();
int conta;
main() {
conta=100;
func1();
}
void func1() {
int temp=conta;
func2();
cout << "conta es " << conta;
}
void func2() {
for(int conta=1;conta<10;conta++)
cout<<".";
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 50
5.3. Argumentos de una función.
Las formas de pasar los argumentos a una función son:
· Llamado por valor, y
· llamado por referencia.
· En el llamado por valor se copia el valor como parámetro.
Por lo tanto los cambios que se hacen a los parámetros de
la función no producen efecto sobre las variables que la
usan.
· En el llamador por referencia se copia una dirección como
parámetro. Dentro de la función, la dirección es usada para
accesar los parámetros actuales. Esto significa que los
cambios que se hagan afectan la variable en la función.
Ejemplo
main() {
int t=10;
cout << sqrt(t)<<“ “<}
sqrt(int x) {
x=x*x;
return (x);
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 51
5.3.1. Creando una Llamada por Referencia.
· En una llamada por referencia se pasa una dirección.
Luego se puede cambiar el valor del argumento.
· Se pueden pasar punteros a una función como si fueran
valores.
Ejemplo swap()
#include
void swap(int *x, int*y);
main() {
int a,b, *pa, *pb;
pa=&a ; pb=&b;
cout<< "ingrese a y b :"; cin>>a; cin>>b;
swap(pa,pb);
cout<<"ahora a y b son :" << a << " y "<}
void swap(int *x, int *y) {
int temp;
temp=*x;
*x=*y;
*y=temp;
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 52
También pudo haberse usado como
int a,b;
cout<< "ingrese a y b :"; cin>>a; cin>>b;
swap(&a,&b);
5.3.2. Llamado de funciones con arreglos.
· Cuando se pasa un arreglo, se pasa sólo su dirección y no
se copia el arreglo completo.
· Esto significa que la declaración de parámetros debe ser
punteros.
· Existen tres formas de parámetros que reciben un puntero
a arreglo:
1.- Se declara como un arreglo, indicando su tamaño.
#include
void display(int num[10]);
main() {
int t[10];
for(int i=0;i<10;i++) t[i]=i;
display(t);
}
void display(int num[10]) {
for(int i=0;i<10;i++) cout<}
LENGUAJES DE PROGRAMACIÓN
C++ Página 53
2.- Se declara el parámetro como un arreglo sin indicar
el tamaño.
#include
void display(int num[],int n);
main() {
int t[10], n=10;
for(int i=0;idisplay(t,n);
}
void display(int num[],int n) {
for(int i=0;i}
3.- Se declara el parámetro como un puntero a un
arreglo.
#include
void display(int *n);
main() {
int t[10], *p;
p=t;
for(int i=0;i<10;i++) t[i]=i;
display(p);
}
void display(int *n) {
for(int i=0;i<10;i++) cout<}
LENGUAJES DE PROGRAMACIÓN
C++ Página 54
Otro Ejemplo
#include
#include
#include
void mayuscula(char *pstring);
main() {
char str[80], *p;
p=str;
cout <<" ingrese una palabra en minusculas ";
gets(str);
mayuscula(p);
}
void mayuscula(char *pstring) {
while(*pstring) cout << char(toupper(*pstring++));
}
Tarea. Construya una función ingr_str(), que funcione
exactamente igual que gets(). Use sólo cin.
LENGUAJES DE PROGRAMACIÓN
C++ Página 55
Argumentos del main()
Para ambientes diferentes a Windows, por ejemplo del tipo
D.O.S o UNIX, es posible ingresar argumentos al main().
Por ejemplo en el Turbo C++, se usan dos argumentos, el
primero un entero que indica el número de argumentos a
ingresar y el segundo en un puntero del tipo caracter a los
argumentos.
5.3.3. Funciones que Retornan Valores.
De debe especificar, cuando una función retorna un tipo de
valor, por ejemplo
#include
float suma(float x, float y);
main() {
float a, b;
cout<<"ingrese dos reales a,b :";cin>>a>>b;
cout<< " la suma es : "<< suma(a,b);
}
float suma(float x, float y) {
return x+y;
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 56
5.3.4. Retorno de Punteros
· Las funciones que retornan punteros son iguales a las
demás funciones.
#include
#include
char *match(char c, char *s);
main() {
char letra, string[80], *p;
cout<<"ingrese una frase "; gets(string);
cout<<"\n ingrese una letra :"; cin>>letra;
p=match(letra,string);
if(*p) {
cout<< "existe la letra a partir de ";
cout<}
else cout<<" no se encuentra ";
}
char *match(char c, char *s) {
int conta=0;
while(c!=s[conta] && s[conta]) conta++;
return &s[conta];
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 57
Sobre carga de funciones
#include
#include
void swap(int *x, int*y);
void swap(float *x, float *y);
main() {
char c;
cout << "intercambia numerso enteros o reales (e/r) ";
cin>>c;
switch(c) {
case 'e' :{
int a,b, *pa, *pb;
pa=&a ; pb=&b;
cout<< "ingrese a y b :"; cin>>a; cin>>b;
swap(pa,pb);
cout<<"ahora a y b son :" << a << " y "<break;
}
case 'r' : {
float a, b, *pa, *pb;
pa=&a ; pb=&b;
cout<< "ingrese a y b :"; cin>>a; cin>>b;
swap(pa,pb);
cout<<"ahora a y b son :" << a << " y "<break;
}
default :
cout <<"se equivoco ";
break;
}
}
void swap(int *x, int *y) {
int temp;
temp=*x;
*x=*y;
*y=temp;
}
void swap(float *x, float *y) {
float temp;
temp=*x;
*x=*y;
*y=temp;
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 58
Archivos de Encabezado o .h (headers)
Corresponden generalmente a un grupo de funciones
similares agrupadas en una función y que se insertan a un
programa cuando se necesitan.
Ejemplo
#include
Tarea. Hacer funciones de encabezado.
Uso de Archivos.
En el archivo stdio.h existen varias funciones asociadas
al manejo de archivos, como fopen, fput, etc.
Tarea : Hacer programas anteriores usando datos en archivo
y de igual forma almacenando resultados en archivos.
LENGUAJES DE PROGRAMACIÓN
C++ Página 59
6. Algoritmos de Ordenamiento
En general existen 3 tipos de algoritmos de
ordenamiento:
· Por intercambio
· Por selección
· Por inserción
Interpretación informal. Supongamos una baraja de naipes:
Por Intercambio: Se colocan las cartas sobre la mesa y se
intercambian hasta ordenarlas.
Por Selección: Se colocan las cartas sobre la mesa y se
selecciona la menor (o mayor), si el orden es ascendente (o
descendente) y de igual modo con las restantes.
Por Inserción: Con la baraja en la mano se saca la primera, la
segunda se coloca bajo (o sobre), si el orden es ascendente
(o descendente). La tercera y las restantes se van insertando
de tal manera que queden ordenadas.
LENGUAJES DE PROGRAMACIÓN
C++ Página 60
6.1. Ordenamiento por Intercambio
El algoritmo mas común es el de burbuja, se llama así
porque en el primer paso el mayor (o menor) se va a un
extremo, si el algoritmo es ascendente (o descendente ).
Se compara el primer elemento con el segundo, si es menor
(ascendente) se intercambian, a continuación se compara el
segundo con el tercero y así sucesivamente.
Cada paso en c++ será
for(int i=0;iif frase(frase[i]>frase[i+1]){
char temp=frase[i];
frase[i]=frase[i+1];
frase[i+1]=temp ;
}
En el peor de los casos se deber repetir n-1 veces el paso
anterior donde n = largo del arreglo. Es decir:
LENGUAJES DE PROGRAMACIÓN
C++ Página 61
for(j=0;jfor(int i=0;iif frase(frase[i]>frase[i+1]){
char temp=frase[i];
frase[i]=frase[i+1];
frase[i+1]=temp ;
}
Sin embargo si los datos están previamente ordenados, no
habrá necesidad de repetir el paso de ordenamiento.
int flag=1;
while flag{
flag=0;
for(int i=0;iif frase(frase[i]>frase[i+1]){
char temp=frase[i];
frase[i]=frase[i+1];
frase[i+1]=temp;
flag=1}
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 62
6.2. Ordenamiento por Selección
El algoritmo mas común elige el menor (o mayor) elemento
si el orden es ascendente (o descendente) y lo coloca en la
primera posición; repite el procedimiento con los restantes.
for(j=0;jfor(int i=j+1;iif frase(frase[j]>frase[i]){
char temp=frase[i];
frase[i]=frase[j];
frase[j]=temp ;
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 63
6.3. Ordenamiento por Inserción
En términos generales en un arreglo, los datos estarán
ordenados hasta el (k-1)-ésimo elemento. De esta forma el késimo
elemento se va a comparar con el anterior ((k-1)-
ésimo), si éste es mayor pasa a ocupar el k-ésimo lugar,
luego se compara con el anterior, nuevamente el mayor se
desplaza y así sucesivamente hasta que se encuentra un
elemento menor o igual y allí se instala.
char temp=frase[i] ;
int i=k-1 ;
while (tempfrase[i+1]=frase[i] ;
i-- ;
}
frase[i+1]=temp ;
< <
>=
Temp
LENGUAJES DE PROGRAMACIÓN
C++ Página 64
7. Estructuras
Colección de variables bajo un mismo nombre.
Ejemplo
struct alumno {
char nombre[30];
char direccion[50];
char ciudad[20];
int cod_area;
long int fono;
};
Termina con (;) porque la definición es una sentencia.
La declaración de una variable se hace de la siguiente forma
struct alumno informatico;
Otra forma de declarar es;
struct alumno {
char nombre[30];
char direccion[50];
char ciudad[20];
int cod_area;
unsigned long int fono;
} informatico, mecanico, electrico;
LENGUAJES DE PROGRAMACIÓN
C++ Página 65
Si no sólo se va a declarar una variable, se puede omitir el
nombre de la estructura,
Ejemplo
struct {
char nombre[30];
char direccion[50];
char ciudad[20];
int cod_area;
long int fono;
} informatico;
El espacio en memoria que ocupará la estructura completa
será:
nombre 30 bytes
direccion 50 bytes
ciudad 20 bytes
cod_area 2 bytes
fono 4 bytes
TOTAL 106 bytes
7.1. Referenciando Elementos de una
estructura.
Se usa el operador punto (.).
Ejemplos
gets(informatico.nombre);
LENGUAJES DE PROGRAMACIÓN
C++ Página 66
gets(ciudad);
if(!strcmp(ciudad,"Valdivia"))
informatico.cod_area=63;
cout<Se pueden accesar los contenidos de los elementos.
Ejemplo
for(int i=0; informatico.nombre[i]; i++)
cout << informatico.nombre[i];
ó
p=informatico.nombre;
while(*p) {
cout << *p;
*p++
}
7.2. Arreglo de Estructuras
Uno de los usos más comunes de estructuras son los arreglos
de estructuras.
Ejemplo
struct alumno informatico[100];
LENGUAJES DE PROGRAMACIÓN
C++ Página 67
Y al igual que un arreglo se puede indicar elemento en
particular.
Ejemplo
cout << informatico[2].fono;
Ejemplo de una lista de direcciones
/* Ejemplo de un lista de direcciones */
#include
#include
#include
#include
#include
#include
#define TAMANO 100
struct alumno {
char nombre[30];
char direccion[50];
char ciudad[20];
int cod_area;
unsigned long int fono;
} informatico[TAMANO];
void ini_lista(),ingresar();
void mostrar(), guardar(), cargar();
char menu();
LENGUAJES DE PROGRAMACIÓN
C++ Página 68
main() {
char elige;
ini_lista();
for(;;){
elige=menu();
switch(elige){
case 'i':ingresar();
break;
case 'm':mostrar();
break;
case 'g':guardar();
break;
case 'c':cargar();
break;
case 's':exit(1);
}
}
}
/* inicializa arreglo */
void ini_lista() {
for(int i=0; i*informatico[i].nombre='\0';
}
/* menu de selección */
char menu() {
char s[80];
do {
cout<<" (I)Ingresar \n";
cout<<" (M)Mostrar \n";
cout<<" (C)Cargar \n";
cout<<" (G)Guardar \n";
cout<<" (S)Salir \n";
gets(s);
}while(!strrchr("imcgs",tolower(*s)));
return char(tolower(*s));
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 69
/* ingreso de nombres a la lista */
void ingresar() {
int i;
for(i=0; iif(!*informatico[i].nombre) break;
if(i==TAMANO) {
cout<<"La lista esta llena \n";
return;
}
cout << " nombre : ";
gets(informatico[i].nombre);
cout << " direccion : ";
gets(informatico[i].direccion);
cout << " ciudad : ";
gets(informatico[i].ciudad);
cout << " código de área : ";
cin >>informatico[i].cod_area;
cout << " teléfono : ";
cin >>informatico[i].fono;
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 70
/* Mostrar la lista */
void mostrar() {
for(int i=0; iif(*informatico[i].nombre) {
cout<<'\n'<cout<<'\n'<cout<<'\n'<cout<<'\n'<cout<<"-"<cout<<'\n';
}
}
}
/* Guardar la lista */
void guardar() {
FILE *fp;
if((fp=fopen("a:datos.txt","a"))==NULL){
cout<<"no se puede abrir el archivo \n";
return;
}
for(int i=0; iif(*informatico[i].nombre)
if(fwrite(&informatico[i],sizeof(struct alumno),1,fp)!=1)
LENGUAJES DE PROGRAMACIÓN
C++ Página 71
cout<<" Error de escritura en el archivo \n";
fclose(fp);
}
/* Cargar el archivo */
void cargar() {
FILE *fp;
if((fp=fopen("a:datos.txt","r"))==NULL){
cout << " No se puede abrir el archivo \n";
return;
}
ini_lista();
for(int i=0; iif(fread(&informatico[i],sizeof(struct alumno),1,fp)!=1){
if(feof(fp)) {
fclose(fp);
return;
};
cout<<"Error de lectura en el archivo \n";
}
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 72
_fstrrchr, strrchr
Finds the last occurrence of c in s
Declaration
char *strrchr(const char *s, int c);
char far * far _fstrrchr(const char far *s, int c);
Remarks
· strrchr scans a string in the reverse direction, looking for a
specific character.
· strrchr finds the last occurrence of the character c in the string s.
· The null-terminator is considered to be part of the string.
Return Value
On success, strrchr returns a pointer to the last occurrence of the
character c.
If c does not occur in s, strrchr returns null.
Portability
Routine DOS UNIX Windows ANSI C C++ only
Near version yes yes yes yes
Far version yes yes
LENGUAJES DE PROGRAMACIÓN
C++ Página 73
fdopen, fopen, freopen, _fsopen
· fdopen associates a stream with a file handle
· fopen opens a stream
· freopen associates a new file with an open stream
· _fsopen opens a stream with file sharing
Declaration
· FILE *fopen(const char *filename, const char *mode);
Remarks
· fopen and _fsopen open a file and associate a stream with it. Both
functions return a pointer that identifies the stream in subsequent
operations.
When a file is opened for update, both input and output can be done
on the resulting stream. However:
· output can't be directly followed by input without an intervening
fseek or rewind
· input can't be directly followed by output without an intervening
fseek or rewind, or an input that encounters end-of-file
Portability
Routine DOS UNIX Windows ANSI C C++ only
fdopen yes yes yes
fopen yes yes yes
freopen yes yes yes yes
_fsopen yes
mode
The mode string used in calls to fopen,, freopen,, and _fsopen (or the
type string used in calls to fdopen) is one of the following values:
String Description
LENGUAJES DE PROGRAMACIÓN
C++ Página 74
r Open for reading only
w Create for writing. If a file by that name already exists, it will
be overwritten.
a Append; open for writing at end of file, or create for writing if
the file does not exist.
r+ Open an existing file for update (reading and writing)
w+ Create a new file for update (reading and writing).
If a file by that name already exists, it will be overwritten.
a+ Open for append; open for update at the end of the file, or
create if the file does not exist.
· To specify that a given file is being opened or created in text
mode, append t to the string (rt, w+t, etc.).
· To specify binary mode, append b to the string (wb, a+b, etc.).
· fopen and _fsopen also allow the t or b to be inserted between the
letter and the + character in the string. For example, rt+ is
equivalent to r+t.
fwrite
Writes to a stream
Declaration
size_t fwrite(const void *ptr, size_t size, size_t n, FILE*stream);
Remarks
fwrite appends a specified number of equal-sized data items to an
output file.
Argument What It Is/Does
ptr Pointer to any object; the data written begins at ptr
LENGUAJES DE PROGRAMACIÓN
C++ Página 75
size Length of each item of data
n Number of data items to be appended
stream Specifies output file
The total number of bytes written is (n * size)
Return Value
· On success, returns the number of items (not bytes) actually
written.
· On error, returns a short count.
Portability
DOS UNIX Windows ANSI C C++ only
yes yes yes yes
feof
Macro that tests if end-of-file has been reached on a stream.
Declaration
int feof(FILE *stream);
Remarks
· feof is a macro that tests the given stream for an end-of-file
indicator.
· Once the indicator is set, read operations on the file return the
indicator until rewind is called, or the file is closed.
· The end-of-file indicator is reset with each input operation.
LENGUAJES DE PROGRAMACIÓN
C++ Página 76
Return Value
· Returns non-zero if an end-of-file indicator was detected on the
last input operation on the named stream.
· Returns 0 if end-of-file has not been reached.
Portability
DOS UNIX Windows ANSI C C++ only
yes yes yes yes
fclose
Closes a stream
Declaration
int fclose(FILE *stream);
Remarks
· fclose closes the named stream.
· All buffers associated with the stream are flushed before closing.
· System-allocated buffers are freed upon closing.
· Buffers assigned with setbuf or setvbuf are not automatically
freed. (But if setvbuf is passed null for the buffer pointer, it will
free it upon close.)
Return Value
· On success, returns 0
· On error, returns EOF
Portability
DOS UNIX Windows ANSI C C++ only
yes yes yes yes
LENGUAJES DE PROGRAMACIÓN
C++ Página 77
7.3. Paso de Estructuras a Funciones
7.3.1. Paso de Elementos
Supongamos
struct alumno{
char nombre[30];
char direccion[50];
char ciudad[20];
int cod_area;
long int fono;
} informatico;
Entonces
funcion1(informatico.cond_area);
funcion2(informatico.fono);
funcion3(&informatico.nombre);
funcion4(&informatico.direccion[2];
Para el caso de arreglos.
funcion1(informatico[5].cod_area);
funcion4(&informatico[4].direccion[2];
LENGUAJES DE PROGRAMACIÓN
C++ Página 78
7.3.2. Paso de Estructuras Enteras a funciones
Ejemplo
funcion(informatico);
La definición será
void funcion(alumno cualquiera) {
...
}
Punteros a Estructuras.
Declaración de una puntero a estructura
alumno *puntero
Existen dos usos para punteros a estructuras
1. Para llamado por referencia a una función
2. Para crear listas enlazadas y otras estructuras
dinámicas.
Se verá el primer caso.
Ejemplo,
struct bal {
float balance;
char nombre[30];
} persona;
bal *p;
LENGUAJES DE PROGRAMACIÓN
C++ Página 79
Así,
p=&persona;
Luego para referenciar algún elemento
(*p).balance
Se usa el paréntesis porque el punto tiene mayor prioridad
que el *.
lo anterior es equivalente a
p->balance;
Ejemplo
#include
struct tm {
int horas;
int minutos;
int segundos;
};
void actualizar(tm *t);
void mostrar(tm *t);
void retardo();
main() {
tm time;
time.horas=0;
LENGUAJES DE PROGRAMACIÓN
C++ Página 80
time.minutos=0;
time.segundos=0;
for(;;) {
actualizar(&time);
mostrar(&time);
}
}
void actualizar(tm *p) {
p->segundos++;
if((p->segundos)==60) {
p->segundos=0;
p->minutos++;
};
if((p->minutos)==60) {
p->minutos=0;
p->horas++;
};
if((p->horas==24)) p->horas=0;
retardo();
}
void mostrar(struct tm *t) {
cout<<"horas :"<horas;
cout<<" minutos :"<minutos;
cout<<" segundos :"<segundos;
cout<<'\n';
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 81
void retardo() {
for(long int i=0;i<5000000;i++);
}
Bit fields
A bit field is an element of a structure that is defined in
terms of bits. Using a special type of struct definition, you
can declare a structure element that can range from 1 to 16
bits in length.
For example, this struct
struct bit_field {
int bit_1 : 1;
int bits_2_to_5 : 4;
int bit_6 : 1;
int bits_7_to_16 : 10;
} bit_var;
corresponds to this collection of bit fields:
16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
LENGUAJES DE PROGRAMACIÓN
C++ Página 82
8. Algunas Estructuras de Datos
Un programa consiste de:
· Algoritmos y,
· Estructuras de datos
· Un buen programa es una mescla de ambos.
· Los lenguajes entregan datos simples como char, int,
long, float, etc.
· Los usuarios pueden organizar los datos en arreglos,
estructuras u otros.
· El nivel final de abstracción trasciende el aspecto físico de
los datos y representa mas bién la forma en que estos van a
ser accesados.
· De acuerdo a esto los datos físicos son accesados por una
“máquina de datos” que controla la forma en que los datos
serán accesados.
· Los tipos de máquinas de datos son:
1. Colas
2. Stacks
3. Listas enlazadas y
4. Árboles binarios
· Cada método provee una solución a una clase de
problemas.
LENGUAJES DE PROGRAMACIÓN
C++ Página 83
· Todos los métodos tienen funciones como guardar y
recuperar un ítem.
8.1. Colas
Un cola es una lista lineal de acceso FIFO (first input first
output) .
Supongamos las funciones guardar() y recuperar().
Un ejemplo se ve en la siguiente tabla.
Acción Contenido de la cola
guardar(A) A
guardar(B) A B
guardar(C) A B C
recuperar()Retorna A B C
guardar(D) B C D
recuperar()Retorna B C D
recuperar()Retorna C D
La función guardar(A) en C++ podría ser
void guardar(char *dato) {
if(gpos==MAX) {
cout<<“La cola está llena \n”;
return;
}
p[gpos]=dato;
gpos++;
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 84
y la función recuperar(),
char *recuperar() {
if(rpos==gpos) {
cout<<“La cola está vacía \n”;
return NULL;
}
rpos++;
return p[rpos-1];
}
El programa completo sería :
#include
#include
#include
#include
#include
#include
#define MAX 100
char *p[MAX], *recupera();
int gpos, rpos;
void ingresar(), guardar(char *dato), listar(),
borrar();
main() {
char s[80];
for(int i=0;igpos=rpos=0;
for(;;) {
cout<<"\n Ingresar, Listar, Borrar o Salir : ";
gets(s);
*s=toupper(*s);
switch(*s) {
case 'I':
ingresar();
break;
LENGUAJES DE PROGRAMACIÓN
C++ Página 85
case 'L':
listar();
break;
case 'B':
borrar();
break;
case 'S':
exit(1);
}
}
}
void ingresar() {
char s[256];
do {
cout<<"ingrese el dato "<gets(s);
if(*s==NULL) break;
p[gpos]=(char *)malloc(strlen(s));
strcpy(p[gpos],s);
if(*s) guardar(p[gpos]);
}while(*s);
}
void listar() {
for(int i=rpos;icout<}
void borrar() {
char *p;
if(!(p=recupera())) return;
cout<<"borrado "<}
void guardar(char *dato) {
if(gpos==MAX) {
cout<<"La cola está llena \n";
return;
}
p[gpos]=dato;
gpos++;
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 86
char *recupera() {
if(rpos==gpos) {
cout<<"La cola está vacía \n";
return NULL;
}
rpos++;
return p[rpos-1];
}
8.2. Colas Circulares
· En el caso de colas simples, cuando gpos llega a MAX,
no se puede seguir ingresando datos.
· Una mejor es que gpos y rpos puedan volver al
principio, esto se conoce como colas circulares.
· En una cola circular las funciones guardar y recuperar
deben ser cambiadas.
void guardar(char dato) {
if(gpos+1==rpos || (gpos+1==MAX && !rpos)) {
cout<<"La cola está llena \n";
return;
}
p[gpos]=dato;
gpos++;
if(gpos==MAX) gpos=0;
}
char recuperar() {
if(rpos==MAX) rpos=0;
if(rpos==gpos) {
cout<<"La cola está vacía \n";
return NULL;
}
rpos++;
return p[rpos-1];
LENGUAJES DE PROGRAMACIÓN
C++ Página 87
}
· Osea, la cola esta llena cuando los índices gpos y rpos
son iguales, de esta manera no pueden comenzar ambos en
cero.
Un ejemplo es:
#include
#include
#include
#define MAX 80
char buf[MAX+1];
int gpos=0;
int rpos=MAX;
void guardar(char dato);
char recuperar();
int main() {
char ch;
buf[80]=NULL;
while (ch!=';') {
if(kbhit()) {
ch=getch();
guardar(ch);
}
}
MAX 0
LENGUAJES DE PROGRAMACIÓN
C++ Página 88
while((ch=recuperar())!=NULL) cout<}
void guardar(char dato) {
if(gpos+1==rpos || (gpos+1==MAX && !rpos)) {
cout<<"\n La cola está llena";
return;
}
buf[gpos]=dato;
gpos++;
if(gpos==MAX) gpos=0;
}
char recuperar() {
if(rpos==MAX) rpos=0;
if(rpos==gpos) {
cout<<"\n La cola está vacía";
return NULL;
}
rpos++;
return buf[rpos-1];
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 89
8.3. Stacks o Pilas.
Los stacks son los opuestos a las colas. Usan acceso LIFO
(Last input, First output). Piense en una pila de platos
sucios, el último que se coloca en la pila es el primero que se
lava.
Por razones históricas a la función guardar() se le llama
push() y a la función recuperar() se le llama pop().
Tabla : Uso de un stack.
Acción Contenido del Stack
push(A) A
push(B) B A
push(C) C B A
pop() Saca C B A
push(F) F B A
pop() Saca F B A
pop() Saca B A
pop() Saca A stack vacío
Las funciones pop() y push() serían:
int stack[MAX];
int tos=0; /* tope del stack */
void push( int i) {
if(tos>=MAX) {
cout<<“La pila está llena \n”;
return;
}
stack[tos]=i;
tos++;
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 90
int pop() {
if(tos==0) {
cout<<“stack vacío \n”;
return;
}
return stack[--tos];
}
Un buen ejemplo de stack es una calculadora con las cuatro
operaciones básica:
Existen dos tipos de calculadores
1. Con notación infix. Por ejemplo si se suman 100 y 200, se
ingresa 100, +, 200 y =.
2. Con notación postfix. Por ejemplo si se sumas 100 y 200,
se ingresa 100, 200 y +.
La notación postfix la usan con frecuencia las calculadoras
Hewlet Packard y operan de la siguiente manera:
· Ingresan los datos a un stack y al presionar un operador
son sacados, el resultado es colocado en el stack.
· Para dar solución a la calculadora, se deberán modificar
las funciones pop() y push().
LENGUAJES DE PROGRAMACIÓN
C++ Página 91
Ejemplo completo.
#include
#include
#include
#define MAX 100
int *p; /* puntero a región de memoria libre */
int *tos; /* apunta al tope del stack */
int *fos; /* apunta al fondo del stack */
void push(int i);
int pop();
main() {
int a,b;
char s[80];
tos=p;
fos=p+MAX-1;
cout<<"Calculadora de cuatro funciones \n";
do {
cout<<": ";
gets(s);
switch(*s) {
case '+':
a=pop();
b=pop();
cout<<" = "<push(a+b);
break;
LENGUAJES DE PROGRAMACIÓN
C++ Página 92
case '-':
a=pop();
b=pop();
cout<<" = "<push(b-a);
break;
case '*':
a=pop();
b=pop();
cout<<" = "<push(a*b);
break;
case '/':
a=pop();
b=pop();
if(a==0) {
cout<<"división por cero \n";
break;
}
cout<<" = "<push(b/a);
break;
case '.': /* muestra el tope del stack */
a=pop();
push(a);
cout<<"El valor del tope es :"<break;
default:
push(atoi(s));
}
}while(*s!='q');
}
void push(int i) {
LENGUAJES DE PROGRAMACIÓN
C++ Página 93
if(p>fos) {
cout<<"La pila está llena \n";
return;
}
*p=i;
p++;
}
int pop() {
p--;
if(pcout<<"stack vacío \n";
return 0;
}
return *p;
}
LENGUAJES DE PROGRAMACIÓN
C++ Página 94
8.4. Listas Enlazadas
Las colas y pilas tienen:
· reglas estrictas para hacer referencias a sus datos.
· Para recuperar un dato se deben “consumir” todos los
anteriores.
· Ocupan regiones contíguas de memoria
· Una lista enlazada puede acceder a datos ubicados en
cualquier parte de la lista sin tener que remover los datos
anteriores.
· Cada ítem de la lista tiene un enlace a la siguiente.
· A diferencia de las colas y pilas, una lista requiere de una
estructura de datos más compleja.
Las lista enlazadas se crean para dos propósitos específicos
que son:
1. Crear un arreglo de tamaño desconocido.
2. Almacenamiento de bases de datos en disco.
Las listas enlazadas pueden ser:
1. Simplemente enlazada. Cada elemento contiene un
enlace al siguiente.
2. Doblemente enlazadas. Cada elemento contiene un
enlaces al siguiente y otro al anterior.
LENGUAJES DE PROGRAMACIÓN
C++ Página 95
Listas simplemente enlazadas
· Requieren que cada item de información contenga un link
al próximo elemento.
· Cada item consiste de una estructura que contiene campos
y un puntero de enlace.
Hay dos formas de construir una lista enlazada que son:
1. Poniendo todo nuevo item al final de la lista.
2. Colocar un nuevo item en un lugar especificado.
Antes de comenzar debemos tener definida una estructura,
Por ejemplo,
struct alumno {
char nombre[30];
char direccion[50];
char ciudad[20];
int cod_area;
unsigned long int fono;
alumno *proximo;
} informatico;
La función guardar_ls() coloca un nuevo elemento al
final
Informático
Link
Informático
Link
Informático
Link
Informático
0
LENGUAJES DE PROGRAMACIÓN
C++ Página 96
void guardar_ls(alumno *i) {
static alumno *ultimo=NULL;
if(!ultimo) ultimo=i;
else ultimo->proximo=i;
i->proximo=NULL;
ultimo=i;
}
Bibliografía
· Sethi, Ravi. : “Lenguajes de Programación. Conceptos y Constructores”. Eddison
Wesley Iberoamericana, S.S. 1992.
· B.W.Kernighan & D.M.Richie : “ El lenguaje de Programación C”, Prentice –Hall
Hispanoamericana S.A.
· Stroustrup, Bjarne. : “ C++ el lenguaje de Programación”, Segunda edición. Eddison
Wesley/Díaz de Santos. 1993.
· Pratt, T. : “Diseño e implementación de lenguajes de Programación”. Prentice Hall.
Segunda edición. 1987.
· Herbert Schildt. : “Using Turbo C”. Borland – Osborne/McGraw – Hill, 1988.
· Herbert Schildt. : “Advanced Turbo C”. Borland – Osborne/McGraw – Hill, 1988.