Ayuda con el uso varias funciones

Iniciado por ciquee, 12 Mayo 2019, 01:34 AM

0 Miembros y 1 Visitante están viendo este tema.

ciquee

Buenas, tengo una duda, estoy empezando a trabajar con varias funciones y no me aclaro para utilizar una desde otra, me explico: tengo que hacer un programa que me diga si un numero tecleado es perfecto, abundante o defectivo. Luego en otro ejercicio me piden que, utilizando esa misma función sin modificarla, haga un programa para saber los números abundantes que hay entre dos numero que se introducen por teclado. Mi código es este:


#include <iostream>
using namespace std;

int Perfecto (int, int, int );
int suma_div, i;

int main (void) {
int valor1, valor2, abund;

cout << "Este programa determina la suma de los numeros abundantes comprendidos entre dos enteros determinados" << endl;

cout << "Escribe un numero: ";
cin >> valor1;

cout << "Escribe otro numero: ";
cin >> valor2;

for (int x = valor1 +1; x < valor2; x++) {
x = Perfecto(x, suma_div, i);
if (x == ??????){
abund++;
}
}

cout << "La suma de los numeros abundantes entre " << valor1 << " y " << valor2 << " es " << abund;

return 0;
}


int Perfecto() {

int num, sum_div = 0, i;

cout<<"\nEscribe un número (Escribe el 0 para salir): ";
cin >> num;

while (num != 0){

for (i = 1; i <= (num / 2); i++) {
if (num%i == 0) {
sum_div = sum_div + i;
}
}

if (sum_div > num){
cout<<"El número introducido es abundante";
}

else if (sum_div == num) {
cout<<"El número introducido es perfecto";
}

else {
cout<<"El número introducido es defectivo";
}

cout << "\n\nEscribe un número (Escribe el 0 para salir): ";
cin >> num;
}

return 0;
}


Creo que el problema lo tengo en el bucle for de la función principal, y es que no sé a que igualar la x para saber cuantos de los números resultantes son abundantes, ya que en la función Perfecto no está declarado como variable ¿Me podéis ayudar por favor?

Ah y otra duda, yo en muchos programas declaro la librería <conio.h> y pongo el getch() antes del return 0 para que el programa no se cierra, pero he leído en un hilo (no me acuerdo cual) que alguien ha dicho que no se utilice esa librería, entonces ¿como se hace para que el programa no se cierre al acabar?

Muchas gracias! Saludos!

K-YreX

Muy bien, vamos por partes. El problema que tienes es el siguiente: tienes una función para saber si un número es perfecto, abundante o defectivo y luego tienes que usar esa misma función para identificar los números abundantes dentro de un rango.
La solución es muy simple y lo vas a ver enseguida. Tu función <Perfecto()> devuelve un <int> pero en la función le haces un <return 0> por lo que siempre devuelve 0. Eso no tiene mucha utilidad. Además acabo de ver que esa función <Perfecto()> hace demasiadas cosas. A ver qué te parece mi propuesta:
Creas una función que sea <int Perfecto(int a)> que devuelve 0 si el a es perfecto, 1 si es abundante y -1 si es defectivo. Quitando todos los <cout> de la función y el bucle.
Entonces en el <main> es algo tan simple como esto:
Código (cpp) [Seleccionar]

for(int i = extremo_inferior; i <= extremo_superior; ++i) // la condicion con < o <= es decision tuya
    if(Perfecto(i) == 1)
        cout << "El numero " << i << " es abundate" << endl;
    else if(Perfecto(i) == 0)
        cout << "El numero " << i << " es perfecto" << endl;
    else // si no es 1 ni 0 no hace falta otra condicion, tiene que ser -1
        cout << "El numero " << i << " es defectivo" << endl;

Y esto lo puedes usar para calcular tanto los que son abundantes como los perfectos como los defectivos; solo tienes que modificar la condición con {-1, 0, 1}.
En casos que la "respuesta" de una función sea "sí/no" puedes retornar un <bool> y la idea es la misma. Usa los retornos de las funciones de forma que aporten información, para no aportar nada mejor usar una función de tipo <void>.
Además te recomiendo no usar variables globales a no ser que sean constantes globales en algunos casos.
De eso se trata una función es como encapsular una funcionalidad que luego puedas usar más veces. Creas una función que calcule algo de un número (normalmente evitando <cout>) y luego cada vez que la quieras usar la puedes acoplar a un <cout>, a un bucle, a una condición, etc.


Respecto al tema de <conio.h>, ciertamente es una librería no estándar por lo que todos los compiladores no pueden usarla por defectos y entonces puede dar errores según con que compilador lo compiles. El uso más frecuente de esa librería es <getch()> para hacer una pausa y es una mejora a utilizar <system("pause")> que usa más recursos del sistema para una tarea tan tonta, pero se puede mejorar más.
La solución es usar <cin.get()> (en <iostream> de C++) o <getchar()> (en <stdio.h> en C). Ambas hacen lo mismo y evitas usar librerías no estándar además de que son funciones que vienen en la librería más común de cada lenguaje, tanto de C como de C++.
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

ciquee

Muchas gracias por la respuesta YreX-DrW!

Pero llevo ya un tiempo dándole vueltas, y aunque entiendo lo que me dices, no consigo hacerlo. No me sale una función para determinar si un numero es abundante defectivo o perfecto con solo una variable como me dices, he conseguido reducirla a 2, una para el número introducido y otra para la suma de divisores, y me ha quedado tal que así:


#include <iostream>
using namespace std;

int Perfecto (int, int);

int main (void) {

    int valor1, valor2, abund;

    cout << "Este programa determina la suma de los numeros abundantes     comprendidos entre dos enteros determinados" << endl;

    cout << "Escribe un numero: ";
    cin >> valor1;

    cout << "Escribe otro numero: ";
    cin >> valor2;

//Debemos averiguar los numeros abundantes que hay entre esos dos valores tecleados:
for (int x = valor1 +1; x < valor2; x++) {
if (Perfecto(x,0) == 1){
abund++;
}
}

cout << "La suma de los numeros abundantes entre " << valor1 << " y " << valor2 << " es " << abund;

        cin.get();
return 0;
}


int Perfecto(int, int) {

int num, sum_div = 0;

while (num != 0){

for (int i = 1; i < num; i++) {
if (num%i == 0) {
sum_div = sum_div + i;
}
}

if (sum_div > num){
cout << "El número introducido es abundante";
return 1;
sum_div = 0;
}

else if (sum_div == num) {
cout << "El número introducido es perfecto";
return 0;
sum_div = 0;
}

else {
cout << "El número introducido es defectivo";
return -1;
sum_div = 0;
}
}
}


No sé si lo de devolver 1 cuando sea abundante, 0 cuando sea perfecto o -1 cuando sea defectivo se hace como lo he hecho yo. Da rabia esto de tenerlo casi pero no encontrarlo, pero a la vez es un reto muy interesante, aunque alfinal tenga que volver a preguntar casi siempre!

Y muchas gracias también por la aclaración de la biblioteca <conio.h> y las variables globales.

K-YreX

Bien, veamos, parece que tienes otro problema con las funciones, los parámetros.
Cuando a una función le pasamos parámetros es porque necesitamos variables que dependen de cada ejecución. Por ejemplo si queremos si un número es perfecto/abundante/defectivo pues debemos pasarle el número no? Lógico.
Para poder usar estas variables dentro de la función debemos darle un nombre. En el prototipo no es necesario, podemos dejarlo en <int Perfecto(int)> porque el prototipo solo necesita saber de qué tipo es cada parámetro y el valor que retorna. Pero en la implementación sí debemos poner un nombre por ejemplo <int Perfecto(int num)>.
Luego tenemos las variables locales a una función. Por ejemplo si necesitamos una variable como parece que ahora es <sum_div> que la vamos a usar dentro de la función para hacer cálculos pero fuera de esa función no tiene utilidad, la podemos crear de forma local en la función. Y quedaría algo así:
Código (cpp) [Seleccionar]

// cabeceras
int Perfecto(int);

// main

int Perfecto(int num){
    int sum_div = 0; // num no lo declaramos aqui porque lo estamos pasando como parametro
    for(int i = 1; i < num; ++i) // desde el 1 hasta num-1
        if(num % i == 0) // si num es divisible por i
            sum_div += i; // sum_div = sum_div + i   acumulamos la i
    if(sum_div > num) // si se cumple esto, num es abundante (me fio de tu definicion de abundante, no he comprobado que sea asi)
        return 1; // devolvemos 1 y la funcion termina
    if(sum_div < num) // si se cumple esto, num es defectivo
        return -1; // devolvemos -1 y la funcion termina
    return 0; // si num no es abundante ni defectivo, entonces tiene que ser perfecto, no queda otra. Devolvemos 0 y termina la funcion
}

Por pasos:
No sé la utilidad del <while()> supongo que es por si te preguntan por el 0, pero no funciona así. Piensa que un <while()> se ejecuta mientras se cumpla la condición por lo tanto si esa función recibe un número distinto a 0 NUNCA saldría del <while()>. En programación es importante diferenciar entre <while()> e <if()> ya que representan cosas distintas.
Como ves ya hemos reducido los parámetros a 1 porque <sum_div> la creamos dentro de la función ya que fuera no tiene utilidad y no varía su valor inicial, siempre la inicializaremos en 0.
También he quitado los <cout> por lo que te decía. Mejor que la función nos responda lo que queremos saber y ya veremos nosotros cómo usamos esa información. Imagina que el que creó la función suma, lo implementó de está forma:
Código (cpp) [Seleccionar]

int suma(int a, int b){
    int suma = a + b;
    cout << "La suma de " << a << " + " << b << " = " << suma << endl;
    return suma;
}

Entonces cada vez que alguien hiciera <suma(a, b)> le saldría esa línea por pantalla. No siempre queremos mostrar el resultado de una suma ya que muchas veces son cálculos parciales, no la solución. Entonces se implementa la suma como:
Código (cpp) [Seleccionar]

int suma(int a, int b){
    return a+b;
}

// Y si en alguna ocasion queremos ver el resultado pues hacemos
cout << "La suma de " << a << " + " << b << " = " << suma(a,b) << endl; // pero esto ya en el main o en otra funcion

Y por último, el <return> es como el final de la función. Si se ejecuta un <return> ya no se van a ejecutar las líneas que sigan porque un <return> "retorna" el control a la función que llama a la que acaba de terminar.

Espero no haberme dejado nada. Si tienes más dudas sobre funciones, ya sabes que puedes preguntar y siempre puedes probar a hacer funciones hasta que las manejes perfectamente. Suerte :-X
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

ciquee

Excelente explicación, como todas las que me das!

He seguido tus indicaciones y he vuelto a cambiar mi código, pero el resultado da mal, creo que no hace lo que debe, ya que me da un numero demasiado elevado, y encima negativo :-(.


#include <iostream>
using namespace std;

int Perfecto (int);

int main (void) {

int valor1, valor2, abund;

cout << "Este programa determina la suma de los numeros abundantes comprendidos entre dos enteros determinados" << endl;

cout << "Escribe un numero: ";
cin >> valor1;

cout << "Escribe otro numero: ";
cin >> valor2;

for (int x = valor1 +1; x < valor2; x++) {
if (Perfecto(x) == 1)
abund++;
}

cout << "La suma de los numeros abundantes entre " << valor1 << " y " << valor2 << " es " << abund;

return 0;
}


int Perfecto(int num) {

int sum_div = 0;

for (int i = 1; i < num; i++) {
if (num%i == 0) {
sum_div += i;
}
}

if (sum_div > num)
return 1;

if (sum_div == num)
return 0;

return -1;
}


He probado a cambiar en el bucle, la linea <if (Perfecto(x) == 1)> por <cout<<x<<endl;> y evidentemente me salen todos los números que hay entre los dos valores tecleados, con lo cual, lo que tengo mal es la función, pero no sé que puede haber mal, a ver si tu si...

Saludos!

K-YreX

El problema no es ese, ya verás ahora que te vas a dar cuenta.
Los números abundantes los contabilizas en <abund> pero... ¿cuánto empieza valiendo <abund>?
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

ciquee

Ostras!! vaya tontería!!
Ya lo tengo!!!
Muchas gracias de nuevo!

K-YreX

Ahora para dejar ya el tema zanjado por el momento, una tontería más que olvidé:
Citar
cout << "La suma de los numeros abundantes entre " << valor1 << " y " << valor2 << " es " << abund;
Cuidado con lo que se dice y lo que se quiere decir. Lo que tú vas a mostrar es la cantidad de números abundantes en (valor1, valor2) que tampoco es lo mismo que la cantidad que hay en [valor1, valor2) (cerrado-abierto) ni (valor1, valor2] (abierto-cerrado) ni [valor1, valor2] (cerrado-cerrado). No la suma de los números abundantes que eso se calcularía sustituyendo <abund++> por <abund += x>. No sé si ves la diferencia pero digamos que es importante saber lo que se está calculando en cada momento.
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

ciquee

Si, si, en cuanto me has dicho lo de iniciar abund he caído en eso y he cambiado <abund++> por <abund +=x>. Y ya lo he probado con varios valores y ¡funciona!
Gracia de nuevo amigo!