Ir al contenido principal

C: Funciones...

Anteriormente realizamos varios post de introducción a C donde pudimos adentrarnos en el mundo de este lenguaje adquiriendo las nociones básicas para codificar algunos programas sencillos. Pero, con ello, recién recorrimos la primera parte del camino y queda mucho por aprender.

Entre todos los temas que quedan por delante, nos encontramos con las funciones que, como vimos en pseudocódigo son subprogramas, es decir que son porciones de código independientes del programa principal que pueden recibir argumentos y devuelven un solo resultado (a excepción de las funciones void a las que dedicaremos una parte de esta entrada).

Ventajas del uso de funciones:

Las funciones nos serán de mucha utilidad ya que podremos programar de manera modular. Gracias a esta manera de programar podremos aplicar aquella idea de refinamiento que venimos viendo desde algoritmos y obtener como resultado un código mucho más claro y reutilizable.

Aunque esto de reutilizable suene a una campaña de reciclaje, es una de las grandes ventajas de usar funciones ya que podremos volver a usarlas en diferentes programas sin necesidad de volver a codificarlas. Y no sólo eso, sino que además podremos llamarlas todas las veces que las necesitemos lo que conllevaría gran cantidad de líneas de código repetidas si deberíamos implementarlo sin funciones en un mismo programa.

Prototipo y definición de una función:

Ahora que ya sabemos lo que son las funciones y las ventajas de usarlas, veamos cómo implementarlas en nuestros programas en C.

Prototipo:

En primer lugar tenemos el prototipo de la función que le dará información al compilador sobre el tipo de retorno  y detalles sobre los argumentos de la misma como el tipo de dato, la cantidad y el orden en que se los pasaremos a nuestra función. Esto le sirve al compilador para hacer las comprobaciones correspondientes en las llamadas a las funciones, dando error en caso que no nos ciñamos al prototipo. También el compilador intentará hacer conversiones de tipo de dato si el que pasamos en la llamada no corresponde con el tipo del argumento que habíamos especificado en el prototipo, esto siempre y cuando se pueda realizar.

El prototipo de una función en C, tendrá el siguiente aspecto:


Como podemos apreciar, se coloca antes de la función main y tiene el formato que se ve en la imagen.



Un ejemplo de un prototipo sería el que vemos a la izquierda. Donde tenemos una función de nombre "funcion1" que retornará un dato de tipo entero y que tendrá como argumentos dos enteros.





Definición:

La definición de nuestra función será la función en sí, osea el código de la misma y tiene la siguiente estructura:


Las definiciones de todas las funciones se colocan luego de la función main. 

Primero se coloca lo que se llama encabezamiento (o header) que, si vemos, es muy similar al prototipo, sólo que en este caso se coloca los nombres de los parámetros de la función (dato1 y dato2 en este caso). 



Dentro de las llaves que delimitan la función encontraremos todas las expresiones que forman parte de la misma, incluyendo la declaración de variables locales.

Al final se utiliza la palabra reservada return para indicar la expresión o variable que retornará nuestra función, este retorno deberá ser del tipo que indicamos en el prototipo, en nuestro ejemplo int.


Diferencia entre parámetros y argumentos: Como nota, agregamos esta aclaración para quien no tenga claras las diferencias entre los mismos. Aunque en algunos lugares se toman como sinónimos, los parámetros son los que aparecen en el prototipo y la definición de la función,  mientras que los argumentos corresponden al valor que le pasamos a la función cuando realizamos la llamada a la misma.

En alguna bibliografía a los parámetros se los llama con el nombre de "argumentos formales" y los argumentos reciben el nombre de "argumentos actuales". 
  

Llamadas a funciones:

El llamado a una función dentro de nuestro programa lo haremos de la misma manera que vimos en pseudocódigo.

Si la función retorna un valor (no es void) podemos asignar ese valor a una variable:


Suponiendo que variable, x e y son enteros, podemos asignar el resultado de nuestra función ejemplo a variable.



 En la imagen lo mostramos de manera general, pero x e y podrían ser variables ingresadas por el usuario anteriormente, números enteros que pasemos directamente como argumentos, resultados de expresiones que devuelvan un tipo entero, etc.



También podemos utilizar el valor que retorne nuestra función en estructuras de control como ejemplificamos en la imagen de la izquierda a través de una estructura if.






Funciones void:

Dentro de las funciones, hay un tipo especial a las que llamamos funciones de tipo void o simplemente funciones void que constituyen lo que habíamos mencionado alguna vez como procedimientos. Estas funciones tienen todas las características de una función sólo que su tipo de retorno es void y no retornan ningún valor.


El prototipo de estas funciones será igual que cualquier otra, sólo que tendrá la palabra reservada void como tipo de retorno.


La definición tendrá la misma estructura que vimos anteriormente, sólo que no retornará ningún valor.





Y simplemente las llamaremos con su nombre y argumentos;








Comentarios

Entradas populares de este blog

C: Conversiones de tipo (casting) en C...

El casting o simplemente cast  nos permite hacer una conversión explícita de un tipo de dato a otro, a criterio del programador siempre y cuando estos tipos sean compatibles. Este cast se realiza a través de un operador de conversión de tipos (type casting operator) y es un recurso a tener en cuenta ya que hay situaciones en que nos puede resultar de gran utilidad. Hacer uso de un cast es tan sencillo como poner (tipo de dato)  delante de la expresión o variable a convertir. Veamos un ejemplo: Declaramos una variable de tipo int con un identificador tan creativo como "a" y le realizamos diferentes cast a a para mostrarlo como si fuera un float, un double y un char en un printf. Lo que obtendríamos en pantalla sería lo siguiente: Donde tenemos el valor de nuestro a, a convertido en float y double (mostrándolo con 3 cifras decimales) y a convertido en char. Si vemos este último caso, al hacer la conversión de "a" a char toma a como el código ascii de

C: Ejemplos: Congruencia de Zeller (nivel básico) ...

La Congruencia de Zeller es un algoritmo que se atribuye al matemático alemán Julius Christian Johannes Zeller que vivió en el siglo XIX. Este algoritmo nos permite determinar el día de la semana que le corresponde a una fecha determinada del calendario Gregoriano. La fórmula que nosotros usaremos (con algunas modificaciones respecto de la original para poder usarla en  informática) es la siguiente: Donde h es el día de la semana (entre 0 y 6), J es año/100 (la centuria) y K es año mod 100 (el año de la centuria). Y hay que tener en cuenta que los meses de enero y febrero cuentan como el mes 13 y 14 del año anterior. Ahora que tenemos la fórmula, programemos el algoritmo en C mediante el uso de una función: Analicemos el código paso a paso: Tenemos en cuenta el caso de enero y febrero: Dijimos que estos meses corresponden a los meses 13 y 14 del año anterior por lo que los asignamos como corresponde (mes + 12 , que dará 13 para enero y 14 para febrero) y le rest

Algoritmos: Resolución de problemas y refinamientos en pseudocódigo...

En otras entradas, vimos las partes que debe tener nuestro algoritmo en pseudocódigo y las estructuras que utilizaremos para resolverlo. Ahora llega el turno de implementar todo en conjunto para dar origen a nuestra creación. Pero ¿cómo resolvemos un problema así? Para hacerlo, utilizaremos lo que llamamos refinamientos sucesivos. Este concepto consiste en dividir el problema en subproblemas más pequeños y a estos, a su vez, en otros más pequeños; y así sucesivamente hasta que la solución de los últimos sea trivial, sencillo de resolver. Luego usaremos todas las soluciones obtenidas para armar la solución de nuestro problema mayor. Este principio, tiene base en parte de la técnica divide and conquer (dependiendo de la traducción: "divide y vencerás") que es una de las muchas técnicas de resolución de algoritmos existentes. Como vemos, al dividir el problema en otros más pequeños y más fáciles de resolver, podemos pasar de un problema complicado a uno cuya solución es much