Asignatura: Fundamentos de Informática | ![]() |
![]() |
Especialidad: Electrónica - UPV/EHU | ||
Curso académico: 2013-2014 | ||
Profesor: Ismael Etxeberria Agiriano |
Como ejercicio resuelto vamos a retomar el problema de decir si un número es primo, visto en el capítulo anterior, ya que en este laboratorio se trata de organizar los programas que ya sabíamos hacer en funciones.
Diseña y codifica un programa que
lea un número n
mayor que 1 y
diga si n
es primo.
Si el número no es válido escribirá un mensaje de error.
Al finalizar preguntará si se quiere volver a repetir la
operación.
Utiliza una función que calcule si el número es primo.
Centraremos la descripción en los aspectos propios de la descomposición en funciones: la especificación de los prototipos, el paso de parámetros, la llamada a las funciones y la devolución de los valores.
En la descomposición del problema vamos a proponer la utilización de la
función EsPrimo
que determinará si el número pasado como
parámetro es primo o no.
Su cabecera se muestra en la figura 9.1.
EsPrimo
.
En la figura 9.2 se propone el diagrama de flujo del programa principal
de la variante 09-pri-1 que hace uso de la función EsPrimo
propuesta, dentro de una instrucción condicional.
Se podrá reconocer la estructura general de la variante 08-002-1
vista en el ejercicio resuelto del capítulo anterior.
Para representar en el diagrama de flujo el valor devuelto por la
función, el valor de la variable primo
en nuestro caso,
utilizaremos la convención de asignarle ese valor al nombre de la
función, como se muestra en la Figura 9.3.
Nótese que siempre que una función devuelve un valor
(mediante la instrucción return
)
ésta termina por lo que siempre irá seguida del
bloque etiquetado Fin.
El diagrama de flujo de la función EsPrimo
(Figura 9.4)
tendrá la cabecera
propuesta en la Figura 9.1 y el cuerpo de ésta, similar a lo que hacíamos en
el capítulo anterior.
Nótese que se ha optado por llamar de la misma manera a la variable que
alberga el número en cuestión n
tanto en el programa principal,
la función main
(en la que es una variable local)
y en la función
EsPrimo
(en la que es un parámetro formal).
Otro aspecto a tener en cuenta es que se trata de un diseño descendente:
primero especificaremos el programa principal (main
)
y luego las funciones creadas por nosotros llamadas por main
,
y así sucesivamente.
Para evitar posibles problemas de compilación es conveniente proporcionar los prototipos de todas las funciones que se declararán después.
La codificación correspondiente a la variante 1 podría ser:
/* 09-pri-1.c (versión laboratorio) * * Lee un número positivo n y dice si es primo. * Si el número no es positivo escribe un mensaje de error. * Al finalizar preguntará si se quiere repetir la operación. * * Utiliza una función que calcule si el número es primo. * * Variante 1. Utilizando while. Variable lógica Cierto y Falso. */ #include <stdio.h> #include <stdlib.h> int EsPrimo (int num); /* Prototipo */ int main (void) { int i, n; char op; do { printf ("Introduce un número mayor de uno: "); scanf ("%d", &n); if (n > 1) if (EsPrimo(n)) printf ("%d es primo\n", n); else printf ("%d no es primo\n", n); else printf ("%d no es un número positivo\n", n); printf ("¿Quieres repetir? (s/n): "); fflush (stdin); /* Vaciar la entrada, si no queda el carácter '\n' */ scanf ("%c", &op); } while (op == 's' || op == 'S'); system ("pause"); return 0; } #define Cierto 1 #define Falso 0 int EsPrimo (int num) { int i; int primo; /* Variable lógica que guarda si es primo o no */ primo = Cierto; /* Mientras no encontremos un un divisor es primo */ i = 2; while (i < num && primo) { if (num%i == 0) primo = Falso; /* Si tiene un divisor no es primo */ i++; } return primo; /* Devuelve resultado: primo */ }
Aunque podríamos hacer múltiples variantes respecto al programa principal, en lo que respecta al diagrama de flujo vamos a centrarnos en lo que puede cambiar sustancialmente frente a lo visto en el capítulo anterior.
La variante 08-002-2 del capítulo anterior presentaba el resultado mediante
una única instrucción printf
.
En esta segunda variante hemos hecho lo mismo, aunque ahora en vez de la
variable lógica hemos introducido directamente la llamada a la función
EsPrimo
.
El resto del código es similar a la variante correspondiente 08-002-2.
Recalcaremos que la utilización de estructuras for
en contextos como éste en el que no conocemos a priori
el número de veces que se va a ejecutar el código
no es muy ortodoxo en el ámbito de la programación estructurada,
aunque es típico entre programadores C.
La codificación asociada podría ser:
/* 09-pri-2.c (versión laboratorio) * * Lee un número positivo n y dice si es primo. * Si el número no es positivo escribe un mensaje de error. * Al finalizar preguntará si se quiere repetir la operación. * * Utiliza una función que calcule si el número es primo. * * Variante 2. Utilizando for y break. Variable lógica 0 y 1. */ #include <stdio.h> #include <stdlib.h> int EsPrimo (int num); /* Prototipo */ int main (void) { int i, n; char op; do { printf ("Introduce un número mayor de uno: "); scanf ("%d", &n); if (n > 1) printf ("%d %ses primo\n", n, EsPrimo(n)? "":"no "); else printf ("%d no es un número positivo\n", n); printf ("¿Quieres repetir? (s/n): "); fflush (stdin); /* Vaciar la entrada, si no queda el carácter '\n' */ scanf ("%c", &op); } while (op == 's' || op == 'S'); system ("pause"); return 0; } int EsPrimo (int n) { int i; int primo; /* Variable lógica que guarda si es primo o no */ primo = 1; for (i = 2; i < n; i++) { if (n%i == 0) { primo = 0; break; } } return primo; }
En este apartado se proporciona el código de las variantes 09-pri-3, 09-pri-4 y 09-pri-5, que se corresponden con sus respectivas variantes 08-002-3, 08-002-4 y 08-002-5 utilizando funciones.
Sólo se proporciona el código correspondiente a la función
EsPrimo
.
El código de la variante 09-pri-3 puede ser:
/* 09-pri-3.c (versión laboratorio) ... int EsPrimo (int n) { int i; for (i = 2; i < n; i++) if (n%i == 0) break; return i == n; }
El código de la variante 09-pri-4 puede ser:
/* 09-pri-4.c (versión laboratorio) ... int EsPrimo (int n) { int i; i = 2; while (i<n && n%i) i++; return i == n; }
El código de la variante 09-pri-5 puede ser:
/* 09-pri-5.c (versión laboratorio) ... int EsPrimo (int n) { int i; for (i = 2; i<n && n%i; i++) ; /* Ojo: sin cuerpo */ return i == n; }
A lo largo de este ejercicio resuelto hemos ido proponiendo variantes similares a las vistas en el capítulo anterior utilizando funciones.
Una variante típica cuando se utilizan funciones es finalizar la función y devolver el resultado cuando ya está disponible.
En muchos lenguajes de programación podemos utilizar el nombre de la función como una variable más y ello no supone una terminación. Si queremos representar explícitamente en el diagrama de flujo que vamos a utilizar una ruptura de secuencia utilizaremos un símbolo especial, que es el que se muestra en la Figura 9.5. Mostramos con líneas discontinuas el flujo normal que seguiría en el caso de que no hubiera una ruptura de secuencia.
En la figura 9.6 se muestra el diagrama de flujo de la función
EsPrimo
utilizando esta práctica, es decir, devolver el resultado
cuando ya está disponible y finalizar.
Nótese que hay un caso normal en el que no se explota la ruptura de secuencia.
EsPrimo
devolviendo el resultado
tan pronto como es conocido.
El código de esta variante 09-pri-6 puede ser:
/* 09-pri-6.c (versión laboratorio) ... int EsPrimo (int n) { int i; for (i = 2; i < n; i++) if (n%i == 0) return 0; /* Si tiene un divisor no es primo */ return 1; /* No tiene ningun divisor: es primo */ }