Asignatura: Fundamentos de Informática | ![]() |
![]() |
Especialidad: Electrónica - UPV/EHU | ||
Curso académico: 2013-2014 | ||
Profesor: Ismael Etxeberria Agiriano |
Se resuelven ejemplos de escasa complejidad algorítmica (como todos los de este laboratorio) pero cierto detalle a la hora de entender el paso de parámetros.
En estos casos vamos a realizar entradas/salidas (del teclado y a pantalla) pero en general las funciones serán de cálculo. Habrá que tener mucho cuidado a la hora de interpretar las especificaciones y no confundir entradas/salidas con parametros de entrada o salida y con el valor devuelto por una función.
Diseña el diagrama de flujo de la cabecera y codifica una función que lea un número complejo en forma binómica, utilizando el siguiente prototipo:
void bLee (double *x, double *y);
La cabecera se muestra en la figura 10.1.
bLee
.
La codificación de esta función no tiene complejidad algorítmica
pero hay que prestar especial atención en el paso de parámetros a la función
scanf
.
Como nuestra función ya dispone de la dirección de las variables donde
queremos dejar el resultado no le volveremos a pasar estas direcciones:
#include <stdio.h> void bLee (double *x, double *y) { printf ("Introduce la parte real: "); scanf ("%lf", x); /* Cuidado, no enviamos &x */ printf ("Introduce la parte imaginaria: "); scanf ("%lf", y); /* Cuidado, no enviamos &y */ }
Diseña el diagrama de flujo de la cabecera y codifica una función que escriba un número complejo en forma binómica, utilizando el siguiente prototipo:
void bEscr (double x, double y);
La cabecera se muestra en la figura 10.2.
bLee
.
Este ejemplo ilustra bien el error común de confundir parámetros de salida y salida (escritura de datos en pantalla). Obsérvese en la cabecera que no hay parámetros de salida, aunque por la naturaleza de la función escribimos datos en pantalla.
Por estética vamos a diferenciar dos casos según la parte imaginaria sea positiva o negativo ya que si no lo hiciéramos, en el segundo caso nos mostraría dos signos.
#include <stdio.h> void bEscr (double x, double y) { if (y >= 0) printf ("%.2lf + %.2lfi ", x, y); else printf ("%.2lf - %.2lfi ", x, -y); }
Para poder comprobar la corrección de las funciones propuesas se proporciona un programa completo.
Obsérvese la estructura típica del diseño descendente en la que primero vienen los prototipos de las funciones, luego el programa principal y finalmente la defición de las funciones, que repetimos por claridad.
/* 10-eje.c (versión laboratorio)*/ #include <stdio.h> #include <stdlib.h> void bLee (double *x, double *y); void bEscr (double x, double y); int main (void) { double x, y; bLee (&x, &y); bEscr (x, y); system ("pause"); return 0; } void bLee (double *x, double *y) { printf ("Introduce la parte real: "); scanf ("%lf", x); /* Cuidado, no enviamos &x */ printf ("Introduce la parte imaginaria: "); scanf ("%lf", y); /* Cuidado, no enviamos &y */ } void bEscr (double x, double y) { if (y >= 0) printf ("%.2lf + %.2lfi ", x, y); else printf ("%.2lf - %.2lfi ", x, -y); }
Si las funciones son suficientemente genéricas lo típico es
crear una biblioteca (librería) que podremos linkar siempre
que se utilicen y especificar los prototipos en un fichero
específico de cabeceras, por ejemplo, complejos.h
.
De esa manera se guardará la consistencia con el tipo de los
parámetros.
Así, el programa principal visto antes podría dividirse en tres ficheros:
complejos.h
: fichero de cabeceras con los prototipos
complejos.c
: fichero con la definición de las funciones
ejemplo.c
: fichero con el programa que utiliza las
funciones de números complejos.
El fichero de cabeceras con los prototipos podría ser:
/* complejos.h */ void bLee (double *x, double *y); void bEscr (double x, double y);
A continuación ilustraremos cómo sería el código correspondiente a la definición de las funciones
en complejos.c
.
Siendo más detallistas vamos a aprovechar para mejorar bEscr
y distinguir más casos distintos de visualización,
según la parte real y/o la imaginaria sean positivas, nulas o negativas.
La versión revisada, incluyendo la definición de bLee
se muestra a continuación:
/* complejos.c */ #include <stdio.h> #include "complejos.h" void bLee (double *x, double *y) { printf ("Introduce la parte real: "); scanf ("%lf", x); /* Cuidado, no enviamos &x */ printf ("Introduce la parte imaginaria: "); scanf ("%lf", y); /* Cuidado, no enviamos &y */ } void bEscr (double x, double y) { if (x != 0 && y > 0) printf ("%.2lf+%.2lfi", x, y); else if (x != 0 && y < 0) printf ("%.2lf-%.2lfi", x, -y); else if (x != 0 && y == 0) printf ("%.2lf", x); else if (x == 0 && y != 0) printf ( "%.2lfi", y); else printf ("0"); }
En este fichero hemos incluido stdio.h
ya que estamos utilizando
llamadas a scanf
y a printf
.
De hecho, si el programa principal no utiliza directamente estas funciones
scanf
y printf
no necesitará incluir stdio.h
.
A continuación se proporciona un ejemplo de programa principal que utiliza
las funciones anteriores.
Es un programa típico de prueba que permitirá estudiar el comportamiento
de bEscr
con todas las combinaciones de números negativos,
nulos y positivos tanto para la parte real como para la imaginaria.
/* 10-main.c (versión laboratorio) */ #include <stdio.h> #include <stdlib.h> #include "complejos.h" int main (void) { double x, y; int i, j; for (i = -1; i <= 1; i++) for (j = -1; j <= 1; j++) { bEscr (i, j); printf ("\n"); } bLee (&x, &y); bEscr (x, y); printf ("\n"); system ("pause"); return 0; }
La función bEscr
no escribe un salto de línea ya que es posible que en un
programa que sea necesario poner dos números complejos en la misma línea.
Por ello en este ejemplo llamamos directamente a printf
y tenemos
que incluir stdio.h
.
Compilados complejos.o
y 10-main.o
habrá que
enlazarlos (linkarlos) para obtener un único ejecutable.
Esta labor la realiza el entorno de trabajo DevC++ cuando definimos un proyecto que incluye a los dos anteriores.