Hasta ahora hemos trabajado con variables que almacenan un único dato: un título, un número de páginas, un booleano. Pero en la práctica, casi cualquier programa necesita manejar varios datos del mismo tipo a la vez —por ejemplo, todos los títulos de libros de BiblioTech— y necesita también manipular texto de forma más avanzada que un simple Console.WriteLine. En esta lección aprenderás a trabajar con arrays (una y varias dimensiones), a recorrerlos con foreach/for, y a explotar toda la potencia de la clase string: concatenación, interpolación, y sus métodos más habituales. Cerraremos con StringBuilder, la herramienta adecuada cuando se concatena texto de forma repetida dentro de un bucle.

Contenido

  1. Arrays de una dimensión
  2. Arrays de varias dimensiones
  3. Arrays de tamaño fijo frente a List<T>
  4. Recorrer un array con foreach y con for
  5. La clase string: inmutabilidad, concatenación e interpolación
  6. Métodos habituales de string
  7. StringBuilder para concatenación eficiente

Arrays de una dimensión

Un array es una colección de elementos del mismo tipo, almacenados de forma contigua y accesibles mediante un índice numérico que empieza en 0. Se declara indicando el tipo de los elementos seguido de corchetes []:

string[] titulosLibros = new string[3];
titulosLibros[0] = "Cien anos de soledad";
titulosLibros[1] = "Rayuela";
titulosLibros[2] = "Ficciones";

Console.WriteLine(titulosLibros[0]); // Cien anos de soledad

También se puede declarar e inicializar en un solo paso, indicando directamente los valores:

string[] titulosLibros = { "Cien anos de soledad", "Rayuela", "Ficciones" };

// Forma equivalente, más explícita:
string[] titulosLibrosB = new string[] { "Cien anos de soledad", "Rayuela", "Ficciones" };

Tamaño fijo y propiedad Length

Una característica fundamental de los arrays en C# es que su tamaño se fija al crearlos y no puede cambiar después. Para saber cuántos elementos contiene, se usa la propiedad Length:

string[] titulosLibros = { "Cien anos de soledad", "Rayuela", "Ficciones" };
Console.WriteLine(titulosLibros.Length); // 3

Acceso fuera de rango

Intentar acceder a un índice que no existe (por ejemplo, titulosLibros[5] en un array de 3 elementos) no da un error al compilar, pero sí provoca un error en tiempo de ejecución (una excepción de tipo IndexOutOfRangeException, que estudiaremos en el Módulo 2 al ver el manejo de excepciones). Por eso siempre hay que asegurarse de que el índice usado esté entre 0 y Length - 1.

string[] titulosLibros = { "Cien anos de soledad", "Rayuela", "Ficciones" };
// Console.WriteLine(titulosLibros[3]); // Error en tiempo de ejecución: índice fuera de rango
Console.WriteLine(titulosLibros[titulosLibros.Length - 1]); // Ficciones (el último elemento)

Arrays de varias dimensiones

Además de los arrays de una dimensión (una simple lista de elementos), C# permite arrays de varias dimensiones, útiles para representar datos organizados en forma de tabla o cuadrícula. El caso más común es el array bidimensional (filas y columnas):

// Un array de 2 filas (estanterías) x 3 columnas (huecos por estantería)
string[,] estanteria = new string[2, 3];

estanteria[0, 0] = "Cien anos de soledad";
estanteria[0, 1] = "Rayuela";
estanteria[0, 2] = "Ficciones";
estanteria[1, 0] = "El Aleph";
estanteria[1, 1] = "Pedro Paramo";
estanteria[1, 2] = "La casa de los espiritus";

Console.WriteLine(estanteria[1, 2]); // La casa de los espiritus

También se pueden inicializar directamente con sus valores:

string[,] estanteria =
{
    { "Cien anos de soledad", "Rayuela", "Ficciones" },
    { "El Aleph", "Pedro Paramo", "La casa de los espiritus" }
};

Para conocer el número de filas y columnas de un array bidimensional se usa el método GetLength, indicando la dimensión (0 para filas, 1 para columnas):

Console.WriteLine(estanteria.GetLength(0)); // 2 (filas / estanterías)
Console.WriteLine(estanteria.GetLength(1)); // 3 (columnas / huecos por estantería)

En este curso los arrays multidimensionales aparecerán de forma puntual; la mayoría de los ejemplos usarán arrays de una dimensión, que son con diferencia los más habituales en el día a día.

Arrays de tamaño fijo frente a List<T>

Como hemos visto, un array tiene un tamaño fijo: una vez creado con, por ejemplo, 3 elementos, no se puede añadir un cuarto título de libro sin crear un array completamente nuevo. En muchos escenarios reales (como ir añadiendo libros al catálogo de BiblioTech a medida que se registran) esta limitación resulta incómoda.

Para esos casos, .NET ofrece List<T>, una colección cuyo tamaño puede crecer y encogerse de forma dinámica, con métodos como Add (añadir un elemento) o Remove (quitarlo). Aquí solo la mencionamos de pasada: List<T> y el resto de colecciones de .NET se estudian en profundidad en el Módulo 4 ("Colecciones"), junto con LINQ, la potente herramienta de consulta que usaremos para explorar el catálogo completo de BiblioTech. Por ahora, quédate con esta idea:

Array (string[]) List<T> (por ejemplo, List<string>)
Tamaño Fijo al crearse Dinámico (crece y decrece)
Cuándo usarlo El número de elementos se conoce de antemano y no cambia El número de elementos puede variar durante la ejecución
Se estudia en detalle en Este módulo Módulo 4

Recorrer un array con foreach y con for

Para procesar todos los elementos de un array, uno a uno, existen dos bucles principales. Aunque los bucles se estudian en profundidad en el Módulo 2 ("Bucles"), aquí veremos su uso básico aplicado a arrays, ya que es una combinación tan habitual que conviene conocerla desde ya.

foreach: recorrer todos los elementos

foreach recorre todos los elementos de una colección, uno detrás de otro, sin necesidad de gestionar manualmente un índice:

string[] titulosLibros = { "Cien anos de soledad", "Rayuela", "Ficciones" };

foreach (string titulo in titulosLibros)
{
    Console.WriteLine(titulo);
}

Este código imprime, uno por línea, cada título del array. foreach es la opción más clara y recomendable cuando simplemente necesitas leer o procesar cada elemento, sin necesitar su posición (índice).

for: recorrer con control explícito del índice

Cuando sí necesitas el índice (por ejemplo, para numerar los libros, o para modificar el propio array durante el recorrido), se usa el bucle for, que da control explícito sobre un contador:

string[] titulosLibros = { "Cien anos de soledad", "Rayuela", "Ficciones" };

for (int i = 0; i < titulosLibros.Length; i++)
{
    Console.WriteLine($"{i + 1}. {titulosLibros[i]}");
}

Este ejemplo imprime cada título precedido de su posición en la lista, empezando en 1 (sumando 1 al índice, que empieza en 0):

1. Cien anos de soledad
2. Rayuela
3. Ficciones
foreach for
Acceso al índice No (solo el valor de cada elemento) Sí, mediante el contador (i)
Modificar el array durante el recorrido No recomendable Posible, con precaución
Legibilidad Más simple y directo Más flexible pero algo más verboso

La clase string: inmutabilidad, concatenación e interpolación

Inmutabilidad

Una string en C# es inmutable: una vez creada, su contenido no puede modificarse. Cualquier operación que "parezca" cambiar una cadena (como concatenarla con otro texto) realmente crea una cadena nueva en memoria, dejando la original intacta:

string tituloOriginal = "Rayuela";
string tituloModificado = tituloOriginal + " (edicion especial)";

Console.WriteLine(tituloOriginal);   // Rayuela (no ha cambiado)
Console.WriteLine(tituloModificado); // Rayuela (edicion especial)

Esta propiedad tiene implicaciones importantes de rendimiento cuando se concatenan muchas cadenas dentro de un bucle, como veremos más adelante en la sección de StringBuilder.

Concatenación

Concatenar significa unir dos o más cadenas en una sola. La forma más básica es con el operador +:

string titulo = "Cien anos de soledad";
string autor = "Gabriel Garcia Marquez";
string descripcion = titulo + " - " + autor;

Console.WriteLine(descripcion); // Cien anos de soledad - Gabriel Garcia Marquez

Interpolación de cadenas ($"")

La interpolación es una forma mucho más legible de construir cadenas que combinan texto fijo con valores de variables. Se antepone el símbolo $ antes de las comillas, y las variables (o incluso expresiones) se insertan directamente entre llaves { }:

string titulo = "Cien anos de soledad";
int paginas = 471;
bool disponible = true;

string resumen = $"El libro '{titulo}' tiene {paginas} paginas y esta disponible: {disponible}";
Console.WriteLine(resumen);

Resultado:

El libro 'Cien anos de soledad' tiene 471 paginas y esta disponible: True

Dentro de las llaves { } de una cadena interpolada se pueden escribir incluso pequeñas expresiones, no solo variables sueltas:

int paginasLeidas = 120;
int totalPaginas = 471;

Console.WriteLine($"Progreso de lectura: {paginasLeidas} de {totalPaginas} paginas ({paginasLeidas * 100 / totalPaginas}%)");
Técnica Ejemplo Legibilidad
Concatenación con + "Libro: " + titulo + ", paginas: " + paginas Se vuelve difícil de leer con muchas variables
Interpolación $"" $"Libro: {titulo}, paginas: {paginas}" Clara incluso con varias variables

En este curso preferiremos la interpolación siempre que combinemos texto con variables, por su claridad.

Métodos habituales de string

La clase string incluye numerosos métodos ya construidos para las tareas más habituales de manipulación de texto. Estos son los más usados:

Método Qué hace Ejemplo
Split Divide una cadena en un array de subcadenas, según un separador "a,b,c".Split(',')["a", "b", "c"]
Trim Elimina espacios en blanco al principio y al final " Rayuela ".Trim()"Rayuela"
Contains Comprueba si una cadena contiene otra "Rayuela".Contains("ayu")true
Substring Extrae una parte de la cadena, indicando posición (y opcionalmente longitud) "Rayuela".Substring(0, 3)"Ray"
ToUpper / ToLower Convierte toda la cadena a mayúsculas o minúsculas "Rayuela".ToUpper()"RAYUELA"

Vamos a verlos aplicados a un ejemplo realista de BiblioTech: procesar una línea de texto con varios datos de un libro separados por comas, tal y como podría venir de un archivo de importación (algo que trataremos en profundidad en el Módulo 5, "Entrada/Salida de Archivos").

string lineaImportada = "  Rayuela, Julio Cortazar, 635  ";

string lineaLimpia = lineaImportada.Trim(); // quita espacios sobrantes al principio/final
string[] campos = lineaLimpia.Split(',');   // separa por comas: ["  Rayuela", " Julio Cortazar", " 635  "]

string titulo = campos[0].Trim();   // "Rayuela"
string autor = campos[1].Trim();    // "Julio Cortazar"
string paginasTexto = campos[2].Trim(); // "635"

Console.WriteLine($"Titulo: {titulo}");
Console.WriteLine($"Autor: {autor}");
Console.WriteLine($"Paginas (texto): {paginasTexto}");

// Búsqueda de texto dentro de un título
bool contieneRay = titulo.Contains("Ray");
Console.WriteLine($"El titulo contiene 'Ray': {contieneRay}");

// Extraer las 3 primeras letras del título
string prefijoTitulo = titulo.Substring(0, 3);
Console.WriteLine($"Prefijo del titulo: {prefijoTitulo}");

// Normalizar a mayúsculas para comparaciones sin distinguir mayúsculas/minúsculas
string tituloEnMayusculas = titulo.ToUpper();
Console.WriteLine(tituloEnMayusculas); // RAYUELA

Fíjate en que cada uno de estos métodos no modifica la cadena original (recuerda: las cadenas son inmutables), sino que devuelve una cadena nueva con el resultado. Por eso siempre asignamos el resultado a una variable (o lo usamos directamente), en lugar de esperar que la variable original cambie por sí sola.

Comparación de cadenas ignorando mayúsculas/minúsculas

Un caso de uso muy habitual al buscar en un catálogo (como el de BiblioTech) es comparar texto sin que importen las mayúsculas o minúsculas. Para ello se pueden convertir ambas cadenas al mismo caso antes de comparar, o usar el método Equals con una opción específica:

string busqueda = "rayuela";
string tituloCatalogo = "Rayuela";

bool coincide = tituloCatalogo.Equals(busqueda, StringComparison.OrdinalIgnoreCase);
Console.WriteLine(coincide); // True

StringBuilder para concatenación eficiente

Como cada string es inmutable, concatenar cadenas repetidamente dentro de un bucle (por ejemplo, para construir un informe con todos los títulos del catálogo) crea, en cada iteración, una cadena nueva completa en memoria, descartando la anterior. Para pocos elementos esto no supone ningún problema, pero si el bucle se repite muchas veces (miles de libros, por ejemplo), puede afectar notablemente al rendimiento.

Para estos casos, .NET ofrece la clase StringBuilder, pensada específicamente para construir cadenas de texto de forma eficiente mediante sucesivas modificaciones, sin crear una cadena nueva completa en cada paso. Se encuentra en el espacio de nombres System.Text.

using System.Text;

string[] titulosLibros = { "Cien anos de soledad", "Rayuela", "Ficciones", "El Aleph" };

StringBuilder informe = new StringBuilder();
informe.Append("Catalogo de BiblioTech:");
informe.AppendLine(); // salto de línea

foreach (string titulo in titulosLibros)
{
    informe.AppendLine($"- {titulo}");
}

string informeFinal = informe.ToString();
Console.WriteLine(informeFinal);

Resultado:

Catalogo de BiblioTech:
- Cien anos de soledad
- Rayuela
- Ficciones
- El Aleph
Situación Recomendación
Concatenar unas pocas cadenas, fuera de un bucle + o interpolación $""
Concatenar dentro de un bucle que puede repetirse muchas veces StringBuilder

No profundizaremos más en StringBuilder en este módulo introductorio; es una herramienta que irá apareciendo de forma natural más adelante en el curso, especialmente cuando trabajemos con grandes catálogos de libros y generación de informes.

Errores Comunes y Consejos

  • Acceder a un índice fuera de rango: recuerda que los índices de un array van de 0 a Length - 1. Acceder a array[Length] es un error muy común y provoca una excepción en tiempo de ejecución.
  • Esperar que un array cambie de tamaño: los arrays tienen tamaño fijo. Si necesitas añadir o quitar elementos dinámicamente, necesitarás List<T> (Módulo 4), no un array. Créar un array de mayor tamaño y copiar los datos es posible, pero engorroso y poco habitual en la práctica.
  • Olvidar que las cadenas son inmutables: escribir titulo.ToUpper(); sin asignar el resultado a ninguna variable no modifica titulo; hay que hacer titulo = titulo.ToUpper(); (o usar el resultado directamente donde se necesite).
  • Usar concatenación con + dentro de bucles grandes: para pocos elementos no pasa nada, pero si el bucle procesa muchísimos elementos, es preferible StringBuilder.
  • Confundir Split sin limpiar espacios: al dividir texto con Split, cada fragmento puede llevar espacios sobrantes; conviene aplicar Trim() a cada uno, como hicimos en el ejemplo de importación de datos.
  • Consejo: cuando trabajes con texto que combine variables, prioriza siempre la interpolación ($"...") sobre la concatenación con +: el código resultante es mucho más legible y menos propenso a errores.

Ejercicios

  1. Declara un array de tipo string[] con al menos 5 títulos de libros de BiblioTech. Recórrelo con foreach y muestra cada título en una línea. Después, recórrelo con un bucle for mostrando cada título numerado, empezando en 1 (por ejemplo: 1. Cien anos de soledad).

  2. Dado el array de títulos del ejercicio anterior, escribe código que recorra el array y muestre solo los títulos que contengan la letra "a" (usando el método Contains, y convirtiendo el título a minúsculas con ToLower() antes de comparar, para que la búsqueda no distinga mayúsculas de minúsculas).

  3. Usando StringBuilder, construye un informe de texto con todos los títulos del array del ejercicio 1, con el formato:

    === Catalogo BiblioTech ===
    1) <titulo 1>
    2) <titulo 2>
    ...
    

    (Pista: puedes combinar un bucle for con StringBuilder.AppendLine e interpolación de cadenas para construir cada línea numerada).

Soluciones

string[] titulosLibros = { "Cien anos de soledad", "Rayuela", "Ficciones", "El Aleph", "Pedro Paramo" };

// Recorrido con foreach
foreach (string titulo in titulosLibros)
{
    Console.WriteLine(titulo);
}

Console.WriteLine("---");

// Recorrido con for, numerado desde 1
for (int i = 0; i < titulosLibros.Length; i++)
{
    Console.WriteLine($"{i + 1}. {titulosLibros[i]}");
}
string[] titulosLibros = { "Cien anos de soledad", "Rayuela", "Ficciones", "El Aleph", "Pedro Paramo" };

foreach (string titulo in titulosLibros)
{
    if (titulo.ToLower().Contains("a"))
    {
        Console.WriteLine(titulo);
    }
}

Todos los títulos del ejemplo contienen la letra "a" en algún punto (mayúscula o minúscula), por lo que el resultado mostraría los cinco; el ejercicio sirve para practicar la combinación de ToLower() y Contains(), no tanto para obtener un subconjunto reducido con estos datos concretos. Puedes probar con otros títulos que no contengan la letra para comprobar que sí se filtran correctamente.

using System.Text;

string[] titulosLibros = { "Cien anos de soledad", "Rayuela", "Ficciones", "El Aleph", "Pedro Paramo" };

StringBuilder informe = new StringBuilder();
informe.AppendLine("=== Catalogo BiblioTech ===");

for (int i = 0; i < titulosLibros.Length; i++)
{
    informe.AppendLine($"{i + 1}) {titulosLibros[i]}");
}

Console.WriteLine(informe.ToString());

Resultado esperado:

=== Catalogo BiblioTech ===
1) Cien anos de soledad
2) Rayuela
3) Ficciones
4) El Aleph
5) Pedro Paramo

Conclusión

En esta lección has aprendido a trabajar con arrays de una y varias dimensiones, a recorrerlos con foreach y for, y has visto por qué List<T> (que estudiaremos en el Módulo 4) resuelve la limitación del tamaño fijo de los arrays. También has profundizado en la clase string: su inmutabilidad, la concatenación, la interpolación $"", sus métodos más habituales (Split, Trim, Contains, Substring, ToUpper/ToLower) y el uso de StringBuilder para concatenar texto de forma eficiente dentro de bucles.

Con esto se cierra el Módulo 1: Introducción a C#. Ya sabes instalar y configurar tu entorno, escribir y ejecutar programas de consola, aplicar correctamente la sintaxis del lenguaje, declarar variables de distintos tipos y trabajar con arrays y cadenas de texto —todo ello aplicado, paso a paso, al proyecto BiblioTech. En el Módulo 2: Estructuras de Control aprenderás a tomar decisiones en tu código con sentencias condicionales, a repetir acciones con bucles, a organizar múltiples casos con switch, y a manejar errores de forma robusta con excepciones: piezas imprescindibles para que BiblioTech empiece a comportarse como una aplicación real, capaz de reaccionar a distintas situaciones y datos.

Curso de Programación en C#

Módulo 1: Introducción a C#

Módulo 2: Estructuras de Control

Módulo 3: Programación Orientada a Objetos

Módulo 4: Conceptos Avanzados de C#

Módulo 5: Trabajando con Datos

Módulo 6: Temas Avanzados

Módulo 7: Construcción de Aplicaciones

Módulo 8: Mejores Prácticas y Patrones de Diseño

Módulo 9: Proyecto Final

© Copyright 2026. Todos los derechos reservados