(C++) Subrutinas: procedimientos y funciones - 1


Subrutinas
Una subrutina es una parte separada del programa que tiene un nombre y resuelve su propia tarea separada. La subrutina se encuentra al comienzo del programa principal y se puede iniciar (llamar) desde el programa principal especificando el nombre.

El uso de subrutinas le permite evitar la duplicación de código, si necesita escribir el mismo código en diferentes lugares del programa. 
Las bibliotecas que se importan al programa (por ejemplo, la biblioteca matemática сmath.h) consisten en subrutinas que ya han sido compiladas por alguien. Los programadores no necesitan pensar en qué algoritmos implementarán, sino simplemente aplicarlos, pensando solo en lo que están haciendo exactamente. Este es un gran ahorro de tiempo. No es necesario escribir un algoritmo que ya haya sido escrito por otra persona.

Cada rutina solo debe hacer una tarea,  simplemente calcule algo, genere algunos datos o haga otra cosa. 

Las subrutinas son de dos tipos: procedimientos y funciones.

Las subrutinas realizan algunas acciones, por ejemplo, muestran el resultado en la pantalla de cierta forma (un ejemplo simple, el operador printf()  es una subrutina estándar que imprime información en la pantalla)

Las subrutinas de función devuelven un resultado (número, cadena de caracteres, etc.) que podemos usar en el programa principal.

Tratemos de escribir un procedimiento simple:
Supongamos que queremos mostrar la cadena "Error" cada vez que puede ocurrir un error en el código por culpa del usuario (por ejemplo, cuando ingresa datos incorrectos)
Esto se puede hacer escribiendo la declaración cout << "Error"; Y ahora imagine que esa línea debe insertarse en muchos lugares del programa. Por supuesto, puedes escribirlo en todas partes. Pero esta solución tiene dos inconvenientes.
1) esta cadena se almacenará en la memoria muchas veces
2) si queremos cambiar la salida en caso de error, tendremos que cambiar esta línea en todo el programa, lo cual es bastante inconveniente

Para tales casos, se necesitan procedimientos.
Un programa con un procedimiento podría verse así: #incluir<iostream> utilizando el espacio de nombres estándar; void printError() // descripción del procedimiento { cout << "Error"; // cuerpo del procedimiento: comandos que ejecutará el procedimiento } principal() { ... printError() // inicia el procedimiento para su ejecución. Solo especificamos el nombre del procedimiento que queremos ejecutar. ... imprimirError() ... } El procedimiento comienza con la palabra void. Hay corchetes vacíos después del nombre del procedimiento.
Todas las sentencias que se ejecutan en un procedimiento están sangradas. 

Los procedimientos se escriben antes de la función principal main()

Para ejecutar un procedimiento, en el programa principal debe llamarlo por su nombre y recordar escribir paréntesis!
Puede llamar a un procedimiento en un programa cualquier número de veces.

Ahora imaginemos que necesitamos mostrar diferentes mensajes en respuesta al error de un usuario, dependiendo del tipo de error que haya cometido.
En este caso, puede escribir su propio procedimiento para cada error:   void imprimirErrorZero() { cout << "Error. ¡División por cero!"; } void imprimirErrorInput() { cout << "¡Error en la entrada!"; } ¿Qué pasa si hay muchos más errores posibles? ¡Esta solución no nos conviene!
Necesitamos aprender a controlar el procedimiento diciéndole qué mensaje de error mostrar.
Para hacer esto, necesitamos parámetros que escribiremos entre paréntesis después del nombre del procedimiento void printError(cadenas) { cout << s; } En este procedimiento, s es un parámetro, una variable especial que le permite controlar el procedimiento.
El parámetro es una variable que determina cómo funciona la subrutina. Los nombres de los parámetros se enumeran separados por comas en el encabezado del subprograma. El tipo de parámetro se escribe antes del parámetro.

Ahora, al llamar al procedimiento, debe indicar entre paréntesis el valor real que se le asignará al parámetro (variable s) dentro de nuestro procedimiento printError("¡Error! ¡División por cero!"); Este valor se llama argumento.
El argumento es el valor del parámetro que se pasa a la subrutina cuando se llama.
Un argumento puede ser no solo un valor constante, sino también una variable o una expresión aritmética.

Variables locales y globales
A menudo es necesario utilizar variables adicionales que solo se utilizarán en la subrutina. Estas variables se denominan locales (o locales) y solo se pueden manipular dentro de la subrutina en la que se crean.
 
Ámbito de variable local es el bloque entre corchetes dentro del cual se declara

El programa principal en C++ también es una subrutina, por lo que todas las variables declaradas dentro de main() son variables locales.
Otras subrutinas no "saben" nada acerca de las variables locales de otras subrutinas.

Así, es posible limitar el alcance (scope) de una variable solo a la subrutina donde realmente se necesita. En programación, esta técnica se denomina encapsulación  - ocultar una variable para que no se modifique desde el exterior.

Si es necesario declarar una variable que sería visible en cualquier lugar del programa (en cualquier subrutina), dichas variables se declaran fuera de todas las subrutinas (consulte el programa 3 de la tabla a continuación).
Estas variables se denominan globales.

En C++, cuando se inicia el programa, todas las variables globales se establecen automáticamente en cero (las variables booleanas toman el valor falso).


Analice tres programas:

1) En este programa, la variable i es local. Una variable local se declara dentro de una subrutina 2) Aquí, aunque haya una variable i en el programa principal (con valor 7), se creará una nueva variable local i con valor 5. 
Cuando ejecute este programa, la pantalla mostrará el valor 75
3) Este programa tiene una variable global i. Su valor se puede cambiar dentro de una subrutina, y dentro del programa principal
El procedimiento trabajará con la variable global i y se le asignará un nuevo valor igual a 2. Se muestra en pantalla el valor 2
prueba nula() {   int i = 5; cout << i; } prueba nula() {   int i = 5;   cout << i; } principal() { int i = 7;   cout << i;   prueba(); } #incluye <iostream> utilizando el espacio de nombres estándar; ent yo; prueba nula() {   yo = 2; } principal() { prueba(); cout << i; }
Tarea
Escriba un procedimiento que intercambie los valores de dos variables.

Las peculiaridades de esta tarea son que necesitamos que los cambios realizados en el procedimiento sean conocidos por el programa que llama.

Intentemos escribir el procedimiento así: void Swap (int a, int b) // con tal descripción de los parámetros del procedimiento, { // se copiarán los valores de los argumentos (x e y), intc; // las variables a y b son variables independientes no relacionadas con x e y c = un; a = b; b=c; } principal() { entero x=1, y=2; Intercambiar (x, y); // los valores de las variables x e y (argumentos) se copian en los parámetros a y b cout << "x=" << x<< ", y=" << y; // x=1, y=2 } Si ejecuta este programa, puede ver que los valores de las variables x y y no han cambiado. Para que los parámetros cambien los valores de los argumentos, debe usar pasar datos por referencia.Para hacer esto, después del nombre del tipo de datos en el encabezado de la subrutina, debe colocar el signo & ("ampersand"). void Swap ( int & a, int & b ) // ahora las variables a y b obtienen las direcciones de las variables x e y en la memoria { intc; c = un; a = b; b=c; } Uso: Si pasa un argumento por referencia, entonces solo el nombre de la variable (NO un número y NO una expresión aritmética) puede estar en este lugar al llamar al procedimiento.< br />
NO llame a un procedimiento como este: Intercambiar(x, 4 ); Intercambiar (5+x, y);