Documentos de Académico
Documentos de Profesional
Documentos de Cultura
3.1 Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
En este capítulo se describe la estructura general de un programa, cuáles son sus partes consti-
tutivas, qué tipos de datos se pueden manejar, qué tipos de instrucciones existen y, en general,
los elementos básicos de cualquier programa. Para finalizar la primera parte, se explica cómo debe
realizarse la escritura de algoritmos y programas en general. En la segunda parte del tema se pre-
sentan las estructuras de control básicas del paradigma de programación estructurada: estructuras
secuenciales, de selección e iterativas. Se explicarán cuáles son sus funciones en los programas, cómo
se utilizan y cómo se representan tanto en pseudocódigo como en organigramas.
82
3.1 Introducción
5. Documentación y mantenimiento.
Conceptualmente un programa se considera una caja negra (ver Figura 3.1) en la que se trans-
forman los datos de entrada del programa en salidas o resultados a través de una serie de códigos e
instrucciones. Al proceso de introducir la información de entrada (datos) en la memoria del compu-
tador se le denomina entrada de datos, operación de lectura o acción de leer. Las salidas de datos
o resultados de un programa se deben presentar en dispositivos periféricos de salida (normalmente
la pantalla). A la operación de salida de datos se le conoce también como escritura o acción de
escribir.
83
Los lenguajes de programación (como cualquier otro tipo de lenguaje) tienen elementos bá-
sicos que se utilizan como bloques constructivos, así como reglas establecidas mediante las que
esos elementos se pueden combinar. Al conjunto de esas reglas se le denomina sintaxis del len-
guaje. Cualquier computador puede interpretar únicamente aquellas instrucciones de un lenguaje
que sean sintácticamente correctas, es decir, que estén bien construidas conforme a las reglas del
propio lenguaje. De esta forma, los programas que contienen errores de sintaxis son rechazados
automáticamente por el computador debido a que no consiguen entender lo que se ha programado
por no haber respetado las reglas del lenguaje.
Los elementos básicos constitutivos de un programa o algoritmo son los siguientes:
Palabras reservadas (inicio, fin, si, entonces, ..., for, if, ...).
Constantes.
Variables.
Además de estos elementos básicos existen otros elementos que forman parte de los programas,
cuya comprensión y funcionamiento será vital para el correcto diseño de un algoritmo y naturalmen-
te la codificación del programa. Algunos de estos elementos son: bucles, contadores, acumuladores,
interruptores o banderas, etc. Todos ellos se explican con más detalle a continuación.
1. Debe ser alfanumérico, es decir, que esté formado por letras y dígitos exclusivamente. El que
las letras sean mayúsculas o minúsculas es indiferente para que el identificador sea válido.
Según estas reglas, ejemplos de identificadores válidos serían: nombre, DIV, año2002, Asignaturas-
Matriculadas, ... Por el contrario, ejemplos de identificadores no válidos serían: 4curso, ?comprobado,
2002, Dia del Mes, ...
En programación los identificadores escogidos deben ser significativos, es decir, los nom-
bres que elijamos para determinados objetos de nuestro programa deben hacer referencia al dato
que representan. Con ello facilitaremos la lectura y comprensión de los algoritmos y programas que
84
diseñemos. Ejemplos de buenos identificadores podrían ser edad, para almacenar la edad de una
persona, o IVA, para almacenar el porcentaje de IVA. El simple hecho de utilizar identificadores
significativos facilitaría la compresión del programa puesto que nos podemos hacer una ligera idea
de lo que contienen los objetos al leer su identificador.
Una constante o literal en programación es un caso especial de identificador cuyo valor no
varía durante la ejecución del programa. La definición de una constante consiste, por tanto, en
asociar un identificador con un determinado valor, valor que permanecerá inalterable durante toda
la ejecución del programa. Desde el punto de vista de la eficiencia de los programas, la utilización
de constantes no ocupa espacio en memoria, ya que el propio compilador o intérprete sustituye
cada aparición del identificador de la constante por su valor correspondiente durante el proceso de
traducción o interpretación. En programación para definir los identificadores de constantes se suele
seguir la regla de utilizar identificadores con todas las letras en mayúscula.
La definición o declaración de constantes durante el diseño de algoritmos mediante pseudo-
código se realiza siempre antes del comienzo del programa, comenzando con la palabra reservada
constantes y, a continuación, asociando cada identificador de constante con su valor separados por
el signo igual, tal y como se muestra en el extracto del Algoritmo 3.1.
constantes
< id_const_1 > = < valor_const_1 >
< id_const_2 > = < valor_const_2 >
...
Por ejemplo, si en nuestro algoritmo queremos definir una constante con identificador PI y valor
3,1416, en pseudocódigo se haría tal y como se representa en el extracto del Algoritmo 3.2.
85
constantes
PI = 3 , 1 4 1 6
variables
valor , x : entero
inicio
leer ( valor )
x ← valor + P I
...
fin
Una de las ventajas que proporciona el uso de constantes en nuestros programas es la fácil
modificación del código del programa, ya que si es necesario modificar un dato considerado como
constante en el programa, la definición de una constante permite hacerlo en un solo paso en lugar
de tener que explorar todo el código en busca de literales que hagan referencia a ese dato. Por
ejemplo, si el IVA variase, bastaría con modificar el valor asociado a la constante en la definición
para que dicha modificación actuara sobre todas las referencias incluidas en el programa.
Por último, el concepto de variable está directamente asociado a la memoria del computador.
Una variable es un caso especial de identificador cuyo valor puede variar, es decir, una va-
riable representa un valor almacenado en memoria que se puede modificar durante la ejecución del
programa y/o conservar para ser usado tantas veces como se desee. Cabe aclarar que el concepto
de variable en el ámbito de la programación es distinto al del ámbito de las Matemáticas, ya que en
programación las variables no representan incógnitas sino datos almacenados en memoria principal.
86
variables
< id_variable_1 > : < tipo_variable_1 >
< id_variable_2 > : < tipo_variable_2 >
...
Como se explica más adelante en el apartado dedicado a los tipos simples de dato, para expresar
los tipos de las variables en pseudocódigo se utilizarán palabras reservadas como entero, real,
caracter... El extracto del Algoritmo 3.4 muestra un ejemplo de la declaración de dos variables de
tipo entero con identificadores suma y numero. Como se puede observar, está permitido declarar
más de una variable del mismo tipo en la misma línea.
variables
suma , numero : e n t e r o
inicio
l e e r ( numero )
suma ← numero + 10
...
fin
87
3.2.2 Instrucciones y tipos de instrucciones
id_variable ← expresion
Un caso especial de asignación será aquel en el que aparece la misma variable tanto en la parte
izquierda como en la parte derecha de la sentencia. En cualquier caso, todos los lenguajes
funcionan de idéntica manera: la parte derecha siempre es evaluada en primer lugar
88
y, una vez hallado su valor, este se asigna a la posición de memoria que representa la variable
de la parte izquierda. Por ejemplo, si tenemos la asignación NumDias ← NumDias+1, el valor
final de la variable NumDias será el que tuviera la variable antes de llegar a esa instrucción
más 1.
Otro aspecto a tener muy en cuenta en las asignaciones y en las expresiones que se utilizan en
las instrucciones de asignación es la compatibilidad de los tipos de datos que aparecen
en ellas, de manera que, de forma general, sólo pueden ser operadas entre sí variables o
expresiones pertenecientes a un mismo tipo de dato.
Así, por ejemplo, la instrucción leer (a, b, c) representa la lectura de tres valores de entrada
desde teclado que se asignan a las variables a, b y c. Por otro lado, la instrucción escribir
(’hola que tal’) visualizaría en pantalla el mensaje hola que tal.
Las expresiones aritméticas son análogas a las fórmulas matemáticas, es decir, están formadas
principalmente por una combinación de operandos y operadores. En una expresión aritmética las
variables y constantes implicadas (operandos) son numéricas (de tipo real o entero) y los operadores
son los aritméticos. En esta asignatura se utilizarán en pseudocódigo los operadores aritméticos que
se muestran en la Tabla 3.1:
Los operadores se utilizan de igual forma que en matemáticas pero, sin embargo, no todos los
operadores aritméticos existen en todos los lenguajes de programación. Por ejemplo, en FORTRAN
89
+ suma
- resta
* multiplicación
/ división real
div división entera
** exponenciación
% módulo (resto)
1. Operador exponencial.
En caso de coincidir varios operadores de igual prioridad en una expresión, el orden de prioridad
que se aplica es de izquierda a derecha, excepto para los operadores unarios que será de derecha
a izquierda. Por ejemplo, el resultado de 4 + 8/ − 2 ∗ 6 sería -20. Así mismo, los paréntesis tienen
prioridad sobre el resto de operaciones, de forma que las expresiones encerradas entre paréntesis
serán las primeras que se evalúen. Si existen paréntesis anidados (interiores unos a otros), las
operaciones internas se evalúan primero. Por ejemplo, el resultado de (4 ∗ (1 + 8))/(−2 ∗ 6) sería -3.
Una expresión lógica es un tipo de expresión cuyo valor o resultado es siempre verdadero o falso.
También se les conoce como expresiones booleanas en honor al matemático británico George
Boole, que desarrolló el Álgebra lógica de Boole. Las expresiones lógicas se forman combinando
90
cualquier tipo de dato (ya sea constante o variable), operadores lógicos y operadores relacionales o
de comparación. La Tabla 3.2 y la Tabla 3.3 muestran los operadores lógicos y relacionales respecti-
vamente que se utilizarán en esta asignatura para las descripciones de algoritmos en pseudocódigo.
Con los operadores relacionales se pueden realizar comparaciones de valores de tipo numérico o
carácter, permitiendo así poder expresar cualquier condición o decisión que haya que controlar en
nuestro algoritmo. El formato general para representar una comparación es:
y el resultado de dicha operación siempre será verdadero o falso. Así, por ejemplo, si x = 4 e
y = 3, entonces la expresión lógica x > y será verdad, mientras que la expresión aritmético-lógica
(x − 2) < (y − 4) será falsa.
Los operadores de relación se pueden aplicar a cualquiera de los cuatro tipos de dato básicos
(entero, real, lógico o caracter). Para realizar comparaciones de datos de tipo caracter se requiere
una secuencia de ordenación de los caracteres similar al orden creciente o decreciente. Esta or-
denación suele ser alfabética, tanto para los caracteres en mayúscula como para los caracteres en
minúscula. Cuando se consideran caracteres mixtos (letras y números, por ejemplo) se debe recurrir
a un código normalizado como es el código ASCII para hacer la comparación. Así, el resultado de
la comparación será el que resulte de comparar los valores ASCII asociados a los caracteres impli-
cados. Por ejemplo, la expresión lógica ’A’ <= ’B’ dará como resultado verdad ya que el código
ASCII del carácter A (65) es menor que el del carácter B (66), mientras que la expresión lógica
’X’ = ’Z’ dará como resultado falso, ya que el código ASCII del carácter X (88) es distinto del
código ASCII del carácter Z (90).
Cuando en una expresión lógica interviene algún operador lógico (y, o, no) el resultado final de
dicha expresión se ha de calcular según unas tablas propuestas por el Álgebra de Boole conocidas
como tablas de verdad (ver Tabla 3.4). Conocer de memoria las tablas de verdad es prácticamente
una obligación para toda persona que quiera diseñar cualquier algoritmo y, por ende, cualquier
programa informático.
Según se muestra en las tablas de verdad del Álgebra de Boole, la expresión lógica A y B será
verdad si y solo si A y B son verdad, mientras que la expresión lógica A o B será verdad cuando
91
A B AyB AoB
A no A verdad verdad verdad verdad
verdad falso verdad falso falso verdad
falso verdad falso verdad falso verdad
falso falso falso falso
alguno de los operandos (o A o B) sean verdad. En las expresiones lógicas se pueden mezclar
operadores relacionales y operadores lógicos. Así, por ejemplo, la expresión lógica (1 < 5) y (5 < 10)
será verdad, al igual que la expresión (5 > 10) o (’A’ < ’B’), ya que el operando de la derecha
representa una expresión lógica cierta (el carácter A es menor alfabéticamente que B según el
código ASCII).
De forma análoga a los operadores aritméticos, los operadores lógicos y los operadores relacio-
nales también tienen un orden de precedencia o reglas de prioridad:
2. =, !=
Además de todos los elementos básicos explicados con anterioridad (palabras reservadas, identi-
ficadores, constantes, variables e instrucciones), existen otros elementos que forman parte de los
programas cuya comprensión y funcionamiento será vital para el correcto diseño de un algoritmo
y, naturalmente, la codificación del mismo para crear el programa informático. Entre estos otros
elementos destacan:
Funciones internas. Las operaciones que se requieren en los programas exigen, en numerosas
ocasiones, un número determinado de operaciones especiales que no se pueden realizar con
los operadores aritméticos básicos explicados anteriormente como, por ejemplo, operaciones
de cálculo trigonométrico, logarítmico, etc. Por ello, en la mayoría de lenguajes, existen ya
implementadas una serie de funciones internas que permiten realizar este tipo de cálculos más
avanzados de forma sencilla. Algunos ejemplos de estas funciones en pseudocódigo son: abs(x)
92
para calcular el valor absoluto de x, cos(x), para calcular el coseno de x, ln(x), para calcular
el logaritmo neperiano de x, raiz2(x), para calcular la raíz cuadrada de x, etc.
Contadores. Los procesos repetitivos son la base del uso de las computadoras. En estos
procesos se necesita normalmente contar los sucesos o acciones internas del bucle, y una
forma de controlar un bucle es mediante un contador. Así, un contador será una variable cuyo
valor se incrementa o decrementa en una cantidad constante en cada iteración del bucle. Por
tanto, un contador en programación puede ser positivo (incrementos de uno en uno, de dos
en dos, etc.) o negativo (decrementos de uno en uno, de dos en dos, etc.).
Banderas o interruptores. Una variable bandera (flag, en inglés) o interruptor puede tomar
diversos valores a lo largo de la ejecución del programa y permite comunicar información
sobre algo que ha cambiado durante la ejecución del mismo. Los interruptores suelen tomar
dos valores diferentes (0 o 1, sí o no, encendido o apagado, etc.), de ahí que este tipo de
variables se vean como variables de tipo lógico, aunque no tienen por qué almacenar valores
lógicos.
93
siguiente iteración (si la condición de continuidad sigue siendo cierta).
• El símbolo almohadilla # para comentarios que ocupen una sola línea, situando el sím-
bolo justo delante del texto que forma parte del comentario.
• Triple comilla simple ”’ para comentarios que ocupen más de una línea, terminando el
comentario multilínea también con triple comilla simple.
En el primer tema se introdujeron brevemente los tipos simples de dato o tipos básicos que general-
mente se consideran en programación. En esta sección se explican de forma más detallada, poniendo
especial énfasis en la notación que se debe utilizar para representar los tipos en la descripción de
algoritmos mediante pseudocódigo y organigramas, y no mediante un lenguaje de programación
específico.
La mayoría de algoritmos que se diseñan manipulan datos que pertenecen a un conjunto o clase
de valores identificados mediante lo que se llama un tipo de dato. Por tanto, tipo de dato se
puede definir como el conjunto de valores que puede tomar ese dato. Así, un tipo de dato determina
el dominio de valores que puede tomar ese dato y qué tipo de operaciones se pueden realizar con
él. Los tipos simples de dato a considerar en esta asignatura cuando se diseñen algoritmos en
pseudocódigo son:
entero. Los números enteros son aquellos que no tienen decimales, tanto positivos como
negativos (además del cero). Mientras que en la mayoría de lenguajes de programación existen
diferentes subtipos del tipo entero, en pseudocódigo utilizaremos la palabra reservada entero
para referirnos a cualquier rango de valores enteros.
real. Los números reales son los que tienen decimales y, como en los enteros, pueden ser
positivos y negativos. En pseudocódigo utilizaremos la palabra reservada real para referirnos
94
a cualquier rango de valores reales aunque, al igual que para el tipo entero, la mayoría de
lenguajes proporcionan diferentes subtipos para números reales en función del rango repre-
sentado.
logico. El tipo de dato logico (sin acento en pseudocódigo) se define mediante un conjunto de
dos únicos valores: True (verdadero) y False (falso). Como ya se ha explicado, estos valores
son especialmente importantes para las expresiones condicionales y los bucles.
En la Sección 3.2.1 se explicó cómo se deben declarar las variables de los algoritmos en pseu-
docódigo, de manera que cada identificador de variable se asocia con su tipo separado por el signo
dos puntos (:). Ahora que ya sabemos las palabras reservadas que se utilizarán para referenciar los
tipos básicos de datos, el extracto del Algoritmo 3.5 muestra un ejemplo de declaración de variables
para cada uno de los tipos simples de dato explicados.
variables
...
v1 , v2 : e n t e r o
x : real
c : caracter
bandera : l o g i c o
...
inicio
...
fin
En el ejemplo del Algoritmo 3.5 se han declarado dos variables de tipo entero con identificadores v1
y v2, una variable de tipo real con identificador x, una variable de tipo caracter con identificador
c y una variable de tipo logico con identificador bandera.
95
3.4 El tipo cadena
Aunque el tipo cadena no se considera formalmente un tipo de dato simple (se definió como tipo
de dato estructurado y se estudiará en profundidad más adelante) se introduce brevemente en este
tema para que se pueda trabajar con información de este tipo desde un principio. No obstante,
algunos lenguajes de programación como Python tienen implementado el tipo cadena como tipo de
dato nativo, es decir, como si fuera un tipo básico propio del lenguaje como un tipo entero o un
tipo real, por ejemplo.
Una cadena (string) de caracteres es una sucesión de caracteres (incluido el espacio en blanco)
que se encuentran delimitados por comillas simples o dobles, dependiendo del tipo de lenguaje
de programación. La longitud de una cadena es el número de caracteres comprendidos entre los
limitadores, y la cadena que no contiene ningún carácter se denomina cadena vacía o nula, siendo
su longitud 0. La cadena vacía no se debe confundir con una cadena compuesta sólo de espacios
en blanco, ya que esta tendrá como longitud el número de espacios en blanco de la misma, ya que
el espacio en blanco es en sí un carácter. En esta asignatura utilizaremos como delimitador para
representar cadenas en pseudocódigo el carácter comilla doble (recordemos que para delimitar el
valor de un tipo caracter se debe utilizar comilla simple). De este modo, tres ejemplos de literales
de tipo cadena serían: “12 de octubre de 1492”, “Esto es un ejemplo de cadena de caracteres” o
“123456789”.
Dado que el lenguaje de programación que vamos a emplear durante las prácticas de la asigna-
tura tiene implementado de forma nativa el tipo de dato cadena, en esta asignatura se permitirá
declarar variables de tipo cadena en pseudocódigo. Para ello se utilizará la palabra reservada cadena
tal y como se muestra en el extracto del Algoritmo 3.6, donde se declaran dos variables de ese tipo
con identificadores cad1 y cad2.
variables
cad1 , cad2 : cadena
inicio
...
cad1 ← " Esto e s un e j e m p l o de cadena "
cad2 ← " 332266 "
...
fin
96
Aunque se verá con más detalle en el tema dedicado al tipo de dato estructurado array, las instruc-
ciones básicas para asignar, leer y escribir variables de tipo cadena se realizan de modo similar al
tratamiento de dichas instrucciones con datos numéricos. Así, por ejemplo, para asignar la cadena
de texto “En un lugar de la Mancha” a la variable de tipo cadena cad1, en pseudocódigo sería:
cad1 ← ‘En un lugar de la Mancha”. Del mismo modo, para leer de teclado o escribir en pantalla
el contenido de la variable de tipo cadena cad2, en pseudocódigo sería leer(cad2) y escribir(cad2),
respectivamente.
El tratamiento de cadenas es un tema importante debido a la gran cantidad de información
que se almacena en ellas. Según el tipo de lenguaje de programación elegido se tendrá mayor o
menor facilidad para realizar distintas operaciones con ellas. En cualquier caso, las operaciones
más usuales con variables de tipo cadena que se verán con detenimiento en el siguiente tema son:
Concatenación. Concatenar dos cadenas significa unirlas entre sí dando lugar a una nueva
cadena compuesta por ambas, una seguida de la otra. Para esta asignatura, en pseudocódigo,
se utilizará el operador aritmético suma + para ejecutar esta acción, combinando tantas
variables de tipo cadena como se quieran concatenar, al igual que se haría para sumar variables
de tipo entero, por ejemplo.
Recordemos que uno de los aspectos fundamentales en los que se basa el paradigma de la progra-
mación estructurada es que todo programa se puede realizar con la combinación de alguna de
las estructuras conocidas como estructuras de control o estructuras básicas, que son la secuen-
cial, la de selección y la iterativa. Estas estructuras básicas de control se explican con detalle a
continuación.
Una estructura secuencial es un bloque de una o más instrucciones que se ejecutan exactamente una
vez en el programa. Dicho de otra manera, la estructura secuencial es aquella en la que una acción
(instrucción) sigue a otra en secuencia, de tal modo que al terminar una se ejecuta la siguiente y
así sucesivamente hasta el final del proceso.
97
Para representar una estructura secuencial en organigrama se debe utilizar la caja rectangular
que representa la ejecución de una acción (o varias), tal y como se muestra en la Figura 3.2. En
pseudocódigo se haría simplemente escribiendo el nombre de las instrucciones que componen la
estructura, una debajo de otra secuencialmente, tal y como se muestra en el Algoritmo 3.7.
acción 1
acción 1
acción 2
...
acción 2
acción n
acción n
inicio
< accion1 >
...
< a c c i o n n>
fin
Para practicar la representación de este tipo de estructura se propone realizar el análisis y diseño
de un algoritmo que calcule el perímetro y el área de un rectángulo a partir de la base y la altura
dadas por el usuario. Una posible solución se expone a continuación:
DATOS DE ENTRADA
Id Descripción Restricciones
base Base del rectángulo en centímetros >0
altura Altura del rectángulo en centímetros. >0
98
DATOS DE SALIDA
Id Descripción
per Perímetro del rectángulo. Se calcula como 2 ∗ base + 2 ∗ altura
area Área del rectángulo. Se calcula como base ∗ altura
PSEUDOCÓDIGO
variables
base , a l t u r a , per , a r e a : e n t e r o
inicio
e s c r i b i r ( " Base y a l t u r a : " )
l e e r ( base , a l t u r a )
per ← 2 ∗ base + 2 ∗ altura
area ← base ∗ altura
e s c r i b i r ( per , a r e a )
fin
ORGANIGRAMA
inicio
fin
99
3.5.2 Estructuras selectivas
La descripción formal de algoritmos es realmente útil cuando el algoritmo requiere de una descripción más
complicada que una simple lista secuencial de instrucciones. Normalmente estos casos se dan cuando existen
diferentes alternativas resultantes de la evaluación de una determinada condición.
Las estructuras selectivas en programación se utilizan para tomar decisiones lógicas, de ahí que se
suelan denominar también estructuras de decisión o alternativas. En las estructuras selectivas se evalúa
una condición lógica y en función de su resultado se realizan unas tareas u otras. Las condiciones se
especifican utilizando expresiones lógicas, de ahí que sea fundamental dominar las tablas de verdad
del álgebra de Boole que permiten resolver ese tipo de expresiones. Las estructuras selectivas pueden ser
simples, dobles o anidarse unas y otras. Todas ellas se explican a continuación.
La estructura alternativa simple ejecuta una acción o conjunto de acciones cuando se cumple una determinada
condición. Esta estructura evalúa la condición y
si la condición es falsa, entonces no hace nada y la ejecución pasa a la siguiente instrucción después
de la estructura simple.
V F
condición
acción S1
100
s i ( < condicion >) entonces
...
< a c c i o n S1 >
...
fin_si
Obsérvese que las palabras del pseudocódigo si y fin_si se alinean verticalmente, indentando (sangrando) un
poco hacia la derecha la <accion S1> o bloque de acciones S1 hacia la derecha, y que la expresión lógica que
representa la condición suele ir encerrada entre paréntesis. Indentar las acciones que pertenecen a la
estructura condicional es muy importante hacerlo siempre, aparte de porque hacemos la descripción
del algoritmo más legible, porque a la hora de codificar el programa posteriormente en lenguajes como Python
es fundamental respetar la indentación en los bloques de código para no incurrir en errores de sintaxis con
el lenguaje.
La estructura de decisión simple es limitada y lo habitual es necesitar una estructura que permita elegir
entre dos opciones o alternativas posibles: un conjunto de acciones a realizar cuando la condición sea cierta y
otro bloque de instrucciones diferente cuando la condición sea falsa. Por tanto, una estructura selectiva doble
deberá emplearse cuando se presenten dos alternativas de actuación mutuamente excluyentes que dependan
del resultado de una misma condición. La representación gráfica de esta estructura es similar a la de la
decisión simple, tal y como se muestra en la Figura 3.5. El pseudocódigo asociado a la estructura condicional
doble se muestra en el Algoritmo 3.10.
V F
condición
acción S1 acción S2
101
s i ( < condicion >) entonces
...
< a c c i o n S1 >
...
si_no
...
< a c c i o n S2 >
...
fin_si
Obsérvese que en el pseudocódigo asociado a la estructura de selección doble que si la expresión lógica de la
condición es verdadera se ejecuta la acción S1 (o bloque de acciones S1 ) y, si es falsa, se ejecuta la acción
S2 (o bloque de acciones S2 ). Al igual que para la estructura de decisión simple, en el pseudocódigo las
acciones que dependen de la parte cierta del si (después de la palabra reservada entonces) y las acciones que
dependen de la parte a ejecutar cuando la condición sea falsa (después de la palabra reservada si_no) están
indentadas hacia la derecha en relación a las palabras reservadas si y fin_si. Esto, como se ha comentado
con anterioridad, es obligatorio hacerlo siempre en lenguajes como Python.
102
V F V F
condición1
condición1
V F
condición2 V F
acción S2 acción S1 condición2
acción S1 acción S2
Figura 3.6: Dos posibles ejemplos de estructuras de selección anidadas mediante organigramas
103
3.5.2.4 Ejemplo de utilización de estructuras selectivas
DATOS DE ENTRADA
Id Descripción Restricciones
a Variable que multiplica a x (real) -
b Variable independiente (real) -
DATOS DE SALIDA
Id Descripción
x Valor de la incógnita x. Se calcula como x = -b/a (siempre que a! = 0)
COMENTARIOS
Habrá que comprobar el valor de b siempre que a sea igual a 0, de modo que si b es distinto de 0
entonces la solución es imposible, y si b es igual a 0 entonces la solución es indeterminada.
variables
a , b : real
inicio
e s c r i b i r ( "Dame e l v a l o r de a y b : " )
l e e r (a , b)
s i ( a != b ) e n t o n c e s
x ← -b/a
e s c r i b i r ( " El v a l o r de x e s " , x )
si_no
s i ( b != 0 ) e n t o n c e s
e s c r i b i r ( " Solución imposible " )
si_no
e s c r i b i r ( " Solución indeterminada " )
fin_si
fin_si
fin
Algoritmo 3.13: Pseudocódigo del algoritmo que calcula una ecuación lineal de primer grado
104
ORGANIGRAMA
inicio
V F
a != b
x ← -b/a b != 0
fin
Figura 3.7: Organigrama del algoritmo que calcula una ecuación líneal de primer grado
Debido a su altísima velocidad de ejecución los computadores son dispositivos especialmente diseñados para
realizar determinadas tareas que deben repetirse un número considerable de veces. Por este motivo, un tipo
de estructura muy importante que viene implementada en casi todos los lenguajes de programación es la
estructura iterativa o estructura repetitiva, cuya utilización es ideal cuando en un algoritmo queremos
que un bloque de instrucciones se repita un número determinado (o indeterminado) de veces. A este tipo
de estructuras también se les conoce en programación como bucles, ya que su comportamiento se asemeja
al de cualquier bucle de repetición. Por otro lado, se denomina iteración al hecho de ejecutar una vez de
forma completa el bloque de acciones que componen el bucle, es decir, una iteración corresponde a una única
repetición completa del bucle.
Veamos la utilidad de este tipo de estructuras con el siguiente ejemplo: supongamos que se desea sumar
una lista de números que se introducen por teclado. El algoritmo para resolver este problema si utilizasemos
las estructuras explicadas hasta el momento (secuenciales y/o selectivas) se compondría de una sucesión de
instrucciones para leer los números y añadir sus valores a una variable suma que fuera la encargada de ir guar-
dando las sumas parciales. Al comenzar el algoritmo la variable suma se inicializaría a 0 y, posteriormente,
se iría incrementando con el valor del número leído por teclado (ver Algoritmo 3.14).
variables
numero , suma : e n t e r o
inicio
suma ← 0
105
l e e r ( numero )
suma ← suma + numero
l e e r ( numero )
suma ← suma + numero
l e e r ( numero )
suma ← suma + numero
...
fin
Algoritmo 3.14: Pseudocódigo del algoritmo para sumar una lista de números de forma secuencial
Como se puede observar en el pseudocódigo del Algoritmo 3.14, las instrucciones leer(numero) y suma ←
suma+numero se repiten muchas veces de forma idéntica, por lo que podríamos decir que ambas instrucciones
forman un bucle que se repite continuamente. En ese caso lo ideal en programación es utilizar una estructura
iterativa, pero siempre que vayamos a utilizar este tipo de estructuras en un algoritmo el programador tiene
que responder a dos preguntas fundamentales:
Siguiendo con el ejemplo de sumar una lista de números necesitaremos saber previamente cuántos números
en total se quieren sumar. Ese requisito es lo que se conoce en programación como la condición de parada
del bucle. En el ejemplo podríamos optar por solicitar al usuario cuántos números en total quiere sumar
antes de empezar a leerlos. Con esa estrategia ya tendríamos perfectamente definida la estructura repetitiva
a utilizar en el algoritmo (conocemos las instrucciones que contendrá el bucle y tenemos definida la condición
de parada).
En programación estructurada existen tres tipos básicos de estructuras iterativas que se diferencian
fundamentalmente en cuándo se comprueba si se ha cumplido la condición de parada:
106
3.5.3.1 Estructura mientras-hacer
La estructura iterativa mientras-hacer (while-do en inglés) es aquella en la que el cuerpo del bucle se repite
mientras se cumpla una determinada condición, es decir, mientras esa condición sea cierta. Este tipo de
estructura evalúa la condición de parada (una expresión lógica) antes de ejecutar la primera instrucción
del bucle. Por tanto, si al comienzo de la estructura esa condición se evalúa como falsa, no se llegaría a
ejecutar ninguna instrucción del bucle, prosiguiendo el programa por la siguiente instrucción que haya justo
a continuación de la estructura repetitiva. Si la condición del bucle es cierta entonces se ejecuta el cuerpo del
bucle entero y, una vez terminada la última instrucción del bucle, se evalúa de nuevo la expresión lógica de la
estructura (condición de parada), y así sucesivamente hasta que la expresión lógica sea falsa. El organigrama y
pseudocódigo asociado a esta estructura se muestran en la Figura 3.8 y en el Algoritmo 3.15, respectivamente.
Nótese que para representar cualquier estructura iterativa mediante organigramas no existe un
símbolo especial, se utiliza el mísmo símbolo rombo que se emplea para especificar la condición en una
estructura selectiva.
F
condición
acciones
Veamos cómo se resolvería el ejemplo del algoritmo para sumar una lista de números utilizando una estructura
mientras-hacer. Para ello, podríamos utilizar una variable auxiliar llamada total que se inicialice al comenzar
con la cantidad de números que se desean leer y, a continuación, se iría decrementando de uno en uno en
107
cada iteración del bucle1 . El Algoritmo 3.16 muestra esta estrategia en pseudocódigo.
variables
t o t a l , suma , numero : e n t e r o
inicio
e s c r i b i r ( " I n t r o d u z c a l a c a n t i d a d t o t a l de números a sumar : " )
leer ( total )
suma ← 0
m i e n t r a s ( total > 0 ) h a c e r
l e e r ( numero )
suma ← suma + numero
total ← total − 1
fin_mientras
e s c r i b i r ( " La suma de l o s " , t o t a l , " números e s " , suma )
fin
Algoritmo 3.16: Pseudocódigo del algoritmo para sumar una lista de números utilizando una es-
tructura mientras-hacer
Obsérvese que para que un bucle mientras-hacer termine en algún momento de iterar y no entre en un estado
de bucle infinito (nuestro programa se quedaría colgado sin responder), la condición de parada debería ser
falsa en algún momento. Por ello, en este tipo de estructuras es obligatorio que en el cuerpo del bucle
exista siempre alguna instrucción que modifique alguno de los operandos que intervienen en
la expresión lógica de la condición ya que, de lo contrario, la condición sería cierta siempre (si se han
inicializado los operandos para que sea cierta la primera vez) y nos encontraríamos ante un temido bucle
infinito. La estructura iterativa mientras-hacer suele emplearse en programación cuando se desconoce a priori
el número exacto de iteraciones que debe ejecutarse el bucle y, además, no se tiene la obligación de ejecutar
al menos una vez las instrucciones del cuerpo del bucle.
Existen muchas situaciones cuando diseñamos algoritmos en las que se desea que un bucle se ejecute al
menos una vez antes de comprobar la condición de repetición. Recordemos que en la estructura iterativa
mientras-hacer si el valor de la expresión lógica de la condición es falso al iniciar el bucle, el cuerpo del bucle
no se ejecutaría, de ahí que se necesite otro tipo de estructura repetitiva para resolver estos casos.
La estructura iterativa repetir-mientras (repeat-while, en inglés) y la estructura iterativa repetir-hasta_que
(repeat-until, en inglés) se ejecutan mientras se cumpla una condición o hasta que se cumpla una condición,
respectivamente, condición que siempre se comprueba al final del bucle, es decir, siempre se ejecuta el bloque
de instrucciones del bucle al menos una vez con cualquiera de las dos estructuras.
1
También se podría haber optado por hacerlo al revés, es decir, inicializar la variable total a 0 o 1, e ir incremen-
tándola de uno en uno en cada iteración del bucle, hasta llegar al número deseado.
108
Obviamente la expresión lógica a utilizar como condición de parada será diferente si utilizamos una u
otra alternativa. Esa expresión lógica vendrá determinada por el propio significado de la estructura que
utilicemos ya que repetir algo mientras se cumpla una condición hace que la expresión lógica de esa con-
dición a configurar sea bien diferente de la que hay que utilizar cuando se desea repetir algo hasta que se
cumpla la condición. Básicamente lo que implicaría sería un cambio en el operador relacional utilizado en la
expresión lógica. El organigrama y pseudocódigos asociados a las dos posibles alternativas de esta estructura
se muestran en la Figura 3.9 y en los Algoritmos 3.17 y 3.18, respectivamente.
acciones acciones
V F
hasta_que mientras
condición condición
F V
repetir
accion1
accion2
...
hasta_que ( < c o n d i c i o n > )
repetir
accion1
accion2
...
mientras ( < condicion >)
El ejemplo del algoritmo que suma una lista de números se podría resolver también utilizando cualquiera de
109
las dos estructuras repetir explicadas, lo único que cambiaría es la condición a comprobar al final del bucle,
dependiendo de si utilizamos la estructura repetir-hasta_que o repetir-mientras. Los Algoritmos 3.19 y 3.20
muestran una posible solución utilizando ambas alternativas.
variables
t o t a l , suma , numero : e n t e r o
inicio
e s c r i b i r ( " I n t r o d u z c a l a c a n t i d a d t o t a l de números a sumar : " )
leer ( total )
suma ← 0
repetir
l e e r ( numero )
suma ← suma + numero
total ← total − 1
hasta_que ( total = 0 )
e s c r i b i r ( " La suma de l o s " , t o t a l , " números e s " , suma )
fin
Algoritmo 3.19: Pseudocódigo del algoritmo para sumar una lista de números utilizando una es-
tructura repetir-hasta_que
variables
t o t a l , suma , numero : e n t e r o
inicio
e s c r i b i r ( " I n t r o d u z c a l a c a n t i d a d t o t a l de números a sumar : " )
leer ( total )
suma ← 0
repetir
l e e r ( numero )
suma ← suma + numero
total ← total − 1
m i e n t r a s ( total > 0 )
e s c r i b i r ( " La suma de l o s " , t o t a l , " números e s " , suma )
fin
Algoritmo 3.20: Pseudocódigo del algoritmo para sumar una lista de números utilizando una es-
tructura repetir-mientras
110
3.5.3.3 Estructura para-hacer
Existen otras situaciones cuando se están diseñando algoritmos en las que se conoce a priori el número de
veces exacto que se tienen que ejecutar las acciones de un bucle. En estos casos es recomendable utilizar
la estructura iterativa para-hacer (for-do, en inglés). Esta estructura ejecuta las acciones del cuerpo del
bucle un número de veces determinado y la ventaja de utilizarlas es que la propia estructura controla de
modo automático las iteraciones, de manera que el programador se despreocupa de tener que incluir una
instrucción dentro del bucle que modifique en algún momento la condición de parada del mismo. Ese control
automático de las iteraciones lo realiza la propia estructura a través de lo que se conoce como variable índice,
contador o variable de control del bucle, de manera que dicha variable se incrementa o decrementa de forma
automática al terminar cada iteración. No obstante, el programador sí deberá especificar en la definición de
la estructura hasta que valor podrá alcanzar la variable de control.
La ejecución de la estructura iterativa para-hacer comienza asignando un valor inicial (vi) a la variable
de control o variable contador (vc) del bucle y, a continuación, comprueba si ese valor supera o iguala el
valor final (vf ) definido, es decir, el número de veces que queremos que se ejecute el cuerpo del bucle. Si
es así, la ejecución del bucle finaliza, pasando la ejecución del algoritmo a la siguiente instrucción que haya
justo después de la estructura iterativa. En otro caso, la ejecución del cuerpo del bucle se repetirá hasta que
el valor vi iguale o supere el valor finalvf establecido, incrementando (o decrementando) automáticamente
el valor de la variable contador cada vez que se produce una iteración completa2 .
En la definición de una estructura iterativa para-hacer cabe reseñar que la variable contador del bucle
se puede configurar para que se incremente o para que se decremente en el valor que sea, de 1 en 1, de 2 en
2, etc. Para esta asignatura, cuando se utilice una estructura de este tipo en pseudocódigo, si no se indica
nada en la cabecera de la estructura, se entenderá que, por defecto, la variable contador se incrementa de 1
en 1. De lo contrario habrá que indicar el incremento o decremento (con su valor) justo después de establecer
el valor final (vf ) y antes de la palabra reservada hacer.
Un aspecto muy importante que hay que tener en cuenta cuando se tiene que representar una es-
tructura iterativa para-hacer mediante organigrama (ver Figura 3.10) es la obligatoriedad de dedicar
una acción al final del bucle para incrementar (o decrementar) manualmente la variable contador, ya que
cuando utilizamos organigramas no existe un símbolo especial para representar estructuras iterativas del
tipo para-hacer. Por tanto, se ha de utilizar el mismo símbolo rombo que para las estructuras iterativas
mientras o repetir y es el programador quien debe indicar el incremento o decremento mediante
una última acción dentro del cuerpo del bucle. En pseudocódigo, como se ha comentado, esto no es
necesario, ya que ese incremento (o decremento) se hace de forma automática en la cabecera que define la
estructura (ver Algoritmo 3.21 y Algoritmo 3.22).
2
De forma análoga, tal y como se muestra en la parte derecha de la Figura 3.10, la estructura para-hacer se puede
configurar inicializando la variable contador al valor final y decrementando dicho valor hasta que se llegue al valor
inicial.
111
vc ← vi vc ← vf
F F
vc < vf vc > vi
V V
acciones acciones
incrementar vc decrementar vc
Figura 3.10: Organigramas asociados a la estructura iterativa para-hacer con incremento o decre-
mento
p a r a vc ← vi h a s t a v f h a c e r
accion1
accion2
...
fin_para
Algoritmo 3.21: Pseudocódigo asociado a la estructura iterativa para-hacer por defecto (incremento
de la variable de control de 1 en 1)
El Algoritmo 3.23 y el Algoritmo 3.24 muestran en pseudocódigo cómo se resolvería el ejemplo de sumar
una lista de números introducidos por teclado utilizando una estructura iterativa para-hacer por defecto
(incremento de 1 en 1) o una estructura iterativa para-hacer con decremento de 1 en 1, respectivamente.
112
variables
t o t a l , suma , numero : e n t e r o
inicio
e s c r i b i r ( " I n t r o d u z c a l a c a n t i d a d t o t a l de números a sumar : " )
leer ( total )
suma ← 0
p a r a vc ← 1 h a s t a total + 1 h a c e r
l e e r ( numero )
suma ← suma + numero
fin_para
e s c r i b i r ( " La suma de l o s " , t o t a l , " números e s " , suma )
fin
Algoritmo 3.23: Pseudocódigo del algoritmo para sumar una lista de números utilizando una es-
tructura iterativa para-hacer por defecto (con incremento de 1 en 1)
variables
t o t a l , suma , numero : e n t e r o
inicio
e s c r i b i r ( " I n t r o d u z c a l a c a n t i d a d t o t a l de números a sumar : " )
leer ( total )
suma ← 0
p a r a vc ← total h a s t a 0 dec 1 h a c e r
l e e r ( numero )
suma ← suma + numero
fin_para
e s c r i b i r ( " La suma de l o s " , t o t a l , " números e s " , suma )
fin
Algoritmo 3.24: Pseudocódigo del algoritmo para sumar una lista de números utilizando una es-
tructura iterativa para-hacer con decremento de 1 en 1
Al igual que puede ocurrir con las estructuras selectivas, al diseñar un algoritmo se pueden anidar estructuras
iterativas, de manera que un bucle se inserte en el cuerpo de instrucciones de otro bucle. La única regla que se
ha de respetar para construir estructuras iterativas anidadas es que la estructura interna debe estar incluida
113
totalmente dentro de la estructura inmediatamente exterior y no puede existir solapamiento. De este modo,
por cada iteración de la estructura más externa se deben ejecutar de forma completa todas
las iteraciones del bucle de la estructura inmediatamente interior (y así sucesivamente).
Para ver un ejemplo de uso de este tipo de estructuras el Algoritmo 3.25 muestra una posible solución
en pseudocódigo para resolver el problema del cálculo del factorial de n números leídos desde teclado.
variables
n , numero , i , j , f a c t o r i a l : e n t e r o
inicio
e s c r i b i r ( "A c u á n t o s números l e q u i e r e c a l c u l a r e l f a c t o r i a l ? " )
l e e r (n)
para i ← 1 hasta n + 1 hacer
e s c r i b i r ( " Dime número : " )
l e e r ( numero )
factorial ← 1
p a r a j ← 1 h a s t a numero + 1 h a c e r
factorial ← factorial ∗ j
fin_para
e s c r i b i r ( " El f a c t o r i a l d e l número " , numero , " e s " , f a c t o r i a l )
fin_para
fin
break, cuyo cometido es romper la ejecución de un bucle y continuar la ejecución del programa por
la instrucción inmediatamente posterior a la estructura iterativa (termina el bucle prematuramente,
aunque no se cumpla la condición de parada).
continue, cuyo efecto es saltar a la siguiente iteración del bucle, reevaluando la condición de continui-
dad del mismo. Es decir, termina la iteración del bucle prematuramente donde estuviera la instrucción
continue y salta a la siguiente iteración, incrementando (o decrementando) la variable de control. Si
la condición de continuidad sigue siendo cierta, el bucle continuará iterando.
114
En el Algoritmo 3.26 se muestra un ejemplo en pseudocódigo de una posible utilización de la instrucción
break. Al ejecutar dicho código, si en algún momento la condición2 es cierta, se ejecutaría la instrucción break
y la ejecución del cuerpo del bucle mientras-hacer se terminaría en ese momento, siguiendo la ejecución del
programa por la instrucción que hubiera justo después de la instrucción fin_mientras.
...
mientras ( < condicion1 >) hacer
accion1
accion2
...
s i ( < condicion2 >) hacer
break
fin_si
...
accion n
fin_mientras
...
2. Parte declarativa. Contiene las declaraciones de constantes y variables que utilizará el algoritmo. En
la sección constantes se declaran todas las constantes del algoritmo, colocando primero el identificador
de la constante seguido del signo igual (=) y el valor que toma la constante. Después, en la sección
variables, se declaran todas las variables del algoritmo colocando el identificador de la variable seguido
del signo dos puntos (:) y el tipo de la variable. Se permite declarar más de una variable del mismo
115
tipo en la misma línea separadas por comas. El tipo podrá ser uno de los tipos de dato simples (entero,
real, carácter o lógico) o alguno de los tipos estructurados que se ven en la asignatura.
3. Pseudocódigo. Contiene las acciones que serán ejecutadas por el programa (el algoritmo) y siempre
deberá comenzar con la palabra reservada inicio y terminar con la palabra reservada fin.
Otros aspectos a tener en cuenta en relación al estilo que debemos utilizar cuando escribamos algoritmos
en pseudocódigo son:
Las secciones de declaración de constantes y/o variables se omitirán cuando no sean necesarias, es
decir, cuando el algoritmo no necesite utilizar constantes y/o variables.
Se deberán indentar aquellas instrucciones que pertenezcan a una determinada estructura para pro-
porcionar mayor legibilidad en la lectura del algoritmo.
Se podrán añadir comentarios en el pseudocódigo utilizando el carácter almohadilla (#) antes del
texto del comentario.
Por ejemplo, el Algoritmo 3.27 muestra cómo se debería escribir en pseudocódigo (de forma completa) el
algoritmo que resuelve una ecuación de segundo grado.
a l g o r i t m o ecuacion_segundo_grado
# a l g o r i t m o que r e s u e l v e una e c u a c i o n de segundo gr a do
variables
a ,b, c ,d : real
inicio
leer (a ,b , c)
d ← b ^ 2 - 4 * a * c
s i d < 0 entonces
e s c r i b i r ( " Raíces complejas " )
si_no
s i d = 0 entonces
e s c r i b i r ( - b / 2* a )
si_no
e s c r i b i r ( ( - b - s q r t (d ) ) / (2* a ) )
e s c r i b i r ( ( - b + s q r t (d ) ) / (2* a ) )
fin_si
fin_si
fin
Algoritmo 3.27: Pseudocódigo del algoritmo que resuelve una ecuación de segundo grado
Como se puede observar en el pseudocódigo del Algoritmo 3.27, la cabecera estaría formada por la primera
línea (algoritmo ecuación_segundo_grado), donde se le asigna un nombre algoritmo, la parte declarativa
116
estaría formada exclusivamente por la sección variables, donde se declaran las variables a, b, c y d de tipo
real, y la parte del pseudocódigo del algoritmo estaría compuesta por todas las instrucciones comprendidas
entre las palabras reservadas inicio y fin inclusive.
Durante las fases de diseño y programación o codificación de programas es habitual cometer errores. En
particular, los errores que se pueden cometer se clasifican en dos tipos principalmente:
De sintaxis, que son errores cometidos a la hora de escribir el código conforme a las normas del
lenguaje de programación. Como consecuencia de estos errores, el programa no puede ser compilado o
interpretado. Los errores de sintaxis son fácilmente detectados porque el propio compilador o intérprete
indican en qué línea del código se produce el error, sólo es necesario conocer las normas sintácticas del
lenguaje para poder corregirlos.
De lógica, que son errores relacionados con la lógica del programa y, por tanto, cometidos durante la
fase de diseño del algoritmo normalmente, propiciando como consecuencia que el programa no haga lo
que se pretendía y que el resultado sea incorrecto. Los errores de lógica pueden llegar a ser difíciles de
detectar, especialmente si el código no presenta una buena legibilidad. Estos errores suelen detectarse
durante la propia ejecución del programa y para solucionarlos se suele realizar una batería o test de
pruebas que permitan mostrar el funcionamiento correcto o incorrecto del programa para diferentes
valores de entrada.
Una de las herramientas habituales que facilitan la detección de posibles errores en el código de un
programa son los depuradores (debugger, en inglés). Un depurador es un programa que acompaña nor-
malmente al compilador o intérprete del lenguaje y que permite hacer un seguimiento paso a paso de las
instrucciones que se ejecutan en el programa. A ese proceso de ejecutar paso a paso las instrucciones de
un programa se le conoce como traza de un programa. Cuando la herramienta con la que trabajamos para
codificar el algoritmo dispone de un editor de código fuente, un compilador y un depurador (todo en la
misma herramienta), decimos que estamos utilizando un entorno de programación integrado o entorno de
desarrollo integrado (IDE, Integrated Development Environment, en inglés).
La utilización de un depurador para detectar posibles errores en nuestro código puede suponer una
ventaja porque permite:
Ejecutar instrucción a instrucción, de modo que se ejecuta una única instrucción y el programa se
detiene hasta que el programador indique que se ejecute la siguiente. De este modo es posible con-
sultar en cualquier momento el estado del programa, es decir, comprobar los valores almacenados por
cualquier variable del programa en ese momento.
Introducir puntos de ruptura (breakpoints) en el código, de manera que podremos indicarle al depurador
que ejecute el programa hasta llegar a ese punto de ruptura definido y, a partir de ahí, continuar paso
a paso, por ejemplo. Utilizando puntos de ruptura podremos saltar código de nuestro programa en el
que tenemos la certeza de que no hay ningún tipo de error y así ahorrar tiempo en la detección de
posibles problemas.
117
Consultar y/o modificar el valor de las variables durante la ejecución paso a paso. En todo momento,
el depurador nos permitirá consultar el valor de una determinada variable durante la ejecución, o el
valor que retorna un módulo, e incluso asignar un valor en tiempo de ejecución a una variable en
concreto, etc.
Además de los errores de sintaxis y los errores de lógica debemos considerar otro tipo de problemas
que pueden presentar los programas y que se deben a los valores no permitidos en los datos de entrada
(restricciones). Por ejemplo, un programa que calcula una raíz cuadrada no debería permitir introducir
un valor negativo, o un programa que calcule el factorial de un número no debería permitir que dicho
número fuera tan grande que sobrepasara la capacidad de cálculo del computador. Ante una situación de
este tipo si el programa no está preparado podría proporcionar un resultado incorrecto o incluso causar un
problema importante en el sistema, dejándolo inutilizado (lo que comúnmente se conoce como colgado). En
este sentido, un buen programador debe construir programas robustos frente a todo tipo de situaciones que
puedan poner en riesgo su funcionamiento, respondiendo adecuadamente ante cualquier eventualidad (datos
de entrada imprevistos, fuera del rango permitido, con formato incorrecto, ausentes, etc.). No obstante,
cuando se detecta una situación de este tipo, el programa siempre debe informar al usuario del error
que se ha producido y, además, se pueden adoptar dos enfoques diferentes:
Prevenir el error, es decir, tomar las medidas necesarias para que no se produzca una situación de
riesgo. Por ejemplo, que sea imposible escribir números negativos para calcular su raíz cuadrada.
Recuperar el error, o lo que es lo mismo, tomar las medidas necesarias para que si se detecta la situa-
ción, poder solucionarlo. Por ejemplo, si se intenta calcular la raíz cuadrada de un número negativo,
retroceder para repetir la entrada de datos hasta que sea válida.
Por último, una vez conocidos los riesgos de un programa siempre se debe probar su funcionamiento con
arreglo a dichos riesgos, es decir, se deberían hacer pruebas (tests) de todo tipo, utilizando valores de entrada
correctos, extremos pero correctos, extremos pero incorrectos, valores totalmente fuera del rango correcto,
valores aleatorios, etc. Cuanto más pruebas se realicen más robusto será nuestro programa.
118