Capítulo 5 — Arrays y Cadenas de Caracteres¶
Objetivos de aprendizaje
- Declarar y recorrer arrays uni y multidimensionales.
- Comprender el decaimiento array → puntero y sus consecuencias.
- Manejar cadenas C (
'\0'-terminadas) y<string.h>con seguridad. - Implementar algoritmos clásicos: búsqueda y ordenación.
5.1 Arrays unidimensionales¶
int v[5] = {10, 20, 30, 40, 50};
v[0]; // primer elemento
v[4]; // último (índice n-1)
size_t n = sizeof v / sizeof v[0]; // número de elementos = 5
Sin comprobación de límites
C no verifica los índices. v[5] o v[-1] son undefined behavior y la
causa nº 1 de vulnerabilidades de corrupción de memoria. Usa
-fsanitize=address durante el desarrollo.
Relación array ↔ puntero¶
En casi todos los contextos, el nombre de un array decae a un puntero a su
primer elemento. Por eso v[i] es exactamente *(v + i). La excepción notable:
sizeof v y &v operan sobre el array completo.
VLA (C99)¶
Los VLA son opcionales en C11/C17 y arriesgados (pueden agotar la pila con
n grande o atacante-controlado). Evítalos en código de producción; usa
malloc (cap. 7).
5.2 Arrays multidimensionales¶
Row-major significa que las filas están contiguas en memoria:
m[i][j] está en base + (i*4 + j). Al pasar a una función hay que conservar
todas las dimensiones salvo la primera:
5.3 Cadenas de caracteres¶
Una cadena C es un array de char terminado en el byte nulo '\0':
<string.h> aporta las operaciones fundamentales:
| Función | Acción | Riesgo |
|---|---|---|
strlen |
Longitud (sin contar \0) |
UB si no está terminada |
strcpy |
Copia | Desbordamiento si destino pequeño |
strncpy |
Copia acotada | Puede no terminar en \0 |
strcat |
Concatena | Desbordamiento |
strcmp |
Compara | — |
strchr/strstr |
Busca carácter/subcadena | — |
strtok |
Tokeniza | No reentrante (usa estado interno) |
Preferir snprintf
snprintf siempre termina en '\0' (salvo tamaño 0) y nunca escribe más allá
del búfer. Es la herramienta por defecto para construir cadenas con seguridad.
strdup/strndup (POSIX, estándar en C23) duplican una cadena reservando
memoria con malloc — recuerda free.
5.4 Arrays de cadenas¶
const char *dias[] = {"Lun", "Mar", "Mié"}; // array de punteros a cadena
// argv es exactamente esto: char *argv[] ≡ char **argv
Distingue una matriz char m[3][4] (memoria contigua, cadenas de tamaño fijo)
de un array de punteros char *p[3] (punteros a cadenas de tamaños distintos).
5.5 Algoritmos clásicos¶
int busqueda_binaria(const int *v, int n, int objetivo) {
int lo = 0, hi = n - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2; // evita desbordar (lo+hi)
if (v[mid] == objetivo) return mid;
if (v[mid] < objetivo) lo = mid + 1;
else hi = mid - 1;
}
return -1; // no encontrado
}
Ordenación por inserción (estable, O(n²), eficiente para arrays casi ordenados):
void insercion(int *v, int n) {
for (int i = 1; i < n; i++) {
int clave = v[i], j = i - 1;
while (j >= 0 && v[j] > clave) { v[j + 1] = v[j]; j--; }
v[j + 1] = clave;
}
}
Conexión con la actualidad¶
Las cadenas terminadas en '\0' y la ausencia de límites en los arrays son el
pecado original de C en materia de seguridad. Funciones como strcpy,
strcat y gets (esta última eliminada del estándar en C11) están detrás de
décadas de buffer overflows. La respuesta de la industria en 2024–2025 es doble:
- Detección: AddressSanitizer y fuzzing (cap. 30) encuentran estos fallos antes de producción; el proyecto OSS-Fuzz de Google ha hallado decenas de miles de bugs así.
- Mitigación hardware: ARM MTE (Memory Tagging Extension) y la arquitectura experimental CHERI (adoptada en el prototipo Morello de ARM) detectan accesos fuera de límites a nivel de CPU, marcando punteros y regiones de memoria.
Las Annex K (strcpy_s, strncpy_s) buscaron estandarizar variantes seguras,
con adopción desigual. La recomendación práctica del curso: trata el tamaño del
búfer como un dato de primera clase y usa snprintf/memcpy con longitudes
explícitas.
Ejercicios¶
Ejercicio 5.1 — Reimplementa string.h ★★
Escribe tus propias mi_strlen, mi_strcpy, mi_strcmp y mi_strcat.
Compáralas con las de la libc.
Ejercicio 5.2 — Frecuencia de palabras ★★★
Lee un texto y cuenta cuántas veces aparece cada palabra. (Más adelante lo mejorarás con una tabla hash, cap. 11.)
Ejercicio 5.3 — Multiplicación de matrices ★★★
Multiplica dos matrices NxN. Mide el tiempo y compáralo recorriéndolas en orden row-major vs column-major (anticipo del cap. 21, cache locality).
Ejercicio 5.4 — Búsqueda binaria robusta ★★
Verifica la búsqueda binaria con casos límite: array vacío, un elemento, objetivo menor que el mínimo y mayor que el máximo.
Referencias¶
- ISO/IEC 9899:2018, §6.7.6 (declaradores de array), §7.24 (
<string.h>). - The Practice of Programming (Kernighan & Pike), capítulo sobre cadenas.
- OSS-Fuzz — fuzzing continuo de software C/C++.
- CHERI / ARM Morello — documentación del proyecto.