Me he encontrado con una experiencia extraña en la programación en C. Considera este código:
int main(){
int array1[6] = {0, 1, 2, 3, 4, 5};
int array2[6] = {6, 7, 8, 9, 10, 11};
printf("%d\n", array1[-1]);
return 0;
}
Cuando compilo y ejecuto esto, no recibo ningún error o advertencia. Como dijo mi profesor, el índice de matriz -1
accede a otra variable. Todavía estoy confundido, ¿por qué demonios un lenguaje de programación tiene esta capacidad? Quiero decir, ¿por qué permitir índices de matriz negativos?
programming-languages
arrays
c
Mohammed Fawzan
fuente
fuente
-1
hacer referencia al elemento de una submatriz es una forma perfectamente válida de referirse al elemento antes de esa matriz en la matriz más grande. La otra es que si el índice no es válido, el programa no es válido, pero en la mayoría de las implementaciones obtendrá un mal comportamiento silencioso, no un error fuera de rango.Respuestas:
La operación de indexación de matriz
a[i]
adquiere su significado a partir de las siguientes características de CLa sintaxis
a[i]
es equivalente a*(a + i)
. Por lo tanto, es válido decir5[a]
para llegar al quinto elemento dea
.La aritmética de puntero dice que dado un puntero
p
y un enteroi
,p + i
el punterop
avanza pori * sizeof(*p)
bytesEl nombre de una matriz
a
se convierte rápidamente en un puntero al elemento 0 dea
En efecto, la indexación de matrices es un caso especial de indexación de puntero. Dado que un puntero puede apuntar a cualquier lugar dentro de una matriz, cualquier expresión arbitraria que parezca no
p[-1]
está mal por examen, por lo que los compiladores no (no pueden) considerar todas esas expresiones como errores.Su ejemplo
a[-1]
dondea
realmente es el nombre de una matriz es realmente inválido. IIRC, no está definido si hay un valor de puntero significativo como resultado de la expresióna - 1
dondea
se sabe que es un puntero al elemento 0 de una matriz. Entonces, un compilador inteligente podría detectar esto y marcarlo como un error. Otros compiladores pueden seguir cumpliendo mientras le permiten dispararse en el pie al darle un puntero a una ranura de pila aleatoria.La respuesta informática es:
En C, el
[]
operador se define en punteros, no en matrices. En particular, se define en términos de aritmética de puntero y desreferencia de puntero.En C, un puntero es abstractamente una tupla
(start, length, offset)
con la condición de que0 <= offset <= length
. La aritmética del puntero es esencialmente aritmética elevada en el desplazamiento, con la advertencia de que si el resultado de la operación viola la condición del puntero, es un valor indefinido. Desreferenciar un puntero agrega una restricción adicional queoffset < length
.C tiene una noción de
undefined behaviour
que permite a un compilador representar concretamente esa tupla como un número único, y no tener que detectar ninguna violación de la condición del puntero. Cualquier programa que satisfaga la semántica abstracta estará seguro con la semántica concreta (con pérdida). Cualquier cosa que viole la semántica abstracta puede ser aceptada, sin comentarios, por el compilador y puede hacer cualquier cosa que quiera hacer con ella.fuente
Las matrices se presentan simplemente como fragmentos contiguos de memoria. Un acceso a una matriz tal como una [i] se convierte en un acceso a la ubicación de memoria AddressOf (a) + i. Este código
a[-1]
es perfectamente comprensible, simplemente se refiere a la dirección anterior al inicio de la matriz.Esto puede parecer una locura, pero hay muchas razones por las cuales esto está permitido:
a[-1]
es válido. Por ejemplo, si sé que ena
realidad no es el comienzo de la matriz, sino un puntero en el medio de la matriz,a[-1]
simplemente obtiene el elemento de la matriz que está a la izquierda del puntero.fuente
a[-1]
tiene mucho sentido para algunos casos dea
, en este caso particular, es completamente ilegal (pero no compilado por el compilador)Como explican las otras respuestas, este es un comportamiento indefinido en C. Considere que C se definió (y se usa principalmente) como un "ensamblador de alto nivel". Los usuarios de C lo valoran por su velocidad inquebrantable, y verificar cosas en tiempo de ejecución está (en su mayoría) fuera de discusión por el mero rendimiento. Algunas construcciones de C que parecen absurdas para las personas que provienen de otros lenguajes tienen perfecto sentido en C, como este
a[-1]
. Sí, no siempre tiene sentido (fuente
Se puede usar dicha función para escribir métodos de asignación de memoria que accedan a la memoria directamente. Uno de estos usos es verificar el bloque de memoria anterior utilizando un índice de matriz negativo para determinar si los dos bloques pueden fusionarse. He usado esta función cuando desarrollo un administrador de memoria no volátil.
fuente
C no está fuertemente tipado. Un compilador de C estándar no verificaría los límites de la matriz. La otra cosa es que una matriz en C no es más que un bloque contiguo de memoria y la indexación comienza en 0, por lo que un índice de -1 es la ubicación de cualquier patrón de bits anterior
a[0]
.Otros idiomas explotan los índices negativos de una manera agradable. En Python,
a[-1]
devolverá el último elemento,a[-2]
devolverá el penúltimo elemento, etc.fuente
int
, por lo quea[-5]
, en general,int i; ... a[i] = ...;
se escriben correctamente. Los errores de índice solo se detectan en tiempo de ejecución. Por supuesto, un compilador inteligente puede detectar algunas violaciones.En palabras simples:
Todas las variables (incluidas las matrices) en C se almacenan en la memoria. Digamos que tiene 14 bytes de "memoria" e inicializa lo siguiente:
Además, considere el tamaño de un int como 2 bytes. Luego, hipotéticamente, en los primeros 2 bytes de memoria se guardará el entero a. En los siguientes 2 bytes se guardará el entero de la primera posición de la matriz (eso significa matriz [0]).
Entonces, cuando dices matriz [-1] es como referirse al entero guardado en la memoria que está justo antes de la matriz [0], que en nuestro es, hipotéticamente, entero a. En realidad, esta no es exactamente la forma en que las variables se almacenan en la memoria.
fuente
fuente