CONTENIDO DE LA LECCIÓN 10
CONOCIMIENTOS BÁSICOS SOBRE FUNCIONES
1. Introducción 2
2. Funciones que regresan un solo valor: funciones sin void 3 2.1. Formato de funciones definidas por el usuario 4
2.2. Encabezado de la función 4
2.3. La clase de datos return 5
2.4. El nombre de la función 5
2.5. Lista de parámetros 6
2.6. Ejemplo 10.1 7
2.7. Sección de enunciado 7
2.8. Ejemplos 10.2, 10.3 8 2.9. Llamada a las funciones sin void 9
2.10. Argumentos reales en comparación con parámetros formales 10 2.11. Retorno de un resultado al programa que invoca a la función 11 2.12. Ejemplo 10.4 11
2.13. Examen breve 27 52
3. Funciones void 12
3.1. Parámetros de valor en comparación con parámetros de referencia 13
3.2. Parámetros de valor 13
3.3. Ejemplos 10.5, 10.6, 10.7, 10.8, 10.9 14
3.4. Parámetros de referencia 17
3.5. Ejemplos 10.10, 10.11 19
4. Localizaciones de las funciones dentro de su programa 20
5. Examen breve 28 52
6. Prototipo de funciones 22
6.1. Ejemplos 10.12, 10.13 23
7. Solución de problemas en acción: Programación estructurada, ley de Ohm 25
7.1. Problema 25
7.2. Definición del problema 25
7.3. Planeación de la solución 26
7.4. Codificación del programa 28
8. Solución de problemas en acción: Estado de cuenta de una cuenta de ahorros 36
8.1. Problema 36
8.2. Definición del problema 36
8.3. Planeación de la solución 36
8.4. Codificación del programa 40
9. Examen breve 29 52
10. Lo que necesita saber 42
11. Preguntas y problemas 44
11.1. Preguntas 44 11.2. Problemas 47
LECCIÓN 10
CONOCIMIENTOS BÁSICOS SOBRE FUNCIONES
INTRODUCCIÓN
Cuando los programas se vuelven más complejos, los programadores descomponen el programa en pequeños subprogramas llamados funciones. Cada función debe realizar una tarea específica. Cuando el programa requiere de la tarea, llama a la función, proporcionándole toda la información que requiera para llevar a cabo la tarea.
Objetivos de esta lección:
•••• Aprender a construir programas de manera modular, a partir de piezas pequeñas llamadas
funciones.
•••• Crear funciones nuevas.
•••• Entender los mecanismos para pasar información entre funciones.
•••• Comprender las clases de retorno de una función.
•••• Crear prototipos de funciones.
En lecciones anteriores se ha presentado el diseño estructurado usando el refinamiento
sucesivo (paso a paso) y las funciones estándar de C++. También se han desarrollado diseños descendentes de programas estructurados, pero se ha empleado una programación linealcuando se codifican estos diseños. Como resultado, hemos estado codificando programas C++
que consisten en una sección principal definida por la función main() Es tiempo de aprender cómo
codificar diseños estructurados usando un programa C++ estructurado que empleafunciones. Como se sabe, las funciones son la base de la programación estructurada en el lenguaje
C++. Además, las funciones proporcionan el único método de comunicación con objetos en programación orientada a objetos. Por lo tanto, esta lección es importante paraaprender la programación estructurada y la orientada a objetos en el lenguaje C++.
Ya se han utilizado funciones estándar preconstruidas o predefinidas, en los programas.
Todas estas funciones forman parte de los diversos archivos de encabezado incluidos en C++.
Ahora es momento de desarrollar sus propias funciones y emplearlas para crear programas C++
bien
estructurados y modulares, así como sus propias clases y objetos cuando estudie la programación orientada a objetos. Las funciones que se crean para uso propio en un programase conocen con el nombre de funciones definidas por el usuario. En este sentido, el usuario es usted, el programador.
Una función definida por el usuario es un bloque de enunciados o un subprograma, que se escribe para realizar una tarea específica requerida por el programador.
Las funciones en C++ tienen la misma estructura del programa main() que ha utilizado a lo largo de estas lecciones:
claseRetorno nombreFuncion(listaParametros) {
declaraciónVariables;
enunciados;
}
A una función se la da un nombre y se le llama o invoca usando su nombre cada vez que se va a realizar la tarea dentro del programa. El programa que llama o invoca una función suele conocerse con el nombre de programa llamador.
Las funciones eliminan la necesidad de duplicar enunciados dentro de un programa.
Dada una tarea que se va a realizar más de una vez, los enunciados, se escriben sólo una vez para la función. Entonces se llama a la función cada vez que se desee realizar la tarea. Además, el uso de las funciones mejora la claridad y la legibilidad de la lista del programa. Y lo que es más importante, el uso de las funciones dentro de un lenguaje estructurado, como C++, permite solucionar problemas complejos y muy largos usando un enfoque de diseño de programación de
arriba-abajo, así como la construcción de clases y objetos en programación orientada a objetos. En C++ es posible hacer que una función sirva para dos propósitos. Puede hacerse unafunción para que regrese un solo valor al programa llamador. En C++, este tipo de función se conoce como sin void. También es posible escribir funciones que realicen tareas específicas sin que regrese valor alguno o regrese varios valores, a estas funciones se les conocen con el nombre de funciones void.
FUNCIONES QUE REGRESAN UN SOLO VALOR: funciones sin void
Ya se cuenta con alguna experiencia en funciones que regresan un valor en C++.
Recuerde las funciones estándar que se utilizaron antes como sqrt(),
sin() y cos(), pormencionar algunas. Vimos que C++ incluye funciones para el manejo de cadenas y funciones matemáticas, así como funciones para el manejo de E/S. Sin embargo, suponga que quiere realizar alguna operación que no es una función predefinida en C++, por ejemplo elevar al
cubo. Debido a que C++ no incluye ninguna función estándar para tal operación, es posiblecodificar en el programa la operación con un enunciado como el siguiente:
cubo = x * x * x
Después, insertar este enunciado dentro del programa cada vez que se quiera elevar al cubo el valor de x. Sin embargo, ¿no sería más sencillo insertar el comando cubo(x) cada vez que se quiera elevar x al cubo, de tal manera que C++ sepa qué hacer al igual que sabe cómo ejecutar
sqrt(x)? Puede hacer esto definiendo su propia función cubo(x). A esta función se le conoce conel nombre de función definida por el usuario, por razones obvias.
Una
función definida por el usuario es un subprograma que, cuando se invoca, realizaalguna tarea o regresa un solo valor que se asigna al nombre de la función en cualquier parte que se utilice el nombre en el programa llamador. De esta manera, si cubo(x) es una función
definida por el usuario que calculará un valor, por decir, x, el enunciado cout << cubo(x);invocará la función y hará que se muestre el cubo de x. Ahora será necesario aprender a crear funciones definidas por el usuario.
FORMATO DE FUNCIONES DEFINIDAS POR EL USUARIO
// Encabezado de la función
<claseRetorno> <nombreFunción> (<listaParámetros>) {// Empieza el bloque de enunciados de la función
// Variables y constantes locales
<los objetos variables y las constantes locales deberán ir aquí>
// Enunciados de la función o cuerpo enunciado #1;
enunciado #2;
...
enunciado #n;
return <valor de regreso>;
} // Final del bloque de enunciados de la función
El
formato de la definición de una función consiste en tres secciones principales: una línea de encabezado de la función, cualquier variable local u objetos constantes requeridos porla función y una sección de enunciados.
ENCABEZADO DE LA FUNCIÓN
El
encabezado de la función proporciona la interfaz de datos para la función. Una interfaz de función o encabezado de la función es un enunciado que forma un marco comúnentre la función y su programa llamador. Esta idea se muestra en la figura 10.1. Observe que el
encabezado indica que datos de la función aceptarán desde el programa llamador y qué datos de la función regresarán al programa llamador. Cuando desarrolle los encabezados de las funciones, su perspectiva necesita ser relativa a la función. Deberá preguntarse dos cosas:1. ¿Qué datos debe aceptar la función desde el programa llamador para realizar la tarea designada?
2. ¿Qué datos, si los hay, deberán regresar la función al programa llamador para cumplir la tarea designada?
Programa llamador
Encabezado Cuerpo de lade la función
función [proceso]
[interfaz]
Figura 10.1. El encabezado de la función forma la interfaz entre el programa llamador y la función Acepta
Regresa
En general, el encabezado de la función consiste en las tres partes siguientes:
•••• La clase de dato que regresará la función, si lo hay.
•••• El nombre de la función.
•••• Una lista de parámetros.
LA CLASE DE DATOS return
Lo primero que aparece en el encabezado de la función es la clase de datos del valor
regresado. Recuerde que la función puede regresar un solo valor que reemplace el nombre de lafunción en donde aparece el nombre en el programa llamador. El valor que reemplaza el
nombre de la función en el programa llamador se conoce con el nombre de valor de retorno ode regreso. Cuando se usa una función para este propósito, la clase de datos del valor de regreso
se deberá especificar en el encabezado de la función. Por ejemplo, suponga que nuestra funcióncubo() regresa el cubo de un entero. Debido a que el cubo de un entero es un entero, la función regresará un valor entero. Como resultado, la clase de datos del valor regresado deberá ser int y especificarse en el encabezado de la función, como sigue:
int cubo(<listaParámetros>)
De otra manera, si nuestra función cubo() fuera el cubo de un valor de punto flotante, la clase regresada deberá ser float y el encabezado deberá verse como sigue:
float cubo(<listaParámetros>)
Cuando una función no regresa ningún valor al programa llamador deberá usar la palabra reservada void como la clase de regreso, como se muestra a continuación:
void funcionMuestra(<listaParámetros>)
Las funciones que no regresan ningún valor al programa llamador se usan para realizar tareas específicas, como E/S.
EL NOMBRE DE LA FUNCIÓN
El
nombre de la función puede ser cualquier identificador legal en C++. Sin embargo, el nombre de la función no deberá empezar con un subguión (guión bajo), porque algunos depuradores colocan un subguión frente al nombre de la función si se encuentra un error en lafunción. El nombre de la función describirá la operación que la función realiza, al igual que cubo() describe el cubo de un valor. Cuando invoque la función dentro de un programa
llamador, usará este nombre.Cada función que cree dentro de su programa debe de tener un nombre único. Como
ocurre con los nombres de variables, los nombres de las funciones deben corresponder con la
tarea que realiza. Por ejemplo:
Nombre de la función Propósito de la función
imprimirCalificacion Imprimir calificación de los alumnos.
cuentasPorPagar Procesa las deudas de una compañía.
pedirNombre Solicita el nombre del usuario.
imprimirDocumento Imprime el archivo correspondiente al documento.
calcularImpuesto Calcula el impuesto del cliente.
Recuerde dos cosas:
1. El nombre de la función nunca se puede usar dentro de la función. En otras palabras, el siguiente enunciado dentro de la función cubo() generará un error:
cubo = x * x * x;
Hay una excepción a esta regla que se llama recursividad, la cual se explicará en la siguiente lección.
2. El identificador de la función nunca se usará del lado izquierdo del símbolo de asignación fuera de la función. Por tanto, el siguiente enunciado causará un error en el programa llamador:
cubo = x * x * x;
LISTA DE PARÁMETROS
La
lista de parámetros de la función incluye variables, llamadas parámetros, que pasarán desde el programa llamador y serán evaluados por la función. Piense en un parámetrocomo una variable de la función que espera recibir un valor desde el programa llamador cuando se invoca la función. Para determinar los parámetros de la función, pregúntese ¿qué datos deberá aceptar la función para realizar su tarea? Suponga que nuestra función cubo() elevará al cubo valores enteros. La función deberá aceptar un valor entero desde el programa llamador y
regresará un valor entero al programa llamador. De esta manera, nuestra interfaz de función sepuede describir como sigue:
Función cubo(): Un entero al cubo.
Acepta: Un valor entero.
Regresa: Un valor entero.
Vamos a diseñar x como un objeto entero que aceptará la función. En C++, un
parámetro dado deberá especificarse en el encabezado de la función indicando su clase de datosseguido por su identificador. Como resultado, la lista de parámetros apropiados para la función
cubo() deberá ser (int x). Colocando todo junto, el encabezado de la función deberá ser:int cubo(int x)
Clase regreso Parámetro de la función Nombre de la función
Sí la
funcióncubo() elevara al cubo valores de punto flotante, el encabezado de la
función apropiado deberá ser:float cubo(float x)
Clase regreso Parámetro de la función Nombre de la función
Ejemplo 10.1
Suponga que quiere escribir una función definida por el usuario para calcular el voltaje en un circuito de cd usando la ley de Ohm. Escriba el encabezado de la función:
Para desarrollar el encabezado de la función, trataremos a la función como a una caja negra y nos haremos las siguientes preguntas: (1) ¿Qué dato deberá aceptar la función desde el programa llamador para realizar la tarea de aplicación? (2) ¿Qué deberá regresar al programador llamador? Las respuestas a estas preguntas dictarán el encabezado de la función o interfaz. Para contestar la primera pregunta, piense en qué deberá evaluar la función. Para calcular el voltaje usando la ley de Ohm, la función deberá evaluar dos cosas: corriente y resistencia. Así que utilicemos las palabras corriente y resistencia como nuestros parámetros. ¿De esta manera, la función deberá aceptar un valor de punto flotante de corriente y un valor de punto flotante de resistencia,
Después, deberá decidir qué datos regresará la función al programa llamador. Debido a que la función evalúa valores de punto flotante, tiene sentido matemático que el valor regresado también deba ser un valor de punto flotante.
Ahora, la interfaz de función se puede describir como sigue:
Función voltaje(): Calcula el voltaje usando la ley de Ohm.
Acepta: Un valor de punto flotante para corriente y un valor de punto flotante para resistencia.
Regresa: Un valor de punto flotante para voltaje.
Una vez que se ha decidido lo que acepta y lo que regresa la función, el encabezado de la función se construye fácilmente con la sintaxis de C++ como sigue:
float voltaje(float corriente, float resistencia) SECCIÓN DE ENUNCIADO
La
sección de enunciado de la función incluye aquellas operaciones que la funcióndeberá realizar para regresar un valor al programa llamador. Observe otra vez el formato general
para la función definida por el usuario. Como puede observar, la sección de enunciado
completa está enmarcada dentro de llaves. Después de abrir una llave, deberá empezar la sección
de enunciado declarando cualquier objeto constante y definiendo objetos variables que seusarán dentro de la función. Cualquier objeto constante o variable listado aquí se llama local,
porque se definen sólo para uso local dentro de la misma función. Las constantes y variables
locales no tienen significado fuera de la función en la cual se definen. No duplique ninguno de sus parámetros defunción
aquí. Liste solamente constantes o variables adicionales que lafunción requiera durante su ejecución. Un ejemplo común de una variable local es un contador
de
ciclo que se emplea como parte de un ciclo while, do/while o for dentro de la función. Enrealidad, puede declarar constantes locales y definir variables locales en cualquier lugar dentro
de la función siempre y cuando se listen antes de usarlas. Sin embargo, el buen estilo dicta que
éstas sean declaradas o definidas al principio de la sección de enunciado de la función.
No confunda las variables locales con los parámetros de la función. Una variable local se define después de abrir la llave de una función para usarle dentro de ésta. Un parámetro de función se define en el encabezado de la función como un lugar que mantiene el espacio para los
valores del argumento que pasan a la función cuando se llama a la misma. También seusará dentro de la función para suministrar datos desde el programa llamador a la función.
Los
enunciados ejecutables de la función siguen a cualquier enunciado o definición local. El último enunciado en una función sin void es el return. Este se usa cuando se regrese unsolo valor al programa llamador. Así, si nuestra función cubo() regresa el cubo de x, un enunciado de regreso apropiado deberá ser:
return (x * x * x);
Combinando el encabezado de la función y la sección de enunciado para la función
cubo(), dará la función completa como sigue:int cubo(int x) {
return(x * x * x);
} // Fin de cubo()
Obviamente, ésta es una función relativamente sencilla que no requiere ningún enunciado de definición local o ejecutable que no sea el enunciado return.
Ejemplo 10.2
Complete la función voltaje() cuyo encabezado se desarrolló en el ejemplo 10.1 Solución
La ley de Ohm requiere la función para multiplicar la corriente por la resistencia para obtener el voltaje.
De esta manera, el único enunciado requerido en la función es un enunciado return que regresará el producto de corriente y resistencia. Colocando todo junto, la función completa se convierte en:
float voltaje(float corriente, float resistencia) {
return (corriente * resistencia);
} // Fin de voltaje()
Una fuente común de error durante la codificación de una función sin void es hacer la asignación al nombre de la función dentro de ésta, como sigue:
float voltaje(float corriente, float resistencia) {
return voltaje = corriente * resistencia;
} // Fin de voltaje()
Esto siempre causará un error de compilación, porque se intenta regresar el nombre de la función. Deberá regresar un valor que, en este caso, es el producto de corriente y resistencia.
Ejemplo 10.3
Escriba una función que regrese la suma de todos los enteros desde 1 a algún valor máximo entero, llamado maximo. La función deberá obtener el valor de maximo desde el programa llamador.
Solución
Vamos a llamar a esta función suma(). Ahora, la función deberá aceptar un valor entero llamado maximo desde el programa llamador. Debido a que la función es para sumar todos los enteros desde 1 hasta maximo, ésta regresará un valor entero. De esta manera nuestra interfaz de función se puede describir como sigue:
Función suma(): Suma todos los enteros desde 1 hasta maximo.
Acepta: Un valor entero: maximo.
Regresa: Un valor entero.
Utilizando esta información, el encabezado de la función se convierte en:
int suma(int maximo)
El siguiente paso es determinar si hay alguna variable local requerida por los enunciados de la función. Se puede usar un ciclo for para calcular la suma de enteros desde 1 hasta maximo. Sin embargo, el enunciado for requiere una variable contador. Esta es una aplicación clásica para una variable local. Vamos a llamar a esta variable utilizada como contador local contador. Después, también necesita una variable temporal dentro del ciclo for para mantener un subtotal de la suma cada vez que el ciclo se ejecuta. Denominaremos a esta variable local subTotal. De acuerdo con lo anterior, la función es:
int suma(int maximo) {
int subTotal = 0;
for(int contador = 1; contador <= maximo; ++ contador) subTotal = subTotal + contador;
return subTotal;
} // Fin de suma() LLAMADA A LAS FUNCIONES sin void
Se
llama o invoca a una función sin void en cualquier parte de su programa de la mismamanera que llama las funciones estándar en
C++. Por ejemplo, puede llamar una funciónusando un operador de asignación o un enunciado cout como el siguiente:
y = cubo(2);
o cout << cubo(2);
En ambos casos, el valor 2 se pasa a la función que se va a elevar al cubo. De esta manera, en nuestra función cubo(), el parámetro
x toma el valor 2. Y la función regresará elcubo de 2, que es 8. Con el enunciado de asignación, la variable y asignará el valor 8, y el enunciado cout hará que el valor 8 se muestre en pantalla.
Aquí están otras dos formas en que nuestra función cubo() se puede llamar:
int a = 2;
y = cubo(a);
o
En estos casos, la función es la variable a elevada al cubo, donde a a se le ha asignado previamente el valor 2. De esta manera el valor de a o 2, pasa a la función. En nuestra función cubo() el parámetro x toma el valor de a.
Las funciones también pueden ser llamadas como parte de expresiones aritméticas o enunciados relacionales. Por ejemplo, nuestra función cubo() puede ser llamada como parte de una expresión aritmética, como ésta:
int a = 1;
y = 1 + cubo(a) * 2;
¿Qué se asignará a y? Bien, primero C++ evalúe la función cubo() para obtener 8, después realiza la operación de multiplicación para obtener 16 y por último suma 1 a 16 para obtener 17.
También puede usar funciones como parte de operaciones relacionales, como ésta:
if(cubo(a) >= 27)
¿Cuándo será verdadera la relación? Cuando a sea mayor o igual a 3, ¿correcto? Cuando
a es mayor o igual a 3, el cubo(a) es mayor o igual a 27. Recuerde que cuando una función sediseña para regresar un solo valor al programa llamador, el valor regresado
reemplaza el nombre de la función donde quiera que se use el nombre en el programa llamador.Generalmente se llamarán las funciones sin void dentro de su programa usando un enunciado de asignación, un objeto cout o como parte de una operación aritmética. Recuerde pensar en la llamada de función como un valor. Esto es, un valor reemplaza la llamada de función donde ésta aparece en el programa. Pregúntese: ¿Tiene sentido un valor aquí? Por ejemplo, todos los siguientes enunciados tienen sentido, porque un valor puede sustituirse fácilmente por la llamada de función:
resultado = cubo(a):
cout << cubo(a);
solucion = x * cubo(a) + 5;
Por otra parte, el siguiente enunciado no tendrá sentido y causará un error de compilación.
cubo(a);
ARGUMENTOS REALES EN COMPARACIÓN CON PARÁMETROS FORMALES
En el ejemplo anterior del cubo(), la variable a que se usa en el programa llamador se llama argumento real. Por otra parte, la variable correspondiente x que se usa en el encabezado
de la función se llama parámetro formal. Los argumentos reales son valores o variables que seutilizan dentro de la llamada de la función y los parámetros formales son variables que se utilizan dentro del encabezado de la función y que reciben valores del argumento real.
De esta manera, decimos que el parámetro formal en nuestra función cubo(), x, toma el
valor del argumento real
a, utilizado en la llamada defunción. Estas son algunas cosas que
querrá recordar de los argumentos reales y los parámetros formales:
•••• Las variables de argumento real se deberán definir en el programa llamador. Estará en la función main(), a menos que las funciones sean llamadas por otras funciones.
•••• La clase de datos de los argumentos reales correspondientes y los parámetros formales deberán ser
los mismos.
•••• Los parámetros formales mantienen el espacio para los valores del argumento real durante la
ejecución de la función. Los parámetros formales siempre se listan en la sección de parámetros del encabezado de la función.
•••• El número de argumentos reales usado durante la llamada de función deberá ser el mismo que el
número de parámetros formales listados en el encabezado de la función, excepto cuando se usan parámetros predeterminados. Los parámetros predeterminados se explicarán posteriormente.
•••• La correspondencia entre argumentos reales y parámetros formales se establece sobre las bases de
uno a uno de acuerdo con el orden de la lista respectiva.
•••• Aunque las variables del argumento real y del parámetro formal a menudo tienen diferentes nombres
de variable, pueden ser las mismas. Cuando éste es el caso, los objetos variables respectivos deberán definirse en el programa llamador y también tendrán que aparecer en la lista de parámetros de la función.
RETORNO DE UN RESULTADO AL PROGRAMA QUE INVOCA A LA FUNCIÓN
En algunas ocasiones la función ejecutará cierto tipo de cálculos. La función posteriormente devolverá este valor a quién la llama. Cuando una función regresa un valor, debe indicarle a C++ la clase del valor que devuelve, tal como int,
float, char y así sucesivamente.Para informarle a C++ de la clase de retorno de la función, simplemente preceda al nombre de
lafunción con la clase correspondiente. Por ejemplo, la siguiente función
sumaValores sumados números enteros y regresa un resultado entero.
Ejemplo 10.4
El siguiente programa SUMAVAL.CPP, utiliza la función sumaValores, para sumar valores diferentes:
/* El siguiente programa: SUMAVAL.CPP, llama a una función llamada sumaValores, la cual calcula la suma de dos números enteros.
*/
#include <iostream.h> //Para cout
int sumaValores(int a, int b) {
return (a+b);
} //Fin de sumaValores()
void main(void) {
cout << "100 + 200 = " << sumaValores(100, 200) << endl;
cout << "500 + 501 = " << sumaValores(500, 501) << endl;
cout << "-1 + 1 = " << sumaValores(-1, 1) << endl;
} //Fin de main()
EXAMEN BREVE 27
FUNCIONES void
Las funciones que no regresan un solo valor al programa llamador a menudo se escriben para realizar alguna tarea específica. Estas se llaman funciones void.
Cuando una función no regresa un solo valor al programa llamador, se deberá usar la palabra reservada void como el regreso de la clase de datos. Además, estas funciones pueden o
no requerir parámetros. Cuando no se requieren parámetros, simplemente deje la lista de parámetros en blanco para indicar al compilador que la función no necesita recibir ningún valordesde el programa llamador. Las funciones que no regresen un valor o no requieran ningún
parámetro son del tipo de funciones más simples en C++. Por ejemplo, suponga que quiereescribir una función que mostrará el siguiente encabezado en la pantalla cada vez que se le
llama:NOMBRE CALLE DIRECCIÓN ESTADO CIUDAD CÓDIGO POSTAL
Vamos a llamar a esta función muestraEncabezado() Para desarrollar el encabezado de
la función, pregúntese que deberá aceptar la función para realizar la tarea diseñada y que deberá regresar. En este caso, la función simplemente muestra la información constante de la línea de encabezado y no necesita aceptar ni regresar ningún dato. De esta manera, nuestra interfaz defunción puede escribirse como sigue:
Función muestraEncabezado(): Muestra la información fija del encabezado.
Acepta: Nada.
Regresa: Nada.
Usando esta información, el encabezado de la función se convierte en:
void muestraEncabezado(void)
Observe el
encabezado de la función y verá que se usa la palabra void como la clase de regreso. La palabra reservada void se emplea aquí para indicar al compilador que no hay valorde
regreso. También, note que no hay parámetros requeridos para esta función, porque la listade
parámetros también contiene void o se deja en blanco. En otras palabras, la función no regresa un valor y no requiere ningún argumento para evaluar. Simplemente realiza una tareadeterminada, en este caso mostrando un encabezado. Para mostrar el encabezado, lo que necesita es un enunciado cout en el cuerpo de la función. Colocando todo junto, la función se convierte en:
void muestraEncabezado(void) {
cout << “\tNOMBRE\tCALLE\tDIRECCION\tESTADO\tCIUDAD\tCODIGO POSTAL”
“\n\t______\t_____\t_________\t______\t______\t______ ______” << endl;
} // Fin de muestraEncabezado()
Por último, no verá un enunciado return al final de la función, porque la función no
regresa ningún valor.¿Cómo puede
llamar a esta función en su programa? Simple, sólo use el nombre de lafunción como un enunciado dentro del programa llamador cada vez que el encabezado se muestre, por ejemplo:
muestraEncabezado();
Ningún argumento real se lista en la llamada de la función, porque la función no evalúa ningún argumento.
Cuando
llame una función void, simplemente liste el nombre de la función y los argumentos requeridos como un enunciado sencillo dentro de su programa. No llame unafunción void con un operador de asignación u objeto cout como lo hace para las funciones sin
void. La siguiente llamada muestraEncabezado() deberá causar un error de compilación.encabezado = muestraEncabezado(); // Error cout << muestraEncabezado(); // Error
La llamada correcta es simplemente:
muestraEncabezado();
PARÁMETROS DE VALOR EN COMPARACIÓN CON PARÁMETROS DE REFERENCIA
La función anterior muestraEncabezado() no requiere ninguna lista de parámetros
formal, porque para evaluar no necesita recibir ningún argumento desde el programa llamador.Cuando se requieren evaluar parámetros formales por la función, éstos deberán listarse en el
encabezado de la función en una de dos formas: como parámetros de valor o como parámetros de referencia.PARÁMETROS DE VALOR
Hasta el momento, se han usado parámetros de valor en esta lección. Los parámetros de
valor permiten una comunicación de datos en un sentido desde el programa llamador a lafunción. Una primera aproximación de este concepto se muestra en la figura 10.2a.
Programa llamador Función
Figura 10.2a. Paso de parámetros mediante un valor
Observe que los valores de los argumentos reales en el programa llamador se pasan (por medio de un valor) a parámetros formales en la función. Otra forma de pensar con respecto a esto es que el parámetro formal recibe una copia del valor del argumento real. Cuando la función opera sobre un parámetro de valor, está operando en una copia, más que en el valor
original en el programa llamador. De esta manera, el valor del argumento real en el programa llamador se protege de un cambio accidental por la función. Algo que se debe recordar cuandose usan parámetros de valor es que cualquier manejo de los parámetros formales dentro de la función no afecta el valor del argumento real usado por la llamada de la función. Por ejemplo, considere la siguiente función:
Parámetros formales Argumentos reales “Copia”
void pasaValor(int x, int y);
{
// Incrementa y decrementa parámetros formales ++x;
--y;
// Muestra los valores del parámetro formal cout << “x = ” << x << endl;
cout << “y = ” << y << endl;
} // Fin de pasaValor()
Aquí, los
parámetros x y y son parámetros de valor. Observe que, dentro de la función,el valor de x se incrementa y el de y se decrementa. Así, los valores resultantes se muestran usando un enunciado cout. Ahora, suponga que la función anterior se llama por medio del programa siguiente:
void main(void) {
// Se definen las variables de argumento real int a = 0;
int b = 0;
// Se llama a la función pasaValor(a, b);
// Muestra los valores de argumento real cout << “a = ” << a << endl;
cout << “b = ” << b << endl;
} // Fin del main()
Primero, observe cómo se hace el llamado a la función. Es simplemente un enunciado en el programa llamador. El nombre de la función se lista seguido por los argumentos reales requeridos dentro de paréntesis. Los argumentos reales son a y b, porque éstos se listan en la
llamada de lafunción. Cuando se ejecuta la llamada de la función, el valor de a
pasa al parámetro de valor x y el de b pasa al de y. Otra forma de decir esto es que x recibe una copiade a y y recibe una copia de b. Observe que antes de la llamada de la función, el programa
llamador inicializa ambos valores a y b a 0. Como resultado, x y y reciben el valor de 0 desde elprograma
llamador. La función después incrementa el valor de x, decrementa el valor de y ymuestra los nuevos valores de x y y. Sin embargo, las operaciones sobre x y y no tienen efecto en los argumentos reales (a y b) en el programa llamador. Los valores de a y b permanecen en 0.
Observe que después de la llamada de la función, el programa llamador muestra los valores de a y b. ¿Qué se verá en la pantalla al ejecutar el programa? Bien, la función pasaValor() muestra x y y, después main() muestra a y b. De esta manera, el resultado que se exhibe es:
x = 1 y = -1 a = 0 b = 0
A continuación veamos algunos ejemplos en los que se muestren los conceptos antes aprendido.
Ejemplo 10.5
El siguiente programa, MSTRMSJ.CPP utiliza una función para enviar un mensaje:
Ejemplo 10.6
El siguiente programa, DOSMSJ.CPP, utiliza las funciones muestraTitulo() y muestraLeccion() para visualizar información acerca de las lecciones:
Para incrementar la capacidad de las funciones,
C++ le permite a sus programas pasarinformación (argumentos) a sus funciones. Cuando una función utiliza parámetros, debe indicarle a C++ la clase de cada uno de los parámetros, tales como int,
float, char y asísucesivamente.
/* El siguiente programa: MSTRMSJ.CPP, crea una función muestraMensaje(), para visualizar un mensaje.
*/
#include <iostream.h> //Para cout
void muestraMensaje(void) {
cout << "Hola, he sido rescatado por C++" << endl;
} //Fin de muestraMensaje()
void main(void) {
cout << "Llamado a una función" << endl << endl;
muestraMensaje();
cout << endl << "Regreso del llamado a la función" << endl;
} //Fin de main()
/* El siguiente programa: DOSMSJ.CPP, utiliza dos funciones para enviar cada una un mensaje.
*/
#include <iostream.h> //Para cout
void muestraTitulo(void) {
cout << "APUNTES: Apuntes de COMPUTACION I" << endl;
} //Fin de muestraTitulo()
void muestraLeccion(void) {
cout << "LECCION: Conocimientos básicos sobre funciones" << endl;
} //Fin de muestraLeccion()
void main(void) {
muestraTitulo();
muestraLeccion();
} //Fin de main()
Ejemplo 10.7
El siguiente programa: USOPAR.CPP, utiliza la función mostrarNumero, varias veces, en cada ocasión se le pasa un valor diferente.
En la mayoría de los casos, sus programas pueden pasar varios valores a la función. Para cada valor pasado, su función debe declarar su nombre y clase.
Ejemplo 10.8
El siguiente programa: GDEPEQ.CPP, utiliza la función mostrarGdeYPeq para visualizar el número más grande y el más pequeño de tres enteros que recibe.
/* El siguiente programa: USOPAR.CPP, elabora una función que muestra los diferentes parámetros que le son enviados.
*/
#include <iostream.h> //Para cout
void mostrarNumero(int valor) {
cout << "El valor del parámetros es: " << valor << endl;
} //Fin de mostrarNumero()
void main(void) {
mostrarNumero(1);
mostrarNumero(1001);
mostrarNumero(-532);
} //Fin de main()
/* El siguiente programa: GDEPEQ.CPP, crea una función que determina y muestra cual es el mayor y el menor de tres enteros que le son enviados.
*/
#include <iostream.h> //Para cout
void mostrarGdeYPeq (int a, int b, int c) {
int pequeno = a;
int grande = a;
if (b > grande) grande = b;
if (b < pequeno) pequeno = b;
if (c > grande) grande = c;
if (c < pequeno) pequeno = c;
cout << "El valor más grande es: " << grande << endl;
cout << "El valor más pequeño es: " << pequeno << endl;
} //Fin de mostrarGdeYPeq()
Ejemplo 10.9
El siguiente programa: MSTEMP.CPP, utiliza la función mostrarEmpleado para visualizar la edad de un empleado (clase int) y su salario (clase float)
PARÁMETROS DE REFERENCIA
Los
parámetros de referencia, algunas veces llamados parámetros de variable, difierede los de valor en que éstos proporcionan una combinación en dos sentidos entre el programa
llamador y la función, como se ilustra en la figura 10.2b.Programa llamador Función
void main (void) {
mostrarGdeYPeq (1, 2, 3);
cout << endl;
mostrarGdeYPeq (500, 0, -500);
cout << endl;
mostrarGdeYPeq (1001, 1001, 1001);
} //Fin de main()
/* El siguiente programa: MSTEMP.CPP, muestra una función que visualiza la edad, y el salario de un empleado.
*/
#include <iostream.h> //Para cout
void mostrarEmpleado(int edad, float salario) {
cout << "El empleado tiene " << edad << " años" << endl;
cout << "El empleado gana $" << salario << endl;
} //Fin de mostrarEmpleado()
void main(void) {
mostrarEmpleado(32, 25000.00);
} //Fin de main()
Parámetros formales Argumentos reales “Dirección”
Un parámetro de referencia proporciona una comunicación de ida y vuelta de datos entre el programa llamador y la función. Observe el camino de comunicación de ida y
vuelta: los valores de los argumento reales pasan a los parámetros formales en la función y después los valores de parámetros formales regresan a los argumentos reales. Esto permite a la función cambiar los valores de argumento real en el programa llamador. Recuerde que un parámetro de valor es simplemente una copia del valor del argumento real; por lo tanto, cualquier operaciónsobre el parámetro dentro de la función no tiene efecto en el valor del argumento original. De otra manera, un parámetro de referencia representa la dirección del valor de argumento real en la memoria. Como resultado, cualquier cambio que se haga al parámetro de referencia dentro de la función cambiará lo que está almacenado en esa dirección. Esto obviamente modifica el valor
original del argumento real en el programa llamador.Para crear un
parámetro de referencia, simplemente inserte un ampersand (&) antes delos identificadores de
parámetro apropiados en el encabezado de la función. Vamos a cambiarnuestro ejemplo pasaValor() para usar parámetros de referencia, como sigue:
void pasaReferencia(int &x, int &y);
{
// Incrementa y decrementa parámetros formales ++x;
--y;
// Muestra los valores del parámetro formal cout << “x = ” << x << endl;
cout << “y = ” << y << endl;
} // Fin de pasaReferencia()
El cambio principal aquí es insertar un ampersand antes de x y y en el encabezado de la
función. Seguro, el nombre de lafunción también se ha cambiado para reflejar la nueva aplicación. ¿Qué deberá ver en la pantalla como resultado de la ejecución del siguiente programa?
void main(void) {
// Se definen las variables de argumento real int a = 0;
int b = 0;
// Se llama a la función pasaReferencia(a, b);
// Muestra los valores de argumento real cout << “a = ” << a << endl;
cout << “b = ” << b << endl;
} // Fin del main()
Debido a que x y
y son ahora parámetros de referencia y no parámetros de valor,cualquier operación que afecta a x y y dentro de la función también afectará los valores de los
argumentos reales a y b que se utilizan en la llamada de la función. Estos son los valores quemuestra el programa:
x = 1
y = -1
a = 1
b = -1
Como puede ver, los nuevos valores de x y y pasan de regreso a a y b respectivamente.
Usamos la expresión pasan de regreso para describir la acción. Sin embargo, recuerde que en realidad nada pasa de regreso, porque la función está simplemente operando sobre las
direcciones de los argumentos reales a y b.Ejemplo 10.10
¿Qué se mostrará como resultado del siguiente programa?
void main(void) {
// Define variables de argumento real int a = 0;
int b = 0;
// Llama a la función muestraParametros(a,b);
// Muestra los valores de argumento real cout << “a = ” << a << endl;
cout << “b = ” << b << endl;
} // Fin de main()
/**********************************************************
Esta función muestra el uso de valores en comparación con parámetros de referencia.
**********************************************************/
void muestraParametros(int &x, int y) {
// Incremente y decrementa parámetros formales ++x;
--y;
//Muestra valores de parámetro formal cout << “x = ” << x << endl;
cout << “y = ” << y << endl;
} // Fin de muestraParametro() Solución
Aquí se ve un programa completo que incorpora una función. La función está localizada inmediatamente después de la llave que encierra la función main() La función se llama entonces dentro de la sección de enunciado main() simplemente listando su nombre seguido por una relación de los argumentos reales requeridos. Observe que los argumentos reales (a y b) se definen como objetos enteros en main() Ahora vea el encabezado de la función. Los parámetros formales son x y y. Ambos son enteros; sin embargo, x es un parámetro de referencia mientras que y es un parámetro de valor. Observe el uso de ampersand antes de x. Esto define x como un parámetro de referencia. Sigue una coma después de x finalizando esta definición. Después y se define por separado como un parámetro de valor (sin ampersand) Como resultado, el valor de x pasa de regreso a main() pero no el valor de y. Esto es lo que se verá en la pantalla:
x = 1 y = -1 a = 1 b = 0
Ejemplo 10.11
Escriba una función llamada intercambio() que acepte dos objetos enteros desde el programa llamador y regrese los objetos con sus valores intercambiados.
Solución
Esta es una aplicación ideal para parámetros de referencia porque, para intercambiar los valores, el proceso de intercambio dentro de la función deberá tener un efecto sobre los valores original en el programa llamador. Así, la función deberá aceptar dos objetos enteros y regresar los mismos dos objetos con los valores intercambiados. A continuación se muestra una descripción de la interfaz de la función:
Función intercambio(): Intercambia los valores de dos objetos enteros.
Acepta: Dos objetos enteros.
Regresa: Los mismos dos objetos enteros.
Debido a que la función deberá regresar las mismas dos variables enteras que los que acepta, ambos serán parámetros de referencia. Vamos a etiquetar los parámetros como objeto1 y objeto2. El encabezado de la función entonces se convierte en:
void intercambio(int &objeto1, int &objeto2)
Observe el uso de ampersand para indicar que los parámetros son parámetros de referencia. Debido a que objeto1 y objeto2 son parámetros de referencia, se intercambiarán los valores de los objetos de argumento real usados en la llamada de la función. Ahora, para intercambiar los dos valores dentro de la función, deberá crear un objeto variable local temporal para que no se pierda uno de los valores. De acuerdo con esta idea, la función completa es:
void intercambio(int &objeto1, int &objeto2) {
// Define como local la variable temporal int temp;
// Intercambia los valores temp = objeto1;
objeto1 = objeto2;
objeto2 = temp;
} // Fin de intercambio()
Para llamar a esta función en un programa, simplemente liste el nombre de la función y proporcione dos objetos variables para intercambiar, por ejemplo:
intercambio(a, b)
Por supuesto, a y b deberán definirse e inicializarse con valores dentro del programa llamador, en algún lugar antes de esta llamada de la función.
LOCALIZACIÓN DE LAS FUNCIONES DENTRO DE SU PROGRAMA
Antes de que su programa pueda llamar a una función, C++ debe saber la clase de valor que la función
regresa y el número y clase de parámetros que la función utiliza. En losejemplos antes presentados las definiciones de las funciones preceden a las llamadas que se hacen a las mismas.
Sin embargo, en muchos casos, las funciones pueden aparecer en diversos lugares de su
programa fuente, por ejemplo, después de cerrar la llave de la función main() No hay límite en el
número de funciones definidas por el usuario que se puedan usar en un programa. Para llamar una función que regresa un valor, deberá insertar el nombre de la función donde se quiera que
regrese el valor. Para llamar una función void, simplemente liste su nombre como un enunciadodentro del programa llamador. En ambos casos, los argumentos reales requeridos por la función deberá listarse dentro de paréntesis después del nombre de la función cuando ésta se llama.
Además, el número de argumentos reales que se utilizan en la llamada de función deberá ser el mismo que el número de parámetros formales definidos en el encabezado de la función respectiva, a menos que se usen parámetros predeterminados.
La colocación de las funciones en un programa C++ se resume en la figura 10.3.
Observe la estructura en bloques de un programa general. La función main() forma el bloque
externo general del programa y las funciones definidas por el usuario forman los bloques internos que se anidan dentro de la función main() por medio de las llamadas de las funciones.Esta es la razón de que C++ sea conocido como lenguaje estructurado en bloques. De ahora en adelante, cuando desarrollemos programas C++, intentaremos dividir el problema de programación general en un grupo de subproblemas más sencillos cuya solución combinada soluciona el problema original. ¿Cómo se codificarán estos subproblemas? Ya sabe, ¡Cómo
funciones! Esta es la esencia de la programación estructurada y diseño descendente de software.Figura 10.3. Las funciones por lo general se colocan después de main() en un programa C++
prototipo funcion1();
prototipo funcion2();
void main(void) {
Llamada a la funcion1();
Llamada a la funcion2();
} // Fin de main()
funcion1() {
enunciado1;
enunciado2;
...;
enunciadoN;
} // Fin de la funcion1()
funcion2()
{enunciado1;
enunciado2;
...;
enunciadoN;
} // Fin de la funcion2()
PROTOTIPO DE FUNCIONES
Para asegurarse de que C++ conoce las características de cada función que utiliza su programa, debe colocar prototipos de las funciones al principio de su programa fuente, algunas veces, se conoce como un enunciado de función; es un modelo de interfaz para la función que usa el compilador para verificar el número apropiado de argumentos y las clases de datos de los
argumentos en las llamadas de la función.Los prototipos fuerzan al compilador a realizar verificaciones adicionales a sus llamadas de función, de esta manera ayudan en la detección de errores de programación asociados con
llamadas defunción. Por ejemplo, si una función espera recibir un valor entero y el programador trata de pasar una cadena de caracteres, el compilador puede detectar el error porque C++ requiere que la función prototipo se especifique antes de la llamada de la función.
Dado que los prototipos obligan al compilador a verificar errores durante la compilación, esto no afecta el tamaño ni la velocidad del tiempo de ejecución del programa. Aunque tome al compilador ligeramente más tiempo en realizar esta tarea de verificación de errores, cualquier error detectado por medio de los prototipos puede ahorrar horas de depuración, que serían necesarias si no se emplearan los prototipos. Por estas razones, el lenguaje C++ requiere las funciones
prototipo. Sin embargo, conviene saber que la función prototipo es opcional en ellenguaje C.
En la definición anterior de prototipo, se infiere que éste proporciona un modelo de
interfaz para la función. Bien, la interfaz de la función es el encabezado de la función; por lotanto, el prototipo de la función es sólo una
copia del encabezado de la función que utiliza elcompilador para verificar las llamadas a la función. Así el prototipo dicta las clases de datos que
aceptará lafunción desde el programa llamador y las que regresará la función al programa
llamador.Los
prototipos defunción se localizan antes de la función
main(). El prototipo defunción puede ser sólo una copia del
encabezado de la función seguida por un punto y como,como lo que sigue:
void estudiante(int numero, float promedio, char calificacion);
Aquí, el prototipo le dice al compilador que la función estudiante() no regresará un valor al programa llamador. Además, estudiante() espera recibir tres parámetros cuando se le llama.
El primer parámetro se interpretará como un entero, el segundo como un valor de punto flotante y el tercero como un carácter. Si se hace un llamado de la función con más o menos el número de parámetros listados en el prototipo, el compilador generará un error, a menos que se especifiquen
parámetros predeterminados. Si se llama a lafunción con parámetros que pertenecen a clases de datos diferentes que las listadas en el prototipo, los parámetros se tratarán como si éstos fueran la lista de clases de datos respectivos.
En general un prototipo de función, contiene información acerca del tipo de retorno y de
sus
parámetros. Los siguientes enunciados ilustran prototipo defunción para varias de las
funciones ya utilizadas:
void muestraMensaje(void);
void mostrarNumero(int);
void mostrarEmpleado(int, float);
int sumaValores(int, int);
float valorPromedio(int, int);
Ejemplo 10.12
El siguiente programa: ESTUDIANTE.CPP, utiliza la función estudiante() cuyo prototipo ya se mostró:
La salida generada por este programa es:
Hay 5 exámenes, que dan como resultado un promedio de 85.6 y una calificación alfabética de B.
Cómo puede observar, los argumentos reales en la llamada de la función pasaron a estudiante() y se utilizaron para construir el enunciado cout. Si se han utilizado más o menos parámetros en la llamada de la función, el resultado será un error de compilación. Pero, ¿qué pasaría si las clases de datos del argumento no fueran las mismas que las listadas en el prototipo? Considere la siguiente llamada a la función:
estudiante(‘B’, ‘A’, 67);
Esta llamada no deberá producir un error de compilación, porque el número de parámetros es correcto. Sin embargo, el compilador interpretará el primer parámetro como un entero, el segundo como un valor de punto flotante y el tercero como un valor carácter. El resultado que genera la llamada de función será:
Hay 66 exámenes, que dan como resultado un promedio de 65.0 y una calificación alfabética de C.
/* El siguiente programa: ESTUDIANTE.CPP, ilustra una función que muestra el número de exámenes realizados, el promedio y la calificación alfabética del estudiante.
*/
#include <iostream.h> //Para cout
// Prototipo de la función
void estudiante(int numeroExamenes, float promedio, char calificacion);
void main(void) {
estudiante(5, 85.6, 'B');
} // Fin del main()
/***********************************************************************************
Esta función mostrará un promedio del estudiante y su calificación.
***********************************************************************************/
void estudiante(int numeroExamenes, float promedio, char calificacion) {
cout.setf(ios::fixed);
cout.precision(1);
cout << "Hay " << numeroExamenes << " exámenes, que dan como resultado "
<< "un promedio de " << promedio << endl;
cout << "y una calificación alfabética de " << calificacion << '.' << endl;
} // Fin de estudiante()