0% encontró este documento útil (0 votos)
12 vistas67 páginas

Programación Modular en C++

El documento aborda la programación modular en C++, centrándose en el uso de subprogramas y funciones. Se discuten conceptos como diseño descendente, transferencia de datos, declaración y llamada a funciones, así como la estructura y tipos de retorno de las mismas. Además, se presentan ejemplos y ejercicios para ilustrar la implementación de estas técnicas en la resolución de problemas complejos.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
12 vistas67 páginas

Programación Modular en C++

El documento aborda la programación modular en C++, centrándose en el uso de subprogramas y funciones. Se discuten conceptos como diseño descendente, transferencia de datos, declaración y llamada a funciones, así como la estructura y tipos de retorno de las mismas. Además, se presentan ejemplos y ejercicios para ilustrar la implementación de estas técnicas en la resolución de problemas complejos.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

1

PROGRAMACIÓN I
C++

Grado en Estadística Aplicada. EUE.


2 Tema 4.- Programación modular
Isabel Riomoros
Programación con subprogramas
3

 Introducción.
 Diseño descendente.
 Subprogramas.
 Definición
 Transferencia/Retorno
 Estructura de una función.
 Nombre de una función
 Tipo de retorno (tipo del valor devuelto)
 Valor retorno
 Lista de parámetros
 Paso por valor
 Paso por referencia
 Declaración de funciones: Prototipos.
 Llamada a funciones.
 Ejercicios y ejemplos.
Introducción
4
 La abstracción es la herramienta mental que nos permite
analizar, comprender y construir sistemas complejos.
 Identificamos y denominamos conceptos abstractos con
significado. Aplicamos Refinamientos Sucesivos.
Introducción
5
 A veces, un determinado problema complejo lo podemos (y
debemos) dividir en problemas más sencillos. Estos
subproblemas se conocen como subprogramas.

Técnica de diseño conocida como


 A la hora de diseñar el programa: TOP DOWN

♦ Se tratará de descomponer el problema original en partes.


♦ Se pueden codificar de forma independiente e incluso por
diferentes personas.
♦ El problema final queda resuelto y estructurado en forma
de subprogramas, lo que hace más sencilla su lectura y
mantenimiento.
Diseño descendente: abstracción y
refinamientos
6
 Divide un problema en subproblemas

 Asocia a cada subproblema un subprograma

 Utilizamos abstracción:
 NO importa como se resuelve un subproblema
 Nos centramos en la funcionalidad del subprograma
 Que subproblema resuelve, que datos necesita, que datos
produce
 Bajo que condiciones se debe ejecutar

 Aplicamos refinamientos sucesivos


 Objetivo: división en subprogramas independientes
 Funcionalidad clara y bien definida
 Aislados: minimizar las dependencias con otros subprogramas
 Transferencia de información simple y bien definida
Diseño descendente: ventajas
7
 Los subprogramas encapsulan y aíslan las diferentes tareas
que componen un programa.
 Simplificación en el diseño y solución del programa.
 Si el método para solucionar una tarea debe cambiar, el
aislamiento evita que dicho cambio influya en las otras
tareas.
 Permite que el programador este concentrado en la
solución individual del subproblema concreto.
 Simplifica la comprensión y legibilidad del programa.
 Facilita la detección y corrección de errores (depuración).
 Posibilidad de reutilización del subprograma en otro
contexto.
Subprogramas
8

 Un subprograma es una serie de instrucciones escritas


independientemente del programa principal. Este
subprograma está ligado al programa principal mediante
un proceso de transferencia/retorno.

Programa Principal Subprograma

Transferencia
El control de ejecución se
pasa al subprograma en el
momento en que se
requieren sus servicios.

El control de ejecución se devuelve al programa


Retorno
principal cuando el subprograma termina
Definición de subprogramas
9
 El cuerpo del subprograma especifica la secuencia de acciones
que resuelven un subproblema.

 Define sus propias variables locales de trabajo.

 Donde sea necesaria la resolución de dicho subproblema, se


realizara una llamada al subprograma.

 La transferencia de información se realiza a través de los


parámetros:
 Parámetros Formales: aparecen en la definición del
subprograma.
 Parámetros Actuales: aparecen en la llamada al subprograma.

 Abstracción de procesamiento y de operaciones


 Funciones: calculan un único valor a partir de la información de
entrada.
 Procedimientos: procesamiento general de información.
Definición de subprograma
10
 Definición de Funciones
 El cuerpo de una función solo debe tener una sentencia
return, se suele escribir la última sentencia del cuerpo de la
función.
 El valor resultado de la función es el resultado de evaluar la
expresión de la sentencia return.

 Definición de Procedimientos, a veces llamados


funciones
 El cuerpo de un procedimiento no debe tener ninguna
sentencia return.
 Procesa información que se transfiere a través de los
parámetros.
Transferencia / Retorno:
11

float sqrt (int a)


... {
int main() float m;
{ ….
int numero, absoluto; return m;
}
float raiz;
cin >> numero;
if (numero > 0 )
int abs (int a)
raiz = sqrt ( numero ); {
else ….
{ return ...;
absoluto = abs (numero); }
numero = cubo( absoluto );
}
cout << raiz; float cubo (int a)
return 0; {
} ….
return ...;
Transferencia/retorno de control y datos }
Estructura de una función
12

 Hasta ahora, hemos visto y utilizado funciones estándar, es


decir definidas en una biblioteca.

resto = sqrt ( 25 ) cin.getline( cadena , 30 )

Valor que devuelve


Argumentos o parámetros
la función
Tranferencia
Retorno
b = isdigit ( carácter )

 C++ nos permite definir nuestras propias funciones. Pocas


veces veremos un programa que no use funciones. Una de
ellas, que usamos siempre, es la función main.
Estructura de una función
13

Sintaxis

<tipo_resultado> <nombre_de_la_función> ( lista_de_parámetros )
{
cuerpo_de_la_función ;
return <expresión> ;
}
Palabra reservada

int maximo (int a, int b )


Tipo_resultado: Es el tipo de dato que {
devuelve la función. int m;
Nombre de la función- Nombre significativo if (a<b) Variable local
que resuma para que sirve la función. m=b;
Cuerpo de la función- instrucciones necesarias else
para resolver el problema. m=a;
Expresión: valor que devuelve la función. return m;
}
Lista de parámetros: aparecen con su tipo. La
función utiliza éstos valores en el cuerpo.
Estructura de una función
14

 Una vez que se ha diseñado y codificado una función, se


puede usar. Para usar una función, debemos llamarla o
invocarla. Una llamada, produce la ejecución de las
instrucciones que se encuentran en el cuerpo.
 Se llama a la función con el nombre y los parámetros
correspondientes.

int maximo ( int a, int b )


{
Programa principal
int m;
int main() if (a<b)
{ m=b;
int x, y, mayor ; else
cin >> x >> y ; m=a;
mayor = maximo( x, y); return m;
cout << mayor; }
}
maximo : int × int → int
Estructura de una función: Nombre de la
función
15
El nombre que se les da a las funciones, debe ser un identificador válido, es
decir,
• Debe comenzar con una letra o subrayado (_).
• Después de la primera letra pueden aparecer otras letras, dígitos
y caracteres.
• No debe contener espacios en blanco.
• C++ distingue entre mayúsculas o minúsculas.

Nombres de funciones : leer , visualizarTabla1 , leerMatriz , etc ...

Es muy importante en la fase de diseño de un algoritmo, utilizar nombres que nos


permitan intuir la tarea que realizan las funciones, sobre todo a la hora de mantener y
modificar programas.
Estructura de una función: Nombre de la
función
16

Por ejemplo, qué hacen los siguientes programas:

... ...
int main() int main()
{ {
…. ….
llenar_matriz(); primera_funcion();
calcular_media(); segunda_funcion();
mayores_que_la_media(); funcion_3();
imprimir_mayores(); mi_funcion();
} }

Si se nos pide un cambio en algún punto


del programa, por ejemplo al actualizar
Parece más intuitivo, ¿no? la matriz,
¿qué función hemos de modificar?
Estructura de una función: Tipo de dato de
retorno
17

Las funciones en C++ las podemos dividir en varios tipos:


 Funciones que realizan una tarea específica pero que
no devuelven valores al programa principal o a la
función que la llamó.
El tipo de dato de retorno ha de ser void Se llaman
Procedimientos

 Funciones que realizan operaciones con los argumentos


o manipulan datos y devuelven un valor. Dicho valor,
puede ser el resultado de esas operaciones ó un
indicador de si la manipulación de los datos ha sido
exitosa o no. Si la función devuelve un valor,
ha de ser uno de los siguientes:
int
char
Un puntero a cualquier tipo C++
float
... Un tipo struct
Lo veremos más adelante
Estructura de una función: Valor de retorno
18

 Una función solo puede devolver un valor. El


valor se devuelve mediante la sentencia return

return <expresión> ;

1. C++ comprueba la compatibilidad de tipos, (no se puede devolver un


valor de tipo int, si el tipo de retorno es struct ).

2. Una vez que se ejecuta ésta sentencia, termina la ejecución de la función.

3. Una función puede tener cualquier número de sentencias return, pero al


menos debe haber una.

4. El valor devuelto puede ser: una constante, variable ó una expresión.


Estructura de una función: Valor de retorno
19

bool funcion( int a )


int maximo (int a, int b ) {
{ bool negativo;
……. if (a <0)
return max; {
} negativo = true;
return negativo;
char siguiente_car (char c ) }
{ while (a < 100) float media (float x, float y )
…. { {
return car; cout << a; ….
} a++; return med;
bool encontrado ( ) } }
{ return false;
…. }
return enc;
} int main()
{
bool resultado;
resultado = funcion (-5);
resultado = funcion (5);
}
Estructura de una función: Valor de retorno
20

int suma_tres ( int a , int b, int c ) int main()


{ {
return (a+b+c); int resultado;
} bool ok;
resultado = suma_tres (2, x, y );
bool dividir ( int a , int b, float& cociente ) ok = dividir (0, 3, resultado);
{ if (ok ==true)
if ( b = 0 ) cout << resultado;
return false; else
else cout << “error-división por cero”;
cociente = a/b; cout << resultado;
return true; }
}
Ejemplos sencillos
21
 Escribir un función que:
1. Dados dos valores enteros nos devuelva el mayor
2. Dado un carácter nos devuelva el siguiente
3. Dados dos números reales nos devuelve la media
4. Dado un número y una cifra nos devuelve true si la cifra forma
parte del número y false en caso contrario
5. Factorial de un número. Dado un número nos devuelve su
factorial
6. Potencia. Dada la base (x) y el exponente(n) nos devuelve xn
7. Algoritmo de Euclides. Dados dos números enteros nos
devuelve su máximo común divisor

 Escribir un programa que llame a cada una de las funciones


Estructura de una función: Valor de retorno
22

Cuando se llama a una función, debe haber una


variable que guarde el valor que devolverá la
función, es decir, llamaremos a la función
mediante una sentencia de asignación, por
ejemplo:

resultado = suma (6 , 8 );
Estructura de una función: Lista de parámetros
23
 Las funciones trabajan con dos tipos de datos:

1. Variables locales: declaradas en el cuerpo de la


función. Estas variables solo son conocidas dentro de la
función y se crean y se destruyen con la función.

2. Parámetros: Los parámetros permiten la comunicación


de la función con el resto del programa mediante
transferencia de datos.
Variable local
int cubo (int a)
... {
int main() int aux;
{ aux = a*a*a ;
int numero, resultado; return aux;
cin >> numero; }
numero = cubo ( numero );
cout << numero;
}
Estructura de una función: Lista de parámetros
24

 C++ proporciona dos métodos para realizar ésta


transferencia de datos a la función. Hablaremos a partir de
ahora de paso de parámetros a la función.

1. Paso de parámetros por valor


...
a 10

...
aux 1000
int cubo (int a)
int main() { Código de la
{ int aux; Función cubo
int num = 10 , res; aux = a*a*a ;
res = cubo ( num ); return aux; res 1000
cout << res; } num 10
}
Código del
* El programa principal se interrumpe para comenzar la Programa
principal
ejecución de la función …

* Se reserva memoria para el código de la función,
para las variables locales y para los parámetros. MEMORIA
Estructura de una función: Lista de parámetros
25

2. Paso de parámetros por referencia …


...

void cubo (int & a) aux


{
1000
... int aux;
aux = a*a*a ; Código de la
int main()
a = aux; Función cubo
{
int num = 10; return;
cubo ( num ); }
num 1000
10
cout << num;
} a
Código del

Programa

principal

* El compilador no reserva memoria para


los parámetros, sino que utiliza la misma
MEMORIA
porción de memoria.
Estructura de una función: Lista de parámetros
26

Paso de parámetros por valor (int x)

 Cuando se llama a la función, se pasa solo el valor de la


variable.
 Este método también se llama paso por copia.
 El compilador hace una copia de los parámetros. Esto
implica que cualquier modificación en el valor de los
parámetros no se mantiene cuando termina la función.
 Utilizaremos éste método cuando no necesitemos que se
modifiquen los parámetros con los que se llama.
Estructura de una función: Lista de parámetros
27

Paso de parámetros por referencia (int& x)

 También se llama paso por dirección.


 Cuando se llama a la función, se pasa la dirección de
memoria donde se encuentra almacenada la variable
parámetro.
 El compilador no hace copia, no reserva memoria para los
parámetros.
 Usaremos éste método cuando necesitamos que la función
modifique el valor de los parámetros y que devuelva el valor
modificado.

 Para pasar un parámetro por referencia, hay que poner


el operador de dirección & detrás del tipo del
parámetro.
void cubo (int & a)
{ …. }
Ejemplo de uso de paso de parámetros
28

int main() int area_rectangulo (int a, int b)


{ {
int m; int aux;
m = area_rectangulo( 2 , 3 ); aux = a*b;
cout << m ; a=0;
b=0;
int lado1 = 2, lado2 = 6 ; return aux;
m = area_rectangulo( lado1 , lado2 ); }
cout << m;
void potencia( int x, int y, int& z)
int b = 10, e = 4, r= 0; {
potencia (b, e, r); z = 1;
cout << r; for ( int i=1; i<= y ; i++ )
z=z*x;
} }

Parámetros por valor: a, b, x, y Parámetros por referencia: z


¿Qué llamadas son correctas?
29
Dadas las siguientes declaraciones:
int i;
double d;
void proc(int x, double & a);
¿Qué llamadas son correctas?
1. proc(3, i, d);
2. proc(i, d);
3. proc(3*i + 12, d);
4. proc(i, 23);
5. proc(d, i);
6. proc(3.5, d);
7. proc(i);
Declaración de las funciones : Prototipos
30

 A excepción de la función main(), en el módulo del


programa debe aparecer la declaración de las funciones
que se utilicen en dicho módulo. Esta declaración recibe el
nombre de PROTOTIPO.

<tipo_resultado> <nombre_de_la_función> ( lista_de_parámetros ) ;



#include <iostream.h>
Sintaxis del prototipo
void potencia (int x, int y, int& z );

int main()
El prototipo, informa de la
Prototipo existencia de la función, el
{
... tipo de datos que devuelve y
}
los parámetros que tiene
void potencia( int x, int y, int& z)
{
definidos.
…. Codificación
}
Características importantes relativas a
funciones
31

1. La instrucción return
a) fuerza la salida inmediata de la función.
b) sirve para devolver un valor. Dicho valor puede ser constante,
variable ó una expresión.

return (4+i); return 7; return x;

2. No se pueden declarar unas funciones dentro de otras.


(No se pueden declarar funciones anidadas)

3. Las constantes, variables y tipos de datos declarados en el cuerpo


de la función son locales a la misma y no se pueden utilizar fuera de
ella.

4. El cuerpo de la función encerrado entre llaves, no acaba en ‘;’.


Funciones: llamada
32
La llamada se realiza mediante el nombre seguido por los
parámetros actuales.

 La llamada a una función no puede constituir por si sola


una sentencia, sino que debe aparecer dentro de alguna
estructura que utilice el valor resultado de la función.

 La llamada a un procedimiento constituye por si sola


una sentencia que puede ser utilizada como tal en el
cuerpo de subprogramas y del programa principal.

 Un subprograma puede invocar a otros subprogramas


(definidos previamente)
Funciones: llamada
33
 Cuando se produce una llamada a un subprograma:

1. Se establecen las vías de comunicación entre los algoritmos


llamante y llamado (parámetros).

2. Se crean las variables locales.

3. El flujo de control pasa a ejecutar la primera instrucción del


cuerpo del subprograma llamado, ejecutándose este.

4. Cuando finaliza la ejecución del subprograma, las variables


locales previamente creadas se destruyen y el flujo de control
continua por la siguiente instrucción a la llamada realizada.
Funciones: Parámetros
34
 El número de parámetros actuales debe coincidir con el de
parámetros formales.

 Correspondencia posicional entre parámetros actuales y


formales.

 El tipo del parámetro actual debe coincidir con el tipo del


correspondiente parámetro formal.

 Un parámetro formal de salida o entrada/salida requiere


que el parámetro actual sea una variable.

 Un parámetro formal de entrada requiere que el


parámetro actual sea una variable, constante o expresión.
Parámetros con referencia constante
35
 Para evitar copias en el paso de parámetros por valor, los
parámetros de entrada se pueden pasar por referencia
constante.
const tipo_Parámetro & nombre_Parámetro

Ejemplo:
void func(const string & nomb);
 En el cuerpo de la función, el parámetro nomb, es una
constante local.
 En las llamadas, el argumento tiene que ser una variable.
Se pasa la referencia de la variable.
 Recomendado cuando el tipo del parámetro no es básico, y
no se necesita una variable local.
Reglas de ámbito
36
1. Un identificador es visible y accesible en la zona
comprendida entre el lugar en que se declara (creación) y
el final del bloque o cuerpo del subprograma donde ha
sido declarado (destrucción). A esta zona se le denomina
ámbito o zona de visibilidad del identificador.

2. Si dentro del ámbito de un determinado identificador, este


mismo aparece declarado en un nivel de anidamiento
(bloque) mas interno, entonces dentro del ámbito de esta
segunda declaración, la declaración mas externa quedará
ocultada (y por lo tanto no accesible).

3. Si la variable de control del bucle for se declara en la zona


de inicialización del mismo, entonces su ámbito de
visibilidad se extiende hasta el final del cuerpo del bucle.
37
Subprogramas en línea
38
 La llamada a un subprograma conlleva un pequeño coste debido
al control y gestión de la misma que ocasiona cierta perdida de
tiempo de ejecución.

 Cuando el subprograma es muy pequeño y nos interesa eliminar


el coste asociado a su invocación, podemos hacer que el
subprograma se traduzca como código en línea en vez de como
una llamada a un subprograma.

 Se escribirá la palabra reservada inline justo antes del tipo. Así


tendremos los beneficios de la abstracción, pero se eliminan los
costes asociados a la invocación.

inline int calcular_menor(int a, int b)


{
return (a < b) ? a : b ;
}
Sobrecarga de subprogramas y operadores
39
 Se denomina sobrecarga cuando distintos subprogramas se
denominan con el mismo identificador u operador, pero se
aplican a parámetros distintos.

 En C++ es posible sobrecargar tanto subprogramas como


operadores siempre y cuando tengan parámetros
diferentes, y el compilador pueda discriminar entre ellos
por la especificación de la llamada.
void imprimir(int x)
{
cout << "entero: " << x << endl;
}
void imprimir(double x)
{
cout << "real: " << x << endl;
}
Ejercicios
40

putchar(c)- escribe el
void escr(char ch, int longitud)
carácter c en el output
{
while (longitud >0){ getchar()- función lee
putchar(ch); un caráter del input
longitud--;
}
}
Ejemplo: Ejecutar y ver la salida
41
//Ejemplo de parámetros por valor y referencia
#include <iostream>
using namespace std;
void dos(int x, int y, int& z)
{
z=x + y + z;
cout<<"x= "<<x<<" y= "<<y<<" z= "<<z<<endl;
}
main ()
{
int a=5,b=8,c=3;
dos(a,b,c);
cout<<" dos(a,b,c) a= "<<a<<" b= "<<b<<" c= "<<c<<endl;
dos(7,a+b+c,a);
cout<<" dos(7,a+b+c,a) a= "<<a<<" b= "<<b<<" c= "<<c<<endl;
dos (a*b, a/b,c);
cout<<" dos (a*b, a/b,c) a= "<<a<<" b= "<<b<<" c= "<<c<<endl;
system("pause");
return 0;
}
¿Cuál será la salida?
#include <iostream>
using namespace std;
int a,b,c,x,y;
void primero()
{
a=3*a;
c=c+4; void tercero(int x, int y)
} {
void segundo() x=x+4;
{ y=y+1;
int b; cout<<"a= "<<a<<" b= "<<b<<" c= "<<c<<" x= "<<x<<" y= "<<y<<endl;
b=8; }
c=a+b+c/3; main ()
} {
a=3;b=2;c=1;x=11;y=22;
} primero();
cout<<"d primero a= "<<a<<" b= "<<b<<" c= "<<c<<" x= "<<x<<" y= "<<y<<endl;
segundo();
cout<<"d de 2º a= "<<a<<" b= "<<b<<" c= "<<c<<" x= "<<x<<" y= "<<y<<endl;
tercero(a,b);
cout<<"d de tercero a= "<<a<<" b= "<<b<<" c= "<<c<<" x= "<<x<<" y= "<<y<<endl;
system("pause");
42 return 0;
Ejemplo
43
Ejercicios propuestos
44

 Dibujar una escalera, solicitando el margen el número de


espacios en horizontal, el numero de vertical y el número
de peldaños.

x2 x4 x6
cos x =1 − + − + ...
2! 4! 6!

 “Números Amigos”.
Dos números son amigos cuando la suma de los divisores
del primero es igual al segundo y viceversa. Escribir un
programa que permita encontrar al menos un par de
amigos.
Ejercicios propuestos
45
Ejercicio
46
Pasar de coordenadas rectangulares a polares
47

Tenemos la coordenada rectangular de un punto (x,y) y queremos


pasarlo a coordenadas polares

Pasar de
rectangulares
a polares

Calcular los
Leer Datos valores de las Escribir los
coordenadas resultados
Pasar de coordenadas rectangulares a polares
48
#include <iostream>
#include <math.h>
using namespace std;
void pasoPolares(float,float,float&,float&);
int main()
{
float x,y,distancia,angulo;
cout<<"Dame la x"<<endl;
cin>>x;
cout<<"Dame la y"<<endl;
cin>>y;
pasoPolares(x,y,distancia,angulo);
cout<<"("<<x<<","<<y<<")"<<"--->"<< "r= "<<distancia<<" angulo= "<<angulo<<endl;
system("pause");
return 0;
}
void pasoPolares(float coorX, float coorY, float& r,float& a)
{
const float AGRADOS=180.0/3.1416;
r=sqrt(coorX*coorX+coorY*coorY);
a=atan(coorY/coorX)*AGRADOS;
return;
}
Escribe un programa que lea un numero entero N por teclado y
dibuje un triangulo de asteriscos con altura N.
49
Por ejemplo si N = 5 deberá dibujarse:
#include <iostream>
void escribirTriangulo ( int nf)
using namespace std ; {
const char SIMBOLO = '*'; for (int f = 0; f < nf; ++f)
void escribirCaracter ( int n, char simb ) escribirFila (f, nf );
{ }
for (int i = 0; i < n; ++i) int main ()
cout << simb ; {
} cout << " Introduzca numero de filas : ";
void escribirFila ( int f, int nf)
int nFilas ;
{
escribirCaracter (nf-f-1, ' ');//escribir
cin >> nFilas ;
blancos escribirTriangulo ( nFilas );
escribirCaracter (2*f+1, SIMBOLO ); system("pause");
//asteriscos return 0;
cout << endl ;//saltar de línea }
}
Ejercicios propuestos
50
Soluciones
51
void escribirFila ( int f, int nf)
#include <iostream> {
using namespace std ; escribirCaracter (nf-f, ' ');
const int MAX_FILAS = 10; escribirAscendente (f);
void escribirCaracter ( int n, char simb ) escribirDescendente (f- 1);
{ cout << endl ;
for (int i = 0; i < n; ++i) }
cout << simb ; void escribirTriangulo ( int nf)
} {
void escribirAscendente ( int n) for (int f = 1; f <= nf; ++f)
{ escribirFila (f, nf );
for (int i = 1; i <= n; ++i) }
cout << i; int main ()
} {
void escribirDescendente (int n) cout << " Introduzca numero de filas : ";
{ int nFilas ;
for (int i = n; i >= 1; --i) cin >> nFilas ;
cout << i; if ( nFilas < MAX_FILAS )
} escribirTriangulo ( nFilas );
system("pause");
return 0;
}
Soluciones
52
void esc_fila ( int f, int nf)
#include <iostream> {
using namespace std ; esc_caracter (nf-f, ' ');
void esc_caracter ( int n, char simb ) esc_ascendente (f, 2*f- 1);
{ esc_descendente (2*f-2, f);
for (int i = 0; i < n; ++i) cout << endl ;
cout << simb ; }
}
void esc_ascendente ( int a, int b) void esc_triangulo ( int nf)
{ {
for (int i = a; i <= b; ++i) for (int f = 1; f <= nf; ++f)
cout << (i %10); esc_fila (f, nf );
} }
void esc_descendente (int a, int b) int main ()
{ {
for (int i = a; i >= b; --i) cout << " Introduzca numero de filas : ";
cout << (i %10); int n_filas ;
} cin >> n_filas ;
esc_triangulo ( n_filas );
system("pause");
return 0;
}
#include <iostream> double serie ( double x)
using namespace std ; {
const int LIMITE_FACTORIAL_UNSIGNED = 14; int i = 0;
const double LIMITE = 1e-4; double res = 1;
double potencia ( double base , int exp ) double term ;
{ do {
double res = 1; ++i;
for (int i = 0; i < exp; ++i) term = termino (x, i);
res *= base ; res += term ;
return res ; } while ( term >= LIMITE );
} return res ;
int factorial ( int n) }
{ int main ()
int res = 1; {
for (int i = 2; i <= n; ++i) cout << " Introduzca el valor de X [0..1]: ";
res *= i; double x;
return res ; cin >> x;
} if (! (x >= 0 && x <= 1))
double termino ( double x, int i) cout << " Error . Valor de X fuera de rango " << endl ;
{ else cout << " Serie : " << serie (x) << endl ;
return potencia (x, i) / double ( factorial (i )); system("pause");
} return 0;
}
53
54

#include <iostream> int primer_perfecto ()


using namespace std ; {
int PRIMER_NUMERO = 29; int i = PRIMER_NUMERO ;
int suma_divisores (int n) while (! es_perfecto (i))
{ ++i;
int suma = 0; return i;
for (int i = 1; i <= n / 2; ++i) }
if (n % i == 0) int main ()
suma += i; {
return suma ; cout << " Primer perfecto mayor que " <<
} PRIMER_NUMERO << ": " ;
inline bool es_perfecto (int n) cout<< primer_perfecto () << endl ;
{ system("pause");
return n == suma_divisores (n); return 0;
} }
Errores frecuentes
55
 Transmitir tipos incorrectos de datos
 Declarar localmente la misma variable dentro de la función
que llama y la que hace la llamada
 Una variable local tiene el mismo nombre que una variable
global
 Omitir el prototipo de la función llamada antes o dentro de
la función que llama
 Terminar la línea de encabezado de una función con ;
 Olvidar incluir en la línea de encabezado el tipo de datos de
los parámetros de la función
Recursión

 Recursión, repetición por autorreferencia,


cuando un subprograma se llama a sí mismo;
un proceso que se repite eternamente a menos
que una estructura de control lo termine.

Una recursión correcta debe satisfacer


los siguientes requisitos:
 Todo subprograma recursivo debe contener una
estructura de control que evite continuar con la
recursión cuando se llegue al estado final.
 Se debe llegar necesariamente al estado final
 Cuando se llegue al estado final el subprograma debe
haber completado el cálculo correcto
Recursión
 Una función se dice definida recursivamente si su
definición consta de dos partes:
 Un caso base, en el cual se especifica el valor de la función
para uno o mas valores
 Un paso inductivo o recursivo, en el cual el valor de la
función para el (los) valor(es) del parámetro se define en
términos de los valores de la función definidos previamente
y los valores de los parámetros.

 La condición para que el proceso recursivo termine, es


decir no genere un nuevo cálculo, se denominará caso
base.
 La recursión es una forma de descomponer un cálculo
en otro más sencillo de la misma especie y continuar
esta descomposición hasta llegar al caso trivial, caso
base.
 Cuando no utilizar la recursión:
 cuando dificulte la compresión del algoritmo
 cuando produzca demandas excesivas de memoria o tarde
mucho en ejecutarse
Recursión: ¿Cuál será la salida?
58
#include<iostream>

using namespace std;

void p(int n)
{
cout << n << endl;
p(n+1);
}

int main()
{
p(1);
system("pause");
return 0;
}
Recursión: ¿Cuál será la salida?
59

La función p es una función recursiva mal definida:

no tiene caso base y el caso recursivo se aplica incondicionalmente.


Se trata de un caso de recursión infinita.

si la variable "local" esta definida, el desbordamiento de pila se produce


con menos invocaciones de p. Esto se debe a que el registro de
activación ocupa mucha mas memoria. double local[10000];
Factorial recursivo
60
double factorial(double a)
{
if (a<=1) return 1.0;
else return (a *factorial(a-1.0));
}
int main ()
{ double n;
cout << "Numero entero:";
cin>> n;
cout<<"El factorial de "<<n<<" es: "<< factorial(n);
return 0;
}
Traza para el factorial recursivo
61
Traza para el factorial recursivo
62
#include <iostream>
using namespace std;
void EscribeBlancos(int n) { int main() {
if (n>0) int i;
{ cout << "numero (negativo para acabar): ";
cout << ' '; cin >> i;
EscribeBlancos(n-1); while (i >= 0)
} {
} cout << traza_factorial(i,0) << endl;
int traza_factorial(int n, int margen) { cout << "numero (negativo para acabar): ";
const int sangrado= 4; // aumento de margen izquierdo cin >> i;
int result; }
EscribeBlancos(margen); system("pause");
cout << "entrando en factorial(" << n << ")\n"; return 0;
if (n==0) }
result= 1;
else
result= n*traza_factorial(n-1, margen+sangrado);
EscribeBlancos(margen);
cout << "saliendo de factorial(" << n << ") con valor " << result << endl;
return result;
}
Recursión: Escribir blancos
63
#include <iostream>
using namespace std;
// El caso base no hace nada. Esto permite escribir el procedimiento solo con un if (sin else).
//Esto solo puede hacerse con procedimientos, las funciones siempre tienen al menos un caso
// base explicito.
void EscribeBlancos(int n)
{
if (n>0) {
cout << ' '; // cout << '*' // para depurar
EscribeBlancos(n-1);
}
}

int main() {
int i;
cout << "numero de blancos (negativo para acabar): ";
cin >> i;
while(i>=0) {
EscribeBlancos(i);
cout << '$' << endl;
cout << "numero de blancos (negativo para acabar): ";
cin >> i;
}
system("pause");
return 0;
}
Recursión: Invertir Cadena Caracteres
64

#include <iostream>
using namespace std;
void invierte()
{
char ch;

ch= getchar();

if (ch != '\n')
{
invierte();
}

cout << ch;


}
int main()
{
cout << "teclea una cadena: ";
invierte();
cout << endl;
system("pause");
return 0;
}
Potencia con exponente positivo o negativo
65

double potencia(double x, int n){


if(n<0) return 1/potencia(x,-n);
double pot;
pot= 1;
for (int i=1;i<=n;i++)
pot=pot*x;
return pot;
}
Triángulo de Pascal
66

El triángulo de Pascal es un triángulo de números enteros, infinito y simétrico Se empieza con un


1 en la primera fila, y en las filas siguientes se van colocando números de forma que cada uno de
ellos sea la suma de los dos números que tiene encima. Se supone que los lugares fuera del
triángulo contienen ceros, de forma que los bordes del triángulo están formados por unos.

P(i,1)=1
P(i,i)=1
P(i,j)=P(i-1,j-1) + P(i-1,j) para 1<j<i
Triángulo de Pascal
67

También podría gustarte