Introduccion A La Programacion en Lenguaje C++
Introduccion A La Programacion en Lenguaje C++
Introduccion A La Programacion en Lenguaje C++
Facultad de Ingeniera
Ctedra de Computacin Ao 2011 Introduccin al Lenguaje C++
FACULTAD DE INGENIERIA
CTEDRA DE COMPUTACION
MATERIAL DE REFERENCIA
Introduccin a la
Programacin en Lenguaje C++
Segundo Ciclo - Ao 2011
Versin 1.0
Autores:
Introduccin
Este material editado por la ctedra de computacin de la Facultad de Ingeniera de la
Universidad Nacional de Asuncin, contiene los captulos que sern desarrollados en las
distintas secciones durante el ciclo, los autores agradecen el permanente apoyo brindado por
las autoridades de la Facultad de Ingeniera.
INDICE
Cap. 1 Introduccin a las computadoras y a los lenguajes de programacin .. 04
Cap. 7 Funciones 54
Cap. 8 Recursividad .. 58
Cap. 9 Arrays . 60
Cap. 12 Punteros .. 93
Bibliografa . 124
Captulo 1
Una computadora es una mquina electrnica controlada 100% por el ser humano, es decir,
funciona de acuerdo a las instrucciones que el hombre le indica. Al unir ms de una instruccin
en forma lgica y coherente, se crea un programa. Mediante el uso de stos, la computadora
es capaz de recibir, procesar y almacenar informacin. En otras palabras, una computadora no
es til si no tiene un programa que le indique lo que tiene que hacer.
El valor de una computadora radica en la velocidad y precisin con la cual sta ejecuta las
instrucciones. La capacidad de una computadora se hace especficamente para el ambiente en
donde sta va a operar. Una microcomputadora personal, para la oficina o el hogar, una
computadora notebook para cuando uno va de viajes, o una computadora tipo servidor para
controlar grandes cantidades de informacin. Cada una de estas mquinas se ha diseado para
procesar diferentes tipos de informacin y por ello, cada una de ellas tendr un valor de
acuerdo a su capacidad.
Las ventajas de las computadoras se pueden resumir en cuatro puntos: rapidez, precisin,
economa y confiabilidad.
Esta generacin se caracteriza por el uso de tubos al vaco para conducir la electricidad. Las
computadoras de esta generacin eran muy grandes en tamao y lentas al procesar datos. A
causa de la gran cantidad de calor que emitan, se requera que siempre estuvieran en un lugar
con mucha ventilacin. Una vez que las computadoras de esta generacin comenzaban un
proceso, el mismo no poda ser interrumpido hasta que la computadora lo terminar por
completo. Podan realizar 1.000 instrucciones por segundo. Entre las computadoras
pertenecientes a esta generacin estn: la ENIAC y la UNIVAC, siendo estas las primeras
computadoras comerciales.
Imagen 1: ENIAC
Aparecen los transistores, estos reemplazan los tubos al vaco de la primera generacin. Un
transistor representa 40 tubos al vaco y son ms pequeos y durareros. Las computadoras de
esta generacin resultaron ms econmicas ya que consuman menos energa y ocupaban
menos espacio. Su capacidad de memoria se ampla al igual que las unidades de entrada y
salida de informacin. Su velocidad de ejecucin aumenta y adems surgen los primeros
lenguajes de computacin, ejemplo: FORTRAN. Estas computadoras podan realizar 1.000
instrucciones por segundo.
Imagen 2: Transistor
Los circuitos integrados pasan a sustituir los transistores. Un circuito integrado (I.C.) es un
pequeo encapsulado de slice que contiene en su interior miles de transistores. Estos proveen
mayor velocidad, durabilidad y a su vez son ms econmicos que los transistores de la segunda
generacin. Las computadoras de sa generacin son ms pequeas y costosas. Estas
computadoras podan realizar 1.000.000 instrucciones por segundo y podan ejecutar varias
tareas al mismo tiempo.
Los circuitos integrados pasan a integraciones a larga escala, es decir se aumenta la cantidad
de transistores de manera considerable en cada circuito integrado. En esta generacin aparece
el microprocesador. Este a su vez promueve el surgimiento de las microcomputadoras y las
computadoras personales, siendo la primera computadora personal la APPLE II en 1977.
El circuito integrado hace que las computadoras de esta generacin sean mucho ms rpidas.
La eficiencia de stas aumenta considerablemente y se reduce el tamao y el costo de las
mismas.
Imagen 4: Aplle II
Entrada
La unidad de entrada, INPUT, es el trmino que se utiliza para referirse a la entrada de datos al
computador. Entre los medios ms usados para la entrada de datos estn: el teclado, el
mouse.
Proceso
Salida
1.4 Memoria
Read Only Memory (ROM) es la memoria de almacenamiento permanente, slo puede ser
leda. Su contenido no puede ser modificado a menos que se cambien los circuitos dentro de la
misma.
Por hardware se entiende, todos los componentes fsicos de una computadora (teclado,
monitor, impresora, unidad de discos, etc.). El software lo componen aquellos programas que
se utilizan en el computador. Un programa se puede definir como una serie o conjunto de
instrucciones que le indica a la computadora lo que debe hacer.
Operacionalmente, un sistema de computadoras est formado tanto por el equipo fsico como
por los programas. El uno no puede trabajar sin el otro. El equipo fsico es quien dice que
instrucciones pueden ser ejecutadas y los programas le indican al equipo qu hacer mediante
el uso de las instrucciones del microprocesador.
Los programas deben escribirse en un lenguaje que la computadora comprenda. Existen una
variedad de lenguajes para computadoras. Entre los ms importantes estn:
Lenguaje de ensamble lenguaje del mismo nivel que el lenguaje mquina, pero que utiliza
smbolos en lugar de 1 0.
Lenguaje de alto nivel lenguaje que utiliza trminos parecidos al idioma ingls y es usado
comnmente por las personas para resolver un problema. Este es traducido a lenguaje de
mquina por medio de un compilador, de manera tal que la computadora lo comprenda.
Las operaciones que debe realizar el hardware son especificadas por una lista de instrucciones,
llamadas programas o software. Un programa de software es un conjunto de sentencias o
instrucciones al computador. El proceso de escritura o codificacin de un programa se
denomina programacin, y las personas que se especializan en esta actividad se denominan
programadores. Existen dos tipos importantes de software: software del sistema y software de
aplicaciones. Cada tipo realiza una funcin diferente.
El software del sistema es un conjunto generalizado de programas que gestiona los recursos
del computador, tal como el procesador central, enlaces de comunicaciones y dispositivos
perifricos. Los programadores que escriben software del sistema se llaman programadores de
sistemas.
Un sistema operativo trabaja en multiproceso cuando puede enlazar a dos o mas CPU para
trabajar en paralelo en un nico sistema de computadora. El sistema operativo puede asignar
mltiples CPU para ejecutar diferentes instrucciones del mismo programa o de programas
diferentes simultneamente, dividiendo el trabajo entre las diferentes CPU.
Imagen 5: Mquina analtica de babbage como se puede apreciar en el Science Museum de Londres.
Ada Augusta Byron (Lady Ada Lovelace), Condesa de Lovelace, matemtica; colaboro con
Babbage econmicamente y promovi activamente la maquina analtica de Babbage.
Lady Ada Lovelace escribi programas para la maquina analtica, estas primeras instrucciones
hacen de Ada Lovelace la primera programadora de computadoras en el mundo.
Hoy da los lenguajes de programacin de alto nivel son muy numerosos, aunque la prctica
demuestra que su uso mayoritario se reduce a:
Los traductores de lenguaje son programas que traducen a su vez los programas fuente
escritos en lenguajes de alto nivel a cdigo mquina. Los traductores se dividen en
compiladores e intrpretes.
Un compilador es un programa que traduce los programas fuente escritos en lenguaje de alto
nivel a lenguaje mquina. Los programas escritos en lenguaje de alto nivel se llaman
programas fuente y el programa traducido programa objeto o cdigo objeto. El compilador
traduce sentencia a sentencia el programa fuente. Los lenguajes compiladores tpicos son C,
Pascal, FORTRAN y COBOL.
C es una evolucin de lenguajes BCPL (desarrollado por Martin Richards) y B (desarrollado por
Ken Thompson en 1970) para el primitivo UNIX de la computadora DEC PDP-7. C naci
realmente en 1978, con la publicacin de The C Programming lenguaje, de Brian Kerninghan y
Dennis Ritchie (Prentice Hall, 1978). En 1983, el American National Standard Institute (ANSI),
que es una organizacin Americana de estandarizacin, la cual cre un comit (el denominado
X3J11) cuya tarea fundamental consista en hacer una definicin no ambigua del lenguaje C, e
independiente de la mquina. Con esta definicin de C se asegura que cualquier fabricante de
software que vende un compliador ANSI C incorpora todas las caractersticas del lenguaje,
especificadas por el estndar. Esto significa tambin que los programadores que escriban
programas en C estndar tendrn la seguridad de que corrern sus modificaciones en
cualquier sistema que tenga un compilador C.
Hoy, en el siglo XXI, C sigue siendo uno de los lenguajes de programacin ms utilizados en la
industria del software, as como en institutos tecnolgicos, escuelas de ingeniera y
universidades. Prcticamente todos los fabricantes de sistemas operativos, UNIX, Linux,
MacOS, Solaris, soportan diferentes tipos de compiladores de lenguaje C.
Ante la gran difusin y xito que iba obteniendo en el mundo de los programadores, la ATT
comenz a estandarizarlo internamente en 1987. En 1989 se form un comit ANSI (seguido
algn tiempo despus por un comit ISO) para estandarizarlo a nivel americano e
internacional.
El nombre C++ fue propuesto por Rick Mascitti en el ao 1983, cuando el lenguaje fue utilizado
por primera vez fuera de un laboratorio cientfico. Antes se haba usado el nombre "C con
clases". En C++, la expresin "C++" significa "incremento de C" y se refiere a que C++ es una
extensin de C.
Hay que sealar que el C++ ha influido en algunos puntos muy importantes del ANSI C, como
por ejemplo en la forma de declarar las funciones, en los punteros a void, etc. En efecto,
aunque el C++ es posterior al C, sus primeras versiones son anteriores al ANSI C, y algunas de
las mejoras de ste fueron tomadas del C++.
1.12 Ventajas de C
El lenguaje C tiene una gran cantidad de ventajas sobre otros lenguajes, y son, precisamente,
la razn fundamental de que despus de ms de dos dcadas de uso, C siga siendo uno de los
lenguajes ms populares y utilizados en empresas, organizaciones y fbricas de software de
todo el mundo. Algunas ventajas que justifican el uso todava creciente del lenguaje C en la
programacin de computadoras son:
Debido a que existen muchos programas escritos en C, se han creado numerosas bibliotecas C
para programadores profesionales que soportan gran variedad de aplicaciones. Existen
bibliotecas del lenguaje C que soportan aplicaciones de bases de datos, grficos, edicin de
texto, comunicaciones, etc.
Todos los compiladores del lenguaje C++ pueden ejecutar programas escritos en lenguaje C,
preferentemente si cumplen el standar ANSI C.
Captulo 2
Fundamentos de programacin
Un programa de computadora es un conjunto de instrucciones (rdenes dadas a la mquina)
que producirn la ejecucin de una determinada tarea. En esencia, un programa es un medio
para conseguir un fin. El fin ser normalmente definido como la informacin necesaria para
solucionar un problema.
2. Diseo de algoritmos.
- diagrama de flujo;
- pseudocdigo.
5. Documentacin.
6. Mantenimiento.
Los smbolos estndar normalizados por ANSI (abreviatura de American National Standards
Institute) son muy variados, aqu se presentan algunos:
2.2 Pseudocdigo
El pseudocdigo utiliza para representar las acciones sucesivas palabras - similares a sus
homnimas en los lenguajes de programacin -, tales como Inicio, fin, parar, si-entonces-de lo
contrario, mientras etc. La escritura del pseudocdigo exige normalmente la indentacin
(sangra en el margen izquierdo) de diferentes lneas. La representacin en pseudocdigo del
diagrama de flujo del ejemplo anterior sera:
Inicio
fin
El algoritmo comienza con la palabra Inicio y finaliza con la palabra fin. Entre estas palabras,
slo se escribe una instruccin o accin por lnea. La lnea encerrada entre llaves { ... } se
denomina comentario. Es una informacin al lector del programa y no realiza ninguna
instruccin ejecutable; slo tiene efecto de documentacin interna del programa. Algunos
autores suelen utilizar corchetes en lugar de llaves [ ... ].
La principal razn para que las personas aprendan a programar en general y los lenguajes de
programacin en particular es utilizar la computadora como una herramienta para la
resolucin de problemas ayudado por una computadora. La resolucin de un problema consta
de ocho etapas:
3. Prueba de escritorio
4. Codificacin
5. Digitacin
El problema debe estar bien definido si se desea llegar a una solucin satisfactoria para poder
definir con precisin el problema se requiere que las especificaciones de entrada y salida sean
descritas con detalle. Una buena definicin del problema, junto con una descripcin detallada
de las especificaciones de entrada y salida, son los requisitos ms importantes para llegar a
una solucin eficaz.
El anlisis del problema exige una lectura previa del problema a fin de obtener una idea
general de lo que se solicita. La segunda lectura deber servir para responder a las preguntas:
La respuesta a la primera pregunta indicar los resultados deseados o las salidas del problema.
La respuesta a la segunda indicar qu datos se proporcionan o las entradas del problema.
En esta etapa es donde se determinan los pasos o instrucciones que deben llevarse a cabo y el
orden lgico de su ejecucin para dar una eficiente solucin al problema.
Para comprobar que un algoritmo realiza la tarea para la cual fue diseado, debe ejecutarse a
mano. Para esto deben utilizarse datos representativos y anotarse los valores que toman las
variables en cada paso. Esto se conoce como prueba de escritorio (se realiza una prueba para
varios valores de las variables de entrada, se verifica si cumple con los resultados esperados
para todas las situaciones).
2.3.4. - Codificacin
2.3.5. - Almacenamiento
Tras la codificacin del programa las instrucciones se graban en un medio legible para la
computadora; a igual procedimiento se someten los datos (en disquetes, cassettes, cintas,
pendrive, etc.).
En esta etapa la computadora chequea si todas las instrucciones estn escritas correctamente
desde el punto de vista de la sintaxis y gramtica de cada lenguaje y las transcribe, dentro de la
memoria, del lenguaje de alto nivel al lenguaje mquina para obtener el llamado programa
objeto.
El programa objeto es ejecutado por la computadora para llegar a los resultados esperados,
utilizando los dispositivos, unidades y memoria necesaria, segn cada caso o programa.
Obtenidos los resultados se les evala para verificar que sean correctos. En caso contrario, se
revisa en las etapas anteriores para detectar la falla o error, entrar a corregirla y reiniciar
desde este punto los pasos para resolver de nuevo y en forma correcta el problema.
Ejemplo No. 1
Disee un algoritmo que dadas 4 calificaciones (Cal1, Cal2, Cal3, Cal4), calcule la calificacin
promedio y escriba el resultado final junto con un mensaje explicativo.
Diagrama de flujo:
Pseudocdigo:
Inicio
Prom = (Cal1+Cal2+Cal3+Cal4)/4
Fin
Ejemplo No. 2
Solucin:
Anlisis:
Diagrama de flujo:
Captulo 3
Para utilizar algo de una biblioteca en un programa, hay que colocar al principio del programa
una directiva de preprocesamiento seguida de la cabecera de la biblioteca entre ngulos.
La directiva #include indica al compilador que lea el archivo fuente (archivo cabecera o de
inclusin) que viene a continuacin de ella y su contenido lo inserte en la posicin donde se
encuentra dicha directiva. Estas instrucciones son de la forma
#include <nombre_archivo.h>.
La directiva define indica al preprocesador que defina un tem de datos u operacin para el
programa C. Por ejemplo, la directiva #define TAM 10 sustituir el valor 10 cada vez que
TAM aparezca en el programa.
Las declaraciones globales indican al usuario que las constantes o variables as declaradas son
comunes a todas las funciones de su programa. Se sitan antes de la funcin main() que es
la funcin principal. La zona de declaraciones globales puede incluir declaraciones de variables
adems de declaraciones de prototipos de funcin.
Cada programa C++ contiene una funcin main() que es un punto inicial de entrada al
programa. Su estructura es en dos casos usuales:
3.5 Caracteres
Los caracteres que se pueden utilizar para construir elementos del lenguaje (componentes
lxicos o tokens) son:
abcdefghi jklmnopqrstuvwxyz
ABCDEFCHIJKLMNOPQRSTUVWXYZ
0123456789
caracteres espacio (blancos y tabulaciones)
3.6 Comentarios
C++ soporta dos tipos de comentarios. Las lneas de comentarios al estilo C y C ANSI, tal como:
/* Comentario estilo C */
La versin /*...* / se utiliza para comentarios que excedan una lnea de longitud y la versin
//... se utiliza, slo, para comentarios de una lnea. Los comentarios no se anidan.
3.7 Identificadores
Los identificadores (nombres de variables, constantes,...) deben comenzar con una letra del
alfabeto (mayscula o minscula) o con un carcter subrayado, y pueden tener uno o ms
caracteres. Los caracteres segundo y posteriores pueden ser: letras, dgitos o un subrayado, no
permitindose caracteres no alfanumricos ni espacios.
tescprueba // legal
Xl23 // legal
multi_palabra // legal
var25 // legal
l5var // no legal
Una buena prctica de programacin aconseja utilizar identificadores significativos que ayudan
a documentar un programa.
Los diferentes compiladores comerciales de C++ pueden incluir, adems, nuevas palabras
reservadas.
Los tipos de datos simples en C++ se dividen en dos grandes grupos: integrales (datos enteros)
y de coma flotante (datos reales). La Tabla B.5. muestra los diferentes tipos de datos en C++,
enumeraciones (enum),
estructuras (struct),
uniones (union),
arrays,
clases (class y struct),
uniones y enumeraciones annimas,
punteros,
3.11 Constantes
C++ contiene constantes para cada tipo de dato simple (integer, char,...). Las constantes
pueden tener dos sufijos, u, l y f. Que indican tipos unsigned, long y float, respectivamente. As
mismo, se pueden aadir los prefijos o y ox, que representan constantes octales y
hexadecimales.
Las cadenas de caracteres se encierran entre comillas dobles (), y las constantes de un solo
carcter se encierran entre comillas simples ().
En ANSI C, todas las declaraciones de variables y funciones se deben hacer al principio del
programa o funcin. Si se necesitan declaraciones adicionales, el programador debe volver al
bloque de declaraciones al objeto de hacer los ajustes o inserciones necesarios. Todas las
declaraciones deben hacerse antes de que se ejecute cualquier sentencia. As, la declaracin
tpica en C++,
(tipo) expresin
C++ ha modificado la notacin anterior por una notacin funcional como alternativa sintctica:
Ejemplo:
main(){
float x=6,58;
y=int(x);
cout<<x<<y;
}
Captulo 4
Operadores y Expresiones
4.1 Operadores
Aritmticos.
Relacionales y lgicos.
Asignacin.
Acceso a datos y tamao.
Manipulacin de bits.
Varios.
Ejemplo:
Los formatos postfijos se conforman de modo diferente segn la expresin en que se aplica
El operador de asignacin (=) hace que el valor situado a la derecha del operador se adjudique
variable situada a su izquierda. La asignacin suele ocurrir como parte de una expresin de
asignacin y las conversiones se producen implcitamente. La asignacin es solo de derecha a
izquierda.
z = b + 5; //asigne (b + 5) a variable z
Ejemplos:
Expresiones equivalentes
Los operadores lgicos y relacionales son los bloques de construccin bsicos para
constructores de toma de decisin en un lenguaje de programacin. A continuacin se
muestran los operadores lgicos y relacionales:
La sentencia if
Reglas prcticas
Los operadores lgicos y relacionales actan sobre valores lgicos el valor/es puede ser o bien
0, o bien el puntero nulo, o bien 0.0; el valor verdadero puede ser cualquier valor distinto de
cero.
Evaluacin en cortocircuito
C++, igual que C, admite reducir el tiempo de las operaciones lgicas; la evaluacin de las
expresiones se reduce cuando alguno de los operandos toman valores concretos.
1. Operacin lgica AND (&&) Si en la expresin expr1 && expr2, expr1 toma el valor cero y la
operacin lgica AND (y) siempre ser cero, sea cual sea el valor de expr2. En consecuencia,
expx2 no se evaluar nunca.
2. Operacin lgica OR (II). Si expr1 toma un valor distinto de cero, la expresin expr1 || expr2
se evaluar a 1, cualquiera que sea el valor de expr2; en consecuencia, expr2 no se evaluar.
Ejemplo:
El Operador sizeof
El operador sizeof proporciona el tamao en bytes de un tipo de dato o variable sizeof toma el
argumento correspondiente (tipo escalar, array, record, etc.). La sintaxis del operador es:
sizeof (nombre variable | tipo de dato)
Ejemplo:
Ejemplo:
Sobrecarga de operadores
La mayora de los operadores de C++ pueden ser sobrecargados o redefinidos para trabajar
con nuevos tipos de datos
Al contrario que muchos lenguajes, C++ no tiene facilidades incorporadas para manejar
entrada o salida. En su lugar, se manejan por rutinas de bibliotecas. Las clases que C++ utiliza
para entrada y salida se conocen como flujos. Un flujo (stream) es una secuencia de caracteres
junto con una coleccin de rutinas para insertar caracteres en flujos (a pantalla) y extraer
caracteres de un flujo (de teclado).
Salida
El flujo cout es el flujo de salida estndar que corresponde a stdout en C. Este flujo se deriva de
la clase ostream construida en iostream.
cout << i;
#include <iostream>
using namespace std;
main()
{
cout << "Hola Mundo\n";
}
Las salidas en C++ se pueden conectar en cascada, con una facilidad de escritura mayor que en
C.
#include <iostream>
using namespace std;
main()
{
int i;
i = 1099;
cout << El valor de i es << i << \n;
}
#include <iostream>
using namespace std;
main()
{
int x = 45;
double y = 496.125;
char *c = "y es multiplicada por x=";
cout << c << y * x << "\n;
}
Entrada
La entrada se maneja por la clase istream. Existe un objeto predefinido istream, llamado cin,
que se refiere al dispositivo de entrada estndar (el teclado).
El operador que se utiliza para obtener un valor del teclado es el operador de extraccin >>.
Por ejemplo, si i era un objeto int, se escribir:
cin >> i;
#include <iostream>
using namespace std;
main()
{
int i;
cin >> i;
cout << i;
}
#include <iostream>
using namespace std;
main()
{
char c[60];
int x,y;
cin >> c >> x >> y;
cout << c << << x << << y << \n;
}
Manipuladores
Un mtodo fcil de cambiar la anchura del flujo y otras variables de formato es utilizar un
operador especial denominado manipulador. Un manipulador acepta una referencia de flujo
como un argumento y devuelve una referencia al mismo flujo.
El siguiente programa muestra el uso de manipuladores especficamente para conversiones de
nmero (dec, oct, y hex):
#include <iostream>
using namespace std;
main ()
{
int i = 36;
cout << dec << i << oct << i << << hex << i <<
\n;
}
Otro manipulador tpico es endl, que representa al carcter de nueva lnea (salto de lnea), es
equivalente a \ n . El programa anterior se puede escribir tambin as:
#include <iostream>
using namespace std;
main ()
{
int i = 36;
cout << dec << i << oct << i << hex << i << endl;
}
Sentencias
Sentencia de declaracin
nombreTipo identificador, ;
nombreTipo identificador = expresin, ;
const NombreTipo identificador = expresin, ;
char cl;
int p, q = 5, r =a + b; //suponiendo que a y b han sido
declaradas e inicializadas antes
const double IVA = 10.0;
Sentencias de expresin
Las sentencias de expresiones hacen que la expresin sea evaluada. Su formato general es:
expresin;
Ejemplo:
n++;
425; // legal, pero no hace nada
a + b; // legal, pero no hace nada
a < b || b != 0;
a += b = 3; // sentencia compleja
Sentencias compuestas
Una sentencia compuesta es una serie de sentencias encerradas entre llaves. Las sentencias
compuestas tienen el formato:
{
Sentencia;
Sentencia;
Sentencia;
....
}
Un ejemplo es:
int i = 5;
double x = 3.14, y = -4.25;
int j = 4 - i
x = 4.5 * (x - y);
Captulo 5
Los programas definidos hasta este punto se ejecutan de modo secuencial, es decir, una
sentencia despus de otra. La ejecucin comienza con la primera sentencia del programa y
prosigue hasta la ltima sentencia, cada una de las cuales se ejecuta una sola vez. Esta forma
de programacin slo permite resolver programas sencillos. Sin embargo, para la resolucin de
problemas de tipo general se necesita la capacidad de controlar cules son las sentencias que
se ejecutan, y en qu momentos.
Estructuras de Seleccin
Sentencia if
La sentencia if elige entre varias alternativas en base al valor de una o ms expresiones lgicas.
if (condicion1)
{
// Sentencias SI
// Accin 1
}
else if (condicion2)
{
// Sentencias SINO
// Accin 2
}
else
{
//Accin por defecto
}
Sentencia switch
La sentencia switch es una sentencia de C++ que se utiliza para seleccionar una de entre
mltiples alternativas. Esta sentencia es especialmente til cuando la seleccin se basa en el
valor de una variable de un tipo simple o de una expresin de un tipo simple denominada
expresin de control o selector.
switch (numero)
{ case 1:
case 3:
case 5: // Sentencias para los valores 1,3 y 5
break;
case 2: // Sentencias para el valor 2
break;
case 4: // Sentencias para el valor 4
break;
default : // Sentencias EN OTRO CASO
break;
}
Escribir un programa que lea un nmero entero entre 1 y 5. Si el nmero es menor que 1 o
mayor que 5 el programa debe avisar y no hacer nada y en caso de que sea vlido debe
mostrar el nmero romano que lo representa.
#include <iostream>
using namespace std;
const int MIN = 1;
const int MAX = 5;
int main()
{
int num;
cout << "Introduzca un nmero entre " <<MIN<< " y " <<MAX<< ": ";
cin >> num;
if (num<MIN)
{
cout << "Error: El Nmero debe ser mayor que " << MIN << endl;
}
else if (num>MAX)
{
cout << "Error: El Nmero debe ser menor que " << MAX << endl;
}
Else
{
switch(num)
{
case 1: cout << num << " = I " << endl;
break;
case 2: cout << num << " = II " << endl;
break;
case 3: cout << num << " = III " << endl;
break;
case 4: cout << num << " = IV " << endl;
break;
case 5: cout << num << " = V " << endl;
break;
}
}
system("PAUSE"); // Hace una pausa
return 0; // Valor de retorno a S.O.
}
Captulo 6
C++ soporta tres tipos de estructuras de iteracin: los bucles while, do-while y for.
Sentencia while
Un bucle while tiene una condicin de control o expresin lgica (<expres_log>), que ha de ir
encerrada entre parntesis, que controla la secuencia de repeticin. La posicin de esta
condicin es delante del cuerpo del bucle, y por este motivo el bucle while es un bucle
preprueba, ya que se evala la condicin antes de que se ejecute el cuerpo del bucle. El cuerpo
del bucle se ejecuta mientras se cumpla la condicin de control. Si la condicin es falsa,
entonces el cuerpo no se ejecuta.
Hay que hacer notar que si la condicin es cierta inicialmente, la sentencia while no terminar
nunca (bucle infinito) a menos que en el cuerpo de la misma se modifique de alguna forma la
condicin de control del bucle. Una sentencia while se ejecutar cero (condicin de control
inicialmente falsa) o ms veces.
while (<condicion>)
{
<sentencias>;
}
Por ejemplo, si queremos leer una secuencia de enteros y calcular su suma detenindonos
cuando se lea un nmero negativo, podemos hacer el siguiente programa:
#include <iostream>
using namespace std;
int main()
{
int sum, i;
cout << "Introduzca un numero:";
cin >> i; //lectura adelantada
sum = 0;
while (i >= 0)
{
sum = sum + i;
cin >> i; //actualizacin
}
cout << "El resultado es:";
cout << sum << endl;
}
#include <iostream>
using namespace std;
main()
{
int n=20;
int contador;
contador=0; //inicializacin
while (contador < n)
{
cout << " * ";
contador++; //incremento
}
}
Sentencia do-while
En esta sentencia, el cuerpo del bucle se ejecuta hasta que sea falsa la expresin lgica
(<expres_log>)(que ha de ir encerrada entre parntesis). Por tanto, al igual que en el bucle
while el cuerpo del bucle se ejecuta mientras la expresin lgica sea cierta. El bucle do-while
tambin se denomina post-prueba, ya que la expresin lgica se comprueba cada vez despus
de la ejecucin del cuerpo del bucle.
do
{
<sentencias>;
}
while (<condicion>);
Como en el caso anterior, la utilizacin de llaves ({ }) antes y despus del bloque de sentencias
nicamente es obligatorio si el nmero se sentencias del bloque es mayor o igual que dos. Sin
embargo, se aconseja siempre su uso en prevencin de posibles errores.
El cuerpo de una sentencia do-while siempre se ejecuta al menos una vez. Cuando esto deba
ocurrir en un programa (el cuerpo del bucle tenga que ejecutarse una o ms veces), es
conveniente el uso de la sentencia do-while en lugar de la sentencia while. Por ejemplo, en
lugar de escribir:
#include <iostream>
using namespace std;
main()
{
int numero;
cout << "Introduzca un numero entre 1 y 10";
cin >> numero;
while !((numero>=1) && (numero <= 10))
{
cout << "Introduzca un nmero entre 1 y 10");
cin >> numero;
}
}
podemos escribir:
#include <iostream>
using namespace std;
main()
{
int numero;
do
{
cout << "Introduzca un numero entre 1 y 10";
cin >> numero;
}
while ((numero < 1) || (numero > 10));
}
Sentencia for
Existen dos formas de implementar la sentencia for: (i) formato ascendente, en el que la
variable de control se incrementa, y (ii) formato descendente, en el que la variable de control
se decrementa. A continuacin mostramos dos ejemplos de formato ascendente y
descendente:
C++ permite declarar la variable de control de bucle al mismo tiempo que se inicializa, sin
embargo nosotros siempre la declararemos en la zona de declaraciones al principio del
programa.
La expresin de incremento no necesita ser una suma o una resta. Tampoco se requiere que la
inicializacin de una variable de control sea igual a una constante. Se puede inicializar y
modificar una variable de control de bucle en cualquier cantidad que se desee.
Lgicamente, cuando la variable de control no sea de tipo int se tendrn menos garantas de
precisin. Por ejemplo:
#include <iostream>
#include <math.h>
using namespace std;
main()
{
double x, y=3;
for (x = pow (y, 3.0); x > 2.0; x = sqrt (x))
{
cout << "x es ahora igual a "<< x << endl;
}
}
Es necesario incluir la librera <cmath> para poder hacer uso de funciones matemticas. En el
ejemplo anterior: sqrt - raz cuadrada y pow - potencia.
Ejemplo:
#include <iostream>
using namespace std;
main()
{
int i, limite =1;
Este ejemplo produce una secuencia infinita de enteros ya que en cada iteracin, la expresin
(limite++) incrementa limite en 1, antes de que i++ incremente a i. A consecuencia de esto, la
condicin del bucle (i <= limite) siempre es cierta.
(2) Se ha de tener cuidado a la hora se situar el punto y coma (;) despus del parntesis final
del bucle for. Por ejemplo el bucle:
#include <iostream>
using namespace std;
main()
{
int i;
for (i = 1; i <= 10; i++); // Atencin al ;
{
cout << "Elementos de Programacin" << endl;
}
}
#include <iostream>
using namespace std;
main()
{
for (; ;)
{
cout << "Siempre igual" << endl;
}
}
Si antes de la ejecucin del bucle se puede conocer el nmero de veces que se ejecutar
ste, es mejor utilizar una sentencia for.
No se permite el uso de las sentencias break O continue en un bucle (for, do-while o while)
Captulo 7
En C++ no hay diferencias entre procedimientos y funciones: todo son funciones, con la
diferencia de que un procedimiento es una funcin que no devuelve nada (void). Tanto
procedimientos como funciones, deben ser declarados antes de poder ser usados. Esto es
posible de dos formas: indicando su cabecera (nombre, parmetros y tipo de retorno) despus
de la zona de constantes y antes del programa principal, o bien escribir el procedimiento o la
funcin entera en dicha zona. Nosotros recomendamos la primera opcin, ya que evita
problemas de orden de implementacin para solucionar problemas de mbito. Mientras que
un procedimiento ejecuta un grupo de sentencias, una funcin adems devuelve un valor al
punto donde se llam. Una llamada a una funcin puede aparecer como operando de alguna
expresin. El valor de la funcin se usa, por tanto, para calcular el valor total de la expresin.
Obsrvese que el tipo del resultado que devolver la funcin debe de aparecer declarado en la
cabecera sustituyendo a la palabra void que identifica a un procedimiento. En este sentido, en
C++, puede verse a un procedimiento como un tipo especial de funcin que devuelve un valor
void (nulo).
Sintaxis de un Funcin:
Implementacin:
<tipo> <identificador> ( <parmetros> )
{
<sentencias>
return <valor>;
}
Ejemplo:
int mi_funcion( int x)
{
return 0;
}
A diferencia del paso por valor, el paso por referencia permite que la funcin invocada
modifique el valor original de las variables usadas como argumentos.
En C++, el paso de parmetros por referencia se realiza creando un alias del identificador de la
variable que forma el parmetro actual,
#include <iostream>
using namespace std;
main()
{ int i=3, j=50;
cout>>i>>i>>j>>j;
intercambio(&i, &j);
cout>>i>>i>>j>>j;
return 0;
}
void intercambio(int* a, int* b)
{ int aux = *a;
*a = *b;
*b = aux;
}
Ambito (alcance)
El mbito es una zona del programa en el cual una variable es visible o en pocas palabras
puede ser utilizada.
Programa
Archivo fuente
Funcin
Bloque
Para el acceso a las variables definidas en los mbitos, se utiliza el operador de mbito, dado
que en C++ existen mltiples espacios de nombres. ste operador debe debe su nombre al
hecho de que sirve como puente o camino para acceder a objetos que momentneamente
estn fuera de mbito.
include<iostream>
int x = 2; // Variable global...
main() {
int x = 3; // Variable local
std::cout << "X = "<< x << std::endl; // L.5: x local
std::cout << "X = "<< ::x << std::endl; // L.6: x global
}
#include<iostream>
using namespaces std;
int x = 2; // Variable global...
main() {
int x = 3; // Variable local
cout << "X = "<< x << endl; // L.5: x local
cout << "X = "<< ::x << endl; // L.6: x global
}
Captulo 8
Recursividad
No todas la funciones pueden llamarse a si mismas, sino que deben estar diseadas
especialmente para que sean recursivas, de otro modo podran conducir a bucles infinitos, o a
que el programa termine inadecuadamente.
C++ permite la recursividad. Cada vez que se llama a una funcin, se crea un juego de variables
locales, de este modo, si la funcin hace una llamada a si misma, se guardan sus variables y
parmetros, usando la pila, y la nueva instancia de la funcin trabajar con su propia copia de
las variables locales. Cuando esta segunda instancia de la funcin retorna, recupera las
variables y los parmetros de la pila y continua la ejecucin en el punto en que haba sido
llamada.
Por ejemplo:
Prodramos crear una funcin recursiva para calcular el factorial de un nmero entero.
El factorial se simboliza como n!, se lee como "n factorial", y la definicin es:
El factorial de cero es 1.
De modo que una funcin bien hecha para clculo de factoriales debera incluir un control para
esos casos:
1a Instancia
n=4
n>1
2a Instancia
n>1
3a Instancia
n>1
4a Instancia
n == 1 retorna 1
3a Instancia
2a instancia
1a instancia
Valor de retorno 24
Aunque la funcin factorial es un buen ejemplo para demostrar cmo funciona una funcin
recursiva, la recursividad no es un buen modo de resolver esta funcin, que sera ms sencilla y
rpida con un simple bucle for.
Captulo 9
Arrays
Un arreglo o array (en ingls) es una coleccin de variables relacionadas a las que se hace
referencia por medio de un nombre comn. Otra definicin vlida es que un arreglo es un
conjunto de datos que se almacenan en memoria de manera contigua con el mismo nombre y
para diferenciar los elementos de un arreglo se utiliza un ndice. En el lenguaje C++ un arreglo
se le conoce como un tipo de dato compuesto.
Array es un trmino del Ingls que no se suele traducir. El trmino arreglo no es en realidad
una traduccin, sino un anglicismo (ms bien, un trmino que no existe en espaol).
Podramos traducir array como coleccin, seleccin, o tal vez mejor, como formacin. En este
curso, de todos modos, usaremos el trmino array.
Sintaxis:
<tipo> <identificador>[<nm_elemen>][[<nm_elemen>]...];
Un detalle muy importante es que los valores para el nmero de elementos deben ser
constantes enteras.
Se pueden usar tantas dimensiones (ndices) como queramos, el lmite lo impone slo la
cantidad de memoria disponible. Cuando slo se usa un ndice se suele hablar de vectores,
cuando se usan dos, de matrices.
C++ no verifica el mbito de los ndices. Para poder hacerlo, el compilador tendra que agregar
cdigo, ya que los ndices pueden ser variables, su valor debe ser verificado durante la
ejecucin, no durante la compilacin. Esto est en contra de la filosofa de C++ de crear
programas compactos y rpidos. As que es tarea nuestra asegurarnos de que los ndices estn
dentro de los mrgenes correctos.
Ejemplos:
En estos casos la dimensin que queda indefinida se calcula a partir del nmero de elementos
en la lista de valores iniciales. El compilador sabe contar y puede calcular el tamao necesario
de la dimensin para contener el nmero de elementos especificados.
En el caso 3, ser 4.
Ya se ha visto que se puede usar el operador de asignacin con arrays, el otro operador que
tiene sentido con los arrays es sizeof.
Aplicado a un array, el operador sizeof devuelve el tamao de todo el array en bytes. Se Puede
obtener el nmero de elementos, de ser necesario, dividiendo ese valor entre el tamao de
uno de los elementos.
int main()
{
int array[231];
int nElementos;
nElementos = sizeof(array)/sizeof(int);
nElementos = sizeof(array)/sizeof(array[0]);
return 0;
}
Las dos formas son vlidas, pero la segunda es, tal vez, ms general.
La utilidad de esta tcnica es, como mucho, limitada. Desde el momento en que se deben usar
constantes al declarar los arrays, su tamao es siempre conocido, y por lo tanto, su clculo es
predecible.
float arreglo[6]
Un elemento del arreglo se accede indexando el arreglo por medio de un nmero del
elemento. En C++ todos los arreglos empiezan en 0, esto quiere decir que si se desea acceder
al primer elemento del arreglo se debe usar el ndice igual a 0. Para indexar un arreglo se
especifica el ndice del elemento que interesa dentro de un corchete, ejemplo;
valor = arreglo[1];
Los arreglos empiezan en 0, de manera que el ndice 1 se refiere al segundo elemento. Para
asignar el valor a un elemento de un arreglo, es necesario colocar el elemento en el lado
izquierdo de una sentencia de asignacin.
mi_arreglo[0] = 100;
C++ almacena arreglos de una sola dimensin en una localizacin de memoria contigua con el
primer elemento en la posicin ms baja. De esta manera, mi_arreglo[0] es adyacente a
mi_arreglo[1], que es adyacente a mi_arreglo[2] y as sucesivamente.
Es vlido utilizar el valor de un elemento de un arreglo donde quiera que uno usara una
variable sencilla o una constante.
Ejemplo:
Cargar el arreglo sqrs con los cuadrados de los nmeros del 1 al 10 y luego visualizarlos.
Matriz bidimensional
En la siguiente tabla se muestra cual sera la forma y los elementos de matriz[4][5], (array de
tamao 45 con el nombre de variable matriz). Vase que el primer elemento del array
bidimensional es el matriz[0][0], el siguiente sera el matriz[0][1], y as, hasta llegar al elemento
matriz[3][4]:
Matriz bidimensional
ndice de columna
Elemento en
0 1 2 3 4
0 matriz [0][0] matriz [0][1] matriz [0][2] matriz [0][3] matriz [0][4]
1 matriz [1][0] matriz [1][1] matriz [1][2] matriz [1][3] matriz [0][4]
ndice de fila
2 matriz [2][0] matriz [2][1] matriz [2][2] matriz [2][3] matriz [0][4]
3 matriz [3][0] matriz [3][1] matriz [3][2] matriz [3][3] matriz [0][4]
Con el fin de leer o escribir sobre cada uno de los componentes de una matriz se deben crear
dos ciclos de iteracin. Ejemplo:
#include <iostream>
using namespace std;
main()
{
int matriz[4][5], i , j;
for (i=0 ; i<4 ; i++)
{
for (j=0 ; j<5 ; j++)
{
matriz[i][j] = i + j ;
cout<<matriz[i][j]<<" ";
}
cout<<endl;
}
system("pause");
}
En este caso se utilizan dos variables, una para iterar sobre las filas i y otra para iterar sobre
las columnas j de la matriz.
Por otra parte, en lenguaje C++ las matrices se almacenan en memoria "por filas", es decir, los
elementos de la fila primera (de ndice 0) van consecutivos y cuando acaba el ltimo de la
primera fila empieza a almacenarse el primero de la segunda, y as sucesivamente hasta llegar
a la ltima fila.
Una matriz bidimensional (AxB) representara solo una cara del cubo mgico.
Para arreglos bidimensionales, basta con recordar que primero estn los elementos de la fila 0,
enseguida los de la fila 1, y as sucesivamente. La inicializacin:
Matrices multidimensionales:
Sintaxis:
Ejemplo:
int matriz[4][4][4];
Ejemplo:
#include <iostream>
using namespace std;
main()
{
int matriz[6][4][4], i, j, k;
for (i=0;i<6;i++)
{
for(j=0;j<4;j++)
{
for (k=0;k<4;k++)
{
matriz[i][j][k] = i+j+k;
cout<<matriz[i][j][k]<<" ";
}
cout<<endl;
}
cout<<endl;
}
system("pause");
}
Una matriz bidimensional (AxB) representara solo una cara del cubo mgico, una matriz de
tres dimensiones (AxBxC) representara todo el cubo mgico.
#include <iostream>
using namespace std;
int matriz[3][5];
int n,m;
main()
{
for (n=0;n<3;n++)
{
for (m=0;m<5;m++)
{
matriz[n][m]=(n+1)*(m+1);
}
}
for (n=0;n<3;n++)
{
for (m=0;m<5;m++)
{
cout<<matriz[n][m]<<" ";
}
cout<<endl;
}
system("pause");
}
Captulo 10
Conceptos Preliminares.
Antes de comenzar a ver cada algoritmo vamos a ponernos de acuerdo en algunos conceptos,
para que no haya confusiones:
Clave: La parte de un registro por la cual se ordena la lista. Por ejemplo, una lista de registros
con campos nombre, direccion y telefono se puede ordenar alfabticamente de acuerdo a la
clave nombre. En este caso los campos direccion y telefono no se toman en cuenta en el
ordenamiento.
Registro: Un grupo de datos que forman la lista. Pueden ser datos atmicos (enteros,
caracteres, reales, etc.) o grupos de ellos, que en C equivalen a las estructuras.
Cuando se estudian algoritmos de todo tipo, no slo de ordenamiento, es bueno tener una
forma de evaluarlos antes de pasarlos a cdigo, que se base en aspectos independientes de la
plataforma o el lenguaje. De esta manera podremos decidir cul se adapta mejor a los
requerimientos de nuestro programa. As que veamos estos aspectos:
Estabilidad: Cmo se comporta con registros que tienen claves iguales. Algunos algoritmos
mantienen el orden relativo entre stos y otros no. Veamos un ejemplo. Si tenemos la
siguiente lista de datos (nombre, edad): "Pedro 19, Juan 23, Felipe 15, Marcela 20, Juan 18,
Marcela 17", y la ordenamos alfabticamente por el nombre con un algoritmo estable
quedara as: "Felipe 15, Marcela 20, Marcela 17, Juan 23, Juan 18, Pedro 19". Un algoritmo no
estable podra dejar a Juan 18 antes de Juan 23, o a Marcela 20 despus de Marcela 17.
Tiempo de ejecucin: La complejidad del algoritmo, que no tiene que ver con dificultad, sino
con rendimiento. Es una funcin independiente de la implementacin. Te la voy a explicar
brevemente: tenemos que identificar una operacin fundamental que realice nuestro
algoritmo, que en este caso es comparar. Ahora contamos cuntas veces el algoritmo necesita
comparar. Si en una lista de n trminos realiza n comparaciones la complejidad es O(n). (En
realidad es un poco ms complicado que eso, pero lo vamos a hacer as: recuerda que dije que
te iba a explicar brevemente). Algunos ejemplos de complejidades comunes son:
Un algoritmo de complejidad O(n) es ms rpido que uno de complejidad O(n2). Otro aspecto
a considerar es la diferencia entre el peor y el mejor caso. Cada algoritmo se comporta de
modo diferente de acuerdo a cmo se le entregue la informacin; por eso es conveniente
estudiar su comportamiento en casos extremos, como cuando los datos estn prcticamente
ordenados o muy desordenados.
Algoritmos ms comunes.
Descripcin: Este probablemente sea el algoritmo ms sencillo. Ideal para empezar. Consiste
en ciclar repetidamente a travs de la lista, comparando elementos adyacentes de dos en dos.
Si un elemento es mayor que el que est en la siguiente posicin se intercambian.
Tabla de variables
Nombre Tipo Uso
lista Cualquiera Lista a ordenar
TAM Constante entera Tamao de la lista
i Entero Contador
j Entero Contador
temp El mismo que los elementos de la lista Para realizar los intercambios
Sea la lista:
4-3-5-2-1
Existen 5 elementos. Es decir, TAM toma el valor 5. Inicialmente se comparan el primero con el
segundo elemento. 4 es mayor que 3, as que son intercambiados. Ahora se tiene la lista:
3-4-5-2-1
Se compara el segundo con el tercero: 4 es menor que 5, as que no se hace nada. Se continua
con el tercero y el cuarto: 5 es mayor que 2, as que son intercambiados. Ahora se tiene la lista:
3-4-2-5-1
3-4-2-1-5
3-2-1-4-5
2-1-3-4-5
1-2-3-45
Optimizando.
Se pueden realizar algunos cambios en este algoritmo que pueden mejorar su rendimiento.
Puede ser que los datos queden ordenados antes de completar el ciclo externo. Podemos
modificar el algoritmo para que verifique si se han realizado intercambios. Si no se han hecho
entonces terminamos con la ejecucin, pues eso significa que los datos ya estn ordenados.
Estabilidad: Este algoritmo nunca intercambia registros con claves iguales. Por lo tanto es
estable.
Requerimientos de Memoria: Este algoritmo slo requiere de una variable adicional para
realizar los intercambios.
Tiempo de Ejecucin: El ciclo interno se ejecuta n veces para una lista de n elementos. El ciclo
externo tambin se ejecuta n veces. Es decir, la complejidad es n * n = O(n2). El
comportamiento del caso promedio depende del orden de entrada de los datos, pero es slo
un poco mejor que el del peor caso, y sigue siendo O(n2).
Ventajas:
Fcil implementacin.
Desventajas:
Muy lento.
Este algoritmo es uno de los ms pobres en rendimiento. No se recomienda su uso. Est aqu
con fines acadmicos.
Descripcin.
Tabla de variables
i Entero Contador
temp El mismo que los elementos de la lista Para realizar los intercambios
Observacin: Menor(lista, TAM, i) es una funcin que busca el menor elemento entre las
posiciones i y TAM-1. La bsqueda es lineal (elemento por elemento).
Un ejemplo.
4-3-5-2-1
1-3-5-2-4
1-2-5-3-4
Buscar el menor elemento entre la tercera posicin y la ltima. Es el 3, que se intercambia con
el 5:
1-2-3-5-4
1-2-3-4-5
Estabilidad: No es estable.
Tiempo de Ejecucin: El ciclo externo se ejecuta n veces para una lista de n elementos. Cada
bsqueda requiere comparar todos los elementos no clasificados. Luego la complejidad es
O(n2). Este algoritmo presenta un comportamiento constante independiente del orden de los
datos. Luego la complejidad promedio es tambin O(n2).
Ventajas:
Fcil implementacin.
Desventajas:
Lento.
Este es un algoritmo lento. No obstante, ya que slo realiza un intercambio en cada ejecucin
del ciclo externo, puede ser una buena opcin para listas con registros grandes y claves
pequeas.
Descripcin.
Este algoritmo tambin es bastante sencillo. Es el utilizado por cualquier jugador de cartas al
recibirlas y empezar su ordenacin: Se toma la primera y se la coloca en la mano. Luego se
toma la segunda y se la compara con la que ya est en la mano, si es mayor, se la coloca a la
derecha, y si es menor a la izquierda. Despus se toma la tercera y se la compara con las que
ya se tienen en la mano, desplazndola hasta que quede en su posicin final. Contino
haciendo esto, insertando cada carta en la posicin que le corresponde, hasta que las tengo
todas en orden.
Para simular esto en un programa necesitamos tener en cuenta algo: no podemos desplazar
los elementos as como as o se perder un elemento. Lo que hacemos es guardar una copia
del elemento actual (que sera como la carta que tomamos) y desplazar todos los elementos
mayores hacia la derecha. Luego copiamos el elemento guardado en la posicin del ltimo
elemento que se desplaz.
Tabla de variables
i Entero Contador
j Entero Contador
temp El mismo que los elementos de la lista Para realizar los intercambios
Nota: Observa que en cada iteracin del ciclo externo los elementos 0 a i forman una lista
ordenada.
Un ejemplo
Sea la lista:
4-3-5-2-1
temp toma el valor del segundo elemento, 3. La primera carta es el 4. Ahora se compara: 3
es menor que 4. Luego se desplaza el 4 una posicin a la derecha y despus se copia el 3 en el
lugar ocupado anteriormente por el 4.
4-4-5-2-1
3-4-5-2-1
3-4-5-5-1
3-4-4-5-1
3-3-4-5-1
2-3-4-5-1
El ltimo elemento a ordenar es el 1. Cinco es menor que 1, as que se lo desplaza una posicin
a la derecha:
2-3-4-5-5
2-3-4-4-5
2-3-3-4-5
2-2-3-4-5
1-2-3-4-5
Estabilidad: Este algoritmo nunca intercambia registros con claves iguales. Por lo tanto es
estable.
Requerimientos de Memoria: Solo una variable adicional para realizar los intercambios.
Tiempo de Ejecucin: Para una lista de n elementos el ciclo externo se ejecuta n-1 veces. El
ciclo interno se ejecuta como mximo una vez en la primera iteracin, 2 veces en la segunda, 3
veces en la tercera, etc. Esto produce una complejidad O(n2).
Ventajas:
Fcil implementacin.
Desventajas:
Lento.
Este tambin es un algoritmo lento, pero puede ser de utilidad para listas que estn ordenadas
o semi-ordenadas, porque en ese caso realiza muy pocos desplazamientos.
Descripcin.
Esta es probablemente la tcnica ms rpida conocida. Fue desarrollada por C.A.R. Hoare en
1960. El algoritmo original es recursivo, pero se utilizan versiones iterativas para mejorar su
rendimiento (los algoritmos recursivos son en general ms lentos que los iterativos, y
consumen ms recursos). El algoritmo fundamental es el siguiente:
Se acomodan los elementos de la lista a cada lado del elemento de divisin, de manera que a
un lado queden todos los menores que l y al otro los mayores (explicado ms abajo tambin).
En este momento el elemento de divisin separa la lista en dos sub-listas (de ah su nombre).
Realizas esto de forma recursiva para cada sub-lista mientras stas tengan un largo mayor que
1 (uno) . Una vez terminado este proceso todos los elementos estarn ordenados.
Una idea preliminar para ubicar el elemento de divisin en su posicin final sera contar la
cantidad de elementos menores y colocarlo un lugar ms arriba. Pero luego habra que mover
todos estos elementos a la izquierda del elemento, para que se cumpla la condicin y pueda
aplicarse la recursividad. Reflexionando un poco ms se obtiene un procedimiento mucho ms
efectivo. Se utilizan dos ndices: i, al contador por la izquierda, y j, al contador por la derecha.
El algoritmo es ste:
Se recorres la lista simultneamente con i y j: por la izquierda con i (desde el primer elemento),
y por la derecha con j (desde el ltimo elemento).
Cuando lista[i] sea mayor que el elemento de divisin y lista[j] sea menor se los intercambia.
El punto en que se cruzan los ndices es la posicin adecuada para colocar el elemento de
divisin, porque es sabido que a un lado los elementos son todos menores y al otro son todos
mayores (o habran sido intercambiados).
Al finalizar este procedimiento el elemento de divisin queda en una posicin en que todos los
elementos a su izquierda son menores que l, y los que estn a su derecha son mayores.
Tabla de variables
temp El mismo que los elementos de la lista Para realizar los intercambios
// Inicializacin de variables
1. elem_div = lista[sup];
2. i = inf - 1;
3. j = sup;
4. cont = 1;
// Clasificamos la sublista
7. while (cont)
8. while (lista[++i] < elem_div);
9. while (lista[--j] > elem_div);
10. if (i < j)
11. temp = lista[i];
12. lista[i] = lista[j];
13. lista[j] = temp;
14. else
15. cont = 0;
// Aplicamos el procedimiento
// recursivamente a cada sublista
19. OrdRap (lista, inf, i - 1);
20. OrdRap (lista, i + 1, sup);
Nota: La primera llamada debera ser con la lista, cero (0) y el tamao de la lista menos 1
como parmetros.
Un ejemplo
Sea la lista:
5-3-7-6-2-1-4
5-3-7-6-2-1-4
5-3-7-6-2-1-4
1-3-7-6-2-5-4
1-3-7-6-2-5-4
1-3-7-6-2-5-4
1-3-2-6-7-5-4
1-3-2-6-7-54
En este momento termina el ciclo principal, porque los ndices se cruzaron. Ahora se
intercambia lista[i] con lista[sup] (pasos 16-18):
1-3-2-4-7-5-6
1-3-2
1 es menor que 2: se avanza por la izquierda. 3 es mayor: se avanza por la derecha. Como se
intercambiaron los ndices termina el ciclo. Se intercambia lista[i] con lista[sup]:
1-2-3
7-5-6
5-7-6
5-6-7
Para cada nueva sub-lista se retorna sin hacer cambios (se cruzan los ndices).
1-2-3-4-5-6-7
Optimizando.
Hacer una versin iterativa: Para ello se utiliza una pila en que se van guardando los lmites
superior e inferior de cada sub-lista.
No clasificar todas las sub-listas: Cuando el largo de las sub-listas va disminuyendo, el proceso
se va encareciendo. Para solucionarlo slo se clasifican las listas que tengan un largo menor
que n. Al terminar la clasificacin se llama a otro algoritmo de ordenamiento que termine la
labor. El indicado es uno que se comporte bien con listas casi ordenadas, como el
ordenamiento por insercin por ejemplo. La eleccin de n depende de varios factores, pero un
valor entre 10 y 25 es adecuado.
Estabilidad: No es estable.
Tiempo de Ejecucin: Caso promedio. La complejidad para dividir una lista de n es O(n). Cada
sub-lista genera en promedio dos sub-listas ms de largo n/2. Por lo tanto la complejidad se
define en forma recurrente como:
f(1) = 1
f(n) = n + 2 f(n/2)
La forma cerrada de esta expresin es: f(n) = n log2n Es decir, la complejidad es O(n log2n).
El peor caso ocurre cuando la lista ya est ordenada, porque cada llamada genera slo una
sub-lista (todos los elementos son menores que el elemento de divisin). En este caso el
rendimiento se degrada a O(n2). Con las optimizaciones mencionadas arriba puede evitarse
este comportamiento.
Ventajas:
Muy rpido
Desventajas:
Algunos algoritmos slo funcionan con un tipo especfico de datos (enteros, enteros positivos,
etc.) y otros son generales, es decir, aplicables a cualquier tipo de dato.
Algunos algoritmos realizan mltiples intercambios (burbuja, insercin). Si los registros son de
gran tamao estos intercambios son ms lentos.
Captulo 11
Estructuras y uniones
Al contrario que los arrays, las estructuras nos permiten agrupar varios datos, que mantengan
algn tipo de relacin, aunque sean de distinto tipo, permitiendo manipularlos todos juntos,
usando un mismo identificador, o cada uno por separado.
Las estructuras son llamadas tambin muy a menudo registros, o en ingls records. Tienen
muchos aspectos en comn con los registros usados en bases de datos. Y siguiendo la misma
analoga, cada objeto de una estructura se denomina a menudo campo, o field.
Sintaxis:
struct [<identificador>] {
[<tipo> <nombre_objeto>[,<nombre_objeto>,...]];
} [<objeto_estructura>[,<objeto_estructura>,...];
Los objetos de estructura son objetos declarados del tipo de la estructura, y su inclusin
tambin es opcional. Si bien, an siendo ambos opcionales, al menos uno de estos elementos
debe existir.
En el interior de una estructura, entre las llaves, se pueden definir todos los elementos que
sean considerados necesarios, del mismo modo que se declaran los objetos.
Las estructuras pueden referenciarse completas, usando su nombre, como se hacen con los
objetos que ya son conocidos, y tambin se puede acceder a los elementos definidos en el
interior de la estructura, usando el operador de seleccin (.), un punto.
Una vez definida una estructura, es decir, si se ha especificado un nombre para ella, se puede
usar igual que cualquier otro tipo de C++. Esto significa que se pueden declarar ms objetos del
tipo de estructura en cualquier parte del programa. Para ello se utiliza la forma normal de
declaracin de objetos, es decir:
Ejemplo:
struct Persona {
char Nombre[65];
char Direccion[65];
int AnyoNacimiento;
} Fulanito;
Este ejemplo define la estructura Persona y declara a Fulanito como un objeto de ese tipo.
Para acceder al nombre de Fulanito, por ejemplo para visualizarlo, usaremos la forma:
C++, permite incluir funciones en el interior de las estructuras. Normalmente estas funciones
tienen la misin de manipular los datos incluidos en la estructura, y su uso est muy
relacionado con la programacin orientada a objetos.
Aunque esta caracterstica se usa casi exclusivamente con las clases, tambin puede usarse en
las estructuras. De hecho, en C++, las diferencias entre estructuras y clases son muy tenues.
El constructor es una funcin sin tipo de retorno y con el mismo nombre que la estructura. El
destructor tiene la misma forma, salvo que el nombre va precedido el smbolo "~".
Nota: para aquellos que usen un teclado espaol, el smbolo "~" se obtiene pulsando las teclas
del teclado numrico 1, 2, 6, mientras se mantiene pulsada la tecla ALT, ([ALT]+126). Tambin
mediante la combinacin [Atl Gr]+[4] y un espacio (la tecla [4] de la zona de las letras, no del
teclado numrico).
Ejemplo 1:
struct Punto {
int x, y;
Punto() {x = 0; y = 0;} // Constructor
} Punto1, Punto2;
Ejemplo 2:
struct Punto {
int x, y;
Punto(); // Declaracin del constructor
} Punto1, Punto2;
Otro ejemplo:
#include <iostream>
using namespace std;
struct stPareja {
int A, B;
int LeeA() { return A;} // Devuelve el valor de A
int LeeB() { return B;} // Devuelve el valor de B
void GuardaA(int n) { A = n;} //Asigna nuevo valor a A
void GuardaB(int n) { B = n;} // Asigna nuevo valor a B
} Par;
int main() {
Par.GuardaA(15);
Par.GuardaB(63);
cout << Par.LeeA() << endl;
cout << Par.LeeB() << endl;
return 0;
}
En este ejemplo se puede ver cmo se define una estructura con dos campos enteros, y dos
funciones para modificar y leer sus valores. El ejemplo es muy simple, pero las funciones de
guardar valores se pueden elaborar para que no permitan determinados valores, o para que
hagan algn tratamiento de los datos.
Inicializacin de estructuras
De un modo parecido al que se inicializan los arrays, se pueden inicializar estructuras, tan slo
hay que tener cuidado con las estructuras anidadas. Por ejemplo:
struct A {
int i;
int j;
int k;
};
struct B {
int x;
struct C {
char c;
char d;
} y;
int z;
};
A ejemploA = {10, 20, 30};
B ejemploB = {10, {'a', 'b'}, 20};
Cada nueva estructura anidada deber inicializarse usando la pareja correspondiente de llaves
"{}", tantas veces como sea necesario.
Uniones
Las uniones son un tipo especial de estructuras que permiten almacenar elementos de
diferentes tipos en las mismas posiciones de memoria, aunque evidentemente, no en forma
simultnea.
Sintaxis:
union [<identificador>] {
[<tipo> <nombre_variable>[,<nombre_variable>,...]];
} [<variable_union>[,<variable_union>,...];
Las variables de unin son objetos declarados del tipo de la unin, y su inclusin tambin es
opcional.
Sin embargo, como en el caso de las estructuras, al menos uno de estos elementos debe
existir, aunque ambos sean opcionales.
En el interior de una unin, entre las llaves, se pueden definir todos los elementos necesarios,
del mismo modo que se declaran los objetos. La particularidad es que cada elemento se
almacenar comenzando en la misma posicin de memoria.
Las uniones pueden referenciarse completas, usando su nombre, como con las estructuras, y
tambin se puede acceder a los elementos en el interior de la unin usando el operador de
seleccin (.), un punto.
Tambin pueden declararse ms objetos del tipo de la unin en cualquier parte del programa,
de la siguiente forma:
Ejemplo:
#include <iostream>
using namespace std;
union unEjemplo {
int A;
char B;
double C;
} UnionEjemplo;
int main() {
UnionEjemplo.A = 100;
cout << UnionEjemplo.A << endl;
UnionEjemplo.B = 'a';
cout << UnionEjemplo.B << endl;
UnionEjemplo.C = 10.32;
cout << UnionEjemplo.C << endl;
cout << &UnionEjemplo.A << endl;
cout << (void*)&UnionEjemplo.B << endl;
cout << &UnionEjemplo.C << endl;
cout << sizeof(unEjemplo) << endl;
cout << sizeof(UnionEjemplo.A) << endl;
cout << sizeof(UnionEjemplo.B) << endl;
cout << sizeof(UnionEjemplo.C) << endl;
return 0;
}
Inicializacin de uniones
Las uniones solo pueden ser inicializadas en su declaracin mediante su primer miembro.
union unEjemplo {
int A;
char B;
double C;
} UnionEjemplo;
Al utilizar un carcter, como en el caso de 'y', se har una conversin de tipo a int de forma
automtica, y se asignar el valor correcto. En el caso de 'z', se produce un aviso, por
democin automtica.
Al igual que pasa con otros tipos agregados, como arrays y estructuras, hay que usar llaves
para incluir una lista de valores iniciales. En el caso de la unin, esa lista tendr un nico
elemento, ya que todos los miembros comparten la misma zona de memoria, y slo est
permitido usar el primero para las inicializaciones.
Captulo 12
Punteros
Estimado lector, no salga corriendo!. Aunque es un tema que suele asustar a los estudiantes
de C++, no es algo tan terrible como se cuenta!.
Fuera del mbito de la programacin. Se utilizan punteros para sealar cosas sobre las que se
quiere llamar la atencin, como marcar puntos en un mapa o detalles en una presentacin en
pantalla. A menudo, se utiliza el dedo ndice para sealar direcciones o lugares sobre los que
se est hablando o explicando algo. Cuando un dedo no es suficiente, se utiliza un puntero (o
apuntador). Antiguamente esos punteros eran una vara de madera, pero actualmente se usan
punteros laser, aunque la idea es la misma. Un puntero tambin es el smbolo que representa
la posicin del ratn en una pantalla grfica. Estos punteros tambin se usan para sealar
objetos: enlaces, opciones de men, botones, etc. Un puntero sirve, pues, para apuntar a los
objetos a los que se est uno refiriendo.
En C++ un puntero es exactamente lo mismo. Los punteros en C++ sirven para sealar objetos,
y tambin para manipularlos.
La memoria de un ordenador est compuesta por unidades bsicas llamadas bits. Cada bit slo
puede tomar dos valores, normalmente denominados alto y bajo, 1 y 0. Pero trabajar con
bits no es prctico, y por eso se agrupan.
Cada grupo de 8 bits forma un byte u octeto. En realidad el microprocesador, y por lo tanto el
programa, slo puede manejar directamente bytes o grupos de dos o cuatro bytes. Para
acceder a los bits hay que acceder antes a los bytes.
Cada byte de la memoria de un ordenador tiene una direccin, llamada direccin de memoria.
Los microprocesadores trabajan con una unidad bsica de informacin, a la que se denomina
palabra (en ingls word). Dependiendo del tipo de microprocesador una palabra puede estar
compuesta por uno, dos, cuatro, ocho o diecisis bytes. Se habla indistintamente de
direcciones de memoria, aunque las palabras sean de distinta longitud. Cada direccin de
memoria contiene siempre un byte. Lo que suceder cuando las palabras sean, por ejemplo,
de 32 bits es que se acceden a posiciones de memoria que son mltiplos de 4.
Por otra parte, la mayor parte de los objetos que se utilizan en los programas no caben en una
direccin de memoria. La solucin utilizada para manejar objetos que ocupen ms de un byte
es usar posiciones de memoria correlativas. De este modo, la direccin de un objeto es la
direccin de memoria de la primera posicin que contiene ese objeto.
Dicho de otro modo, si para almacenar un objeto se precisan cuatro bytes, y la direccin de
memoria de la primera posicin es n, el objeto ocupar las posiciones desde n a n+3, y la
direccin del objeto ser, tambin, n.
Por supuesto, almacenada a partir de esa direccin de memoria puede haber cualquier clase
de objeto: un char, un int, un float, un array, una estructura, una funcin u otro puntero. El
programador es el responsable de decidir ese contenido, al declarar el puntero.
De hecho, existen tantos tipos diferentes de punteros como tipos de objetos puedan ser
referenciados mediante punteros. Si se tiene esto en cuenta, los punteros que apunten a tipos
de objetos distintos, sern tipos diferentes. Por ejemplo, no es permitido asignar a un puntero
a char el valor de un puntero a int.
Se considera la memoria del ordenador como un gran array, de modo que es posible acceder a
cada celda de memoria a travs de un ndice en donde la primera posicin del array es la
celda[0].
Si se utiliza una variable para almacenar el ndice, por ejemplo, indice=0, entonces celda[0] ==
celda[indice]. Finalmente, si se prescinde de la notacin de los arrays, el ndice se comporta
exactamente igual que un puntero.
El puntero indice podra tener por ejemplo, el valor 3, en ese caso, el valor apuntado por indice
tendra el valor 'val3'.
Las celdas de memoria tienen una existencia fsica, es decir son algo real y existirn siempre,
independientemente del valor del puntero. Existirn incluso si no existe el puntero.
Del mismo modo, el valor de la direccin que contiene un puntero no implica que esa direccin
sea vlida, en el sentido de que no tiene por qu contener la direccin de un objeto del tipo
especificado por el puntero.
Suponiendo que se cuenta con un mapa en la pared, y tambin que existen diferentes tipos de
punteros lser para sealar diferentes tipos de puntos en el mapa. Se crea un puntero para
sealar ciudades. En el momento de crearlo (o encenderlo), el puntero sealar a cualquier
sitio, podra sealar incluso a un punto fuera del mapa. En general, se d por sentado que una
vez creado, el puntero no tiene por qu apuntar a una ciudad, y aunque apunte al mapa,
podra estar sealando a un mar o a un ro.
Con los punteros en C++ ocurre lo mismo. El valor inicial del puntero, cuando se declara, podra
estar fuera del mapa, es decir, contener direcciones de memoria que no existen. Pero, incluso
sealando a un punto de la memoria, es muy probable que no seale a un objeto del tipo
adecuado. Es necesario considerar esto como el caso ms probable, y no usar jams un
puntero que no haya sido inicializado correctamente.
Dentro del array de celdas de memoria existirn zonas que contendrn programas y datos,
tanto del usuario como del propio sistema operativo o de otros programas, el sistema
operativo se encarga de gestionar esa memoria, prohibiendo o protegiendo determinadas
zonas.
Pero el propio puntero, como objeto que es, tambin se almacenar en memoria, y por lo
tanto, tambin tendr una direccin de memoria. Cuando se declara un puntero se est
reservando la memoria necesaria para almacenarlo, aunque, como pasa con el resto de los
objetos, el contenido de esa memoria contendr basura.
Declaracin de punteros
Los punteros se declaran igual que el resto de los objetos, pero precediendo el identificador
con un asterisco (*).
Sintaxis:
<tipo> *<identificador>;
Ejemplos:
int *pEntero;
char *pCaracter;
struct stPunto *pPunto;
Los punteros slo pueden apuntar a objetos de un tipo determinado, en el ejemplo, pEntero
slo puede apuntar a un objeto de tipo int.
La forma:
<tipo>* <identificador>;
con el (*) junto al tipo, en lugar de junto al identificador del objeto, tambin est permitida. De
hecho, tambin es legal la forma:
<tipo> * <identificador>;
Por lo tanto:
int *pEntero;
equivale a:
int* pEntero;
Otro detalle importante es que, aunque las tres formas de situar el asterisco en la declaracin
son equivalentes, algunas de ellas pueden inducir a error, sobre todo si se declaran varios
objetos en la misma lnea:
int* x, y;
En este caso, x es un puntero a int, pero y no es ms que un objeto de tipo int. Colocar el
asterisco junto al tipo puede que indique ms claramente que se est declarando un puntero,
pero hay que tener en cuenta que slo afecta al primer objeto declarado, si se quiere declarar
ambos objetos como punteros a int se debe de hacerlo de otro modo:
int* x, *y;
// O:
int *x, *y;
// O:
int* x;
int* y;
Los punteros apuntan a objetos, por lo tanto, lo primero que se debe saber hacer con los
punteros es asignarles direcciones de memoria vlidas de objetos.
Por supuesto, los tipos tienen que ser "compatibles", no es permitido almacenar la direccin
de un objeto de tipo char en un puntero de tipo int.
Por ejemplo:
int A;
int *pA;
pA = &A;
Segn este ejemplo, pA es un puntero a int que apunta a la direccin donde se almacena el
valor del entero A.
Para manipular el objeto apuntado por un puntero se utiliza el operador de indireccin, que es
un asterisco (*).
En C++ es muy habitual que el mismo smbolo se use para varias cosas diferentes, este es el
caso del asterisco, que se usa como operador de multiplicacin, para la declaracin de
punteros y como operador de indireccin.
Como operador de indireccin slo est permitido usarlo con punteros, y se leer "objeto
apuntado por".
Por ejemplo:
int *pEntero;
int x = 10;
int y;
pEntero = &y;
*pEntero = x;
En la ltima lnea se asigna al objeto apuntado por pEntero el valor del objeto x. Como
pEntero apunta al objeto y, esta sentencia equivale (segn la secuencia del programa), a
asignar a y el valor de x.
Hay que tener muy claro, en el ejemplo anterior, que pEntero es un objeto del tipo "puntero
a int", pero que *pEntero NO es un objeto de tipo int, sino una expresin.
Como pasa con todos los objetos en C++, cuando se declaran, slo se reserva espacio para
almacenarlos, pero no se asigna ningn valor inicial, (recordar que el puntero para rboles no
crea un rbol cada vez que se seala con l). El contenido del objeto permanecer sin cambios,
de modo que el valor inicial del puntero ser aleatorio e indeterminado. Es de suponer que
contiene una direccin no vlida.
Si pEntero apunta a un objeto de tipo int, *pEntero ser el contenido de ese objeto, pero
no hay que olvidar que *pEntero es un operador aplicado a un objeto de tipo "puntero a
int". Es decir, *pEntero es una expresin, no un objeto.
Declarar un puntero no crear un objeto del tipo al que apunta. Por ejemplo: int *pEntero;
no crea un objeto de tipo int en memoria. Lo que crea es un objeto que puede contener la
direccin de memoria de un entero.
Se puede decir que existe fsicamente un objeto pEntero, y tambin que ese objeto puede
(aunque esto no es siempre cierto) contener la direccin de un objeto de tipo int.
Como todos los objetos, los punteros tambin contienen "basura" cuando son declarados. Es
costumbre dar valores iniciales nulos a los punteros que no apuntan a ningn sitio concreto:
NULL es una constante, que est definida como cero en varios ficheros de cabecera, como
"cstdio" o "iostream", y normalmente vale 0L. Sin embargo, hay muchos textos que
recomiendan usar el valor 0 para asignar a punteros nulos, al menos en C++.
Repasando punteros:
Los punteros permiten cdigo ms compacto y eficiente; utilizndolos en forma ordenada dan
gran flexibilidad a la programacin.
Dado el ejemplo:
int x = 1, y = 2;
int *ip; /* ip es un puntero a int */
ip = &x; /* ip apunta a x */
y = *ip; /* a y se le asigna lo apuntado por ip */
*ip = *ip + 3; /* incrementa lo apuntado por ip, x */
ip = NULL; /* ip apunta a direcc. especial (nada) */
La direccin especial NULL (o cero) indica que un puntero apunta a nada y es usada como
centinela para establecer el fin de estructuras autoreferenciadas. Adems, esta es retornada
por la funcin de asignacin de memoria, malloc, en el caso de no haber suficiente memoria. El
operador new, en cambio, aborta el programa cuando no tiene ms memoria que dar.
int *ip;
cout << *ip << endl;
Los compiladores en general informan (warning) que se est utilizando una variable no
inicializada.
int *ip;
*ip = 10;
No solo modifica un espacio de memoria que no le fue asignado; sino que, al no estar
inicializado el puntero, se modifica el espacio de memoria al que casualmente direccione el
puntero. La declaracin int *ip solo asigna memoria para la variable puntero, no para los datos
apuntados por ste. En general (lo cual no quiere decir que ocurra siempre) provoca la
excepcin de violacin de acceso de memoria (segmentation fault) y detiene el programa.
int *ip;
ip = new int; //(1)
*ip = 10;
Donde la funcin new establece memoria para el entero y la asignacin inicializa el puntero. En
caso de querer utilizar estrictamente el lenguaje C (el operador new es propio de C++), la
sentencia (1) pasara a ser la siguiente:
Ejercicio:
#include <iostream>
using namespace std;
void leer(float *A,int f,int c);
void print(float *A,int f,int c);
int ent (void);
main()
{
int i, j, n;
float s=0, t=0;
cout<<"\n\t\tDigite el orden de la matriz: ";
n=ent();
float mat[n][n];
leer(mat[0],n,n);
for ( i = 0; i < n; i++ )//entrada de la matriz y suma
{
for ( j = 0; j < n; j++ )
{
if ( (i + j)%2 == 0 )s += mat[i][j];
else{ t += mat[i][j]; }
}
}
cout<<"\n\t\tOrden de la matriz:
"<<n<<"\t"<<sizeof(mat)<<"\t"<<sizeof(mat[0])<<"\t"<<sizeof(mat[
0][0]);
print(mat[0],n,n);
cout<<"\n\n\t\tSuma de los elementos cuya suma de ndices es par
: "<<s;
cout<<"\n\t\tSuma de los elementos cuya suma de ndices es
impar: "<<t<<endl;
system ("PAUSE");
}
for(int j=0;j<c;j++)
{
cout<<"["<<i<<"]["<<j<<"]=";
cin>>*(A+c*i+j);
}
}
}
Apndice
Ejercicios
#include<iostream>
using namespace std;
main()
{ int vect[100], i, a;
srand( time(NULL) );
for ( i = 0; i < 100; i++ )
vect[i] = rand()%1000 + 1;
for ( i = 0; i < 100; i++ )
{ if ( i%10 == 0 ) cout << "\n";
cout << vect[i] << ", "; }
do { cout << "\nDigite el numero a buscar ";
cin >> a;
if ( a <= 0 ) break;
for ( i = 0; i < 100; i++ )
{ if ( a == vect[i] ) break; }
if ( i < 100 )
{ cout << "\n\tEl numero " << a;
cout << " ocupa la posicion " << i + 1;
cout << " en el vector"; }
else
{ cout << "\n\tEl numero " << a;
cout << " no se encuentra en el vector"; }
}
while( a );}
2. Determinacion del intervalo de tiempo entre la hora inicial y final de una actividad
#include<iostream>
using namespace std;
int validah ( int h );
int validams ( int m );
int validaint ( float f );
int main()
{ int hi, mi, si, ti, hf, mf, sf, tf, dh, dm, ds, dt, error;
float aux;
error = 0;
while ( error == 0 )
{ cout << "\nDigite la hora inicial : ";
cin >> aux;
error = validaint( aux );
if ( error == 1 )
{ hi = (int)aux;
error = validah ( hi
); } }
error = 0;
while ( error == 0 )
{ cout << "\nDigite el minuto inicial : ";
cin >> aux;
error = validaint( aux );
if ( error == 1 )
{ mi = (int)aux;
error = validams ( mi );
} }
error = 0;
while ( error == 0 )
{ cout << "\nDigite el segundo inicial: ";
cin >> aux;
error = validaint( aux );
if ( error == 1 )
{ si = (int)aux;
error = validams ( si ); }
}
ti = si + mi*60 + hi*3600;
error = 0;
while ( error == 0 )
{ cout << "\nDigite la hora final : ";
cin >> aux;
error = validaint( aux );
if ( error == 1 )
{ hf = (int)aux;
error = validah ( hf );
} }
error = 0;
while ( error == 0 )
{ cout << "\nDigite el minuto final : ";
cin >> aux;
error = validaint( aux );
if ( error == 1 )
{ mf = (int)aux;
error = validams ( mf ); }
}
error = 0;
while ( error == 0 )
{ cout << "\nDigite el segundo final: ";
cin >> aux;
error = validaint( aux );
if ( error == 1 )
{ sf = (int)aux;
error = validams ( sf );
} }
tf = sf + mf*60 + hf*3600;
if ( tf <= ti )
{ cout << "\nEl tiempo final no es mayor que el
inicial\n";
Barreto, Gonzalez, Ovelar, Rojas, Velazquez Pgina 106
Universidad Nacional de Asuncin
Facultad de Ingeniera
Ctedra de Computacin Ao 2011 Introduccin al Lenguaje C++
system ( "pause" );
return 0; }
dt = tf - ti;
dh = dt/3600;
dt = dt%3600;
dm = dt/60;
ds = dt%60;
cout << "\nLa diferencia de tiempo es ";
cout << dh << " h " << dm << " min " << ds << " s";
cout << "\n";
system ( "pause" );}
int validah ( int h )
{ if ( h < 0 || h > 23 ) return 0; // con error
return 1; // valor correcto
}
int validams ( int m )
{ if ( m < 0 || m > 59 ) return 0;
return 1; }
int validaint ( float f )
{ if ( f != (int)f ) return 0;
return 1;}
#include<iostream>
using namespace std;
int factorial( int n );
int main()
{ int n;
do {
cout << "\nDigite un numero entero no negativo ";
cin >> n; } while ( n < 0 );
cout << "\n\t" << n << "! = " << factorial( n ) << "\n\n\t";
system ( "pause" ); }
int factorial( int n )
{ if ( n <= 1 ) return 1;
cout << "\n\t n = " << n;
return n*factorial( n - 1 );}
4. Numeros de Fibonacci
#include<iostream>
using namespace std;
int main()
{ int i, j, k, n;
do { cout << "\nDigite el numero de terminos de la serie
de Fibonacci a generar ";
cin >> n; } while ( n < 0 );
i = 0, j = 1;
cout << "\n\t fib = { " << i << ", " << j;
for ( k = 1; k < n; k++ )
{ j = i + j;
i = j - i;
cout << "; " << j; }
cout << " }\n\n";
system ( "pause" );}
#include<iostream>
using namespace std;
int fibonacci( int n );
int main()
{ int i, n;
do { cout << "\nDigite un numero entero no negativo ";
cin >> n; } while ( n < 0 );
cout << "\n\t fib = { " << fibonacci( 0 );
for ( i = 1; i < n; i++ )
cout << "; " << fibonacci( i );
cout << " }\n\n";
system ( "pause" );}
int fibonacci( int n )
{ if ( n <= 1 ) return n;
return ( fibonacci( n - 1 ) + fibonacci( n - 2 ) );}
#include<iostream>
using namespace std;
void modifVect( float vect[], int n );
main()
{ int i, n;
float nf;
Barreto, Gonzalez, Ovelar, Rojas, Velazquez Pgina 108
Universidad Nacional de Asuncin
Facultad de Ingeniera
Ctedra de Computacin Ao 2011 Introduccin al Lenguaje C++
#include<iostream>
using namespace std;
int main()
{ int i, j, n, auxMaes, auxEscl, randMax = 100;
/* Variables del programa.
Entrada: n : numero componentes de los
vectores.
maestro: vector de n componentes (se genera con
numeros pseudoaleatorios)
esclavo: vector de n compoentens (se genera con
numeros naturales en secuencia)
Salida: maestro: vector ordenado en secuencia
ascendente
esclavo: vector indicando las posiciones iniciales
de la componentes de maestro */
do { cout << "\nDigite un numero entero ";
cin >> n;
} while ( n < 2 );
int maestro[n], esclavo[n];
// Generacion de datos
srand( time( NULL ) );
for ( i = 0; i < n; i++ )
{ maestro[i] = rand()%randMax + 1;
esclavo[i] = i + 1; }
// Impresion de los vectores generados
cout << "\tmaestro esclavo";
for ( i = 0; i < n; i++ )
{ cout << "\n\t " << maestro[i] << "\t " << esclavo[i];
}
cout << "\n";
system ( "pause" );
// Ordenacion de maestro y movimiento de esclavo
for ( i = 1; i < n; i++ )
{ auxMaes = maestro[i];
auxEscl = esclavo[i];
j = i - 1;
while ( j >= 0 && auxMaes < maestro[j] )
{ maestro[j+1] = maestro[j];
esclavo[j+1] = esclavo[j];
j--; }
maestro[j+1] = auxMaes;
esclavo[j+1] = auxEscl; }
// Impresion de los vectores ordenados
cout << "\tmaestro esclavo";
for ( i = 0; i < n; i++ )
{ cout << "\n\t " << maestro[i] << "\t " << esclavo[i];
}
cout << "\n";
system ( "pause" );}
#include<iostream>
using namespace std;
int indice( int *cont );
main()
{ int i, n, menor, contMen, var;
var = 0;
n = indice( &var );
cout << "\nParametro de entrada " << var;
int vect[n], posMen[n];
var = 1;
for ( i = 0; i < n; i++ )
vect[i] = indice( &var );
cout << "\nValor del parametro de entrada " <<
var;
cout << "\nvect = { " << vect[0];
for ( i = 1; i < n; i++ )
cout << ", " << vect[i];
Barreto, Gonzalez, Ovelar, Rojas, Velazquez Pgina 110
Universidad Nacional de Asuncin
Facultad de Ingeniera
Ctedra de Computacin Ao 2011 Introduccin al Lenguaje C++
#include<iostream>
#include<stdlib.h>
using namespace std;
int leer( void );
main()
{ int i, j, n, ls, lg, aux, max = 100; // max es el mayor
numero generado al azar
// Lectura del numero de componentes y carga del vector
n = leer( ); int vect[n]; srand( time(NULL) );
// cout << "Rand_max = " << RAND_MAX;
for ( i = 0; i < n; i++ )
vect[i] = rand()%max + 1;
Barreto, Gonzalez, Ovelar, Rojas, Velazquez Pgina 111
Universidad Nacional de Asuncin
Facultad de Ingeniera
Ctedra de Computacin Ao 2011 Introduccin al Lenguaje C++
#include<iostream>
void impresion( int *v, int li, int ls );
using namespace std;
int main()
{ int i, j, n, aux, max = 100;
// Lectura de datos.
do { cout << "Digite el numero de componentes del
vector ";
cin >> n;
} while ( n < 2 );
int vect[n];
// Generacion de datos
#include<iostream>
using namespace std;
void quicksort( int *v, int izq, int der );
void impresion( int *v, int li, int ls );
int n;
int main()
{ int i, max = 100; // max el el mayor numero al azar a ser
generado
// Lectura de datos.
do {
cout << "Digite el numero de componentes del vector ";
cin >> n;
} while ( n < 2 );
int vect[n];
srand( time( NULL ) );
for ( i = 0; i < n; i++ ) vect[i] = rand()%max + 1;
cout << "\n\tDatos:";
impresion( vect, 0, n - 1 );
// Ordenacion.
quicksort ( vect, 0, n - 1 );
cout << "\n\tDatos ordenados:";
impresion( vect, 0, n - 1 );
}
void quicksort ( int *v, int izq, int der )
{ int i, j, aux1, aux2;
Barreto, Gonzalez, Ovelar, Rojas, Velazquez Pgina 113
Universidad Nacional de Asuncin
Facultad de Ingeniera
Ctedra de Computacin Ao 2011 Introduccin al Lenguaje C++
#include<iostream>
#include<stdlib.h>
using namespace std;
int leer( void );
main()
{ int i, j, k, n, aux, max = 100; // max es el mayor
numero generado al azar
// Lectura del numero de componentes y carga del vector
n = leer( );
int vect[n];
srand( time(NULL) );
// cout << "Rand_max = " << RAND_MAX;
for ( i = 0; i < n; i++ )
vect[i] = rand()%max + 1;
// Impresion de las componentes del vector
cout << "\nNro. de componentes del vector " << n;
cout << "\n\nLas componentes del vector son";
for ( i = 0; i < n; i++ )
{ if ( i%10 == 0 ) cout << "\n";
cout << vect[i] << ", " ; }
// Ordenamiento de las componentes del vector (Metodo de
seleccion)
for ( i = 0; i < n - 1; i++ )
{ k = i;
for ( j = i + 1; j < n; j++ )
Barreto, Gonzalez, Ovelar, Rojas, Velazquez Pgina 114
Universidad Nacional de Asuncin
Facultad de Ingeniera
Ctedra de Computacin Ao 2011 Introduccin al Lenguaje C++
#include<iostream>
void impresion( int *v, int li, int ls );
using namespace std;
int main()
{
int i, j, aux, paso, n, max = 100;
// Lectura de datos.
do
{
cout << "Digite el numero de componentes del vector ";
cin >> n;
} while ( n < 2 );
int vect[n];
// Generacion de datos
srand( time( NULL ) );
for ( i = 0; i < n; i++ ) vect[i] = rand()%max + 1;
cout << "\n\tDatos:";
impresion( vect, 0, n - 1 );
// Ordenacion.
paso = n/2;
while ( paso > 0 )
{
for ( i = paso; i < n; i++ )
{
aux = vect[i];
for ( j = i - paso; (j >= 0 ) && (aux < vect[j]); j -
= paso )
14. Ejercicio: 8.6. Pag. 135: C Algoritmos, programacion y estructura de datos - Joyanes -
Fernandez - Sanchez Zahonero Escribir un programa. en lenguaje C/C++, que tenga como
entrada una secuencia de numeros enteros positivos(mediante una variable entera). El
programa debe hallar la suma de los digitos de cada entero y encontrar cual es el entero
cuya suma de digitos es mayor. La suma de digitos ha de ser con una funcion recursiva.
Observacion: El programa lee numeros enteros. Finaliza cuando lee un numero que no lo es.
#include<iostream>
using namespace std;
int sumadig( int nro );
int main()
{ int n, max = 0, sum, sumMax = 0;
/* Variables del programa.
Entrada: n : numero entero a considerar.
Salida: max : numero entero cuya suma de digitos es
la mayor en el conuunto.
sumMax: suma de los digitos de max */
do { cout << "\nDigite un numero entero ";
cin >> n;
if ( n > 0 )
{ sum = sumadig( n );
if ( sum > sumMax )
{ sumMax = sum;
max = n; } }
} while ( n > 0 );
cout << "\n\tEl numero seleccionado es " << max;
cout << "\n\tLa suma de sus digitos es " << sumMax;
cout << "\n";
system ( "pause" );
}
int sumadig( int nro )
Barreto, Gonzalez, Ovelar, Rojas, Velazquez Pgina 116
Universidad Nacional de Asuncin
Facultad de Ingeniera
Ctedra de Computacin Ao 2011 Introduccin al Lenguaje C++
#include<iostream>
using namespace std;
main()
{ int d;
enum dias
{ domingo = 1, lunes, martes, miercoles,
jueves, viernes, sabado };
enum dias semana;
cout << "\n\n\tDigite en dia ";
cin >> d;
switch ( d ) { case domingo: cout << "\tDia
domingo"; break;
case lunes : cout << "\tDia lunes";
break;
case martes : cout << "\tDia martes";
break;
case miercoles: cout << "\tDia
miercoles"; break;
case jueves: cout << "\tDia jueves";
break;
case viernes: cout << "\tDia viernes";
break;
case sabado: cout << "\tDia sabado";
break;
default: cout << "\n\tDia Dia invalido";
}
// Observese que ocurre si se imprimen los siquientes:
cout << "\n\n\tDomingo = " << domingo << ", lunes = "
<< lunes;
cout << ", martes = " << martes << ", miercoles = "
<< miercoles << ",";
cout << "\n\tjueves = " << jueves << ", viernes = "
<< viernes;
cout << ", sabado = " << sabado;
cout << "\n\n";
system ( "pause" );}
Barreto, Gonzalez, Ovelar, Rojas, Velazquez Pgina 117
Universidad Nacional de Asuncin
Facultad de Ingeniera
Ctedra de Computacin Ao 2011 Introduccin al Lenguaje C++
16. Uso de ?
#include<iostream>
using namespace std;
main()
{ int n;
float x;
cout << "Digite un numero entero ";
cin >> n;
x = n > 0 ? 1 : 2;
if ( x == 1 ) cout << "\n\nEl valor dado de n es
positivo";
else cout << "\n\nEl valor dado de n es negativo o nulo";
cout << "\n\n";
// Observe lo que sigue
x = n > 0;
if ( x ) cout << "\n\nEl valor dado de n es positivo";
else cout << "\n\nEl valor dado de n es negativo o nulo";
cout << "\n\n";
system("pause");}
#include<iostream>
using namespace std;
int main()
{ int i, n;
char *p; // Declaracion de puntero
do {
cout << "\n\t\tDigite el numero de componentes del vector
";
cin >> n;
} while( n < 2 );
char v[n]; // Vector de caracteres
for ( i = 0; i < n; i++ )
{ cout << "\tDigite v[" << i << "]: ";
cin >> v[i]; }
// Impresion de v, utilizando el nombre del vector
cout << "\n\nv = { " << v[0];
for ( i = 1; i < n; i++ )
cout << ", " << v[i];
cout << " }";
// Impresion de v, utilizando el puntero p
p = v;
cout << "\n\nv = { " << *p;
for ( i = 1; i < n; i++ )
cout << ", " << *(p + i);
cout << " }";
// Impresion de las componentes, a partir de uno determinado
Barreto, Gonzalez, Ovelar, Rojas, Velazquez Pgina 118
Universidad Nacional de Asuncin
Facultad de Ingeniera
Ctedra de Computacin Ao 2011 Introduccin al Lenguaje C++
#include<iostream>
using namespace std;
int main()
{ cout << "\nPlataforma de " << 8*sizeof(int) << "
bits\n\n";
system ( "pause" );}
#include<iostream>
using namespace std;
int main()
{ int i, n;
do {
cout << "\n\t\tDigite el numero de empleados ";
cin >> n;
} while( n < 2 );
struct varEst // Declaracion de la estructura
{ long int DocId;
char nom[30];
double salario; };
struct varEst empl[10];
for ( i = 0; i < n; i++ )
{ cout << "\tDigite DocId[" << i << "]: ";
cin >> empl[i].DocId;
cout << "\tDigite Nombre[" << i << "]: ";
cin >> empl[i].nom;
cout << "\tDigite Salario[" << i << "]: ";
cin >> empl[i].salario; }
// Impresion de empl
cout << "\n\nDocumento Nombre y Apellido Salario";
for ( i = 0; i < n; i++ )
Barreto, Gonzalez, Ovelar, Rojas, Velazquez Pgina 119
Universidad Nacional de Asuncin
Facultad de Ingeniera
Ctedra de Computacin Ao 2011 Introduccin al Lenguaje C++
#include<iostream>
#include<stdio.h>
using namespace std;
int lect();
int mcd( int a, int b );
struct fraccion
{ int numer, deno; };
fraccion suma( fraccion f1, fraccion f2 );
fraccion prod( fraccion f1, fraccion f2 );
int main()
{ int aux, ope = 1;
fraccion f1, f2, f;
char msg[][20] = {"de la suma", "de la diferencia", "del
producto", "del cociente" };
while ( ope )
{ cout << "\nNumerador de la primera fraccion";
f1.numer = lect();
cout << "\nDenominador de la primera fraccion";
f1.deno = lect();
cout << "\nNumerador de la segunda fraccion";
f2.numer = lect();
cout << "\nDenominador de la segunda fraccion";
f2.deno = lect();
cout << "\n\t\t1. Suma de fracciones";
cout << "\n\t\t2. Diferencia de fracciones";
cout << "\n\t\t3. Producto de fracciones";
cout << "\n\t\t4. Cociente de fracciones\n";
cout << "\n\t\t0. Fin del programa\n";
ope = lect();
switch(ope)
{
case 1: f = suma( f1, f2 );
break;
case 2: f2.numer = -f2.numer;
f = suma( f1, f2 );
break;
case 3: f = prod( f1, f2 );
break;
case 4: aux = f2.numer;
f2.numer = f2.deno;
f2.deno = aux;
f = prod( f1, f2 );
break;
default: cout << "\nOperacion no valida";
}
Barreto, Gonzalez, Ovelar, Rojas, Velazquez Pgina 120
Universidad Nacional de Asuncin
Facultad de Ingeniera
Ctedra de Computacin Ao 2011 Introduccin al Lenguaje C++
return f; }
fraccion prod( fraccion f1, fraccion f2 )
{ int aux;
fraccion f;
f.numer = f1.numer*f2.numer;
f.deno = f1.deno*f2.deno;
aux = mcd( f.numer, f.deno );
return f; }
#include<iostream>
using namespace std;
main()
{
int n;
cout << "\n\n\t\t Menu Principal";
cout << "\n\n\t1. Realizar la tarea uno";
cout << "\n\t2. Realizar la tarea dos";
cout << "\n\t3. Realizar la tarea tres";
cout << "\n\n\t0. Salir del sistema";
cout << "\n\n\t\tDigite un numero entero ";
cin >> n;
switch(n)
{ case 1: cout << "\nDebo realizar la tarea
uno"; break;
case 2: cout << "\nDebo realizar la tarea dos";
break;
case 3: cout << "\nDebo realizar la tarea tres";
break;
case 0: cout << "\nMe retiro a descanzar";
break;
default: cout << "\nNo es una opcion valida"; }
cout << "\n\n\t";
system("pause");}
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int main()
{ int i, recnum = 0;
char registro[128], *regaux, nombre[32],
archivos[100][32];
FILE *pf;
system("dir > archivos.txt ");
pf = fopen ( "archivos.txt", "r" );
if ( pf == NULL )
cout << "\n\tError al abrir el achivo\n";
else
{ while ( !feof( pf ) )
{ fgets( registro, 128, pf );
recnum++;
if ( recnum > 7 && !strstr( registro, "bytes" ) )
{ regaux = registro;
strcpy ( nombre, ( registro + 36 ) );
strcpy( archivos[recnum - 8], nombre );
Barreto, Gonzalez, Ovelar, Rojas, Velazquez Pgina 122
Universidad Nacional de Asuncin
Facultad de Ingeniera
Ctedra de Computacin Ao 2011 Introduccin al Lenguaje C++
} } }
cout << "\n";
for ( i = 0; i < recnum - 10; i++ )
{ cout << "Archivo[" << i << "] : " << archivos[i];
if ( i && i%20 == 0 )
{ cout << "\n";
system ( "pause" );
system ( "cls" );
cout << "\n"; } }
cout << "\n";
system("pause");}
#include<iostream>
#include<string.h>
using namespace std;
main()
{
int d;
char entrada[30];
union nombres
{ char nomCompl[30];
char apell[20];
char nom; };
union nombres ApeNom;
cout << "\n\n\tDigite el nombre comleto (sin
espacios) ";
cin >> entrada;
strcpy( ApeNom.nomCompl, entrada );
cout << "\n\n" << ApeNom.nomCompl;
cout << "\n" << ApeNom.apell;
cout << "\n" << ApeNom.nom;
cout << "\n\n";
system ( "pause" );}
Bibliografa
http://correo.uan.edu.mx/~iavalos/introprog.htm
http://www.uhu.es/04004/material/
http://c.conclase.net