Muestra las diferencias entre dos versiones de la página.
Ambos lados, revisión anterior Revisión previa Próxima revisión | Revisión previa Última revisión Ambos lados, revisión siguiente | ||
curso-cpp:modularizacion-funciones [2017/03/19 20:54] santo [Por qué es mejor usar funciones] |
curso-cpp:modularizacion-funciones [2017/09/22 16:26] santo [Algunos ejemplos de macros muy útiles] |
||
---|---|---|---|
Línea 93: | Línea 93: | ||
==== Facilitar un enfoque top-down ==== | ==== Facilitar un enfoque top-down ==== | ||
- | Esta ventaja está estrechamente relacionada con la anterior. Supongamos que nos dieran la siguiente consiga: | + | Esta ventaja está estrechamente relacionada con la anterior. Supongamos que nos dieran la siguiente consigna: |
"Crear un programa que lea dos números ''a'' y ''b'', que indican un rango de números (inclusive), y calcule y muestre en la pantalla dos valores: La suma de los cuadrados de todos los números primos entre a y b, y además, la suma de todos los números entre a y b que son múltiplos de 3 y de 10, pero no de 30." | "Crear un programa que lea dos números ''a'' y ''b'', que indican un rango de números (inclusive), y calcule y muestre en la pantalla dos valores: La suma de los cuadrados de todos los números primos entre a y b, y además, la suma de todos los números entre a y b que son múltiplos de 3 y de 10, pero no de 30." | ||
Línea 231: | Línea 231: | ||
===== Parámetros ===== | ===== Parámetros ===== | ||
- | No siempre queremos que una función haga exactamente lo mismo cada vez que usa. A veces, queremos que haga **casi** lo mismo, pero cambiando algún **dato** entre usos. Por ejemplo, podríamos querer una función que eleve un número al cuadrado, es decir, que permita calcular ''x*x'' si ya tenemos un entero ''x''. Así, cuando usamos la función con 3, queremos que devuelva ''3*3 == 9'', y cuando la usamos con -4 queremos que devuelva ''(-4)*(-4) == 16''. | + | No siempre queremos que una función haga exactamente lo mismo cada vez que se usa. A veces, queremos que haga **casi** lo mismo, pero cambiando algún **dato** entre usos. Por ejemplo, podríamos querer una función que eleve un número al cuadrado, es decir, que permita calcular ''x*x'' si ya tenemos un entero ''x''. Así, cuando usamos la función con 3, queremos que devuelva ''3*3 == 9'', y cuando la usamos con -4 queremos que devuelva ''(-4)*(-4) == 16''. |
En el ejemplo anterior la función no hace siempre lo mismo, porque a veces hace 3*3 y a veces (-4)*(-4), pero más allá del número que vamos a elevar, las **operaciones** que hace la función son siempre las mismas, y solo cambia este **dato** inicial. A ese **dato que cambia**, lo llamamos en programación un **parámetro** de la función. Una función puede tener 1 o más parámetros, o incluso cero: Las funciones que vimos antes tenían cero parámetros. La función de elevar al cuadrado tendría un único parámetro: El número entero que vamos a querer elevar. | En el ejemplo anterior la función no hace siempre lo mismo, porque a veces hace 3*3 y a veces (-4)*(-4), pero más allá del número que vamos a elevar, las **operaciones** que hace la función son siempre las mismas, y solo cambia este **dato** inicial. A ese **dato que cambia**, lo llamamos en programación un **parámetro** de la función. Una función puede tener 1 o más parámetros, o incluso cero: Las funciones que vimos antes tenían cero parámetros. La función de elevar al cuadrado tendría un único parámetro: El número entero que vamos a querer elevar. | ||
Línea 550: | Línea 550: | ||
* Variables con el mismo nombre pero definidas en funciones distintas, representan variables **diferentes** (como el ''x'' del main y el ''x'' de la función en el ejemplo anterior de ''incrementar'') | * Variables con el mismo nombre pero definidas en funciones distintas, representan variables **diferentes** (como el ''x'' del main y el ''x'' de la función en el ejemplo anterior de ''incrementar'') | ||
+ | |||
+ | ===== Ejemplos de implementación de funciones ===== | ||
+ | |||
+ | * Nuestro primer ejemplo es la función ''main'', que ya venimos usando en todos nuestros programas: Es una función que devuelve un ''int'', que usa la computadora para saber si hubo errores. Por convención, se debe devolver cero si todo salió bien, y por eso es buena costumbre terminar todos los programas con ''return 0''. La función ''main'' es importante porque tiene la característica especial de que allí comienzan a ejecutarse todos nuestros programas, aunque tengan otras funciones. | ||
+ | * Como ejemplo de pensamiento top-down, supongamos que debemos realizar un programa que lea una secuencia de números, y luego calcule y muestre por pantalla la suma, el máximo y el mínimo de todos estos números. Podemos programar primero que anda el main de la siguiente manera:<code> | ||
+ | int main() | ||
+ | { | ||
+ | vector<int> v; | ||
+ | v = leerNumeros(); | ||
+ | imprimirResultados(suma(v), maximo(v), minimo(v)); | ||
+ | return 0; | ||
+ | } | ||
+ | </code> Donde nos hemos ordenado y hemos logrado **descomponer** el problema entero en tareas más pequeñas. Luego podríamos agregarle las funciones que faltan al programa, para completarlo, dejando inalterado el mismo main que ya escribimos: <code> | ||
+ | vector<int> leerNumeros() | ||
+ | { | ||
+ | // instrucciones... | ||
+ | } | ||
+ | |||
+ | int suma(vector<int> v) | ||
+ | { | ||
+ | // instrucciones... | ||
+ | } | ||
+ | |||
+ | int maximo(vector<int> v) | ||
+ | { | ||
+ | // instrucciones... | ||
+ | } | ||
+ | |||
+ | int minimo(vector<int> v) | ||
+ | { | ||
+ | // instrucciones... | ||
+ | } | ||
+ | |||
+ | void imprimirResultados(int laSuma,int elMaximo, int elMinimo) | ||
+ | { | ||
+ | // instrucciones... | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | * El siguiente es un ejemplo con funciones que calculan áreas de figuras geométricas, que muestra como podemos reutilizar ciertas funciones dentro de otras: <code> | ||
+ | int areaParalelogramo(int base, int altura) | ||
+ | { | ||
+ | return base * altura; | ||
+ | } | ||
+ | int areaCuadrado(int lado) | ||
+ | { | ||
+ | return areaParalelogramo(lado, lado); | ||
+ | } | ||
+ | int areaTriangulo(int base, int altura) // Trabaja con enteros: Redondea hacia abajo | ||
+ | { | ||
+ | return areaParalelogramo(base, altura) / 2; | ||
+ | } | ||
+ | </code> | ||
+ | * El siguiente es un ejemplo de función que recibe dos variables enteras, e intercambia sus valores. ¡Notar el uso del ampersand! <code> | ||
+ | void intercambiar(int &variable1, int &variable2) | ||
+ | { | ||
+ | int auxiliar = variable1; // Es necesario un auxiliar: ¿Por qué? | ||
+ | variable1 = variable2; | ||
+ | variable2 = auxiliar; | ||
+ | } </code> Similarmente, el siguiente ejemplo permite "rotar" los valores de tres variables dadas: Es decir, transforma [a,b,c] en [b,c,a]: <code> | ||
+ | void rotar3(int &a, int &b, int &c) | ||
+ | { | ||
+ | int auxiliar = a; // Nuevamente, ¿Por qué es necesario el auxiliar? | ||
+ | a = b; | ||
+ | b = c; | ||
+ | c = auxiliar; | ||
+ | } | ||
+ | </code> | ||
+ | ===== Algunas funciones predefinidas ===== | ||
+ | |||
+ | En C++, existen algunas funciones predefinidas que ya existen, y conocerlas puede simplificarnos la tarea de programar ya que nos ahorramos tener que escribirlas nosotros mismos. Mencionamos algunas a continuación: | ||
+ | |||
+ | * ''max'': Dados dos números, devuelve el máximo. Por ejemplo ''max(2,9) == 9'' y ''max(5,3) == 5''. Similarmente tenemos ''min'' para el mínimo. | ||
+ | * ''swap'': Intercambia los valores de las dos variables que se le indica. Por ejemplo si ''x'' tiene un ''3'', y ''q[i]'' tiene un ''8'', luego de hacer ''swap(x,q[i])'' quedará ''q[i]'' con un 3 y ''x'' con un 8. | ||
+ | * ''abs'': Devuelve el valor absoluto (módulo) de un entero. Por ejemplo ''abs(-3) == 3'', ''abs(0) == 0'' y ''abs(15) == 15''. | ||
+ | |||
+ | Todas estas funciones requieren utilizar ''#include <algorithm>'' para tenerlas disponibles. | ||
+ | |||
+ | ===== Algunos errores comunes ===== | ||
+ | |||
+ | * Pasar a la función una cantidad de parámetros diferente de las que la función necesita, o con el tipo incorrecto. Por ejemplo si tenemos la función <code> | ||
+ | int mayor(int num1, int num2) | ||
+ | { | ||
+ | if (num1 > num2) | ||
+ | return num1; | ||
+ | else | ||
+ | return num2; | ||
+ | } | ||
+ | </code> serían incorrectas las siguientes llamadas: <code> | ||
+ | mayor(k,m,n) // Pasa 3 parámetros, pero la función toma solamente 2 | ||
+ | mayor(23, "miliwatt") // Pasa 2 parámetros, pero el segundo es una cadena y debería ser un int | ||
+ | </code> | ||
+ | * Diseñar una función con la idea de que **modifique** uno de sus parámetros, pero trabajar con una copia por no utilizar el ampersand ''&''. | ||
+ | * Intentar utilizar un parámetro (con su nombre) **fuera** de una función: Los parámetros solamente están definidos dentro de la función, y no tiene sentido utilizarlos fuera de ella (son variables locales). | ||
+ | * Utilizar una función que todavía no se definió. Se debe programar el código de una función, antes de utilizarla. | ||
===== Ejercicios ===== | ===== Ejercicios ===== | ||
Línea 556: | Línea 651: | ||
Por ejemplo, en los ejercicios en los que se hablaba de números primos, se podría escribir una función que toma un ''int N'', y devuelve un ''bool'' indicando si es primo. O por ejemplo, escribir una función ''sumaDeDivisores'' puede ser útil para escribir de forma más fácil y clara programas que buscan números perfectos. | Por ejemplo, en los ejercicios en los que se hablaba de números primos, se podría escribir una función que toma un ''int N'', y devuelve un ''bool'' indicando si es primo. O por ejemplo, escribir una función ''sumaDeDivisores'' puede ser útil para escribir de forma más fácil y clara programas que buscan números perfectos. | ||
+ | Otros ejercicios: | ||
+ | |||
+ | * Escribir una función ''string escribirEnBase(int numero, int base)'', que tome un número y una base (Entre 2 y 16 inclusive) y devuelva una cadena con la escritura de ese número en la base indicada. | ||
+ | * Escribir una función ''int leerNumeroEnBase(string escritura, int base)'', que tome la escritura de un cierto número en la base indicada (Entre 2 y 16 inclusive) y devuelva el número en cuestión. | ||
+ | |||
+ | Puede ver aquí [[algoritmos-oia:enteros:cambio-de-base|cómo realizar cambios de base]]. | ||
===== Los #define ===== | ===== Los #define ===== | ||
Línea 647: | Línea 748: | ||
Vemos que ahora solamente hace falta especificar **una vez** el nombre de la variable, y todo lo demás es copiado automáticamente en forma mecánica por el ''#define''. | Vemos que ahora solamente hace falta especificar **una vez** el nombre de la variable, y todo lo demás es copiado automáticamente en forma mecánica por el ''#define''. | ||
- | Se puede consultar [[cpp-avanzado:macros |aquí]] otros ejemplos de macros muy útiles para programación competitiva, además del ''forn'' ya mostrado. | + | Se puede consultar [[cpp-avanzado:macros |aquí]] otros ejemplos de macros más avanzadas, muy útiles para programación competitiva, además del ''forn'' ya mostrado. |
==== Por qué es mejor usar funciones ==== | ==== Por qué es mejor usar funciones ==== | ||