quiz Programación · 10 preguntas

Fundamentos de la Programación Estructurada

help_outline 10 preguntas
timer ~5 min
auto_awesome Generado por IA
0 / 10
Puntuación : 0%
1

Según el teorema de Böhm‑Jacopini, ¿cuáles son las tres estructuras de control necesarias para expresar cualquier algoritmo computable?

2

En un programa estructurado, ¿qué ventaja principal aporta la modularidad al dividir el código en funciones o métodos?

3

¿Cuál de los siguientes enunciados describe mejor la diferencia entre los paradigmas imperativo y declarativo?

4

En C#, ¿cuál es la diferencia semántica entre los bucles 'while' y 'do‑while'?

5

Un estudiante afirma que usar una estructura 'switch' en C# es siempre preferible a una cadena de 'if‑else' porque reduce la complejidad ciclomática. ¿Qué error conceptual contiene esta afirmación?

6

En el contexto histórico de la crisis del software, ¿qué papel jugó la carta de Dijkstra de 1968?

7

Si un algoritmo necesita procesar una colección de datos de tamaño desconocido hasta que se encuentre un elemento que cumpla una condición, ¿qué estructura de iteración es la más adecuada en C#?

8

¿Cuál es la afirmación correcta respecto al uso de la programación estructurada dentro de un método de una clase orientada a objetos en C#?

9

En la práctica, ¿por qué la programación estructurada sigue siendo relevante pese al predominio de la programación orientada a objetos?

10

Una función en C# recibe dos enteros y devuelve su mayor valor sin usar la instrucción 'if'. ¿Qué característica del paradigma declarativo se está aplicando?

menu_book

Fundamentos de la Programación Estructurada

Repasa los conceptos clave antes del quiz

Introducción a la programación estructurada

La programación estructurada es un paradigma que, desde la década de 1970, ha transformado la forma en que diseñamos y mantenemos software. Su objetivo principal es reducir la complejidad mediante el uso de tres estructuras de control básicas, la modularidad y la claridad en la lógica del programa. En este curso exploraremos los conceptos clave que aparecen en el cuestionario, proporcionando ejemplos en C#, analogías didácticas y buenas prácticas para que puedas aplicar estos principios en tus proyectos.

El teorema de Böhm‑Jacopini y sus tres estructuras de control

Según el teorema de Böhm‑Jacopini, cualquier algoritmo computable puede expresarse usando únicamente:

  • Secuencia: ejecución lineal de instrucciones una tras otra.
  • Selección (también llamada decisión): estructuras if‑else o switch que eligen entre caminos alternativos.
  • Iteración: bucles como while, do‑while o for que repiten un bloque de código.

Estas tres construcciones son suficientes para describir cualquier proceso lógico, siempre que se evite el uso indiscriminado del salto goto. La ausencia de goto favorece la legibilidad y facilita el análisis estático del código.

Modularidad: dividir el código en funciones o métodos

Una de las ventajas más importantes de la modularidad es facilitar el mantenimiento. Al encapsular la lógica en funciones pequeñas y bien nombradas, los desarrolladores pueden localizar y corregir errores sin tener que revisar todo el programa.

Beneficios concretos

  • Reutilización de código: una función bien diseñada puede ser llamada desde varios lugares.
  • Pruebas unitarias más simples: cada módulo se puede probar de forma aislada.
  • Mejor legibilidad: el flujo principal del programa se vuelve más claro al delegar tareas a sub‑rutinas.

En C# la modularidad se logra mediante métodos dentro de clases, pero el principio sigue siendo el mismo: separar responsabilidades.

public int Sumar(int a, int b)
{
    return a + b; // función simple y reutilizable
}

public void ProcesarDatos()
{
    int total = Sumar(5, 7);
    Console.WriteLine($"Resultado: {total}");
}

Imperativo vs. declarativo: ¿cómo describimos la solución?

El paradigma imperativo indica cómo lograr un resultado, describiendo paso a paso la secuencia de operaciones. En cambio, el paradigma declarativo especifica qué se desea obtener, dejando que el motor del lenguaje descubra el proceso.

Ejemplo culinario

Imagínate una receta de pastel. En un enfoque imperativo se escribiría:

// Imperativo
Mezclar harina, azúcar y huevos;
Batir la mezcla 5 minutos;
Hornear a 180°C durante 30 minutos;

Mientras que en un enfoque declarativo simplemente se diría:

// Declarativo
Obtener pastel de chocolate;

El motor de la cocina (el horno, la batidora) se encarga de los detalles. En programación, lenguajes como SQL o LINQ son ejemplos declarativos, mientras que C#, Java o Python son típicamente imperativos.

Diferencia semántica entre while y do‑while en C#

Ambos bucles repiten un bloque de código mientras una condición sea verdadera, pero la evaluación de la condición ocurre en momentos diferentes:

  • while: la condición se evalúa antes de ejecutar el cuerpo. Si la condición es falsa desde el inicio, el cuerpo nunca se ejecuta.
  • do‑while: el cuerpo se ejecuta al menos una vez y luego se evalúa la condición.

Ejemplo práctico:

// while: puede no ejecutarse
int i = 0;
while (i > 0)
{
    Console.WriteLine(i);
    i--;
}

// do‑while: siempre se ejecuta una vez
int j = 0;
do
{
    Console.WriteLine(j);
    j--;
} while (j > 0);

Switch vs. if‑else: complejidad ciclomática

Una afirmación frecuente es que switch siempre reduce la complejidad ciclomática. Esto es un error conceptual porque la métrica de complejidad ciclomática cuenta el número de caminos de ejecución independientes, sin importar la sentencia utilizada.

Por qué el tipo de sentencia no altera la métrica

Si un switch tiene cinco casos, la complejidad será 6 (una rama por caso más la salida). Un conjunto de if‑else con cinco condiciones también genera 6 caminos. Lo que sí influye es el número de ramas, no si se usan switch o if‑else.

Un truco visual: imagine cada caso como una puerta. Tanto con una llave (if) como con un panel de selección (switch), el número de puertas que debes abrir sigue siendo el mismo.

// Ejemplo con switch
switch (opcion)
{
    case 1: /* ... */ break;
    case 2: /* ... */ break;
    case 3: /* ... */ break;
    default: /* ... */ break;
}

// Equivalente con if‑else
if (opcion == 1) { /* ... */ }
else if (opcion == 2) { /* ... */ }
else if (opcion == 3) { /* ... */ }
else { /* ... */ }

La carta de Dijkstra de 1968 y la crisis del software

En 1968, Edsger W. Dijkstra publicó la influyente carta “Go To Statement Considered Harmful”. En ella argumentó contra el uso indiscriminado del goto, señalando que los saltos arbitrarios dificultan la comprensión y el razonamiento formal del código.

La carta impulsó la adopción de estructuras de control bien definidas (secuencia, selección, iteración) y sentó las bases de la programación estructurada. Fue un hito clave en la llamada crisis del software, que describía la creciente incapacidad de los equipos para producir sistemas fiables y mantenibles.

Elección de la estructura de iteración adecuada para colecciones de tamaño desconocido

Cuando el número de elementos a procesar no se conoce de antemano y la búsqueda termina al encontrar un elemento que cumple una condición, el bucle más natural es while con una condición basada en la búsqueda.

// Búsqueda de un número primo en una lista indefinida
int numero;
Console.WriteLine("Introduce números (0 para terminar):");
while ((numero = int.Parse(Console.ReadLine())) != 0)
{
    if (EsPrimo(numero))
    {
        Console.WriteLine($"{numero} es primo");
        break; // sale al encontrar el primer primo
    }
}

Un for con contador fijo no sirve porque el límite no está definido, y un do‑while obligaría a ejecutar el cuerpo al menos una vez, lo que puede no ser deseado.

Programación estructurada dentro de métodos de clases orientadas a objetos

En C# la programación orientada a objetos (POO) y la estructurada no son excluyentes. Un método de una clase sigue aplicando las mismas tres estructuras de control (secuencia, selección, iteración) aunque esté encapsulado dentro de un objeto.

Ejemplo de método estructurado en una clase

public class Calculadora
{
    public int Factorial(int n)
    {
        // Secuencia: declaración de variables
        int resultado = 1;
        // Iteración: bucle while
        while (n > 1)
        {
            resultado *= n; // Selección implícita dentro del bucle
            n--;
        }
        return resultado; // Secuencia final
    }
}

El hecho de que el método pertenezca a una clase no elimina la modularidad ni la necesidad de estructuras de control; simplemente añade encapsulación y reutilización a nivel de objeto.

Conclusión y próximos pasos

Dominar los fundamentos de la programación estructurada es esencial para escribir código claro, mantenible y fácil de probar. Recuerda:

  • Usar siempre secuencia, selección e iteración como bloques básicos.
  • Aprovechar la modularidad para aislar funcionalidades.
  • Distinguir entre enfoques imperativos y declarativos según el problema.
  • Elegir el bucle adecuado (while vs do‑while) según la necesidad de una ejecución previa.
  • Entender que la complejidad ciclomática depende del número de ramas, no del tipo de sentencia.
  • Valorar la influencia histórica de Dijkstra y su llamado a evitar goto.
  • Aplicar estructuras de iteración apropiadas a colecciones de tamaño desconocido.
  • Integrar la programación estructurada dentro de la POO sin perder sus principios.

Practica cada concepto con pequeños ejercicios en C#. Con la práctica constante, estos principios pasarán de ser teoría a convertirse en hábitos de desarrollo que mejorarán la calidad de tus proyectos.

Deja de subrayar.
Empieza a aprender.

Únete a los estudiantes que ya han generado más de 50.000 quizzes en Quizly. Es gratis para empezar.