Programación estructurada y pseudocódigo

La informática se suele definir como la ciencia que estudia el tratamiento automatizado de la información. Para realizar dicho tratamiento automatizado es necesario una máquina que lo realice (el hardware), pero también es necesario una serie de datos a procesar y unas instrucciones para llevar a cabo este proceso (software). Por tanto una de las principales áreas de estudio es el conjunto de lenguajes y la forma en que se  pueden definir las instrucciones que procesarán los datos sobre un ordenador. En este artículo  se va  a describir el paradigma de la programación estructurada, que se considera el primer paradigma de programación moderno.

 

 

 

Historia de la programación estructurada

 

Los primeros computadores con código almacenado en memoria se programaban dictando las instrucciones en lenguaje máquina, esto es, siguiendo la misma codificación en binario  que comprende la CPU del ordenador. 

 

Ya que este método de programación resultaba demasiado engorroso, pronto surgió el lenguaje ensamblador, como un nemotécnico del lenguaje máquina: cada código binario es substituido por una breve palabra clave más fácil de utilizar y recordar por el programador.

 

La utilización del lenguaje máquina y el ensamblador conlleva dos desventajas importantes. En primer lugar el código generado está completamente ligado a la máquina para la que de desarrolla, ya que cada CPU cuenta con su propio lenguaje máquina, siendo casi imposible la portabilidad del código. Y en segundo lugar hace que las tareas de programación sean bastante complejas, ya que el nivel de abstracción al que se mueven estos lenguajes es bastante bajo.

 

Para soslayar estos inconvenientes, surgieron los lenguajes de programación de alto nivel, que reciben esta denominación debido a que el nivel de abstracción al que se programa es más elevado que el del lenguaje ensamblador. Además de facilitar las tareas de programación permitía la migración de programas desde unas máquinas a otras.

 

Los primeros lenguajes de programación de alto nivel dejaban al programador mucha libertad para definir que estructura le daban al código, si le daban alguna. Se permitía que el programador alterara el flujo de ejecución del programa a su antojo (instrucciones “goto”), no imponían ningún tipo de ámbito a las variables, con los consiguientes efectos colaterales que esto puede conllevar y no proporcionaban ningún mecanismo para dividir un programa en partes o módulos que puedan desarrollarse por separado e integrarse de manera eficiente.

 

Este hecho, unido al desconocimiento de buenas prácticas de programación llevó a lo que se denominó la crisis del software a principios de los años 70. Los programadores se dieron cuenta de que una gran parte de los programas desarrollados hasta el momento eran imposibles de mantener, corregir y mejorar debido a que el código desarrollado era completamente ilegible (lo que se llamó código espagueti).

 

La programación estructurada investigó una solución a este problema, en primer lugar buscando las mínimas estructuras básicas para poder desarrollar un programa, así como las prácticas de programación necesarias para que los programas desarrollados pudieran ser fácilmente legibles y mantenibles. Fue en primer lugar propuesta por Dijktra aunque posteriormente otros muchos autores trabajaron en los sistemas de representación de algoritmos y lenguajes de programación estructurados.

Objetivos de la programación estructurada

Los objetivos de la programación estructurada son:

 

  • El código fuente de un programa deberá contener información suficiente como para ser comprendido y verificado sin necesidad de información adicional (esto es ser legible).

 

  • Distintas partes de un programa deben poder ser cambiadas sin que estos cambios afecten al resto del programa.

Estructuras básicas

Un programa, o más genéricamente un algoritmo (una secuencia finita de pasos elementales que resuelven un problema) que utilice el `paradigma de la programación estructurada estará formado por una secuencia finita y definida de las tres estructuras básicas (secuencial, condicional e iterativa). Como demostraron Böhm y Jacopini con el teorema fundamental de la estructura, cualquier problema computacionalmente resoluble puede resolverse con un algoritmo que únicamente haga uso de estas tres estructuras. Las mencionadas estructuras son las siguientes:

Estructura secuencial

Consiste en una secuencia finita de instrucciones elementales. Las instrucciones elementales pueden ser de dos tipos, asignaciones y utilización de recursos abstractos.

 

  • Asignación: mediante esta operación se almacena en una variable (que básicamente identifica por un nombre una posición de memoria) el resultado de una operación aritmética o lógica.

 

  • Recursos abstractos: Consisten básicamente en una llamada a un procedimiento (un algoritmo al que se identifica por un nombre), al que se le pasan una serie de parámetros y devuelve otros. Dentro de estos recursos abstractos se encontrarán los procedimientos de E/S que permitirán al programa interactuar con el exterior.

Estructura condicional

Contiene fundamentalmente tres elementos: un predicado y una o dos estructuras secuenciales (con otras estructuras en su interior si hace falta). Un predicado es una sentencia que puede evaluarse como verdadera o falsa. Los predicados están formados tanto por expresiones booleanas que relacionan varios subpredicados como por expresiones relacionales (mayor que, menor que, igual, diferente) que relacionan entre sí constantes y variables numéricas o alfanuméricas.

 

Al comienzo de la estructura secuencial se evalúa el predicado, y si este se determina que es cierto se ejecuta el conjunto de la estructura secuencial. A esta estructura condicional básica se le conoce con el nombre de si..entonces.

 

Como ampliación de la estructura condicional básica, esta puede incluir dos estructuras secuenciales. Una vez se evalúe el predicado si es cierto se ejecuta la primera de ellas, y si es falso la segunda. A esta estructura se de denomina, si…entonces…sino.

 

Una tercera estructura condicional surge como ampliación de las dos anteriores. Sus componentes son una variable y un conjunto de constantes con las que se comparará esta variable. Cada constante llevará asociado una estructura secuencial. Si se cumple el predicado de que la variable es igual a la constante se ejecutará la estructura secuencial asociada a ésta. A esta estructura condicional se le conoce con el nombre de en caso de…

Estructura iterativa

Está formada fundamentalmente por una estructura secuencial (con otras estructuras embebidas si es necesario) y un predicado. La estructura iterativa se ejecutará tantas veces como sea necesario hasta que el predicado se evalúe como verdadero (o como falso dependiendo del tipo). Según el momento en el que se evalúe el predicado existen tres estructuras iterativas:

 

  • Estructura mientras: El predicado se evalúa antes de ejecutarse la estructura secuencial asociada. La estructura secuencial se ejecutará hasta que el predicado sea evaluado como falso. Si la primera vez que se evalúa el predicado este es falso, no se ejecuta nunca.

 

  • Estructura repetir… hasta que: El predicado se evalúa tras ejecutar una primera vez la estructura secuencial. Si este es falso vuelve a ejecutarse hasta que este se evalúe como verdadero.

 

  • Estructura iterar: En este caso el predicado puede evaluarse en un instante previamente definido de la estructura secuencial, y en este momento dependiendo de si es verdadero o falso se continuará la ejecución de la estructura iterativa o no. Esta estructura es una generalización de las dos anteriores, no siendo estrictamente necesario su uso a la hora de definir un algoritmo de manera estructurada. De hecho hay autores que mencionan que su uso puede devenir en código de baja calidad o pobremente estructurado.

 

Además de esas tres estructuras iterativas se utiliza una más, que podía teóricamente construirse utilizando las anteriores pero que se añade por su gran utilidad y versatilidad. La estructura para

 

  • Estructura para: Está formada por cinco elementos, una variable, un valor inicial, un valor final, un incremento y una estructura secuencial. La variable toma el valor inicial, y si este no ha llegado al valor final, se ejecuta la estructura secuencial con el valor de la variable asignado. En cada iteración se incrementa el valor de la variable en lo designado por incremento, iterándose la estructura secuencial tantas veces como sea necesario para que la variable llegue al valor final.

 

Funciones y procedimientos

Un procedimiento es básicamente un recurso abstracto, es decir, un algoritmo al que se le da un nombre para poder ser utilizado posteriormente en otros algoritmos, simplemente nombrándolo, sin necesidad de escribir, o siquiera conocer, su estructura interna.

 

Un procedimiento está formado por dos partes el cuerpo del procedimiento y loas parámetros.

 

  • Cuerpo del procedimiento: Constituido por un conjunto de estructuras básicas y si es necesario, llamadas a otros procedimientos o a sí mismo (recursividad).

 

  • Parámetros: son los componentes de entrada o salida al procedimiento, mediante los cuales el procedimiento recibe datos del exterior (de otro procedimiento llamador) y se los devuelve. Cuando se define un procedimiento se definirán sus parámetros formales, esto es se le asignará un nombre a cada parámetro que se utilizará internamente como si de otra variable cualquiera se tratara. A la hora de definir los parámetros formales estos pueden ser asignados a tres tipos:

 

  • Parámetros de entrada: Parámetros mediante los cuales el procedimiento recibirá una serie de datos del exterior.

 

  • Parámetros de salida: Parámetros sobre los cuales el procedimiento enviará al exterior la información que haya procesado.

 

  • Parámetros de entrada/salida: Son parámetros mediante los cuales un procedimiento recibe una serie de datos, opera con ellos y mediante el mismo parámetro devuelve al exterior un resultado

.

Cuando un procedimiento es invocado, es decir, otro procedimiento o programa hace uso de el, ha de asignar una serie de parámetros reales a los formales, es decir, ha de dar un valor a cada parámetro formal que será el que utilice  el proveimiento durante el curso de esta invocación. Esta operación de traducción de los parámetros reales a formales, denominada paso de parámetros, puede ser realizada de varias maneras:

 

  • Paso de parámetros por copia: El valor del parámetro real es copiado a la zona de memoria identificada por el parámetro formal. Puede ser de tres tipos, dependiendo del tipo de parámetro formal que se trate:

 

  • Paso por valor: El valor de la variable del parámetro real se copia a la variable del parámetro formal. Utilizado cuando el parámetro es de entrada.

 

  • Paso por valor-resultado: El valor de la variable del parámetro real se copia a la variable del parámetro formal, y cuando finaliza su ejecución el procedimiento, se vuelve a copiar el valor final del parámetro a la variable que representaba el parámetro real. Se utiliza cuando el parámetro formal es un parámetro de entrada/salida.

 

  • Paso por resultado: Se copia el valor final del parámetro formal en la variable que representa al parámetro real al finalizar el procedimiento. Usado cuando el parámetro formal es de salida.

 

  • Paso de parámetros por referencia: En este caso lo que recibe el procedimiento es la posición de memoria que está asociada al parámetro real, operando en su interior con ella y devolviendo implícitamente el resultado a través de la misma. Es muy parecido al paso por valor-resultado, con la diferencia que no hay ningún tipo de copia de valores de variables.

 

  • Paso de parámetros por nombre: En este caso el parámetro formal se substituye por el real solamente cuando el procedimiento haga uso internamente de el.

 

Ámbito de una variable: Un procedimiento además define un ámbito de visibilidad para una variable, es decir, define que las variables internas al procedimiento solamente serán accesibles por éste y las variables externas a el no lo serán (salvo que se especifique un paso de parámetros por nombre). Además proporciona un interfaz estricto (el paso de parámetros) para la comunicación entre procedimientos. Estos mecanismos existen para evitar los efectos colaterales, es decir, que un procedimiento altere variables situadas fuera de el. Los efectos laterales eran muy comunes antes de la utilización del paradigma estructurado, ya que el ámbito de todas las variables era global (el programa entero). Utilizando programación estructurada no deben de utilizarse variables globales aunque lo permita el lenguaje de programación, pues además de ser innecesario su uso (siempre puede plantearse un paso de parámetros alternativo) puede conllevar estos efectos.

 

Funciones: Una función es un procedimiento con una serie de características definidas: Solamente devuelve un valor (de salida) y recibe uno o varios valores (de entrada). No se admiten en una función parámetros de entrada/salida (aunque en algunos lenguajes puede utilizarse paso por referencia o por nombre). De esta manera una función puede utilizarse a la hora de ser llamada como parte de expresiones más complejas.

Representación mediante pseudocódigo

 

En Pseudocódigo los algoritmos se representan mediante una serie de instrucciones escritas en lenguaje natural, pero próximo a la sintaxis utilizada por la mayoría de los lenguajes de programación. Las estructuras básicas se utilizan de la siguiente manera:

 

  • Estructura secuencial: La asignación se representa con una flecha apuntando hacia la variable donde se almacenará el valor. Como valor a asignar puede utilizarse una expresión matemática o lógica o una constante. La entrada salida se realiza mediante  dos instrucciones denominadas leer y escribir. Por ejemplo, un programa que devuelve el cuadrado de un valor introducido seria:

    

INICIO
    Leer x

    Y <-  x*x

    Escribir y

FIN

 

  • Estructura condicional: Se representa mediante la sintaxis SI [condición] entonces [sentencias] opcionalmente puede incluirse una sentencia sino [sentencias]. Termina con la expresión finsi. Por ejemplo un programa que muestra por pantalla si el número introducido es positivo o negativo quedaría:
INICIO
    Leer X

    SI X<0 entonces

    Escribir “negativo”

    SINO

    Escribir “positivo”

    FINSI

FIN

 

Además la estructura condicional múltiple se representa mediante la expresión en caso de:

 

INICIO
    Leer x

    EN CASO DE x

        0:

            Escribir “Vale 0”

        1:    Escribir “Vale 1”

        2:    Escribir “Vale 2”

    EN OTRO CASO

            Escribir” No vale ni 0, ni 1 ni 2”

    FIN_CASO

FIN

    

  • Estructuras iterativas: Dependiendo de la estructura iterativa se representa mediante las palabras MIENTRAS REPETIR…HASTA QUE, ITERAR o PARA. A continuación se muestran cuatro ejemplos de programas que muestran por pantalla los 10 primero números utilizando los 4 tipos de estructuras:
INICIO    
i<-1

MIENTRAS i<11

Escribe i

i<-i+1

FIN MIENTRAS

FIN


INICIO

i<-1

REPETIR

Escribe i

i<-i+1

HASTA QUE i=10

FIN


INCIO

i<-1

ITERAR

Escribe i

i<-i+1

SALIR SI i=10

FIN ITERAR

FIN

    

INICIO

PARA i=1 HASTA 10

Escribe i

FIN PARA

FIN

 

 

Procedimientos

 Los procedimientos se especifican mediante un nombre, seguido entre paréntesis de los parámetros de entrada, de entrada-salida y de salida separados por punto y coma. Si hay más de un parámetro de cada tipo esos se separa por comas. Tras esto aparecerá el cuerpo del procedimiento embebido entre las palabras inicio y fin. A continuación se muestra un ejemplo de un procedimiento que calcula el factorial de un número, pudiéndose observar en su interior como se realiza la llamada a un procedimiento (es un procedimiento recursivo).

 

    Factorial(x;;y)

    INICIO

    SI (x=1) ENTONCES

    y 1

    SINO

    Factorial(x-1;;a)

    y a*x

    FINSI

    FIN

 

La llamada al método se haría simplemente especificando los parámetros de entrada y salida entre paréntesis, por ejemplo:

 

 

    INCIO

    Leer a

    Factorial(a;;b)

    Escribir “el factorial de “ a “es” b

    FIN

 

Utilización de la programación estructurada

La forma de resolver un problema utilizando programación estructurada se basa en la utilización de recursos abstractos (procedimientos) y estructuras básicas siguiendo un razonamiento descendiente (o razonamiento top-down).

De esta manera en primer lugar se descompondrá el problema en una serie de subproblemas, de los que se supondrá se cuenta con un procedimiento que es capaz de resolverlo. Estos procedimientos ser relacionarán entre sí mediante las estructuras básicas, finalizando la primera fase de la resolución. Posteriormente se procederá de la misma manera con los procedimientos anteriormente concebidos, creándolos a partir de otros procedimientos más sencillos y estructuras básicas, continuando hasta que todos los procedimientos hayan sido descompuestos en sus operaciones básicas.

 

Hay otra forma de realizar este proceso, no tan común, que es el razonamiento ascendente (Botton up). Partiendo de procedimientos sencillos éstos se van combinando hasta crear un procedimiento que resuelva el problema.

 

En la práctica los programadores suelen utilizar una combinación de ambos procedimientos, pues si bien es cierto que la programación estructurada pemite realizar una abstracción entre lo que hace un procedimiento y lo que posteriormente será su implementación, generalmente a la hora de programar suele ser más fácil pendar tanto en la implementación de los procedimientos de alto nivel como en los de un nivel de abstracción más bajo.

Licencia Creative Commons

Este artículo publicado en TicArte pertenece a José Luis Ávila y está protegido bajo una Licencia Creative Commons.

Ir arriba