¿Puedo tomar la dirección del elemento one-past-the-end de una matriz?

Posible duplicado:
Tome la dirección de un elemento de matriz de un extremo al otro a través del subíndice: ¿legal por el estándar de C ++ o no?

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

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

Sí, puede tomar la dirección más allá del final de una matriz, pero no puede desreferenciarla. Para su matriz de 10 elementos, la array+10 funcionaría. Se ha argumentado algunas 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 comstackdor para el cual no funciona, nadie en ninguno de los argumentos ha sido capaz para encontrarlo o citarlo

Editar: Por una vez mi memoria era la mitad correcta – esto era (parte de) un Informe de Defecto oficial para el comité, y al menos algunos miembros del comité (por ejemplo, Tom Plum) pensaron que la redacción había cambiado para que no causara 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, claramente no es un comportamiento indefinido.

Como han indicado otras respuestas, la array[10] expresión array[10] es equivalente a *(array + 10) , lo que parece dar como resultado una desreferenciación 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 deja en claro (6.5.3.2 operadores de dirección e indirección):

El operador unario 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 unario * , 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 todavía se aplican y el resultado no es un valor l. De manera similar, si el operando es el resultado de un operador [] , ni el operador & ni el unario * implícito en [] se evalúa y el resultado es como si el operador & hubiera eliminado y el operador [] se hubiera cambiado a un operador +

Entonces, no hay nada indefinido sobre &array[10] – no hay una operación de desreferencia que tenga lugar.

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

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

Esto es realmente algo bastante simple de responder.

Todo lo que estás 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  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; } 

Comstackr:

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

no debe dar NINGUNA advertencia porque el int * b = & array [10] es válido

De hecho, también lo es la línea subsiguiente que agregué para señalar algo acerca de las matemáticas del puntero.

no solo comstackrá foo, sino que funcionará sin problemas:

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

Básicamente, la syntax de matriz foo [idx] es un atajo y una representación clara de las matemáticas del puntero.

En caso de confusión con respecto a c99, la norma NO afecta a las matemáticas de ninguna manera y está bien definida.

Lo mismo en C99:

 #include  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; } 

Entonces:

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

Productos:

 Pointers are: 0x7fff2c7d22c8, 0x7fff2c7d22c8, 0x7fff2c7d5180