Nuestros cursos:

Nuestros cursos:

Programación estructurada

La programación estructurada fue un enfoque revolucionario en el desarrollo de software que surgió en la década de 1960. Antes de su adopción, los programadores utilizaban principalmente la programación no estructurada, también conocida como programación en lenguaje ensamblador o programación basada en saltos incondicionales (goto).

La programación monolítica o no estructurada permitía a los programadores escribir código con saltos incondicionales o instrucciones de salto a cualquier parte del programa. Esto llevaba a programas difíciles de leer, entender y mantener, debido a la falta de estructura y organización.

Los programas grandes y complejos se volvían especialmente difíciles de manejar, y los errores eran más propensos a ocurrir debido a la complejidad y la falta de control en la lógica del programa.

La programación estructurada introdujo principios y técnicas para mejorar la claridad, la eficiencia y la calidad del software con base en tres conceptos fundamentales:

  1. Secuencialidad: La ejecución de un programa sigue un flujo secuencial de instrucciones de arriba a abajo. Las instrucciones se ejecutan en orden y cada una se completa antes de pasar a la siguiente.
  2. Selección: Se introdujo la estructura de control de selección para tomar decisiones en función de condiciones lógicas. Esto se logró mediante el uso de declaraciones condicionales, como if-else (si-entonces-sino), switch (caso) y operadores relacionales.
  3. Iteración: Se introdujo la estructura de control de iteración para repetir una serie de instrucciones en función de una condición. Esto se logró mediante el uso de bucles, como for, while y do-while.

Estas estructuras de control permiten una lógica más clara, facilitan el seguimiento y la depuración del código y hacen que los programas sean más fáciles de entender y mantener.

La programación estructurada se centra en el modularidad, la reutilización de código y la minimización de la complejidad, lo que facilita el desarrollo de software confiable y de alta calidad. Sentó las bases para los enfoques de programación posteriores, como la programación orientada a objetos (POO) y la programación orientada a eventos (POE), que aportaron más mejoras en la organización y la abstracción del software.

Aunque no se adopte un enfoque estrictamente estructurado, hay un conjunto de algoritmos y estructuras de datos fundamentales que todo programador debe aprender al comenzar su carrera profesional. Estos conceptos se explican mejor desde un paradigma estructurado, que permite una comprensión clara de los principios básicos de organización y control en un programa.

A medida que el programador se familiariza con estas herramientas, puede aplicarlas en otros paradigmas de programación, como la programación orientada a objetos o funcional, enriqueciendo su capacidad para abordar problemas complejos. Estas técnicas iniciales no solo facilitan el desarrollo de programas sencillos, sino que también se convierten en la base para la creación de sistemas más complejos y robustos.

A medida que un programador progresa en su habilidad para abstraer problemas, comienza a identificar procesos más generales, debido a su conocimiento de los detalles de bajo nivel. En este punto, puede adoptar un enfoque ‘top-down’, es decir, desde lo general a lo particular, descomponiendo grandes bloques de trabajo en partes más pequeñas. Sin embargo, si el estudiante no logra identificar estos procesos más amplios debido a la falta de experiencia o a la falta de modelos mentales desarrollados, puede optar por resolver problemas más pequeños, enfocándose en porciones de código más simples.

Una estrategia para abordar la diversidad en el nivel de conocimiento entre los estudiantes es comenzar con pequeños bloques de código, y gradualmente avanzar hacia problemas más complejos a medida que los estudiantes adquieren confianza y comprensión.

Ignorar cómo cambia el pensamiento de un programador a medida que gana experiencia puede llevar a ideas equivocadas. Por ejemplo, cuando alguien encuentra una solución a un problema, puede no ser consciente del proceso que lo llevó a esa solución y creer que se trató de una ‘inspiración’ o de una ‘capacidad innata’.

En contraste, aquellos que no logran encontrar soluciones de forma espontánea pueden sentir que carecen de esa habilidad, lo que les genera frustración. Sin embargo, la realidad es que estas soluciones ‘mágicas’ solo aparecen tras mucha práctica o a través de un recorrido educativo que enseña a pensar.

Estos procesos educativos que ayudan a aprender a pensar siempre incluyen la posibilidad de expresar con palabras propias el contenido de situaciones, problemas y argumentos, así como la provisión de abundante práctica..

Ahora bien, sabemos que entre la comprensión del problema y la escritura del código en un lenguaje de programación existe una distancia que no conviene acortar demasiado. Mientras aprendemos a comprender los problemas y a planificar los primeros algoritmos en pseudocódigo, no es conveniente complicar el proceso centrándonos en la sintaxis de un lenguaje profesional de programación.

En otras palabras, es preferible aprender primero a programar en pseudocódigo y a plantear las ideas generales de manera más accesible, y luego, una vez que los problemas y algoritmos básicos se entienden, pasar a la programación en un lenguaje específico (por ejemplo, C, C#, JavaScript, Python, PHP, entre otros).

En general, las prácticas de algoritmia suelen incluir enunciados de ejercicios y sus respectivas soluciones. Durante la clase, el profesor explica de manera extensa, pero los estudiantes a menudo no logran captar todo lo que se dice. Por un lado, los profesores, al ser programadores experimentados, tienden a automatizar el proceso de programación y no se detienen lo suficiente en explicaciones importantes, avanzando rápidamente. Por otro lado, la gran cantidad de detalles que deben considerarse también contribuye a que el estudiante no logre comprender de inmediato la totalidad del proceso.

Una característica particular de los problemas algorítmicos es que la solución, a menudo expresada en pseudocódigo, necesita tanto palabras como estructura. Sin palabras, comentarios o la capacidad de explicar cómo se está resolviendo el problema, no es posible comprender ni razonar sobre la solución. Además, sin una estructura adecuada, sin abstracción o sin la capacidad de comparar diferentes casos para identificar lo común, no es posible adquirir los conceptos necesarios. En programación, no solo se necesita práctica, sino también una sólida comprensión conceptual.

En este trabajo mostramos los enunciados y soluciones a los ejercicios, junto con los pasos intermedios de razonamiento que justifican cada solución (lo que el profesor podría decir, pero con un poco más de detalle).

Dos roles o momentos: programador y usuario

Seguramente has tenido experiencia diseñando diapositivas para una clase. Probablemente invertiste tiempo buscando fotos y creando esquemas para que la información se presentara de manera clara en la pantalla.

Durante el diseño, siempre tenías en cuenta que luego habría un momento de presentación, cuando el público vería la diapositiva. Querías que todo funcionara perfectamente. Es difícil separar estos dos roles: el de diseñador y el de observador.

De manera similar, habrás participado en ensayos de una obra de teatro. Sabes que en los ensayos puedes cometer errores, pero el objetivo es que, cuando llegue la representación final, todo salga bien. Estos dos momentos—la preparación y la puesta en práctica—se parecen a los dos momentos que atraviesa un programador: el de diseñar el código y el de depurarlo actuando como usuario.

El programador es el diseñador del código, mientras que el usuario es quien probará ese código para ver si funciona correctamente. Mientras el programador escribe el código, debe tener presente que los datos que se mostrarán en la pantalla serán vistos por el usuario, y que los datos que este ingrese serán procesados y almacenados en variables preparadas por el programador.

Ser programador implica tener siempre en mente que la razón de ser de una computadora es la comunicación entre el usuario y el sistema. Todo lo que se programa se realiza para que el usuario obtenga los resultados que necesita, cargando datos de entrada que serán procesados por el código.

Entrada y salida de datos: LEER y MOSTRAR

En el capítulo anterior, sobre la capa física, se mencionaron las operaciones de lectura y escritura referidas a las memorias. En informática, la lectura o la escritura se piensan desde el punto de vista de los dispositivos, no desde el ser humano. Se lee y escribe información en los dispositivos: en las memorias, en la pantalla, en un disco. No se trata de que el usuario humano lee o escribe, como suele pensarse erróneamente.

En el caso de los lenguajes de programación, hay dos funciones, también las consideramos palabras reservadas del lenguaje, que se utilizan para capturar datos desde el teclado (cuando una persona los escribe) y para mostrar datos por pantalla (para que una persona los lea). Estas funciones se denominan LEER y ESCRIBIR/MOSTRAR.

Estas funciones forman parte de todos los lenguajes con diferentes expresiones. En este libro utilizaremos LEER y MOSTRAR (en PseInt pueden utilizarse tanto ESCRIBIR como MOSTRAR, son sinónimos).

LEER, en pseudocódigo, significa, detener el funcionamiento del programa en espera a que un usuario ingrese contenido con el teclado. Ese contenido queda depositado en una variable, es decir una posición de memoria con un nombre.

Por ejemplo, supongamos que debemos escribir un programa que le pida al usuario que ingrese dos números y luego le muestra la suma de los números por pantalla. ¿Cómo haría ese programa para comunicarse con el usuario y pedirle eso? Lo único de lo que dispone es una pantalla y un teclado.

En pseudocódigo hay ciertas restricciones. No se hacen lecturas del movimiento del mouse ni se muestran botones para que el usuario haga clic. Tan sólo se pueden mostrar y capturar palabras o números escritos. Por lo tanto, en primer lugar, el programa le debe mostrar un mensaje al usuario, explicándole que es un programa de suma y pidiéndole el primer número. En pseudocódigo podría ser una instrucción como ésta:

MOSTRAR “Hola. Este programa suma dos números. Escriba un número”

Imaginemos la memoria RAM como una cuadrícula en la que cada celda tiene una dirección. En lugar de recordar su dirección numérica, le colocamos un nombre, y con ese nombre podemos volver a localizar la celda. Para crear esa variable en memoria usamos la función DEFINIR.

Por ejemplo, si escribimos en PseInt “DEFINIR num1 como Real”, le estamos pidiendo que reserve una posición en la memoria para la variable num1, que no se puede utilizar ese espacio para otra cosa. Es como si bloqueara esa posición que ahora se denomina num1.

Esa posición no es un bit ni un byte. El número de bytes que contenga dependerá del tipo de datos. El tipo de datos llamado “Real” ocupa más espacio que el tipo de datos “Entero” o “Carácter”. La operación “DEFINIR” asigna el espacio que corresponde a cada variable.

Luego de que están definidas, las variables pueden ser utilizadas en el código.

La memoria RAM es electrónica y es más rápida comparada con la memoria magnética de un disco duro, que tiene partes mecánicas lentas, ya que necesita activar cabezales, entre otras cosas. Por eso esta memoria, aunque es bastante frágil ya que depende del suministro eléctrico, es la que utiliza permanentemente el sistema operativo para ciertas operaciones básicas. Por ejemplo, cuando usamos un procesador de texto, antes de que grabemos el documento en el disco duro de manera definitiva, vamos grabando el contenido temporal en la memoria RAM.

LEER num1 es una operación que deja el teclado suspendido hasta que el operador escribe algo. El usuario verá un cursor titilando en espera.

Una vez que el usuario pulse ENTER, habrá terminado la operación de lectura y en la casilla num1 de la memoria se habrá guardado un número real (ya que esta variable sólo admite números reales).

LEER num2

Guarda un número en la celda num2.

Luego, se deben sumar los números y mostrar la suma al usuario.

suma:= num1 + num2

Es la operación que suma los números y los guarda dentro de la variable suma. Esa operación se denomina asignación.

MOSTRAR suma muestra el contenido de la variable suma por la pantalla.

Es importante que el futuro programador pueda imaginar y graficar estos escenarios y estos espacios, como la memoria y sus variables, lo que aparecerá en pantalla, o lo que se asigna en una operación.

Descubrir secuencias

Las operaciones más potentes que puede realizar un ordenador son secuenciales, como la iteración (repetición) que le permite realizar miles o millones de veces la misma acción sobre datos distintos.

Al ser secuenciales los procesos, todos los conjuntos de datos que aparezcan en el enunciado, y que sean relevantes para el problema, tendrán forma de secuencias (“tiras” de datos, o contenedores con filas y columnas). Habrá datos aislados, variables individuales que se utilizan por única vez o pocas veces, pero los más importantes son los conjuntos de datos que pueden ser vistos como secuencias.

Las secuencias están presentes en diversas actividades y situaciones de la vida cotidiana y en la naturaleza. En un supermercado, los clientes forman una fila para esperar su turno en la caja registradora, en un semáforo, los vehículos se alinean en una secuencia ordenada mientras esperan que la luz cambie, en un aeropuerto, los pasajeros forman una cola para embarcar, en el cine las personas esperan para presentar su entrada. Las gotas de lluvia el mismo proceso: se forman a partir de vapor condensado en la nube, alcanza una masa crítica y cae hacia la Tierra debido a la gravedad. Cada glóbulo rojo sigue el mismo recorrido impulsado por el corazón y viajando por arterias. En una bandada de aves en vuelo cada ave se alinea en la formación, reduce la resistencia del viento y rota posiciones para compartir el esfuerzo.

La automatización de los procesos del mundo es la búsqueda de introducir secuencias en algunos de estos procesos para hacerlos eficientes en alguna medida. Algunos procesos naturales se automatizan en algún aspecto cuando se intenta controlarlos. Por ejemplo, a cada paciente en un hospital se le toma la temperatura, la presión arterial, el pulso y, en algunos casos, la saturación de oxígeno, los valores se registran en su historial clínico. Algunos dispositivos médicos conectados pueden medir automáticamente los signos vitales y enviarlos al sistema del hospital.

Debemos recordar que el ordenador es un procesador eficiente de secuencias. Si un enunciado, en una plantilla de ejercicios de programación, no menciona secuencias ni de manera directa ni indirecta, es probable que se trate de un ejercicio trivial, como aquellos destinados a practicar el ingreso de datos o la muestra de resultados.

Por lo tanto, cuando leas el enunciado de un ejercicio, primero trata de identificar qué estructuras de datos están involucradas. Luego, dibújalas en papel para poder deducir cómo deberían ser las estructuras de proceso que las manipularán. Cuando el profesor escribe un nuevo ejercicio, intenta emular situaciones que podrías encontrar en el mundo real. Los enunciados no especifican exactamente cómo hacer el programa; a veces te presentan la situación desde el punto de vista de un cliente, un problema matemático o un usuario.

Supongamos un enunciado muy simple que sólo pide lo siguiente:

“Mostrar en pantalla 5 números que ingresan por teclado secuencialmente”

A partir de este sencillo enunciado se pueden deducir varias cosas. Habrá un usuario que ingresará los números por teclado, uno a uno, es decir, introduce un número, presiona ENTER, luego introduce otro, y así sucesivamente. Esto implica que hay un programa en la computadora que está en funcionamiento (está “corriendo”) y se encarga de pedirle al usuario los números de forma secuencial. ¿Cómo se los pide? Con uno de los medios de expresión de las computadoras, la pantalla. Para que el usuario entienda lo que debe hacer, el programa debe proporcionar alguna señal, en este caso muestra un mensaje en pantalla que explica al usuario lo que debe hacer.

En este caso, el programa le indicaría al usuario que debe ingresar cinco números y pulsar ENTER después de cada uno.

Todo ese proceso puede requerir varias líneas de código, pero el enunciado no especifica esos detalles al programador. Sólo se le pide que el programa muestre por pantalla los números que ingresa el usuario. Tampoco menciona que los números deben almacenarse para luego mostrarlos todos juntos. Se supone que no deberíamos almacenar nada en la memoria a menos que sea necesario para uso futuro. Por lo tanto, aunque parezca algo sin sentido, este simple programa sólo debe “recibir” el número que escribe el usuario, guardarlo temporalmente en algún lugar para que no se pierda, sólo unos segundos, y luego mostrar en la pantalla el mismo número.

Una vez que el número fue mostrado, el lugar de memoria puede quedar libre para guardar el número siguiente.

Cuando el usuario escribe un número en el teclado, ese número se envía a la memoria RAM y se almacena temporalmente en una variable, que en este caso llamamos num. Además, al escribir algo en el teclado, se produce por defecto una operación: lo que se escribe se muestra en la pantalla.

Sin embargo, el enunciado del programa solicita mostrar nuevamente el número por pantalla, lo que provocará que aparezca dos veces: una como resultado de la acción automática de mostrar lo que se escribe, y otra al ejecutar el comando de mostrar el número.

Para que el número se vea nuevamente en pantalla, es necesario utilizar una instrucción específica, como MOSTRAR (num), que es la encargada de imprimir el valor de la variable num en la pantalla.

Si el enunciado indicara “Ingresar cinco números por teclado y luego mostrarlos todos juntos”, la repetición no se aplicaría a leer la misma variable, porque surge una nueva restricción: si usamos la misma variable para leer los cinco números, cada número ingresado sobrescribiría el contenido del anterior. Por lo tanto, necesitaríamos cinco variables diferentes. La solución sería la siguiente:

Estas cinco lecturas de diferentes variables son una estrategia válida para leer cinco números. Sin embargo, ¿qué ocurriría si fueran quinientos o más? En esos casos, tendríamos que utilizar una estructura de control denominada iteración, también conocida como repetición, ciclo o bucle.

En la solución inicial de este ejercicio, se utiliza una repetición que le indica al procesador que realice cinco veces la misma operación: LEER un número y MOSTRAR ese número.

En ejercicios simples, es probable que la secuencia de datos sea solo una. Por ejemplo, una lista de números como en el enunciado anterior, o una lista de palabras a las cuales se les aplica una determinada operación. Sin embargo, en problemas que implican la organización de grandes cantidades de información, las secuencias de datos suelen estar ocultas entre otras secuencias o estructuras más complejas.

Por ejemplo, en una secuencia de nombres se pueden identificar, a su vez, una secuencia de letras dentro de cada nombre. Una secuencia de números que ingresan al ordenador puede representarse como una tira (izquierda), si esos números se guardan en memoria y tienen un orden, puede indicarse con un subíndice (derecha). Estos son simplemente representaciones gráficas de los datos que facilitan poder pensar en ellos.

Por fortuna, las estructuras de control que debemos utilizar en el programa sirven precisamente para procesar secuencias de datos. Es decir que, una vez identificada la secuencia de datos, se hace más fácil identificar el bloque de procesamiento adecuado. Por eso es aconsejable dibujar en primer lugar las estructuras de datos.

Existen estructuras de control para procesar repeticiones de acciones, y también para la selección de alternativas.

Para dar un marco más claro a las estructuras, especialmente cuando hay anidamiento (es decir, una estructura dentro de otra), en esta etapa de tu aprendizaje hemos utilizado diagramas que conocidos como NSD o Chapin. Te sugerimos que los pruebes, pero son opcionales. Es sólo un marco alrededor del pseudocódigo, las instrucciones no varían al agregar diagramas.

La estructura de iteración PARA permite aplicar el mismo tratamiento (acción o acciones) a cada elemento de una secuencia. La iteración MIENTRAS ejecuta la acción mientras se cumpla una condición; si la condición no se cumple al inicio, no habrá ningún ciclo de procesamiento.

Por otro lado, la estructura REPETIR MIENTRAS repite la acción mientras no se cumpla la condición de fin; en este caso, siempre habrá al menos un ciclo de procesamiento, ya que la condición se verifica después de cada iteración.

El enfoque de esta guía de ejercicios pretende ayudarte a realizar el análisis de los enunciados. Una vez que un programa está terminado, es recomendable que el programador incluya comentarios junto a las instrucciones para que otros programadores puedan comprender lo que se hizo.

Sin embargo, antes de llegar a ese punto, durante la construcción del programa en borrador, también es muy importante que el programador explique lo que significan las instrucciones para seguir la lógica del proceso.

Este análisis de los enunciados es lo que hemos incluido junto a las instrucciones de los problemas resueltos a continuación, y te invitamos a hacer lo mismo con los problemas que debas resolver en las prácticas que te han entregado en la Universidad.

Una salvedad que hacemos en este apunte es que no hemos declarado variables al principio de todos los programas en las secciones. Damos por sentado que esta acción ya ha sido realizada y que las variables han sido creadas. Lo que sí hemos hecho es la inicialización de las variables, es decir, asignarles valores iniciales adecuados para su tratamiento posterior.

Comentarios en programación: haciendo el código claro y comprensible

Cuando escribimos programas, no solo estamos dando instrucciones a la computadora, sino también comunicándonos con otros programadores (o con nuestro “yo” del futuro). Para facilitar esta comunicación, los programadores utilizan comentarios, que son notas escritas dentro del código que no afectan su ejecución, pero explican su funcionamiento. Estas notas escritas suelen ser subestimadas por la mayoría de los programadores, pero tienen una función esencial no sólo en la comunicación sino en la comprensión del código por parte de los estudiantes.

Cuanto más escriban al lado del código para explicar lo que este código realiza, más comprenderás el código y mayor nitidez alcanzará tu razonamiento. Cuando te esfuerzas por explicar el código, es probable que incluso debas modificarlo por haber al descubrir nuevos aspecto o errores.

¿Por qué son importantes los comentarios?

  • Facilitan el entendimiento: Ayudan a otros a comprender qué hace cada parte del programa.
  • Ahorro de tiempo: Revisar un código bien comentado es mucho más rápido.
  • Mantenimiento y actualización: Los comentarios facilitan corregir errores y agregar nuevas funciones.
  • Trabajo en equipo: Los proyectos de software suelen involucrar a múltiples programadores. Los comentarios aseguran que todos entiendan el propósito del código.

¿Qué puedo explicar en un comentario?

  • Qué hace una función o un bloque de código.
  • El propósito de una variable o constante.
  • Explicaciones de decisiones complejas o inusuales.
  • Aspectos técnicos que puedan no ser evidentes.

No hay límites para lo que puedes explicar en los comentarios. Incluso anotaciones simples como “Revisar esta parte más tarde” pueden ser útiles. El verdadero límite suele ser la falta de voluntad, ya que no siempre se percibe claramente la importancia de escribir comentarios.

A menudo se considera que los comentarios son innecesarios porque no afectan directamente el funcionamiento del programa en el ordenador. Sin embargo, su valor radica en que activan procesos en ti. La escritura explicativa no solo documenta el código agregando comentarios y utilizando nombres representativos de variables y funciones, sino que también produce modificaciones en el programador o razonador, ayudándole a reflexionar y mejorar su comprensión.

Ejemplo de un programa con escritura no explicativa

def c(x, y):

return x ** 2 + y ** 2

a = 3

b = 4

r = c(a, b)

print(r)

A primera vista, es difícil entender lo que hace este programa. ¿Qué significa “c”? ¿Qué está calculando? Sin contexto, es confuso.

Ejemplo de un programa con escritura explicativa

# Calcula la suma de los cuadrados de dos números

def suma_de_cuadrados(x, y):

# Eleva x e y al cuadrado y devuelve su suma

return x ** 2 + y ** 2

# Asignamos valores a las variables

a = 3 # Primer número

b = 4 # Segundo número

# Calculamos la suma de los cuadrados y mostramos el resultado

resultado = suma_de_cuadrados(a, b)

print(resultado) # Imprime 25

En este segundo ejemplo, los comentarios explican claramente cada parte del programa, lo que hace que sea fácil de leer y entender.

Te invitamos a utilizar la escritura explicativa en tus programas, añadiendo comentarios, haciendo acotaciones al margen de los algoritmos y enunciados, y utilizando variables y nombres de funciones representativos del contenido.

A continuación, te presentamos una serie de ejercicios resueltos como modelo de lo que deberías hacer para comprender los programas. En ellos, primero analizamos los enunciados, dividiéndolos en partes, y luego escribimos comentarios al costado, los cuales podrían incorporarse directamente al código cuando utilices un lenguaje de programación específico.

En la sección siguiente, te invitamos a realizar análisis similares de los programas.

Te sugerimos que frenes el impulso de ver el programa en funcionamiento y generando resultados de inmediato. Evita caer en el ciclo repetitivo de programar, depurar y corregir, que puede llevarte a perder el sentido de esta etapa: comprender la lógica de los procesos.

Es recomendable que no estés siempre frente a la computadora; en su lugar, utiliza papel y herramientas gráficas que desaceleren ese proceso cíclico (programar, depurar, corregir pequeños bloques por el simple placer de ver el resultado). Este ciclo puede llevarte a copiar programas solo para que funcionen, delegando el esfuerzo de explicar y razonarlos, lo cual limita el desarrollo de tu capacidad de razonamiento y experiencia.



Deja un comentario