Como ya se ha escrito antes, una forma de solucionar un problema complejo es dividirlo en subproblemas utilizando un desarrollo por refinamiento sucesivo. Esta técnica de dividir el problema principal en subproblemas se suele denominar diseño descendente (top-down). Se le llama así ya que se parte del problema general y mediante soluciones de distintos subproblemas más simples se llega a obtener el resultado deseado.
Las partes en que se divide un programa deben desarrollarse independientemente entre sí y cada una de esas partes se constituye en un subprograma del problema inicial. Los subprogramas se suelen denominar procedimientos y funciones.
La estructura de un programa en el que se han implementado subprogramas estará constituida por:
Programa principal
Subprogramas
Cuando en un programa se invoca un subprograma, ese subprograma se ejecuta en su totalidad, instrucción por instrucción, hasta llegar a la última que puede ser (return o retorno), en este momento se devuelve el control al programa principal o al subprograma desde donde fue invocado en el punto en el que se produjo la llamada.
La llamada o invocación a un subprograma, indistintamente del tipo que sea, se hace directamente con el nombre del subprograma y la lista de parámetros requeridos.
Cuando un subprograma llama a otro (procedimiento o función), deberá suministrar los datos que debe procesar. Esos valores son enviados a la función por medio de unos identificadores o expresiones denominados argumentos o parámetros.
Los parámetros enviados cuando se hace la llamada de la función se denominan parámetros actuales, mientras que los argumentos recibidos por la función se denominan parámetros formales. El paso de información se realiza estableciéndose un emparejamiento posicional entre los parámetros formales y los actuales.
En C++ que es el lenguaje en el cual estamos codificando nuestros algoritmos, existen dos opciones para el paso de parámetros, parámetros por valor o parámetros por referencia.
Los parámetros formales son variables locales a la función, es decir, solo accesibles en el ámbito de ésta. Reciben como valores iniciales los valores de los parámetros actuales. Posteriores modificaciones en la función de los parámetros formales, al ser locales, no afectan al valor de los parámetros actuales.
Los parámetros formales corresponden a la dirección de las variables, por tanto, lo que se está pasando es la variable y no el valor de la misma, así que ese valor admite ser modificado por el subprograma.
La diferencia fundamental entre el paso por valor y pro referencia consiste en que el paso de parámetros por valor limita al subprograma a la lectura de los argumentos solamente, mientras en el paso por referencia se permite tanto la lectura, como la modificación y escritura de los argumentos.
Las variables utilizadas en los programas y subprogramas se clasifican en dos tipos:
• Variables locales
• Variables globales
Una variable local es declarada y definida dentro de un subprograma, su ámbito de acción o dominio está limitada al entorno del subprograma y es distinta de las variables con el mismo nombre declaradas en cualquier parte del programa principal. Cuando otro subprograma utiliza una variable con el mismo nombre se refiere a una posición de memoria diferente. Se dice que tales variables son locales al subprograma en el que están declaradas.
La variable global es aquella que está declarada para el programa o algoritmo principal, del que dependen todos los subprogramas.
La parte del programa/algoritmo en que una variable se define se conoce como ámbito o alcance de la variable.
El uso de variables locales permite que los subprogramas sean independientes del programa principal, y su posible dependencia está en función de las llamadas que hay entre el programa principal y los subprogramas a través de la lista de argumentos o parámetros.
Algunas veces se requieren subprogramas que procesen varios cálculos o acciones, o que realicen rutinas más complejas como ordenar de un conjunto de datos, intercambiar valores en una serie de datos u otros procesos largos y repetitivos. En estas situaciones se necesita de un tipo de subprograma, denominado procedimiento o subrutina.
Se invoca o llama un procedimiento escribiendo su nombre, por ejemplo, intercambiar, para indicar que un procedimiento denominado intercambiar se va a utilizar. Cuando se llama el procedimiento, los pasos que lo definen se ejecutan y a continuación se devuelve el control al programa que lo llamó.
En pseudocódigo, la sintaxis para escribir un procedimiento es muy similar a la que se usa para escribir un algoritmo:
procedimiento nombre [(lista de parámetros formales)]
<acciones>
fin_procedimiento
Además, para hacer una llamada a un procedimiento, se utiliza la sintaxis:
<nombre_procedimiento>([<parámetros_actuales>])
Ejemplo:
Leer dos variables a y b enteras positivas e intercambiar el valor de esas variables, tomando la variable a el valor de b y la variable b el valor de a. Se debe imprimir los valores actuales de a y b y los valores formales después del intercambio.
Solución:
Algoritmo
entero a = 0, b = 0
procedimiento Intercambiar(entero &a, entero &b)
entero Aux = 0
Aux = a
a = b
b = Aux
fin-procedimiento
// Programa principal
Inicio
Escriba(“Teclee dos números enteros positivos: “)
Leer (a, b)
Escriba(“Valor actual de a: “, a, “y valor actual de b es “, b)
Intercambiar(a, b) //Paso por referencia
Escriba(“Los números intercambiados son: a = ", a, " y b = ",b)
Fin
Código C++
En matemática una función es una relación que se establece entre dos conjuntos, por medio de la cual a cada elemento del primer conjunto se le asigna un único elemento del segundo conjunto o ninguno. De igual forma en informática una función es una operación que toma uno o más valores llamados argumentos y produce un valor denominado resultado.
En pseudocódigo, la sintaxis que se utiliza para escribir una función es muy similar a la que se usa para escribir un procedimiento.
<tipo_de_dato> funcion <nombre_fun> (parametros)
[declaraciones locales]
inicio
<acciones> //cuerpo de la funcion
devolver (<expresion>)
fin_función
Existen una diferencia importante entre la sintaxis de un procedimiento y de una función:
Una función devuelve siempre un valor. Por tanto, en una función siempre debe indicarse el <tipo_de_dato> del valor que devuelve la función, y el valor en sí, mediante la instrucción devolver <expresión>. El resultado de evaluar la <expresión> puede ser de cualquier tipo, excepto un array.
Ejemplo:
Escriba un algoritmo que lea un número entero y determine si es primo, para determinar si el número es primo deberá escribir una función llamada esPrimo que devolverá un valor booleano indicando si el número es o no primo.
Solución:
Algoritmo
entero a = 0
booleano funcion esPrimo(entero num)
i = 3
esPrimo = verdadero
si(num % 2 = 0)
entonces si(num > 2)
entonces esPrimo = falso
mientras(i <= raíz_cuadrada(num))
si(num % i = 0)
entonces
esPrimo = falso
i = num
sino
i = i + 2
fin-si
fin-funcion
// Programa principal
Inicio
Escriba(“Digite un número entero positivo: “)
Leer (a)
Si(esPrimo(a))
escriba(a, “ es un número primo”)
Sino
Escriba(a, “ no es un número primo”)
Fin
Código C++
Ejemplo:
Escriba un algoritmo que lea dos números enteros y determine el máximo común divisor de esos números, para determinar el máximo común divisor deberá escribir una función llamada mcd que devolverá un valor entero que corresponde al mcd.
Solución:
Algoritmo
entero x, y
entero funcion mcd(entero a, entero b)
mientras (a <> b) haga
si(a > b)
entonces a = a -b
sino b = b – a
fin-si
fin-mientras
mcd = a
fin-funcion
// Programa principal
Inicio
Escriba(“Digite dos números enteros positivos: “)
Leer (x, y)
Escriba(“El mcd de “, x, “ y “, y, “ es “, mcd(x, y))
Fin
Código C++