Por mucho que ame C y C ++, no puedo evitar rascarme la cabeza al elegir cadenas terminadas en nulo:
- Las cadenas de longitud prefijadas (es decir, Pascal) existían antes de C
- Las cadenas prefijadas de longitud hacen que varios algoritmos sean más rápidos al permitir una búsqueda de longitud de tiempo constante.
- Las cadenas prefijadas de longitud hacen que sea más difícil causar errores de desbordamiento del búfer.
- Incluso en una máquina de 32 bits, si permite que la cadena sea del tamaño de la memoria disponible, una cadena prefijada de longitud es solo tres bytes más ancha que una cadena terminada en nulo. En máquinas de 16 bits, este es un solo byte. En máquinas de 64 bits, 4 GB es un límite de longitud de cadena razonable, pero incluso si desea expandirlo al tamaño de la palabra de máquina, las máquinas de 64 bits generalmente tienen memoria suficiente, lo que hace que los siete bytes adicionales sean un argumento nulo. Sé que el estándar C original fue escrito para máquinas increíblemente pobres (en términos de memoria), pero el argumento de la eficiencia no me vende aquí.
- Casi todos los demás idiomas (es decir, Perl, Pascal, Python, Java, C #, etc.) usan cadenas prefijadas de longitud. Estos lenguajes generalmente superan a C en los puntos de referencia de manipulación de cadenas porque son más eficientes con las cadenas.
- C ++ rectificó esto un poco con la
std::basic_string
plantilla, pero las matrices de caracteres simples que esperan cadenas terminadas en nulo siguen siendo dominantes. Esto también es imperfecto porque requiere la asignación del montón. - Las cadenas terminadas en nulo deben reservar un carácter (es decir, nulo), que no puede existir en la cadena, mientras que las cadenas con prefijo de longitud pueden contener nulos incrustados.
Varias de estas cosas han salido a la luz más recientemente que C, por lo que tendría sentido que C no las supiera. Sin embargo, varios eran evidentes mucho antes de que C surgiera. ¿Por qué se habrían elegido cadenas terminadas en cero en lugar del prefijo de longitud obviamente superior?
EDITAR : Dado que algunos pidieron datos (y no les gustaron los que ya proporcioné) en mi punto de eficiencia anterior, provienen de algunas cosas:
- Concat que utiliza cadenas terminadas en nulo requiere una complejidad de tiempo O (n + m). El prefijo de longitud a menudo requiere solo O (m).
- La longitud que usa cadenas terminadas en nulo requiere una complejidad de tiempo O (n). El prefijo de longitud es O (1).
- Longitud y concat son, con mucho, las operaciones de cadena más comunes. Hay varios casos en los que las cadenas terminadas en nulo pueden ser más eficientes, pero ocurren con mucha menos frecuencia.
De las respuestas a continuación, estos son algunos casos en los que las cadenas terminadas en nulo son más eficientes:
- Cuando necesita cortar el inicio de una cadena y necesita pasarla a algún método. Realmente no puede hacer esto en tiempo constante con el prefijo de longitud, incluso si se le permite destruir la cadena original, porque el prefijo de longitud probablemente deba seguir las reglas de alineación.
- En algunos casos en los que solo está recorriendo la cadena carácter por carácter, es posible que pueda guardar un registro de CPU. Tenga en cuenta que esto funciona solo en el caso de que no haya asignado dinámicamente la cadena (porque entonces tendría que liberarla, necesitando usar ese registro de CPU que guardó para contener el puntero que originalmente obtuvo de malloc y amigos).
Ninguno de los anteriores es tan común como la longitud y la concat.
Hay uno más afirmado en las respuestas a continuación:
- Necesitas cortar el final de la cuerda
pero este es incorrecto: es la misma cantidad de tiempo para las cadenas con terminación nula y con prefijo de longitud. (Las cadenas terminadas en nulo solo pegan un nulo donde desea que esté el nuevo final, los prefijos de longitud solo se restan del prefijo).