¿Por qué las cadenas en C necesitan ser terminadas?

Me pregunto por qué este es el caso. Estoy ansioso por saber más sobre idiomas de bajo nivel, y solo conozco los conceptos básicos de C, y esto ya me está confundiendo.

¿Los lenguajes como PHP anulan automáticamente las cadenas mientras se interpretan y / o se analizan?

    Del excelente artículo de Joel sobre el tema:

    Recuerde la forma en que las cadenas funcionan en C: consisten en un grupo de bytes seguido de un carácter nulo, que tiene el valor 0. Esto tiene dos implicaciones obvias:

    No hay forma de saber dónde termina la cuerda (es decir, la longitud de la cuerda) sin moverse a través de ella, buscando el carácter nulo al final. Su cadena no puede tener ceros. Por lo tanto, no puede almacenar un blob binario arbitrario como una imagen JPEG en una cadena C. ¿Por qué las cadenas C funcionan de esta manera? Se debe a que el microprocesador PDP-7, en el que se inventaron UNIX y el lenguaje de progtwigción C, tenía un tipo de cadena ASCIZ. ASCIZ significaba “ASCII con Z (cero) al final”.

    ¿Es esta la única forma de almacenar cadenas? No, de hecho, es una de las peores maneras de almacenar cadenas. Para progtwigs no triviales, API, sistemas operativos, bibliotecas de clases, debe evitar cadenas ASCIZ como la peste.

    Las cadenas C son matrices de caracteres, y una matriz C es solo un puntero a una ubicación de memoria, que es la ubicación de inicio de la matriz. Pero también la longitud (o el final) de la matriz debe expressse de alguna manera; en el caso de cadenas, se utiliza una terminación nula. Otra alternativa sería llevar de alguna manera la longitud de la cadena junto con el puntero de memoria, o poner la longitud en la primera ubicación de la matriz, o lo que sea. Es solo una cuestión de convención.

    Los lenguajes de nivel superior como Java o PHP almacenan la información de tamaño con la matriz de forma automática y transparente, por lo que el usuario no tiene que preocuparse por ellos.

    Porque en C las cadenas son solo una secuencia de caracteres a la que se accede viua un puntero al primer caracter.

    No hay espacio en un puntero para almacenar la longitud, por lo que necesita alguna indicación de dónde está el final de la cadena.

    En C se decidió que esto estaría indicado por un carácter nulo.

    En pascal, por ejemplo, la longitud de una cadena se registra en el byte que precede inmediatamente al puntero, por lo que las cadenas pascales tienen una longitud máxima de 255 caracteres.

    C no tiene ninguna noción de cadenas por sí mismo. Las cadenas son simplemente matrices de caracteres (o wchars para Unicode y tal).

    Debido a esos hechos, C no tiene forma de verificar, es decir, la longitud de la cadena, ya que no existe “mystring-> length”, no hay ningún valor de longitud establecido en algún lugar. La única forma de encontrar el final de la cadena es iterar sobre ella y verificar el \ 0.

    Hay cadenas de bibliotecas para C que usan estructuras como

    struct string { int length; char *data; }; 

    para eliminar la necesidad de la terminación \ 0, pero esto no es estándar C.

    Los lenguajes como C ++, PHP, Perl, etc. tienen sus propias bibliotecas de cadenas internas que a menudo tienen un campo de longitud separado que acelera algunas funciones de cadena y elimina la necesidad de \ 0.

    Algunos otros lenguajes (como Pascal) usan un tipo de cadena que se llama (sorprendentemente) Pascal String, almacena la longitud en el primer byte de la cadena, que es la razón por la cual esas cadenas están limitadas a una longitud de 255 caracteres.

    Piense en qué es la memoria: un bloque contiguo de unidades de tamaño byte que puede rellenarse con cualquier patrón de bits.

     2a c6 90 f6 

    Un personaje es simplemente uno de esos patrones de bits. Su significado como cadena está determinada por la forma en que lo tratas. Si miraras la misma parte de la memoria, pero usando una vista entera (o algún otro tipo), obtendrías un valor diferente.

    Si tiene una variable que es un puntero al inicio de un grupo de caracteres en la memoria, debe saber cuándo termina esa cadena y comienza la siguiente pieza de datos (o basura).

    Ejemplo

    Miremos esta cadena en memoria …

     H ello , world ! \0 ^ | +------ Pointer to string 

    … podemos ver que la cadena lógicamente termina después de ! personaje. Si no hubiera \0 (o cualquier otro método para determinar su final), ¿cómo sabríamos cuando buscamos a través de la memoria que hemos terminado con esa cadena? Otros idiomas llevan la longitud de la cuerda alrededor con el tipo de cadena para resolver esto.

    Hice esta pregunta cuando mi conocimiento subyacente de las computadoras era limitado, y esta es la respuesta que habría ayudado hace muchos años. Espero que ayude a alguien más también. 🙂

    Es una convención: se podría haber implementado con otro algoritmo (por ejemplo, la longitud al comienzo del búfer).

    En un lenguaje de “bajo nivel” como ensamblador, es fácil probar “NULO” de manera eficiente: eso podría haber facilitado la decisión de ir con cadenas terminadas NULL en lugar de hacer un seguimiento de un contador de longitud.

    Necesitan ser terminados nulos para que sepa cuánto tiempo son. Y sí, son simplemente matrices de char.

    Los lenguajes de nivel superior como PHP pueden optar por ocultar la terminación nula de usted o no usarla en absoluto; pueden mantener una longitud, por ejemplo. C no lo hace así debido a la sobrecarga involucrada. Los lenguajes de alto nivel tampoco pueden implementar cadenas como una matriz de caracteres: podrían (y algunos lo hacen) implementarlos como listas de matrices de caracteres, por ejemplo.

    En C, las cadenas se representan mediante una matriz de caracteres asignados en un bloque contiguo de memoria y, por lo tanto, debe haber un indicador que indique el final del bloque (es decir, el carácter nulo) o una forma de almacenar la longitud (como cadenas de Pascal que están prefijados por una longitud).

    En idiomas como PHP, Perl, C # etc., las cadenas pueden tener o no estructuras de datos complejas, por lo que no puede suponer que tienen un carácter nulo. Como un ejemplo artificial, podrías tener un lenguaje que represente una cadena así:

     class string { int length; char[] data; } 

    pero solo lo ve como una cadena normal sin campo de longitud, ya que puede ser calculado por el entorno de tiempo de ejecución del idioma y solo se usa internamente para asignar y acceder a la memoria correctamente.

    Están terminados en nulo porque todas las funciones de la Biblioteca estándar esperan que lo sean.