2010-04-19 17 views
11

Me estoy metiendo en C/C++ y aparecen muchos términos desconocidos para mí. Uno de ellos es una variable o puntero que termina con un cero. ¿Qué significa que un espacio en la memoria sea terminado por un cero?¿Qué significa ser "terminado por un cero"?

+6

Esta frase se termina por un punto. Entonces este es este. PERO NO ESTE! – polygenelubricants

+2

Joel tiene un buen artículo sobre esto (y cosas relacionadas): http://www.joelonsoftware.com/articles/fog0000000319.html – NomeN

Respuesta

16

Tome la cadena Hi en ASCII. Su representación más simple en la memoria es de dos bytes:

0x48 
0x69 

Pero ¿de dónde viene esa parte de memoria termina? A menos que también esté preparado para pasar la cantidad de bytes en la cadena, no lo sabe: las piezas de memoria no tienen una longitud intrínseca.

Así C tiene una norma que las cadenas terminan con un byte cero, también conocido como un personaje NUL:

0x48 
0x69 
0x00 

la cadena es ahora sin ambigüedades dos caracteres de largo, porque hay dos caracteres antes del NUL.

+1

Y los desbordamientos de búfer ocurren cuando no se da cuenta de que necesita tres bytes para almacenar dos caracteres. – MSalters

+1

@MSalters: No, suceden cuando te das cuenta de que una cadena de longitud dos consta de tres caracteres. :-) –

14

Es un valor reservado para indicar el final de una secuencia de caracteres (por ejemplo) en una cadena.

Más correctamente conocido como null (or NUL) terminated. Esto se debe a que el valor utilizado es cero, en lugar de ser el código de carácter para '0'. Para aclarar la distinción, consulte una tabla del ASCII character set.

Esto es necesario porque los lenguajes como C tienen un tipo de datos char, pero ningún tipo de datos string. Por lo tanto, se deja al devleoper decidir cómo administrar cadenas en su aplicación. La forma habitual de hacerlo es tener una matriz de char s con un valor nulo utilizado para terminar (es decir, significa el final de) la cadena.

Tenga en cuenta que hay una distinción entre la longitud de la cadena y la longitud de la matriz de caracteres que se declaró originalmente.

char name[50]; 

Esto declara una matriz de 50 caracteres. Sin embargo, estos valores no se inicializarán. Entonces, si quiero almacenar la cadena "Hello" (5 caracteres de largo), realmente no quiero molestarme en configurar los 45 caracteres restantes en espacios (o algún otro valor). En cambio, almaceno un valor NUL después del último caracter en mi cadena.

Los idiomas más recientes como Pascal, Java y C# tienen un tipo específico de string definido. Estos tienen un valor de encabezado para indicar el número de caracteres en la cadena. Esto tiene un par de beneficios; en primer lugar, no necesita caminar hasta el final de la cuerda para averiguar su longitud, en segundo lugar su cuerda puede contain null characters.

Wikipedia tiene más información en la entrada .

+0

Re: idiomas más recientes: IIRC, que se llama una cadena de Pascal – Hasturkun

+0

cadenas de Pascal utilizado específicamente un solo byte para mantener la longitud de la cadena. Como puedes adivinar rápidamente, ¡eso no es suficiente! Los tipos modernos de "cadena" probablemente estén usando un 'size_t' en su lugar; si la cadena no encaja en eso, la cadena tampoco se mantendrá en su totalidad en la memoria. –

0

Las matrices y la cadena en C son solo punteros a una ubicación de memoria. Con el puntero, puede encontrar un inicio de matriz. El final de la matriz no está definido. El final de la matriz de caracteres (que es la cadena) es cero byte.

Así, en la memoria hola cadena se escribe como:

68 65 6c 6c 6f 00         |hello| 
0

Se refiere a la forma en cadenas de C se almacenan en la memoria. El carácter NUL representado por \ 0 en iteraciones de cadena está presente al final de una cadena C en la memoria. No hay otros metadatos asociados con una cadena C como la longitud, por ejemplo. Tenga en cuenta la ortografía diferente entre el carácter NUL y el puntero NULL.

0

Las cadenas estilo C terminan con un carácter NUL ('\ 0'). Esto proporciona un marcador para las funciones que operan en cadenas (por ejemplo, strlen, strcpy) para identificar el final de la cadena.

4

terminada por un cero

Es cuando su jefe de pelo puntiagudo lo despide.

0

Hay dos formas comunes de manejar matrices que pueden tener contenidos de longitud variable (como Strings). El primero es guardar por separado la longitud de los datos almacenados en la matriz. Los lenguajes como el std :: string de Fortran y Ada y C++ hacen esto. La desventaja de hacer esto es que de alguna manera tiene que pasar esa información adicional a todo lo relacionado con su matriz.

De la otra manera, es reservar un elemento extra de datos al final de la matriz para servir como un centinela. Para el centinela utiliza un valor que nunca debería aparecer en los datos reales. Para cadenas, 0 (o "NUL") es una buena opción, ya que no es imprimible y no tiene otro propósito en ASCII. Entonces, ¿qué C (y muchos idiomas copiados de C) hacen es suponer que todas las cadenas terminan (o "están terminadas por") un 0.

Hay varios inconvenientes en esto. Por un lado, es lento. Cada vez que una rutina necesita saber la longitud de la cadena, es una operación O (n) (buscando a través de la cadena entera buscando el 0). Otro problema es que algún día puede querer poner un 0 en su cadena por alguna razón, por lo que ahora necesita un segundo conjunto de rutinas de cadena que ignoren el nulo y usen una longitud diferente de todos modos (p. Ej .: strnlen()). El tercer gran problema es que si alguien se olvida de poner ese 0 al final (o se borra de alguna manera), la siguiente operación de cadena para hacer una comprobación lenth marchará alegremente a través de la memoria hasta que encuentre aleatoriamente otro 0, fallas, o el usuario pierde la paciencia y lo mata. Dichos errores pueden ser un PITA serio para rastrear.

Por todas estas razones, el enfoque C generalmente se ve con desaprobación.

0

Mientras que el ejemplo clásico de "terminado por un cero" es el de las cadenas en C, el concepto es más general. Se puede aplicar a cualquier lista de cosas almacenadas en una matriz, cuyo tamaño no se conoce explícitamente.

El truco consiste simplemente en evitar pasar un tamaño de matriz al agregar un valor centinela al final de la matriz. Normalmente, se utiliza alguna forma de cero, pero puede ser cualquier otra cosa (como NAN si la matriz contiene valores de coma flotante).

Éstos son tres ejemplos de este concepto: cadenas

  1. C, por supuesto. Se agrega un carácter de cero a la cadena: "Hello" se codifica como 48 65 6c 6c 6f 00.

  2. Las matrices de punteros permiten naturalmente la terminación cero, porque el puntero nulo (el que apunta a la dirección cero) se define para que nunca apunte a un objeto válido.Como tal, es posible encontrar código como este:

    Foo list[] = { somePointer, anotherPointer, NULL }; 
    bar(list); 
    

    en lugar de

    Foo list[] = { somePointer, anotherPointer }; 
    bar(sizeof(list)/sizeof(*list), list); 
    

    Esta es la razón por la execvpe() sólo tiene tres argumentos, dos de los cuales pasan las matrices de longitud definida por el usuario. Como todo lo que pasó a execvpe() son (posiblemente muchas) cadenas, esta pequeña función en realidad tiene dos niveles de terminación cero: punteros nulos que terminan las listas de cadenas y caracteres nulos que terminan las cadenas.

  3. Incluso cuando el tipo de elemento de la matriz es un struct más complejo, aún puede ser terminado por cero. En muchos casos, uno de los miembros struct se define como el que señala el final de la lista. He visto tales definiciones de funciones, pero no puedo descubrir un buen ejemplo de esto en este momento, lo siento. De todos modos, el código de llamada sería algo como esto:

    Foo list[] = { 
        { someValue, somePointer }, 
        { anotherValue, anotherPointer }, 
        { 0, NULL } 
    }; 
    bar(list); 
    

    o incluso

    Foo list[] = { 
        { someValue, somePointer }, 
        { anotherValue, anotherPointer }, 
        {} //C zeros out an object initialized with an empty initializer list. 
    }; 
    bar(list); 
    
Cuestiones relacionadas