Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Fundamentos de Computación y Algoritmos

Conceptos básicos antes de programar en C

Universidad Nacional de Río Negro

Introducción

Antes de escribir tu primera línea de código en C, es fundamental repasar (y comprender) algunos conceptos básicos sobre cómo funcionan las computadoras y cómo comunicarnos con ellas de manera efectiva. En este apunte, sentaremos las bases algorítmicas de forma independiente de cualquier lenguaje, utilizando un pseudocódigo estructurado similar a C en español. Esto te permitirá concentrarte en el pensamiento lógico antes de abordar la sintaxis formal de C.


Desarrollo

¿Qué es una computadora?

Una computadora es una máquina electrónica diseñada para procesar información de manera automática, siguiendo instrucciones precisas y explícitas. A diferencia de los seres humanos, una computadora:

Componentes básicos

Para entender cómo programar, es útil conocer los componentes físicos de una computadora y cómo interactúan entre sí.

Hardware

El hardware son los componentes físicos de la computadora:

Componentes de una computadora

Arquitectura básica de una computadora: el CPU coordina el flujo de datos entre la memoria RAM (rápida y volátil), el almacenamiento permanente (lento pero persistente), y los dispositivos de entrada/salida.

Software

El software son los programas e instrucciones de control:

Capas de software

Las aplicaciones utilizan los servicios del sistema operativo, que a su vez controla y gestiona el hardware.

¿Qué es programar?

Programar es el proceso de estructurar instrucciones detalladas para que una computadora realice una tarea específica.

Cuando programamos, debemos considerar:

  1. ¿Qué problema queremos resolver? - Entender el objetivo.

  2. ¿Qué datos necesitamos? - Identificar las entradas de información y las salidas resultantes.

  3. ¿Qué pasos seguir? - Diseñar el algoritmo.

  4. ¿Cómo traducirlo a código? - Escribir en un lenguaje de programación.

  5. ¿Funciona correctamente? - Probar y depurar.

Especificación Formal: Máquina de Transición de Estados

En lugar de analogías informales, en ciencias de la computación modelamos los algoritmos como un sistema formal que transforma un conjunto de entradas (II) en un conjunto de salidas (OO) a través de una secuencia finita de transiciones de estado (SS).

Consideremos el algoritmo de control de un sistema de autenticación de sensor industrial. El algoritmo debe procesar una señal física (una secuencia de caracteres ASCII que ingresa de a un byte por vez) y determinar si se ha recibido la clave de activación exacta ON.

A continuación se detalla la tabla de transición que define formalmente el comportamiento unívoco de este algoritmo:

Table 1:Tabla de Transición de Estados del Algoritmo

Estado Actual (SS)Evento / Entrada (iki_k)Siguiente Estado (SS')Salida Emitida (oko_k)
S0S_0 (Reposo)'O'S1S_1 (Coincidencia parcial)BLOQUEADO
S0S_0 (Reposo)Cualquier otro carácterS0S_0 (Reposo)BLOQUEADO
S1S_1 (Parcial)'N'S2S_2 (Activado)ACTIVO
S1S_1 (Parcial)'O'S1S_1 (Coincidencia parcial)BLOQUEADO
S1S_1 (Parcial)Cualquier otro carácterS0S_0 (Reposo)BLOQUEADO
S2S_2 (Activado)Cualquier carácterS0S_0 (Reposo)BLOQUEADO

Este modelo formal demuestra que un algoritmo no es una receta subjetiva, sino una definición determinista de comportamiento donde cada combinación de estado interno y datos de entrada produce una transición y una salida perfectamente predecibles.

La computadora necesita instrucciones de este segundo tipo: específicas, ordenadas, sin ambigüedades y detalladas al extremo.

¿Qué es un algoritmo?

Un algoritmo es una secuencia finita, ordenada y no ambigua de pasos bien definidos que resuelve un problema o realiza una tarea específica. Los algoritmos son la base fundamental de la programación y el diseño de sistemas.

Del problema a la solución

El algoritmo es el puente conceptual que transforma un problema de entrada en su solución.

Características de un buen algoritmo

Un algoritmo efectivo debe cumplir con los siguientes vectores de diseño:

  1. Finito: Debe finalizar en algún momento, después de un número determinado de pasos ejecutados.

  1. Bien definido: Cada paso debe ser unívoco, claro y libre de toda ambigüedad en su interpretación.

  1. Con entrada (opcional): Puede recibir cero o más datos iniciales del entorno para procesar.

  1. Con salida: Debe retornar o producir al menos un resultado o cambio de estado visible.

  1. Efectivo: Cada paso debe ser realizable y computable en un tiempo finito utilizando recursos de memoria finitos.

  1. Determinista: Dado el mismo conjunto de datos de entrada, debe producir siempre exactamente el mismo resultado de salida.

Representación de Algoritmos y Diagramas de Flujo

Los diagramas de flujo son representaciones gráficas estandarizadas de algoritmos. Permiten visualizar la lógica de control, bifurcaciones e iteraciones antes de escribir código.

Símbolos estándar de diagramas de flujo

Símbolos estándar de diagramas de flujo

Símbolos universales utilizados en diagramas de flujo para representar diferentes procesos de un algoritmo.

Ejemplos de Algoritmos en Pseudocódigo y Diagramas de Flujo

Ejemplo 1: Algoritmo para hacer café

Homogeneizando la estructura cotidiana mediante ramificaciones secuenciales condicionales:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
=================================================
 Algoritmo: Hacer café
=================================================
 Entrada: ninguna
 Salida: taza de café servida
-------------------------------------------------
 Pasos:
 1. Inicio
 2. Verificar depósito de agua
 3. Si (depósito de agua está vacío) entonces:
        a. Llenar depósito con agua
    Sino:
        b. No hacer nada
 4. Verificar portafiltro
 5. Si (filtro está sucio o ausente) entonces:
        a. Limpiar portafiltro y colocar filtro nuevo
    Sino:
        b. No hacer nada
 6. Agregar 2 cucharadas de café molido al filtro
 7. Encender cafetera
 8. Esperar a que finalice el filtrado de agua
 9. Servir café en una taza limpia
 10. Fin
=================================================

Ejemplo 2: Verificar si N es par

Este algoritmo calcula si un número entero es par utilizando el operador módulo % (resto de la división entera):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
=================================================
 Algoritmo: Verificar si N es par
=================================================
 Entrada: número entero N
 Salida: mensaje por pantalla "par" o "impar"
-------------------------------------------------
 Pasos:
 1. Inicio
 2. Leer N
 3. entero resto = N % 2
 4. Si (resto == 0) entonces:
        a. Escribir "El número es par"
    Sino:
        b. Escribir "El número es impar"
 5. Fin
=================================================

Representación de datos y memoria

Las computadoras operan sobre datos almacenados en memoria física. Para procesar esta información, es necesario asignarle un tipo de dato que defina su rango y operaciones válidas.

Tipos de información fundamentales

Tipos de datos fundamentales

Los cuatro tipos de datos fundamentales: enteros, reales, cadenas de caracteres y valores lógicos.

  1. Enteros (entero / int): Números sin parte fraccionaria (ej. 5, -20, 0). Se utilizan para conteos, índices de lazos y posiciones.

  2. Decimales / Punto Flotante (float / double): Representan aproximaciones numéricas finitas de números racionales bajo el estándar internacional IEEE 754.

  3. Carácter (char): Representa un único símbolo físico (letra, dígito, signo de puntuación) que ocupa exactamente 1 byte de memoria RAM.

  4. Lógicos / Booleanos (logico / bool): Solo admiten dos estados lógicos: verdadero (true) o falso (false).

Variables: Direcciones físicas de memoria

Una variable es un espacio reservado en la memoria física RAM de la computadora para almacenar un dato que puede cambiar durante la ejecución del programa.

Visualmente, una variable vincula una etiqueta lógica con una dirección física en el hardware:

1
2
3
4
5
6
7
+------------------------------------------+
| Dirección Física (ej. 0x7ffd8)            | <- Celda en la memoria RAM
+------------------------------------------+
|  nombre: edad                            | <- Identificador de la variable
|  tipo: entero                            | <- Tipo de dato asignado
|  valor: 25                               | <- Dato de almacenamiento actual
+------------------------------------------+

Cada variable posee:

  1. Dirección física de memoria: La dirección hexadecimal real en el hardware RAM donde se ubica el dato.

  2. Nombre (identificador): La etiqueta lógica que usa el programador en el código (ej. edad, temperatura).

  3. Tipo de dato: Define el tamaño en bytes reservado y cómo el hardware interpretará los bits guardados.

  4. Valor: El contenido binario actual de la celda de memoria.

El ciclo de vida de una variable en memoria

Ciclo de vida de una variable

Una variable se declara e inicializa en memoria, es leída o modificada durante la ejecución, y finalmente se libera de la memoria física.

Estructuras lógicas y operaciones básicas

Operaciones aritméticas

A nivel de hardware, se ejecutan operaciones aritméticas sobre celdas numéricas:

Operaciones aritméticas

Operaciones aritméticas básicas y especiales, con precedencia de evaluación.

Operaciones lógicas y tablas de verdad

Las operaciones lógicas combinan valores booleanos para evaluar condiciones complejas:

Operaciones lógicas

Las tres operaciones lógicas fundamentales (Y, O, NO) con sus tablas de verdad.

Las Tres Estructuras Fundamentales del Pensamiento Lógico

Todo algoritmo de control estructurado puede resolverse utilizando únicamente tres estructuras lógicas:

Tres estructuras fundamentales de control

Las tres estructuras fundamentales del pensamiento algorítmico: secuencia, decisión y repetición.

1. Secuencia

Ejecución lineal de instrucciones en orden cronológico estricto de arriba hacia abajo. El cambio del orden de los factores altera el resultado lógico o provoca fallas en tiempo de ejecución.

2. Decisiones (Condicionales)

Bifurcación del flujo lógico en base al resultado de una condición booleana (Si... Sino).

3. Repetición (Lazos)

Estructuras de iteración de código. Se clasifican didácticamente en:

Ejemplos de Programas Traducidos a Pseudocódigo Estricto (Estilo C)

A continuación se presentan los ejemplos lógicos resueltos en pseudocódigo estricto con sintaxis cercana a C en español, eliminando dependencias de lenguajes interpretados dinámicos.

Ejemplo 1: Calculadora simple

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// Algoritmo: Calculadora Simple
// Entrada: dos números reales y un carácter de operación
// Salida: el resultado de la operación matemática por pantalla

real numero1;
real numero2;
real resultado;
caracter operacion;

Escribir("=== CALCULADORA SIMPLE ===");
Escribir("Ingrese el primer número: ");
Leer(numero1);
Escribir("Ingrese el segundo número: ");
Leer(numero2);
Escribir("Ingrese la operación (+, -, *, /): ");
Leer(operacion);

Si (operacion == '+')
{
    resultado = numero1 + numero2;
    Escribir("Resultado: ", resultado);
}
Sino Si (operacion == '-')
{
    resultado = numero1 - numero2;
    Escribir("Resultado: ", resultado);
}
Sino Si (operacion == '*')
{
    resultado = numero1 * numero2;
    Escribir("Resultado: ", resultado);
}
Sino Si (operacion == '/')
{
    Si (numero2 != 0.0)
    {
        resultado = numero1 / numero2;
        Escribir("Resultado: ", resultado);
    }
    Sino
    {
        Escribir("Error: No se puede dividir por cero.");
    }
}
Sino
{
    Escribir("Error: Operación no válida.");
}

Ejemplo 2: Tabla de multiplicar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Algoritmo: Tabla de Multiplicar
// Entrada: un número entero
// Salida: la tabla de multiplicar de N del 1 al 10

entero numero;
entero contador;
entero resultado;

Escribir("=== TABLA DE MULTIPLICAR ===");
Escribir("Ingrese un número: ");
Leer(numero);

Escribir("Tabla del ", numero, ":");
Escribir("-----------------");

// Lazo controlado por contador (Para) de 1 a 10
Para (contador = 1; contador <= 10; contador = contador + 1)
{
    resultado = numero * contador;
    Escribir(numero, " x ", contador, " = ", resultado);
}

Ejemplo 3: Adivinar número

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// Algoritmo: Adivinar Número
// Entrada: intento numérico del usuario
// Salida: mensajes guía (mayor/menor) e indicación de éxito o derrota

entero numero_secreto = 42; // Simulado para propósitos de prueba
entero intentos_maximos = 5;
entero intentos_realizados = 0;
entero intento;
logico adivinado = false;

Escribir("=== ADIVINA EL NÚMERO ===");
Escribir("Tenés 5 intentos para adivinar un número entre 1 y 100");

Mientras (intentos_realizados < intentos_maximos y adivinado == false)
{
    intentos_realizados = intentos_realizados + 1;
    Escribir("Intento ", intentos_realizados, " de ", intentos_maximos, ":");
    Leer(intento);

    Si (intento == numero_secreto)
    {
        adivinado = true;
        Escribir("¡Adivinaste el número!");
    }
    Sino Si (intento < numero_secreto)
    {
        Escribir("El número secreto es MAYOR");
    }
    Sino
    {
        Escribir("El número secreto es MENOR");
    }
}

Si (adivinado == false)
{
    Escribir("Game Over. El número secreto era: ", numero_secreto);
}

Ejercicios de Autoevaluación

Ejercicio 1: Instrucciones precisas

Solution to Exercise 1

Hacer un sándwich de jamón y queso:

  1. Retirar 2 rebanadas de pan del paquete.

  2. Colocar ambas rebanadas horizontalmente sobre un plato limpio.

  3. Retirar una rebanada de jamón del paquete correspondiente.

  4. Colocar la rebanada de jamón cubriendo la primera rebanada de pan.

  5. Retirar una rebanada de queso del paquete.

  6. Colocar la rebanada de queso sobre el jamón.

  7. Tomar la segunda rebanada de pan.

  8. Colocarla sobre el queso, tapando el sándwich.

  9. Presionar suavemente hacia abajo para asentar el sándwich.

Calcular el promedio de tres números:

  1. Obtener el primer número (llamémoslo A).

  2. Obtener el segundo número (llamémoslo B).

  3. Obtener el tercer número (llamémoslo C).

  4. Sumar los tres valores: suma = A + B + C.

  5. Dividir el resultado de la suma por 3: promedio = suma / 3.

  6. Mostrar el valor del promedio obtenido.

Ejercicio 2: Tipos de variables

Solution to Exercise 2
  1. entero: Se cuentan individuos discretos.

  2. real: Requiere representar centavos fraccionarios.

  3. cadena: Secuencia de caracteres alfabéticos.

  4. logico: Estado binario (verdadero/falso).

  5. real: Contiene parte fraccionaria (ej: 8.5).

Ejercicio 3: Aplicación Algorítmica

Solution to Exercise 3

A. Conversión de temperatura:

1
2
3
4
5
6
7
8
real celsius;
real fahrenheit;

Escribir("Ingrese temperatura en Celsius: ");
Leer(celsius);

fahrenheit = celsius * 9.0 / 5.0 + 32.0;
Escribir("Equivalente en Fahrenheit: ", fahrenheit);

B. Verificar triángulo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
real lado1;
real lado2;
real lado3;

Escribir("Ingrese lado 1: ");
Leer(lado1);
Escribir("Ingrese lado 2: ");
Leer(lado2);
Escribir("Ingrese lado 3: ");
Leer(lado3);

Si (lado1 + lado2 > lado3 y lado1 + lado3 > lado2 y lado2 + lado3 > lado1)
{
    Escribir("Los lados pueden formar un triángulo.");
}
Sino
{
    Escribir("Los lados NO pueden formar un triángulo.");
}

C. MCD (Algoritmo de Euclides):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
entero a;
entero b;
entero temporal;

Escribir("Ingrese el primer número: ");
Leer(a);
Escribir("Ingrese el segundo número: ");
Leer(b);

Mientras (b != 0)
{
    temporal = b;
    b = a % b;
    a = temporal;
}

Escribir("El MCD es: ", a);

D. Palíndromo (lazo de comparación de extremos):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
cadena palabra;
entero longitud;
entero inicio = 0;
entero fin;
logico coincide = true;

Escribir("Ingrese la palabra: ");
Leer(palabra);
Escribir("Ingrese la longitud de la palabra: ");
Leer(longitud);

fin = longitud - 1;

Mientras (inicio < fin y coincide == true)
{
    Si (palabra[inicio] != palabra[fin])
    {
        coincide = false;
    }
    inicio = inicio + 1;
    fin = fin - 1;
}

Si (coincide == true)
{
    Escribir("La palabra es un palíndromo.");
}
Sino
{
    Escribir("La palabra NO es un palíndromo.");
}

Ejercicio 4: Integradores

References
  1. Cormen, T. H., Leiserson, C. E., Rivest, R. L., & Stein, C. (2009). Introduction to Algorithms (3rd ed.). MIT Press.
  2. Sedgewick, R., & Wayne, K. (2011). Algorithms (4th ed.). Addison-Wesley. https://algs4.cs.princeton.edu/
  3. Wing, J. M. (2006). Computational Thinking. Communications of the ACM, 49(3), 33–35. 10.1145/1118178.1118215
  4. Aho, A. V., & Ullman, J. D. (1995). Foundations of Computer Science. W. H. Freeman. http://infolab.stanford.edu/~ullman/focs.html
  5. Polya, G. (2014). How to Solve It: A New Aspect of Mathematical Method. Princeton University Press.
  6. Bentley, J. (1999). Programming Pearls (2nd ed.). Addison-Wesley.