¿Te resulta más fácil leer con fondo crema, un tono de color, más contraste o un texto más grande? Elige tus colores y tu texto una sola vez, para todas las páginas.

Lección gratuita

Arrays y cadenas de texto en C

Después de esta lección: Puedo explicar un array como memoria y una cadena como bytes que acaban en cero.

Lección de 55 min10 comandosLaboratorio de compiladores y arquitectura: gcc, flex, bison y RISC-V en una VM

Un nombre de usuario de ocho letras

Una cadena de texto en C es una fila de bytes que termina en un byte con valor cero. Si olvidas ese cero, o escribes más bytes de los que caben, el programa lee o rompe memoria que no es suya.

Una web de matrícula guarda el nombre de usuario en un hueco de 8 bytes. Alguien escribe un nombre de 20 letras, y los 12 bytes sobrantes caen encima de otros datos.

Al final de esta lección

Nota

Puedo explicar un array como memoria y una cadena como bytes que acaban en cero.

Palabras clave

PalabraQué significaEjemplo
Arrayelementos del mismo tipo guardados uno tras otroint v[5]
Cadenabytes de texto que terminan en un byte con valor 0
Terminadorel byte 0 que marca el final de una cadena
strlenla función que cuenta los bytes hasta el terminador
Búferun hueco de memoria de tamaño fijo para unos datos
Desbordamientoescribir más allá del final de un búfer

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Un array son elementos seguidos en la memoria

Un array guarda varios elementos del mismo tipo, uno tras otro, sin huecos. Un int v[5] ocupa 5 por 4, o sea 20 bytes.

El elemento número i está i elementos después del primero. Por eso contar empieza en 0: el primer elemento está a distancia cero. C no comprueba si i está dentro del array: eso lo tienes que vigilar tú.

Una cadena son bytes que terminan en cero

C no tiene un tipo texto. Una cadena es un array de char cuyo último byte vale 0, el terminador.

La palabra "hola" son cuatro letras y un cero: cinco bytes. La función strlen cuenta hasta el terminador, sin contarlo, y da 4. Pero sizeof da 5, porque cuenta todo el array.

Ejemplo resuelto: la cadena "hola"

PosiciónLetraCódigo guardado
0h104
1o111
2l108
3a97
4el terminador0

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Entra en la carpeta de trabajo

Comando
mkdir -p ~/c && cd ~/c

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Escribe cad.c: "hola" byte a byte

Comando
printf '#include <stdio.h>\n#include <string.h>\nint main(void) {\n  char s[] = "hola";\n  printf("%%zu %%zu\\n", sizeof(s), strlen(s));\n  for (int i = 0; i < 5; i++) printf("%%d ", s[i]);\n  printf("\\n");\n  return 0;\n}\n' > cad.c

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Compila cad.c con avisos

Comando
gcc -Wall -o cad cad.c

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Ejecuta cad

Comando
./cad

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Cuenta una cadena como lo hace strlen

Código: python
# Una cadena de C: bytes seguidos que terminan en 0.
memory = [104, 111, 108, 97, 0, 55, 55, 0]
length = 0
while memory[length] != 0:
    length = length + 1
print("longitud:", length)
print("bytes que ocupa:", length + 1)
# Cambia el 0 de la posición 4 por 33 y vuelve a ejecutar: ahora cuenta hasta el 0 que sigue.

Escribe cero.c: un cero dentro del texto

Comando
printf '#include <stdio.h>\n#include <string.h>\nint main(void) {\n  char s[] = "ab\\0cd";\n  printf("%%zu %%zu\\n", sizeof(s), strlen(s));\n  return 0;\n}\n' > cero.c

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Compila cero.c

Comando
gcc -Wall -o cero cero.c

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Ejecuta cero: 6 y 2

Comando
./cero

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Un texto largo en un búfer corto desborda

Un búfer tiene un tamaño fijo. Copiar una cadena más larga que el búfer escribe más allá de su final: un desbordamiento.

Esos bytes caen sobre otras variables, o sobre datos que el programa necesita para volver de una función. El resultado no está definido: puede parecer que funciona, o romperse. No lo ejecutamos; la solución es comprobar el tamaño antes de copiar.

Ejemplo: 16 bytes en un búfer de 5

DatoBytesDónde cae
Búfer de destino5posiciones 0 a 4
Texto "mesa de estudio"15 letras y el cero: 16posiciones 0 a 15
Bytes que sobran11posiciones 5 a 15, fuera del búfer
Con strncpy y un máximo de 44 letras y un cero a manoposiciones 0 a 4, dentro

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Escribe corta.c, que copia con límite

Comando
printf '#include <stdio.h>\n#include <string.h>\nint main(void) {\n  char destino[5];\n  strncpy(destino, "mesa de estudio", 4);\n  destino[4] = 0;\n  printf("%%s %%zu\\n", destino, strlen(destino));\n  return 0;\n}\n' > corta.c

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Compila corta.c

Comando
gcc -Wall -o corta corta.c

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Ejecuta corta: mesa 4

Comando
./corta

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Un error frecuente

Advertencia

Mucha gente cree que sizeof y strlen dan lo mismo para una cadena. sizeof da el tamaño del array, con el terminador. strlen cuenta hasta el terminador, sin él. Para "hola" son 5 y 4. Y cuando copies, reserva siempre un byte más para el cero.

Sobre este laboratorio y su código: Laboratorio de compiladores y arquitectura: gcc, flex, bison y RISC-V en una VM

¿Enseñas a una clase? Asigna este módulo a tus alumnos con guía del profesor, tareas con corrección automática y un laboratorio para cada alumno.