2009-06-20 16 views
11

He estado leyendo el libro de K & R y encontré que la aritmética del puntero en C permite el acceso a un elemento más allá del final de una matriz. Sé que C permite hacer casi cualquier cosa con memoria pero no entiendo, ¿cuál es el propósito de esta peculiaridad?C - elemento más allá del final de una matriz

+1

Vea también esta pregunta: http://stackoverflow.com/questions/988158/take-the-address-of-a-one-past-the-end-array-element-via-subscript-legal-by- el –

Respuesta

19

C no permite acceso a la memoria más allá del final de la matriz. Sin embargo, permite que un puntero apunte a un elemento más allá del final de la matriz. La distinción es importante.

Por lo tanto, esto está bien:

char array[N]; 
char *p; 
char *end; 

for (p = array, end = array + N; p < end; ++p) 
    do_something(p); 

(Hacer *end sería un error.)

Y que muestra la razón por la que esta característica es útil: un puntero que apunta a la (inexistente) elemento después del final de la matriz es útil para las comparaciones, como en los bucles.

Técnicamente hablando, eso es todo lo que permite el estándar C. Sin embargo, en la práctica, la implementación C (compilador y tiempo de ejecución) no verifica si accede a la memoria más allá del final de la matriz, si es un elemento o más. Tendría que haber comprobación de límites y eso ralentizaría la ejecución del programa. Los tipos de programas C más adecuados (programación de sistemas, bibliotecas de propósito general) tienden a beneficiarse más de la velocidad que la seguridad y la seguridad que proporcionaría la verificación de límites.

Eso significa que C quizás no sea una buena herramienta para la programación de aplicaciones de propósito general.

15

A menudo, es útil para indicar la posición "final", que es uno más allá de la asignación real, por lo que puede escribir código como:

char * end = begin + size; 
for (char * curr = begin; curr < /* or != */ end ; ++curr) { 
    /* do something in the loop */ 
} 

El estándar de C dice explícitamente que este elemento es un válido dirección de memoria, pero desreferenciando aún no sería una buena idea.

¿Por qué tiene esta garantía? Supongamos que tiene una máquina con 2^16 bytes de memoria, direcciones 0000-FFFF, punteros de 16 bits. Digamos que creó una matriz de 16 bytes. ¿Se podría asignar la memoria en FFF0?

Hay 16 bytes libres de forma contigua, pero:

begin + size == FFF0 + 10 (16 in hex) == 10000 

que envuelve a 0000 debido al tamaño del puntero. Ahora la condición de bucle:

curr < end == FFF0 < 0000 == false 

En lugar de iterar sobre la matriz, el bucle no haría nada. Esto rompería una gran cantidad de código, por lo que el estándar C dice que la asignación no es permisible.

-1

se puede ir mucho más allá de 1 pasada la matriz para example`

int main() 
{ 
     char *string = "string"; 
     int i = 0; 
     for(i=0; i< 10;i++) 
     { 
       printf("%c\n", string[i]); 
     } 
     return 0; 
} 

imprimirá la basura después del final de la cadena de palabras, lo que estaba sentado en la memoria antes de la mano.

+6

Puede imprimir basura, formatear su disco duro o hacer que los demonios salgan volando de su nariz; tal es la naturaleza del Comportamiento Indefinido. – aib

+0

Bueno, simplemente leyendo desde la ubicación de la memoria es poco probable que formatee su disco duro o haga que los demonios salgan volando de su nariz. Escribiéndole, sin embargo ... –

+3

Incluso leer un puntero malo puede hacer que su programa falle en el futuro. Consulte http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx – Eclipse

Cuestiones relacionadas