Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

4 - Funciones

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 17

4.

-FUNCIONES
1.-INTRODUCCIÓN A FUNCIONES
Básicamente una función es un bloque de código reutilizable

Como se observa en la imagen, después de que la máquina completa la ejecución de las


instrucciones 1 y 2 del programa principal, el control del flujo se transfiere al inicio de la función 'a'.
En este punto, se ejecutan las tres instrucciones contenidas en 'a'. Finalizada esta ejecución, el
En este punto, se ejecutan las tres instrucciones contenidas en 'a'. Finalizada esta ejecución, el
control retorna al programa principal para seguir con las instrucciones 3 y 4. Después, el flujo de
ejecución se dirige nuevamente hacia la función 'a', repitiendo las instrucciones de esta. Una vez
completadas, el control vuelve al programa principal para continuar y finalizar con la ejecución de la
instrucción 5.
En conclusión, la imagen ilustra la reutilización del código de la función 'a' en dos ocasiones. Esta
práctica de reiterar el uso de una porción de código mediante su llamado se conoce como
'invocación de la función'. Por lo tanto, lo que se muestra es que la función 'a' está siendo invocada
dos veces.

2.-DEFINICIÓN Y DECLARACIÓN DE FUNCIONES


En el lenguaje de programación C, comprender la declaración y la definición de funciones es
esencial para estructurar el código de forma modular, reutilizable y legible. A continuación, se
detallan estos dos conceptos clave:
Declaración de una Función
La declaración de una función, también conocida como 'prototipo de función', informa al
compilador sobre la existencia de una función. Esto incluye el nombre de la función, los tipos de
datos de sus argumentos y su tipo de retorno. Sin embargo, esta declaración no detalla la
implementación o el cuerpo de la función. Su propósito principal es permitir que la función sea
llamada desde otras partes del código antes de su definición completa, asegurando así la
modularidad y la organización del programa.
La sintaxis para declarar una función es la siguiente:

tipo_de_retorno nombre_de_la_función(tipo_parametro1 nombre_parametro1, tipo_parametro2


nombre_parametro2, ...);

Por ejemplo, una declaración de función para una función que suma dos números podría verse así:

int sumar(int numero1, int numero2);

Esta declaración informa al compilador de que existe una función llamada sumar que toma dos
argumentos de tipo int y devuelve un int .

Definición de una Función


La definición de una función, por otro lado, es la implementación real de la función. Incluye el
cuerpo de la función, que contiene el código que se ejecutará cuando se llame a la función. La
definición de la función especifica qué hará la función con los argumentos que recibe y qué valor
retornará.
La sintaxis para definir una función es similar a la declaración, pero incluye el cuerpo de la función
encerrado en llaves {} :

tipo_de_retorno nombre_de_la_función(tipo_parametro1 nombre_parametro1, tipo_parametro2


nombre_parametro2, ...) { // Cuerpo de la función }

Siguiendo con el ejemplo anterior, una definición de la función sumar sería:

int sumar(int numero1, int numero2) { return numero1 + numero2; }

Esta definición completa la declaración al proporcionar el cuerpo de la función, que simplemente


suma los dos parámetros y devuelve el resultado.

EJEMPLO

#include <stdio.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include


"driver/gpio.h" int sumar(int numero1, int numero2); void app_main(void){ int s; s =
sumar(4,3); printf("La suma es: %d", s); } int sumar(int numero1, int numero2) { return
numero1 + numero2; }
3.-INVOCACIÓN A FUNCIONES
Definida y declarada la función, se puede llamar desde cualquier otra función, incluyendo
app_main() , utilizando su nombre y pasando los argumentos necesarios, acordes con los tipos y la
cantidad de parámetros especificados:

int resultado = nombre_funcion(valor_para_parametro1, valor_para_parametro2);

Ejemplo Completo
Veamos un ejemplo práctico que ilustra la definición, declaración e invocación de funciones en C:

#include <stdio.h> // Declaración de la función int suma(int a, int b); void app_main()
{ int resultado; // Invocación de la función resultado = suma(5, 3); printf("El resultad
o es: %d\n", resultado); } // Definición de la función int suma(int a, int b) { return a
+ b; }
Este código demuestra la creación de una función suma , que recibe dos enteros y devuelve su
suma. La función se declara antes de main y se invoca dentro de esta, pasando dos argumentos. El
resultado se muestra en consola.
Seguir correctamente estos pasos y las normas de sintaxis es crucial para el uso efectivo de
funciones en tus programas en C."

4.-(SCOPE) VARIABLES DENTRO Y FUERA DE UNA


FUNCIÓN

En C, comprender el ámbito y la duración de las variables es fundamental para determinar su


visibilidad y tiempo de existencia en memoria durante la ejecución del programa. Estos conceptos
influyen directamente en cómo y dónde se pueden usar las variables, y su manejo adecuado es
crucial para la modularidad y mantenimiento del código.
Variables Locales
Definidas dentro de funciones, las variables locales tienen un ámbito restringido al bloque de la
función. Son creadas al invocar la función y destruidas al finalizar su ejecución, no conservando
función. Son creadas al invocar la función y destruidas al finalizar su ejecución, no conservando
valores entre llamadas sucesivas. Esta transitoriedad las hace ideales para datos que no necesitan
persistir más allá del uso de la función.
Ejemplo:

void funcionEjemplo() { int variableLocal = 10; // Solo dentro de esta función }

Variables Globales
Las variables globales, declaradas fuera de funciones, son accesibles desde cualquier parte del
archivo. Persisten durante toda la ejecución del programa, facilitando el compartir datos entre
funciones. No obstante, su uso excesivo puede complicar la comprensión y el mantenimiento del
código debido a posibles efectos secundarios.
Ejemplo:

int variableGlobal = 20; // Accesible globalmente void funcionEjemplo() { variableGlobal


= 25; }

Variables Estáticas
Declarar una variable como static dentro de una función permite que retenga su valor entre
llamadas sin cambiar su ámbito local. Esto es útil para mantener estados entre llamadas sin exponer
la variable fuera de la función.
Ejemplo:

void funcionEjemplo() { static int variableEstatica = 0; variableEstatica++; printf("%d


\n", variableEstatica); }
Buenas Prácticas
Minimizar el uso de variables globales: Reduce efectos secundarios y mejora la legibilidad.
Priorizar variables locales: Fomenta la independencia del código.
Usar variables estáticas con cuidado: Útiles pero pueden complicar el seguimiento del estado del
programa.
Entender y aplicar estos principios es esencial para escribir código eficiente, legible y fácil de
mantener en C.
Ejemplo Completo Variable local

#include <stdio.h> // Declaración de la función int suma(int a, int b); void app_main()
{ int resultado; // Invocación de la función resultado = suma(5, 3); printf("El
resultado es: %d\n", resultado); } // Definición de la función int suma(int a, int b) {
int s = a + b; return s; }
Ejemplo Completo Variable global

#include <stdio.h> // Declaración de la función int suma(int a, int b); int s ; void
app_main() { int resultado; // Invocación de la función resultado = suma(5, 7);
printf("El resultado es: %d\n", resultado); } // Definición de la función int suma(int
a, int b) { s = a + b; return s; }
Ejemplo Completo Variable static

#include <stdio.h> // Declaración de la función void fun(void); void app_main() {


printf("prueba 1\n"); fun(); printf("Prueba 2\n"); fun(); } // Definición de la función
void fun() { static int var=0; var++; printf("%d\n",var); }

5.-FUNCIONES INLINE
Las funciones inline en C son una extensión del estándar del lenguaje introducida con el estándar
C99. El propósito de las funciones inline es sugerir al compilador que inserte el código de la
función directamente en el punto donde se llama a la función, en lugar de realizar una llamada a la
función en el sentido tradicional. Este proceso se conoce como "inlining" y puede reducir la
sobrecarga (overhead) asociada con las llamadas a funciones, especialmente en el caso de
funciones pequeñas que se llaman frecuentemente dentro de bucles críticos para el rendimiento.

Sintaxis
Para declarar una función como inline , simplemente se utiliza la palabra clave inline antes del
tipo de retorno de la función en su definición o declaración:
inline int suma(int a, int b) { return a + b; }

Cómo Funcionan
Cuando el compilador procesa una función inline , intenta expandir el código de la función
directamente en el lugar donde se llama a la función. Esto elimina la necesidad de una llamada y
retorno de función, lo que puede mejorar el rendimiento al reducir la cantidad de instrucciones de
salto y la manipulación de la pila.

Consideraciones
Decisión del Compilador: Aunque se sugiere al compilador que trate la función como inline , es
solo eso, una sugerencia. El compilador tiene la libertad de ignorar esta sugerencia basándose en
su propio análisis y las optimizaciones que considere adecuadas. Por ejemplo, una función muy
grande o una que incluya bucles complejos, llamadas a otras funciones, o uso intensivo de recursos
puede no ser tratada como inline por el compilador.
Uso de Memoria: Aunque el inlining puede mejorar el rendimiento, también puede aumentar el
tamaño del código binario generado si se abusa de él, ya que el código de la función se duplica en
cada punto de llamada. Esto es algo a tener en cuenta especialmente en sistemas con memoria
limitada.
Definiciones Múltiples: Dado que el código de una función inline puede ser insertado en
múltiples lugares, es importante que la definición de la función esté disponible para cada unidad
de traducción (archivo de código fuente) que la llama. Esto a menudo significa que la definición
completa de la función inline debe estar en un archivo de cabecera (header file) incluido por
todos los archivos de código fuente que utilizan la función, a diferencia de las funciones normales,
cuya definición suele estar separada de su declaración.

Buenas Prácticas
Buenas Prácticas
Funciones Pequeñas: Las funciones inline son más efectivas cuando se utilizan para funciones
pequeñas y críticas para el rendimiento, como getters/setters o funciones matemáticas simples.
Pruebas de Rendimiento: Utiliza perfiles de rendimiento para determinar si el uso de inline
realmente ofrece beneficios de rendimiento en tu caso de uso específico.

7.-RECURSIÓN DE FUNCIONES
La recursión en el contexto de la programación con C (o cualquier otro lenguaje de programación)
se refiere a la técnica en la cual una función se llama a sí misma directamente o indirectamente para
resolver un problema. La recursión es una herramienta poderosa, especialmente útil para resolver
problemas que pueden dividirse en subproblemas más pequeños de la misma naturaleza que el
problema original, como la búsqueda binaria, la ordenación rápida (quicksort), el cálculo de
factorial, entre otros.
Para implementar la recursión de manera efectiva y segura, es crucial entender sus componentes
fundamentales y seguir ciertas prácticas.

Componentes de una Función Recursiva


Caso Base: Es la condición que detiene la recursión. Sin un caso base, una función recursiva
continuaría llamándose a sí misma indefinidamente, lo que eventualmente provocaría un
desbordamiento de la pila de llamadas (stack overflow). El caso base define un escenario en el que
la función puede devolver un resultado sin necesidad de llamarse a sí misma.
Caso Recursivo: Es la parte de la función que incluye la llamada a sí misma. El caso recursivo debe
modificar los argumentos de la función de tal manera que eventualmente se alcance el caso base.

Ejemplo: Cálculo del Factorial


Un ejemplo clásico de recursión es el cálculo del factorial de un número. El factorial de un número
entero positivo �n, denotado como �!n!, es el producto de todos los enteros positivos menores o
iguales a �n. Matemáticamente, el factorial se define como:
�!=�×(�−1)×(�−2)×⋯×1n!=n×(n−1)×(n−2)×⋯×1
0!=10!=1 (por definición)
La implementación recursiva de esta función en C sería:

#include <stdio.h> // Declaración de la función int fac(int y); void app_main() { int x
= 5; int f; f = fac(x); printf("%d\n",f); } // Definición de la función int fac(int y) {
if (y == 0) { // Caso base return 1; } else { // Caso recursivo return y * fac(y - 1); }
}

En este ejemplo, el caso base es cuando n es 0, en cuyo caso la función devuelve 1 directamente
sin hacer más llamadas recursivas. El caso recursivo reduce el problema al calcular el factorial de
n-1 y multiplicarlo por n , acercándose al caso base en cada iteración.

Consideraciones al Usar Recursión


Profundidad de Recursión: Cada llamada recursiva consume memoria en la pila de llamadas. Si la
profundidad de la recursión es demasiado grande, puedes exceder el espacio disponible en la pila,
resultando en un desbordamiento de la pila y, por lo tanto, en un fallo del programa.
Eficiencia: En algunos casos, la recursión puede ser menos eficiente que las alternativas iterativas
debido a la sobrecarga de las llamadas a funciones. Sin embargo, para ciertos problemas, la
claridad y la simplicidad del código recursivo pueden justificar su uso.
Recursión de Cola: Algunos compiladores optimizan las llamadas recursivas de cola, donde la
llamada recursiva es la última acción de la función. Esta optimización puede reducir el consumo de
memoria de la pila, pero su soporte y efectividad pueden variar entre diferentes compiladores y
configuraciones.
La recursión es una técnica fundamental en la programación que, cuando se utiliza correctamente,
puede simplificar el código y hacerlo más legible, al tiempo que resuelve problemas complejos de
manera elegante.

EJERCICIOS
Ejercicio 1: Encendido y Apagado de un LED con un Pulsador
Objetivo: Escribir un programa que encienda un LED cuando un pulsador esté presionado y lo
apague cuando se suelte.
Funciones a Implementar:
configurarGPIO() : Configura los pines del LED y del pulsador.

leerPulsador() : Devuelve el estado actual del pulsador (presionado o no).

controlarLED(bool estado) : Enciende o apaga el LED basado en el estado proporcionado.

Ejercicio 2: Alternar el Estado de un LED con Cada Presión de un Pulsador


Objetivo: Modificar el estado del LED (de encendido a apagado y viceversa) cada vez que se
presione y suelte el pulsador.
Funciones a Implementar:
configurarGPIO() : Configura los pines del LED y del pulsador.

leerPulsador() : Detecta el flanco de subida o bajada del pulsador.


alternarLED() : Cambia el estado del LED.

Ejercicio 3: Control de Múltiples LEDs con un Pulsador


Objetivo: Utilizar un solo pulsador para controlar varios LEDs de forma secuencial. Cada vez que se
presione el pulsador, se enciende el siguiente LED y se apagan los anteriores.
Funciones a Implementar:
configurarGPIO() : Configura los pines de los LEDs y del pulsador.

leerPulsador() : Detecta el flanco de subida del pulsador.

encenderLEDsecuencial() : Enciende los LEDs de forma secuencial.

Ejercicio 4: Crear un Patrón de Parpadeo para los LEDs Basado en la Entrada


de Pulsadores
Objetivo: Implementar un sistema donde el número de veces que se presiona un pulsador
determina el patrón de parpadeo de un LED (por ejemplo, presionar 1 vez para parpadeo lento, 2
veces para parpadeo rápido).
Funciones a Implementar:
configurarGPIO() : Configura los pines del LED y del pulsador.

contarPresiones() : Cuenta las veces que se presiona el pulsador.

parpadearLED(int velocidad) : Hace parpadear el LED a la velocidad especificada.

Ejercicio 5: Sistema de Contraseña con Pulsadores


Objetivo: Crear un sistema de "contraseña" simple usando pulsadores. Por ejemplo, la "contraseña"
podría ser una secuencia específica de presiones de pulsadores. Si la secuencia es correcta, se
enciende un LED verde; si es incorrecta, se enciende un LED rojo.
Funciones a Implementar:
configurarGPIO() : Configura los pines de los LEDs y de los pulsadores.

leerSecuencia() : Lee la secuencia de presiones de pulsadores y la almacena.

verificarSecuencia() : Compara la secuencia ingresada con la secuencia correcta.

indicarResultado(bool esCorrecto) : Enciende el LED verde si la secuencia es correcta, o el LED


rojo si es incorrecta.

PRÁCTICA D EAPLICACIÓN

MENU DE DOS PULSADORES Y 4 OPERACIONES


Realizar un programa que con 2 pulsadores, se seleccionen 4 operaciones, de la siguiente manera:
Pulsador 1 se utiliza para cambiar entre opciones
Pulsador 2 se utiliza para activar la operación de la opción actual
Utilizar 4 leds para indicar en que opción se encuentra el menu
Codificar cada operación en una función
Utilizar punteros a funciones

También podría gustarte