19/04/2024
# Tags
#C++ #Programación

Funciones – II

Funciones – II

Continuamos revisando el tema de funciones, en la sección anterior presentamos generalidades de las funciones, es esta sección ahondaremos en sus características.

Funciones con parámetros fijos.

Anteriormente revisamos las funciones con parámetros fijos, es decir, al momento de compilar, le indicamos al compilador cuántos y de que tipo, una función recibirá los parámetros que se le pasen. De hecho es la forma más habitual de definir una función, recordemos la sintaxis.

[extern|static] <tipo_valor_retorno> [modificadores] <identificador>(<lista_parámetros>)
{

[sentencias]

}

A modo de repaso definiremos un programa que utiliza funciones, a continuación desarrollamos un programa para realizar conversiones, te sugiero revisar el código, entenderlo y modificarlo.

Comentarios acerca del programa de conversión de temperaturas.

El programa no realiza (ni pretende) ninguna tarea sofisticada, pero es un punto de partida que vale la pena revisar en su estructura en general.

  1. Como puedes observar, puedes generar tantas funciones como sean necesarias, recuerda nuevamente, debemos empezar por definir las funciones de la forma más primitiva que nos sea posible (es decir, que resuelvan una sola tarea)
  2. Utiliza nombres descriptivos y fáciles de documentar, tal vez en el momento que estás escribiendo el programa recuerdes fácilmente el nombre de una función (y qué hace) pero conforme hagas programas la memoria suele traicionarnos. Más aún si alguien más va usar nuestro código, toma mayor relevancia este punto.
  3. Documenta ampliamente tus funciones, muchas veces verás que los comentarios suelen ser incluso más grandes que el código en sí, pero cuando pase el tiempo y mejores tus habilidades, verás que es un recurso invaluable. Muchas veces, de los comentarios se genera la documentación para tus librerías de funciones. recuerda que los comentarios no impactan en el tamaño, ni el rendimiento del programa ejecutable, así que úsalos sin remordimientos.
  4. Considerando el resto del programa, es importante que veas cómo utilizando funciones logramos código más limpio y fácil de leer, pues para hacer una conversión únicamente tomamos la función que requerimos y realizamos la conversión, no nos interesa ni cómo se obtiene tal o cual resultado, lo único que nos interesa es que sea correcto. Además no «ensuciamos» nuestro programa con operaciones que pueden llegar a ser muy complejas y repetitivas.
  5. En caso que una función no «se comporte de forma correcta», basta con dirigirnos a la misma y realizar todos los cambios que sean necesarios. Mientras respetemos la entrada de datos y la salida de los resultados, podremos utilizarla en nuestro programa sin tocarla en el código que la utiliza.
  6. En otros temas generales, nota que nuestro código va creciendo más y más, pero si notas, la parte que corresponde a la conversión de temperaturas es muy corta y podríamos programarla en muy pocas líneas. El código crecerá por la necesidad que tenemos de informar al usuario de forma clara y precisa de lo que hace nuestro programa, de los datos que esperamos, para presentar la información de forma más amigable, y sobre todo, por el manejo de errores que implementemos.
  7. Si observas gran parte del código que se duplica corresponde a la tarea de preguntar si se desea realizar otro cálculo, podríamos «ahorrarnos» decenas de líneas, pero nuestro programa perdería flexibilidad y funcionalidad, y esto se traduce en que tus usuarios perderían interés en tu programa… por muy bueno que sea.
  8. Finalmente este programa te sirve como repaso en el uso de diversas estructuras de control.

A continuación te presentamos el código, como siempre es importante que lo analices y entiendas. Y después hagas de todo con él. Cambia todo lo que puedas cambiar y observa los resultados.

// cpp_58__funciones3.cpp
// Este programa forma parte del tutorial de introducción al lenguaje C++
// http://a.ehack.info/leguaje-c-introduccion/
// Se ilustra el uso de funciones con varios parámetros y la llamada de funciones
// por otra función
// 2018, Por http://about.me/carlosgbr
// Versión 1
// Compilado en https://www.onlinegdb.com/online_c++_compiler
#include <iostream>
using namespace std;
float Suma(float x, float y)
{
    return x+y;
}
float Resta(float x, float y)
{
    return x-y;
}
float Producto(float x, float y)
{
    return x*y;
}
float Division(float x, float y)
{
    return x/y;
}
float Operacion(float x, float y, char operando)
{
    float resultado = 0;
    switch (operando)
    {
        case '+': {
            resultado = Suma(x, y);
            break;
        }
        case '-': {
            resultado = Resta(x, y);
            break;
        }
        case '*': {
            resultado = Producto(x, y);
            break;
        }
        case '/': {
            resultado = Division(x, y);
            break;
        }
    }
    return resultado;
}
int main()
{
    float operando1 = 0, operando2 = 0;
    char operador;
    cout << "Este programa realiza la operación solicitada sobre 2 operandos" << endl << endl;
    cout << "Escribe el símbolo de la operación que deseas realizar: + - * /" << endl;
    cin >> operador;
    cout << "Escribe el primero operando: ";
    cin >> operando1;
    cout << "Escribe el segundo operando: ";
    cin >> operando2;
    cout << "El resultado de " << operando1 << " " << operador << " " << operando2
                        << " = " << Operacion(operando1, operando2, operador) << endl;
    return 0;
}

Salida del programa

Cuando ejecutes el programa verás que aunque básico, ya es una unidad «autocontenida», te ofrece una descripción, te guía en su uso, te presenta un menú, controla si quieres continuar realizando más conversiones, y termina de forma controlada. Nota que el simple hecho de solo aceptar 2 entradas (S/N) requiere muchas líneas de código, aunque no sean parte de la conversión de temperaturas.

Por otra parte el programa tiene un «error» premeditado, si observas los resultados de convertir grados centígrados a Kelvin y de Kelvin a grados Centígrados, están invertidos, como puedes apreciar en la siguiente salida del programa:

Salida del programa de Temperaturas
Salida del programa de Temperaturas
  • De acuerdo a nuestro programa 0 ºC son -273.15 K, lo cual es erróneo, el valor correcto es 273.15 K
  • De acuerdo a nuestro programa 0 K son 273.15 ºC, lo cual es erróneo, el valor correcto es -273.15 K

En este caso es solo cuestión de poner el cálculo correcto para cada conversión y para ello solo debemos modificar la función correspondiente, no es necesario tocar el código principal, reduciendo de este modo errores potenciales de olvidar cambiar cada punto en donde se utilice nuestra función.

Realiza el cambio de código entre las funciones de ºC a K y viceversa para que ofrezcan conversiones correctas.

Funciones que llaman a otras funciones.

Nuestras funciones pueden llamar a otras funciones (de hecho desde el primer programa hemos estado llamado a varias funciones), de modo que puedes definir funciones primitivas como los bloques sobre los cuales puedes construir funciones de mayor complejidad.

En el siguiente ejemplo se ilustra una función que recibirá 3 parámetros (recuerda que nuestras funciones pueden recibir cualquier cantidad de parámetros que necesitemos). Uno de los parámetros nos indicará la operación que queremos realizar (en nuestro caso solo consideramos la suma, resta, multiplicación y división real), los otros 2 parámetros serán los operandos.

Podríamos hacer todo en una función pero para ilustrar funciones que llaman a otras funciones, lo haremos todo en funciones distintas.

En la siguiente liga puedes descargar el código completo en donde puedes revisar el código, puedes notar que las funciones «primitivas» toman 2 parámetros y nuestra función principal toma 3 parámetros de los cuales uno es de tipo distinto.

Antes de ver el código, te sugiero que intentes generar las funciones que permitan que el código principal que a continuación se muestra, funcione.

int main()
float operando1 = 0, operando2 = 0;
char operador;
cout << "Este programa realiza la operación solicitada sobre 2 operandos" << endl << endl; cout << "Escribe el símbolo de la operación que deseas realizar: + - * /" << endl;
cin >> operador;
cout << "Escribe el primero operando: ";
cin >> operando1;
cout << "Escribe el segundo operando: ";
cin >> operando2;
cout << "El resultado de " << operando1 << " " << operador << " " << operando2 << " = " << Operacion(operando1, operando2, operador) << endl;
return 0;
}

A continuación te muestro 2 posibles salidas del programa:

Salida: Funciones 02
Salida: Funciones 02
Salida: Funciones 03
Salida: Funciones 03

Nota: Esta es otra de las características de las funciones, puedes asignar la implementación de funciones a tu equipo de trabajo, solo definiendo la información que vas a proporcionar y el valor que deseas recibir. De modo que la implementación no afecte el desarrollo de otras partes del código.

Funciones con parámetros variables.

C++. como herencia de C nos permite pasar un número variable de parámetros a una función, de modo que no es necesario saber cuántos parámetros recibirá una función al momento de compilarla.

Para utilizar parámetros variables, es necesario tener en consideración algunos puntos importantes(1):

  • Todos los parámetros que se pasan deben ser del mismo tipo.
  • La declaración de una función que toma un número variable de argumentos requiere al menos un argumento de marcador de posición, incluso si no se utiliza. Si no se proporciona este argumento de marcador de posición, no existe ninguna forma de obtener acceso a los argumentos restantes.
  • Cuando los argumentos de tipo char se pasan como argumentos variables, se convierten al tipo int. De igual forma, cuando los argumentos de tipo float se pasan como argumentos variables, se convierten al tipo double. Los argumentos de otros tipos están sujetos a las promociones habituales de entero y de punto flotante.
  • Las macros y funciones que requieren listas de variables se declaran con puntos suspensivos (…) en la lista de argumentos. Para obtener acceso a los argumentos que pasa una lista de variables. debes utilizar las funciones va_arg, va_copy, va_end, va_start

Sintaxis para utilizar una función con parámetros variables. (2)(3)

tipo funcion (tipo last, ... );

en donde,

  • tipo: Tipo de retorno de la función.
  • función: Nombre de la función
  • tipo last, nombre genérico de nuestra variable y su respectivo tipo de dato.
  • : obligatorios, le indican al compilador que se espera una lista variable de argumentos (parámetros)

Para poder utilizar una lista de argumentos variable C++ tienen definido en el archivo de cabecera estándar stdarg.h una serie de macros y un tipo de dato, que nos permiten gestionar las l istas de argumentos variables.

  • va_list. Este tipo de dato va a albergar el puntero a las direcciones de memoria que contienen los argumentos, , se maneja a través de las macros siguientes.
  • void va_start(va_list pa, last). Esta función inicializa nuestra variable de tipo va_list. Toma dos parámetros. El primero es nuestra variable de tipo va_list. El segundo es el último parámetro conocido. Lo que hace esta función (o macro) es lo antes mencionado, toma la dirección de memoria del último parámetro conocido y posiciona el búfer pasada ésta dirección.
  • tipo va_arg(va_list pa, tipo). Nos devuelve el valor del siguiente parámetro variable  -apuntado por el puntero pa y de tipo tipo-, que puede ser de cualquier tipo valido que pueda pasarse como argumento a una función. Además, esta macro, manipula pa haciendo que apunte al siguiente argumento de la lista para que invocaciones sucesivas devuelvan los valores del resto de argumentos.
  • void va_end(va_list pa). Una vez que terminamos, hay que emplear esta macro para indicar que hemos terminado. El único parámetro es nuestro puntero va_list.

Macros, búfer, direcciones de memoria, cast, typedef, promoción, cabecera, pseudocódigo… En 2 párrafos un mundo de términos que ni en todo lo que va de este tutorial… si no estudias sistemas, te pido ignores estos términos. No los necesitarás. Pero es imprescindible, por rigor, utilizar los términos para documentar adecuadamente los parámetros variables.

Pseudocódigo para utilizar una función de parámetros variables

A continuación tienes el pseudocódigo que muestra el uso de parámetros variables en funciones.

tipo funcionVariable(tipo ultimo , ...) {
va_list pa;
tipo_X argumento_de_tipo_X;
va_start(pa, ultimo);
while (quedanArgumentos)
argumento_de_tipo_X = va_arg(pa, tipo_X);
va_end(pa);
}

Ejemplo 1 de argumentos variables en funciones

// cpp_59_funciones4.cpp
// Este programa forma parte del tutorial de introducción al lenguaje C++
// http://a.ehack.info/leguaje-c-introduccion/
// Se ilustra el uso de parámetros variables en una función
// 2018, Por http://about.me/carlosgbr
// Versión 1
// Compilado en https://www.onlinegdb.com/online_c++_compiler
#include <iostream>
#include <stdarg.h> // Necesaria para utilizar  va_list, va_start, va_arg, va_end
using namespace std;
float Promedio(int calificacion, ...)   // Los ... indican que son parC!metros variables
{
    float sumaCalif = 0;
    int cuenta = 0;
    int indice = calificacion;  // C-dice = calificacion para determinar un punto
                                // para determinar cuando es el C:ltimo valor.
    va_list marcador;           // Definimos a marcador como lista variable
    va_start(marcador, calificacion); // Asignamos el argumento al puntero marcador
while (indice != -1){
        sumaCalif += indice;
        cuenta++;
        indice = va_arg(marcador,int); //recuperamos el valor actual de marcador
                                       // le asignamos tipo
    }
  va_end (marcador);    // Terminamos la lista variable
    return sumaCalif;
}
int main()
{
   cout << "La suma de boletas entregadas es: " << Promedio(1,2,3,9,-1) << endl;
   cout << "La suma de boletas entregadas es: " << Promedio(6, 8, 9, 10, 4, 7, 9,-1) << endl;
   cout << "La suma de boletas entregadas es: " << Promedio(10, 7,-1) << endl;
   cout << "La suma de boletas entregadas es: " << Promedio(10, 10, 0,-1) << endl;
    return 0;
}

Puedes comprobar que nuestra función recibe cualquier número de argumentos y realiza la suma de los mismos. Puedes probar mejorar el código haciendo que sea el usuario quien introduzca los números a sumar.

En los comentarios dentro del programa se realizan las observaciones que considero oportunas.

Después de los punteros, creo que este tema es el más complejo, expuesto hasta el momento. Por el perfil de este tutorial (para no programadores) dejo en este punto la exposición de parámetros variables en funciones. El objetivo es dejar señalada la existencia de este tema y una exposición inicial. Si el lector desea profundizar en el tema, antes de publicar nuestro curso para programadores, les sugiero revisar las siguientes lecturas:

Conclusión

Para finalizar este tema concluyo con un extracto de la obra del Ing. Ubaldo José Bonaparte (2):

Funciones con argumentos Variables

“Los parámetros juegan un papel demasiado importante en los desarrollos, donde el programador haciendo el uso adecuado de los mismos, alimentará el buen hábito de controlar exhaustivamente
la persistencia y manipulación de sus variables u objetos y como consecuencia mantendrá distancia de los efectos colaterales.
En la actualidad, la programación con lenguajes como Java, J#, .Net, C# y otros, continua sobre la base de los conceptos expuestos. De modo tal que recomendamos este artículo, especialmente a principiantes que deseen manejar cuidadosamente los parámetros y argumentos.”


Ethical Hack

Referencias

Fuente Imágenes:

  • «Todas las demás imágenes de esta sección»: by Nala Systems

Código Fuente:

Licencia de Creative Commons
Funciones II en C++ by Roberto C. González is licensed under a Creative Commons Reconocimiento-NoComercial-CompartirIgual 4.0 Internacional License.
Funciones – II

Funciones – I

Funciones – II

Funciones III – Bibliotecas

Leave a comment

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *