2010-06-29 9 views
11

Duplicar posibles:
Take the address of a one-past-the-end array element via subscript: legal by the C++ Standard or not?¿Puedo tomar la dirección del elemento one-past-the-end de una matriz?

int array[10]; 

int* a = array + 10; // well-defined 
int* b = &array[10]; // not sure... 

es la última línea válida o no?

+2

Dupe del legendario http://stackoverflow.com/questions/988158/ take-the-address-of-a-one-past-the-end-array-element-via-subscript-legal-by-the –

+0

@Johannes - Tienes razón, votando para cerrar. – Omnifarious

Respuesta

19

Sí, puede tomar la dirección más allá del final de una matriz, pero no puede desreferenciarla. Para su matriz de 10 elementos, array+10 funcionaría. Se ha argumentado varias veces (por el comité, entre otros) si &array[10] realmente causa un comportamiento indefinido o no (y si lo hace, si realmente debería). El resultado final es que al menos de acuerdo con los estándares actuales (tanto C como C++) oficialmente causa un comportamiento indefinido, pero si hay un único compilador para el cual no funciona, nadie en ninguno de los argumentos ha sido capaz para encontrarlo o citarlo

Editar: Para una vez que mi memoria era la mitad correcta - esto era (parte de) un funcionario Defect Report al comité, y al menos algunos miembros del comité (por ejemplo, Tom ciruela) pensó que el texto había sido cambiado por lo que sería no causa un comportamiento indefinido. OTOH, el DR data de 2000, y el estado sigue siendo "Drafting", por lo que está abierto a cuestionarse si realmente está arreglado, o si es probable que lo sea (no he examinado N3090/3092 para descubrirlo).

En C99, sin embargo, es claramente no comportamiento indefinido.

+1

Buena respuesta. Como un punto interesante de la historia, en realidad vi un compilador de C que no eliminó correctamente la referencia y la matriz [N]. Estaba en HP RTE en un marco principal HP-1000.Había establecido una "valla" de memoria justo encima de mi matriz, por lo que la dirección de referencia no existía en el espacio de direcciones del programa. Esto fue incluso antes del estándar C de 1989, por lo que creo que es seguro decir que este compilador ya no existe. –

+0

El idioma de esa DR no está en N3092. Aunque no puedo encontrarlos ahora, hay varios DR _closed_ que se basan en el lenguaje "lvalue vacío" en la resolución propuesta para ese defecto ... –

1

No. No está definido. array[10] asciende a *(array + 10). En otras palabras, ha desreferenciado un puntero no válido.

+3

Pero no lo desreferencia ... –

+1

@clmh Existe un debate definitivo sobre si '& * p' técnicamente constituye un no-op, o una desreferencia seguida de una dirección-de. –

+1

'& array [10]' es legal y no desreferencia al elemento. –

2

array[10] es equivalente a *(array + 10) (y también equivalente a 10[array]), SO &array[10] actúa como la eliminación de la * de *(array+10). Cualquier compilador decente debería emitir el mismo código (y la misma advertencia).

8

Como han indicado otras respuestas, la expresión array[10] es equivalente a *(array + 10), lo que parece dar como resultado una desreferencia indefinida del elemento justo después del final de la matriz. Sin embargo, la expresión &array[10] es equivalente a &*(array + 10), y el estándar C99 hace (6.5.3.2 operadores de dirección y de indirección) borrar:

El & operador unitario devuelve la dirección de su operando. Si el operando tiene el tipo '' tipo '', el resultado tiene el tipo '' puntero para escribir ''. Si el operando es el resultado de un operador único *, ni ese operador ni el operador & se evalúan y el resultado es como si ambos se hubieran omitido, excepto que las restricciones sobre los operadores aún se aplican y el resultado no es un valor l. De forma similar, si el operando es el resultado de un operador [], ni el operador & ni el * unificado que está implícito en el [] se evalúa y el resultado es como si el operador & se hubiera eliminado y el operador [] se hubiera cambiado a un operador + .

Por lo tanto, no hay nada indefinido en &array[10] - no se produce ninguna operación de desreferencia.

+5

C99 no es C++. –

-2

Esto es realmente una cosa bastante simple de responder.

Todo lo que está haciendo es matemáticas de puntero, no hay nada inválido al respecto. Si intenta USAR los punteros resultantes de alguna manera, entonces depende de si su proceso tiene acceso a la memoria apuntada por ese puntero y, de ser así, ¿cuáles son sus permisos?

foo.cc:

#include <iostream> 

using namespace std; 
int main() { 
     int array[10]; 
     int *a = array + 10; 
     int *b = &array[10]; 
     int *c = &array[3000]; 

     cerr << "Pointers values are: " << a << " " << b << " " << c << endl; 
     return 0; 
} 

Para compilar:

g++ -Werror -Wall foo.cc -o foo 

debe producir ninguna advertencia porque el int * b = & array [10] es válida

en realidad tan es la línea subsiguiente agregada por mí para simplemente señalar algo acerca de matemáticas de puntero.

no sólo compilar foo, se ejecutará sin problemas:

./foo 
    Pointers are: 0x7fff1d356e68 0x7fff1d356e68 0x7fff1d359d20 

Básicamente gama sintaxis foo [idx] se corta y representación limpia de matemáticas puntero.

En caso de confusión con respecto a c99, la norma NO afecta a esta matemática de todos modos y está bien definida.

Lo mismo en C99:

#include <stdio.h> 

int main() { 
     int array[10]; 
     int *a = array + 10; 
     int *b = &array[10]; 
     int *c = &array[3000]; 

     fprintf(stderr, "Pointers are: %p, %p, %p\n" , a , b , c); 
     return 0; 
} 

continuación:

gcc -std=c99 -Wall -Werror -o foo foo.c 

./foo 

Salidas:

Pointers are: 0x7fff2c7d22c8, 0x7fff2c7d22c8, 0x7fff2c7d5180 
Cuestiones relacionadas