cpp-null-terminated-string

Null-terminated string en C++

Una de las formas de manejar cadenas de texto en C++ es mediante las denominadas null-terminated string.

Este modelo fue heredado directamente del lenguaje C. Aunque en C++ std::string como alternativa más potente, cómoda, segura (y normalmente más segura)

Siempre que sea posible, debemos que preferir std::string a una null-terminated string.

Sin embargo, aún sigue siendo utilizado en programación de bajo nivel, sistemas embebidos y bibliotecas. Así que toca aprender a usarlo 👇.

Qué es un Null-Terminated String

Un null-terminated string es simplemente un array de caracteres de tamaño fijo y suficiente para meter nuestro texto.

Este carácter nulo (\0) es un carácter especial que sirve como marcador para indicar el final de la cadena, lo que permite que las funciones que operan sobre cadenas sepan dónde detenerse.

Por ejemplo, la cadena "Hola" en memoria se representaría así:

['H', 'o', 'l', 'a', '\0']

Características:

  • Array de caracteres: Se define usando el tipo char[] en C++.
  • Carácter nulo al final: El carácter '\0' es obligatorio (y debe ser manejado con cuidaitooo).
  • Tamaño real: El tamaño real de la cadena debe incluir en carácter nulo (es decir, sera caracteres + 1).

Declaración de cadenas null-terminated

Podemos declarar cadenas null-terminated de las siguientes maneras:

char saludo[] = "Hola";
  • Esto crea un array de 5 caracteres ('H', 'o', 'l', 'a', y '\0').
  • La inclusión del carácter nulo es automática.
char saludo[6] = {'H', 'o', 'l', 'a', '\0'};

Aquí especificamos manualmente el carácter nulo y el tamaño del array. Si omitimos '\0', el array no será un string válido:

char saludo[] = {'H', 'o', 'l', 'a'}; // Incorrecto como cadena null-terminated

¿Porqué iba a querer alguien hacer esto? No lo sé, dímelo tu 😆

char vacia[] = "";

Esto crea un array de un solo carácter ('\0').

Operaciones Básicas con Null-Terminated Strings

El manejo de null-terminated strings requiere cuidado, ya que tenemos que gestionar manualmente la memoria y el carácter nulo.

Para copiar cadenas, usamos la función strcpy de la biblioteca <cstring>:

char origen[] = "Hola";
char destino[10];

strcpy(destino, origen);
  • strcpy copia origen en destino, incluyendo el carácter nulo.

Tienes que asegurarte de que destino tenga suficiente espacio para evitar desbordamientos.

Para concatenar cadenas, usamos strcat:

int main() {
char saludo[20] = "Hola, ";
char nombre[] = "Mundo";

strcat(saludo, nombre);
  • strcat añade nombre al final de saludo.

El array saludo debe tener suficiente espacio para almacenar el resultado completo, incluido el carácter nulo.

La función strlen devuelve la longitud de la cadena, excluyendo el carácter nulo:

char texto[] = "Hola";

std::cout << "Longitud: " << strlen(texto) << std::endl;

Salida:

Longitud: 4

Para comparar cadenas, usamos strcmp:

char cadena1[] = "Hola";
char cadena2[] = "Hola";

if (strcmp(cadena1, cadena2) == 0) {
	std::cout << "Las cadenas son iguales." << std::endl;
} else {
	std::cout << "Las cadenas son diferentes." << std::endl;
}
  • Devuelve 0 si las cadenas son iguales, un valor negativo si la primera es menor que la segunda, y un valor positivo en caso contrario.

Cualquier operación incorrecta puede causar desbordamientos o resultados inesperados (y en tu programa cerrándose de forma poco elegante) 💥

Manejo Seguro de Null-Terminated Strings

Los null-terminated strings son susceptibles muy susceptibles a errores, especialmente en la gestión de memoria y corrupción de datos.

En lugar de strcpy, utiliza strncpy para limitar el número de caracteres copiados:

strncpy(destino, origen, sizeof(destino) - 1);
destino[sizeof(destino) - 1] = '\0'; // Garantiza el carácter nulo

Antes de concatenar cadenas, verifica que el tamaño del búfer sea suficiente:

if (strlen(saludo) + strlen(nombre) + 1 < sizeof(saludo)) {
    strcat(saludo, nombre);
} else {
    std::cerr << "Error: tamaño insuficiente para concatenar." << std::endl;
}

Asegúrate de no acceder a índices fuera del rango del array:

char cadena[10];
cadena[10] = 'x'; // Error: fuera del rango válido

Desventajas de las Null-Terminated Strings

Aunque pueden ser eficientes, los null-terminated strings presentan varias limitaciones:

  • Gestión manual de memoria: El programador debe asegurarse de que los búferes sean suficientemente grandes.
  • Falta de seguridad: Errores como desbordamientos de búfer son comunes si no se manejan correctamente.
  • Operaciones complejas: Manipular cadenas largas o realizar operaciones avanzadas requiere mucho código adicional.

En resumen, que son un dolor de usar 🤷. Aunque, también tienen alguna ventaja.