Anda di halaman 1dari 12

Funciones

Una funcin es un conjunto de lneas de cdigo que realizan una tarea especfica y puede retornar un valor. Las funciones pueden tomar parmetros que modifiquen su funcionamiento. Las funciones son utilizadas para descomponer grandes problemas en tareas simples y para implementar operaciones que son comnmente utilizadas durante un programa y de esta manera reducir la cantidad de cdigo. Cuando una funcin es invocada se le pasa el control a la misma, una vez que esta finaliz con su tarea el control es devuelto al punto desde el cual la funcin fue llamada.

[editar] Definiendo una funcin


<tipo> [clase::] <nombre> ( [Parmetros] ) { cuerpo; }

Ejemplo de una funcin Para comenzar, vamos a considerar el caso en el cual se desea crear la funcin cuadrado(), misma que deber volver el cuadrado de un nmero real (de punto flotante), es decir, cuadrado() aceptar nmeros de punto flotante y regresar una respuesta como nmero flotante. Nota: aunque para la funcin que veremos el tipo de retorno coincide con el tipo de parmetro pasado, algunas veces las cosas pueden cambiar, es decir, no es obligatorio que una funcin reciba un parmetro de un tipo y que tenga que regresar una respuesta de dicho tipo.
// regresar el cuadrado de un nmero double cuadrado(double n) { return n*n; }

[editar] Parmetros
Normalmente, las funciones operan sobre ciertos valores pasados a las mismas ya sea como constantes literales o como variables, aunque se pueden definir funciones que no reciban parmetros. Existen dos formas en C++ de pasar parmetros a una funcin; por referencia o por valor. El hecho es que si en una declaracin de funcin se declaran parmetros por referencia, a los mismos no se les podr pasar valores literales ya que las referencias apuntan a objetos (variables o funciones) residentes en la memoria; por otro lado, si un parmetro es declarado para ser pasado por valor, el mismo puede pasarse como una constante literal o como una variable. Los parmetros pasados por referencia pueden ser alterados por la funcin que los reciba, mientras que los parametros pasados por valor o copa no pueden ser alterados por la funcin que los recibe, es decir, la funcin puede manipular a su antojo al parmetro, pero ningn cambio hecho sobre este se reflejar en el parmetro original. Parametros por valor La funcin cuadrado() (ver arriba) es un clsico ejemplo que muestra el paso de parmetros por valor, en ese sentido la funcin cuadrado() recibe una copia del parmetro n. En la misma funcin se puede observar que se realiza un calculo ( n*n ), sin embargo el parmetro original no sufrir cambio alguno, esto seguir siendo cierto an cuando dentro de la funcin hubiera una instruccin parecida a n = n * n; o n*=n;. Parametros por referencia Para mostrar un ejemplo del paso de parmetros por referencia, vamos a retomar el caso de la funcin cuadrado, salvo que en esta ocasin cambiaremos ligeramente la sintaxis para definir la misma. Veamos:
// regresar el cuadrado de un nmero double cuadrado2(double &n) { n *= n; return n; }

Al poner a prueba las funciones cuadrado() y cuadrado2() se podr verificar que la primera de estas no cambia el valor del parmetro original, mientras que la segunda s lo hace.

[editar] Llamar a una funcin


Una vez que en su programa se ha definido una funcin, esta puede ser llamada las veces que sean necesarias. Para llamar a una funcin basta con hacer referencia a su nombre y si la misma requiere de parmetros estos debern indicarse dentro de parentesis. Para llamar a una funcin que no requiera de parmetros se deber indicar el nombre de la misma seguida de parentesis vacios. Por ejemplo, para llamar a la funcin cuadrado() vista anteriormente, podemos emplear:
cout << cuadrado(25); cout << cuadrado(X); R = cuadrado(X); // guardar en R el cuadrado de X

[editar] Funciones void


Bajo ciertas circunstancias se desear escribir funciones que no regresen valor alguno (esto sera algo parecido a escribir procedures en Pascal) y para ello podemos declarar a la funcin como void. La palabra reservada void es utilizada para declarar funciones sin valor de retorno y tambin para indicar que una funcin especfica no requiere de parmetros. Por ejemplo, la funcin pausa() que se ver en seguida, no devolver valor alguno y la misma no requiere de parmetros.
// esta funcin requiere de la librera iostream void pausa(void) { cout "Por favor presione <Enter>..."; cin.get(); cin.ignore(255, '\n'); // rechazar caracteres introducidos antes de <Enter> }

Notas: se debe de aclarar que el uso de la palabra void dentro de los parentesis es opcional al momento de declarar una funcin. Asi, la funcin pausa() podra haberse declarado como void pausa(), y la misma puede invocarse como: pausa();.

[editar] Funciones anidadas


A diferencia de Pascal, el lenguaje C,C++ no permite anidar funciones, sin embargo, dentro de una funcon puede existir la llamada a una o ms funciones declaradas previamente.

[editar] Funciones de tipo puntero (*)


En muchas ocasiones se desea que ciertas funciones regresen una referencia o puntero hacia un tipo ( sea ste estructurado o no) especfico de dato en lugar de un valor especfico. En tales casos, la funcin se deber declarar como para que regrese un puntero. Por ejemplo, supongamos que deseamos crear una funcin para convertir un nmero entero en notacin decimal a una cadena de caracteres en forma de nmeros binarios, luego, la funcin mencionada podra escribirse para que reciba el nmero entero como parmetro y regrese un puntero a una cadena de caracteres conteniendo la conversin. Para ser ms puntuales, vamos a escribir un programa en donde se ver la funcin binstr(), y cuyo objetivo ser precisamente convertir nmeros decimales en cadenas binarias. Nota: observe que en la sintaxis para declarar funciones tipo puntero se debe de poner el smbolo * despues del tipo y antes del nombre de la funcin que se est declarando. Esto se puede ver en el programa, ya que la funcin binstr se declara como: char *binstr(unsigned int);
// programa : funciones01.cpp // autor : Wikipedia #include <iostream.h> #include <string.h> using namespace std;

// declaracin de prototipo char *binstr(unsigned int); // punto de prueba int main() { int n = 128; count << "decimal = " << n << ", endl; cin.get(); }

binario = " << binstr(n) <<

// definicin de funcin binstr() // nota: esta funcion requiere de la librera estndar string char *binstr(unsigned int n) { static char buffer[65]; int i = 0; strcpy(buffer, "0"); if (n > 0) { while (n > 0) { buffer[i] = ( n & 1 ) + '0'; i++; n >>= 1; } buffer[i] = '\0'; strrev(buffer); } // fin (n > 0) return buffer;

[editar] Variables estticas y automticas


Dentro de una funcin, las variables y/o constantes pueden ser declaradas como: auto (por omisin) o como static. Si una variable dentro de una funcin es declarada como esttica significa que la misma retendr su valor entre las llamadas a la funcin. Por otro lado, la variables automticas pierden su valor entre las llamadas. En el programa anterior puede verse que el arreglo de caracteres (buffer[65]) se ha declarado como esttico para garantizar que dicho buffer retenga los datos an despues de que la funcin termine. En el mismo ejemplo, si el buffer no se declara como esttico, el contenido del mismo podra ser destruido al salir de la funcin y los resultados obtenidos podran ser no deseados.

[editar] Parmetros constantes


Los parmetros usados por una funcin pueden declararse como constantes ( const ) al momento de la declaracin de la funcin. Un parmetro que ha sido declarado como constante significa que la funcin no podr cambiar el valor del mismo ( sin importar si dicho parmetro se recibe por valor o por referencia ). Ejemplo:

int funcionX( const int n ); void printstr( const char *str );

[editar] Parmetros con valor por defecto


Los parmetros usados por una funcin pueden declararse con un valor por defecto. Un parmetro que ha sido declarado con valor por defecto es opcional a la hora de hacer la llamada a la funcin. Ejemplo: Dada la funcin:
void saludo( char* mensaje = "Hola mundo" );

la misma puede ser invocada como:


saludo(); // sin parmetro saludo("Sea usted bienvenido a C++"); // con parmetro

Para ver un ejemplo ms, vamos a considerar el caso de la funcin binstr() del programa funciones01. Ahora, vamos modificar dicha funcin, salvo que esta ocasin nos interesa que la misma sirva para convertir nmeros decimales en cadenas numricas y cuya base de conversin sea pasada como parmetro. Es decir, la funcin de la que estamos hablando podr convertir nmeros decimales a: binario, octal, decimal, hexadecimal, etc.; y la nica condicin ser que la base indicada est entre el 2 y el 36, inclusive. Nota: Ya que la funcin servir para convertir nmeros a cualquier representacin la nombraremos como numstr() en lugar de binstr(). Si la funcin es invocada sin el parmetro base regresar una cadena de digitos decimales.
// programa : funciones02.cpp // autor : Oscar E. Palacios #include <iostream.h> #include <stdlib.h> using namespace std; // declaracin de prototipo char *numstr(unsigned int, const int base = 10); // punto de prueba int main() { int n = 128; count "decimal = " << n << ", endl; count "decimal = " << n << ", endl; cin.get(); }

binario = " << numstr(n, 2) << octal.. = " << numstr(n, 8) <<

// definicin de funcin numstr() // nota: esta funcion requiere de la librera stdlib.h char *numstr(unsigned int n, const int base) { static char buffer[65]; itoa(n, buffer, base);

return buffer; }

[editar] Parmetros de tipo puntero


Anteriormente se mencion que en C++ los parmetros a una funcin pueden pasarse por valor o por referencia, al respecto, podemos agregar que los parmetros tambin pueden pasarse como punteros. El paso de parmetros de punteros es bastante parecido al paso de parmetros por referencia, salvo que el proceso de los datos dentro de la funcin es diferente. Por ejemplo, las funciones:
void referencia( int &X ) { X = 100; } void puntero( int *X ) { *X = 100; }

ambas reciben un puntero o referencia a un objeto de tipo entero, por lo tanto cualquiera de las funciones del ejemplo puede cambiar el valor de la variable entera apuntada por X, la diferencia radica en la forma en que cada una de las mismas lleva cabo la tarea. Si en la funcin puntero() en lugar de usar *X = 100; se usara X = 100; se le asignara 100 al puntero X, ms no al objeto apuntado por X, y esto podra ser la causa de que el programa se terminara de manera abrupta.

[editar] Parmetros estructurados


Al igual que cualquier otro tipo los parmetros de tipo estruturado pueden pasarse por valor o por referencia, sin embargo, podra ser que si una estructura es pasada por valor el compilador mostrara una advertencia ( warning ) indicando que se pasado por valor una estructura, puesto que el paso de estructuras por valor es permitido usted puede ignorar la advertencia, pero lo mejor es pasar estructuras por referencia. Si una estructura es pasada por valor y si esta es muy grande podria ser que se agotara la memoria en el segmento de pila ( Stack Segment ), aparte de que la llamada a la funcin sera ms lenta. Para ver un ejemplo, consideremos el caso del siguiente tipo estructurado:
struct empleado { char nombre[32]; int edad; char sexo; };

Ahora, pensemos que deseamos escribir una funcin para imprimir variables del tipo empleado. As, la funcin puede escribirse de las tres maneras siguientes:
// Parametro empleado pasado por valor void ImprimeEmpleadoV( empleado e) { printf("Nombre: %s\n", e.nombre); printf("Edad : %i\n", e.edad); printf("Sexo : %c\n", e.sexo); return; } // Parametro empleado pasado por referencia void ImprimeEmpleadoR( empleado &e ) {

printf("Nombre: %s\n", e.nombre); printf("Edad : %i\n", e.edad); printf("Sexo : %c\n", e.sexo); return;

// Parametro empleado pasado como puntero void ImprimeEmpleadoP( empleado *e ) { printf("Nombre: %s\n", e->nombre); printf("Edad : %i\n", e->edad); printf("Sexo : %c\n", e->sexo); return; }

[editar] Funciones sobrecargadas


C++, a diferencia del C estndar, permite declarar funciones con el mismo nombre y a esto se conoce como sobrecarga de funciones. Las funciones sobrecargadas pueden coincidir en tipo, pero al menos uno de sus parmetros tiene que ser diferente. En todo caso, si usted trata de declarar funciones sobrecargadas que coincidan en tipo y nmero de parmetros el compilador no se lo permitir. Para poner un ejemplo vamos a considerar el caso de dos funciones cuyo nombre ser divide, ambas regresarn el cociente de dos nmeros, salvo que una de ellas operar sobre nmeros enteros y la otra lo har sobre nmeros reales ( de punto flotante ). Nota: cuando en los programas se hace una llamada a una funcin sobrecargada, el compilador determina a cual de las funciones invocar en base al tipo y nmero de parmetros pasados a la funcin.
// programa : funciones03.cpp // autor : Oscar E. Palacios #include <iostream.h> #include <stdlib.h> using namespace std; // divide enteros int divide(int a, int b) { cout << "divisin entera" << endl; return ( (b != 0) ? a/b : 0); } // divide reales double divide(double a, double b) { cout << "divisin real" << endl; return ( (b != 0) ? a/b : 0); } // punto de prueba int main() { cout << divide(10, 3) << endl; cout << divide(10.0, 3.0) << endl; cin.get(); }

[editar] Funciones recursivas


Una funcin recursiva es aquella que contiene una llamada a si misma. Usted probablemente se pregunte cal es el objetivo de que una funcin se llame a si misma ?. Bueno, djeme decirle que habr ocasiones en las cuales el uso de sta tcnica tiene sus ventajas. Por ejemplo, las personas que manejan el lenguaje de las matemticas saben que hay ciertos procesos que son repetitivos, tal es el caso del procedimiento para obtener el factorial de un nmero. As, procederemos a escibir un programa y dentro del mismo la funcin Factorial, misma que servir como ejemplo de una funcin recursiva. factorial tomar un solo parmetro tipo Long (entero largo) pasado por valor y regresar el factorial del nmero.

! ADVERTENCIA ! Las funciones recursivas deben tener

una forma para poder salir y as evitar que stas se esten llamado de manera infinita, ya que sto ocasionara un error conocido como desbordamiento de pila (Stack Overflow). En el programa titulado funciones04.cpp que se ver enseguida, se crean dos funciones; Factorial y Factorial2, con el objetivo de que el estudiante pueda observar la diferencia entre la construccin de una funcin recursiva y otra igual pero no recursiva.

Nota: El factorial de un nmero se define como n! y significa "Multiplicar todos los


nmeros comprendidos entre el 1 y n; inclusive, n > 0". Tambien se considera que el factorial de 0 es igual a 1, y se define como: 0! = 1.
Ejemplo. Dado el nmero 5, calcular el factorial. Solucion: 5! = 1 x 2 x 3 x 4 x 5 = 120

La formula general para calcular el factorial de un nmero n puede expresarse como: n (n-1) (n-2)...(1), misma que ser utilizada por la funcin recursiva factorial() del siguiente programa.
// programa funciones04.cpp // Autor: Oscar E. Palacios #include <stdlib.h> #include <iostream.h> // factorial es una funcion recursiva. // Nota: el maximo valor para el parmetro n es 16 long factorial(long n) { if (n <=1) return(1); else return( n * factorial(n - 1) ); } // factorial2 es una funcion no recursiva. // Nota: el maximo valor para el parmetro n es 16 long factorial2(long n) { long p, r; r = 1; if (n >1) { for (p=1; p<=n; p++) r = r * p; } return r; }

// punto de prueba int main() { cout << "Demostracin de una funcin recursiva" << endl << endl; // llamada a la funcion recursiva cout << "Factorial de 6 = " << factorial(6) << endl; // llamada a la funcion no recursiva cout << "Factorial de 6 = " << factorial2(6) << ednl; system("pause"); return 0;

[editar] Nmero variable de parmetros


En C,C++ se pueden crear funciones que operen sobre una lista variable de parmetros, es decir, en donde el nmero de parmetros es indeterminado. En esta seccin se mostrar un ejemplo de la manera en que podemos crear funciones para manejar tales asuntos, y para ello haremos uso de tres macros soportadas por C++: 1. va_list puntero de argumentos 2. va_start inicializar puntero de argumentos 3. va_end liberar puntero de argumentos La sintaxis que usaremos para declarar funciones con lista de parmetros variables es:
1) tipo nombrefuncion(...) 2) tipo nombrefuncion(int num, ...)

donde: 1. 2. 3. 4. tipo es el tipo regresado por la funcin nombrefuncion es el nombre de la funcin int num es el nmero de parmetros que la funcin procesar ... esta notacin se emplea para indicar que el nmero de parmetros es variable

Nota: observe que la primera forma de declaracin es realmente variable el nmero de parmetros a procesar y en estos casos se debe establecer el mecanismo para determinar cuando se ha procesado el ltimo de los argumentos, en el segundo tipo de declaracin el nmero total de parmetros a procesar es igual al valor del parmetro num. En el siguiente programa, por ejemplo, se define una funcin ( printstr ) que despliega una lista variable de cadenas de caracteres.
// programa funciones05.cpp // Autor: Oscar E. Palacios #include <iostream.h> #include <stdarg.h> // despliega una lista de cadenas, la ultima debe ser NULL

void printstr(...) { va_list ap; char *arg; va_start(ap, 0); while ( (arg = va_arg(ap, char*) ) != NULL) { cout << arg; } va_end(ap); } int main() { printstr("Hola, ", "Esta es\n", "una prueba\n", NULL); cin.get(); return 0; }

En el programa que se listar en seguida, se define la funcin suma(), misma que operar sobre listas de nmeros enteros, la funcin devolver la suma de dichos nmeros.
// programa funciones06.cpp // Autor: Oscar E. Palacios #include <iostream.h> #include <stdarg.h> // Esta funcin opera sobre una lista variable de nmeros enteros int suma( int num, ... ) { int total = 0; va_list argptr; va_start( argptr, num ); while( num > 0 ) { total += va_arg( argptr, int ); num--; } va_end( argptr ); return( total ); } int main() { cout << suma(4, 100, 200, 300, 400) << endl; cin.get(); return 0; }

[editar] Plantillas ( Templates )

de

funcin

Uno de los paradgmas de la programacin es lo que se conoce como: Programacin Genrica. En ese sentido, las plantillas de funciones nos acercan al mencionado

paradgma puesto que podemos usar el mecanismo conocido como plantillas (en ingles, Templates ). Las plantillas de funciones estan pensadas con la idea de crear 'moldes' en donde el cdigo para llevar a cabo determinadas tareas es bsicamente el mismo y donde la diferencia sera el tipo de datos sobre los que opera la funcin. Por ejemplo, pensemos en la creacin de una funcin que reciba un par de objetos y que intecambie el valor de los mismos, es decir, si a la funcin se le pasan los parmetros ( X, Y ) el valor de X se le asignara a Y, y el valor de Y se le pasar a X. Para comenzar, podemos pensar en crear una funcin llamada Swap() para intercambiar un par de nmeros enteros y el cdigo de la misma se vera ms o menos como:
void Swap(int &a, int &b) { int temp = a; a = b; b = temp; }

Ahora bien, si usted pone a prueba la funcin Swap() ver que la misma funciona perfectamente, salvo que tiene la limitante de operar solamente con nmeros de tipo int. Luego, si quisieramos intercambiar objetos de tipo double, float, char, etc. sera que debemos repetir el mismo cdigo para cada uno de los tipos deseados ?. La respuesta a dicha interrogante es No, ya que la mayora de compiladores actuales para C++ permiten el use de plantillas. Con el fin de poner un ejemplo, vamos a escribir un programa y en el mismo declararemos la plantilla de funcin SwapGenerico(), misma que servir para intercambiar el valor de dos objetos de cualquier tipo.
// programa funciones06.cpp // Autor: Oscar E. Palacios #include <iostream.h> template <class T> void SwapGenerico(T &a, T &b) { T temp = a; a = b; b = temp; }; int main() { int i1 = 100; int i2 = 5; cout << "antes.. "<< "i1 = " << i1 << " i2 = " << i2 << endl; SwapGenerico(i1, i2); // swap de nmeros enteros cout << "despues "<< "i1 = " << i1 << " i2 = " << i2 << endl; cout << endl; char c1 = 'a'; char c2 = 'b'; cout << "antes.. " << "c1 = " << c1 << " c2 = " << c2 << endl; SwapGenerico(c1, c2); // swap de caracteres cout << "despues " << "c1 = " << c1 << " c2 = " << c2 << endl; cin.get();

return 0; }

Otro problema
En el ejemplo anterior vimos que la plantilla SwapGenerico solucion el problema de intercambiar el contenido de una pareja de objetos primitivos ( char, int, float, double, etc. ). Sin embargo, si usted pone a prueba la misma plantilla para hacer un Swap de cadenas de caracteres, ver que el compilador le informar de un error, ya que a las cadenas de caracteres no es posible aplicarles el operador de asignacon (=). Pero, ya que C++ lo permite, podemos escribir una funcin SwapGenerico sobrecargada y as el compilador decidir si usar la plantilla o usar la funcin de sobrecarga. Y de tal manera abremos resuelto el problema. As, puede agregar la siguiente funcin al programa visto anteriormente.
void SwapGenerico(char *a, char *b ) { char *tmp = new char[strlen(a)]; strcpy(tmp, a); strcpy(a, b); strcpy(b, tmp); delete tmp; }

Anda mungkin juga menyukai