¿Por qué la indexación en una matriz comienza con cero en C y no con 1?
¿Por qué la indexación en una matriz comienza con cero en C y no con 1?
Respuestas:
En C, el nombre de una matriz es esencialmente un puntero [pero vea los comentarios] , una referencia a una ubicación de memoria, por lo que la expresión se array[n]
refiere a n
elementos de ubicación de memoria alejados del elemento inicial. Esto significa que el índice se usa como un desplazamiento. El primer elemento de la matriz está contenido exactamente en la ubicación de la memoria a la que se refiere la matriz (0 elementos de distancia), por lo que debe indicarse como array[0]
.
Para más información:
http://developeronline.blogspot.com/2008/04/why-array-index-should-start-from-0.html
sizeof arr
produce el tamaño del objeto de matriz, no el tamaño de un puntero.
sizeof
operador, o el &
operador unario , o es un literal de cadena utilizado para inicializar una matriz, una expresión que tiene tipo" matriz de tipo "se convierte en una expresión con el tipo" puntero para escribir "que apunta al elemento inicial del objeto de matriz y no es un valor. Si el objeto de matriz tiene una clase de almacenamiento de registro, el comportamiento es indefinido. "
Esta pregunta fue publicada hace más de un año, pero aquí va ...
Si bien el artículo de Dijkstra (mencionado anteriormente en una respuesta ahora eliminada ) tiene sentido desde una perspectiva matemática, no es tan relevante cuando se trata de programación.
La decisión tomada por la especificación del lenguaje y los diseñadores del compilador se basa en la decisión tomada por los diseñadores de sistemas informáticos de comenzar a contar en 0.
Citando de una súplica por la paz por Danny Cohen.
Para cualquier base b, los primeros enteros no negativos b ^ N están representados por exactamente N dígitos (incluidos los ceros a la izquierda) solo si la numeración comienza en 0.
Esto se puede probar con bastante facilidad. En base-2, toma 2^3 = 8
El octavo número es:
111
se puede representar usando 3
bits, mientras 1000
que requerirá un bit adicional (4 bits).
Las direcciones de memoria de la computadora tienen 2^N
celdas direccionadas por N
bits. Ahora, si comenzamos a contar en 1, las 2^N
celdas necesitarían N+1
líneas de dirección. Se necesita el bit extra para acceder exactamente a 1 dirección. ( 1000
en el caso anterior). Otra forma de resolverlo sería dejar la última dirección inaccesible y usar N
líneas de dirección.
Ambas son soluciones subóptimas , en comparación con el recuento inicial en 0, que mantendría todas las direcciones accesibles, ¡usando exactamente N
líneas de dirección!
La decisión de comenzar a contar 0
desde entonces ha permeado todos los sistemas digitales , incluido el software que se ejecuta en ellos, porque simplifica la traducción del código a lo que el sistema subyacente puede interpretar. Si no fuera así, habría una operación de traducción innecesaria entre la máquina y el programador, para cada acceso a la matriz. Hace que la compilación sea más fácil.
Citando del periódico:
a[b]
se implementan como *(a+b)
en los primeros compiladores. Incluso hoy todavía puedes escribir en 2[a]
lugar de a[2]
. Ahora, si los índices no comenzaran en 0, a[b]
se convertirían en *(a+b-1)
. Esto habría requerido 2 adiciones en las CPU del tiempo en lugar de 0, lo que significa la mitad de la velocidad. Claramente no es deseable.
Porque 0 es qué tan lejos del puntero a la cabeza de la matriz al primer elemento de la matriz.
Considerar:
int foo[5] = {1,2,3,4,5};
Para acceder a 0 hacemos:
foo[0]
Pero foo se descompone en un puntero, y el acceso anterior tiene una forma aritmética de puntero análogo para acceder a él.
*(foo + 0)
En estos días, la aritmética de puntero no se usa con tanta frecuencia. Sin embargo, en el pasado, era una forma conveniente de tomar una dirección y alejar X "ints" de ese punto de partida. Por supuesto, si quisieras quedarte donde estás, ¡solo agregas 0!
Porque el índice basado en 0 permite ...
array[index]
... para ser implementado como ...
*(array + index)
Si el índice estuviera basado en 1, el compilador necesitaría generar:, *(array + index - 1)
y este "-1" dañaría el rendimiento.
Porque simplificó el compilador y el enlazador (más fácil de escribir).
"... Hacer referencia a la memoria mediante una dirección y un desplazamiento se representa directamente en el hardware en prácticamente todas las arquitecturas de computadora, por lo que este detalle de diseño en C facilita la compilación"
y
"... esto hace que la implementación sea más simple ..."
El índice de matriz siempre comienza con cero. Supongamos que la dirección base es 2000. Ahora arr[i] = *(arr+i)
. Ahora if i= 0
, esto significa *(2000+0
) es igual a la dirección base o la dirección del primer elemento en la matriz. este índice se trata como desplazamiento, por lo que el índice predeterminado comienza desde cero.
Por la misma razón que, cuando es miércoles y alguien te pregunta cuántos días hasta el miércoles, dices 0 en lugar de 1, y que cuando es miércoles y alguien te pregunta cuántos días hasta el jueves, dices 1 en lugar de 2.
La explicación más elegante que he leído para la numeración basada en cero es una observación de que los valores no se almacenan en los lugares marcados en la línea numérica, sino en los espacios entre ellos. El primer elemento se almacena entre cero y uno, el siguiente entre uno y dos, etc. El enésimo elemento se almacena entre N-1 y N. Se puede describir un rango de elementos utilizando los números a cada lado. Los artículos individuales se describen por convención usando los números debajo de él. Si a uno se le asigna un rango (X, Y), la identificación de números individuales usando el número a continuación significa que se puede identificar el primer elemento sin usar ninguna aritmética (es el elemento X), pero se debe restar uno de Y para identificar el último elemento (Y -1). Identificar los elementos con el número anterior facilitaría la identificación del último elemento de un rango (sería el elemento Y)
Aunque no sería horrible identificar elementos basados en el número que se encuentra sobre ellos, definir el primer elemento en el rango (X, Y) como el que está arriba de X generalmente funciona mejor que definirlo como el siguiente (X + 1)
La razón técnica podría derivarse del hecho de que el puntero a una ubicación de memoria de una matriz es el contenido del primer elemento de la matriz. Si declara el puntero con un índice de uno, los programas normalmente agregarían ese valor de uno al puntero para acceder al contenido que no es lo que desea, por supuesto.
Intente acceder a una pantalla de píxeles utilizando las coordenadas X, Y en una matriz basada en 1. La fórmula es completamente compleja. ¿Por qué es complejo? Debido a que terminas convirtiendo las coordenadas X, Y en un número, el desplazamiento. ¿Por qué necesita convertir X, Y en un desplazamiento? Porque así es como se organiza la memoria dentro de las computadoras, como un flujo continuo de celdas de memoria (matrices). ¿Cómo se ocupan las computadoras con las células de la matriz? Uso de desplazamientos (desplazamientos desde la primera celda, un modelo de indexación basado en cero).
Entonces, en algún punto del código que necesita (o el compilador necesita) para convertir la fórmula de 1 base en una fórmula basada en 0 porque así es como las computadoras manejan la memoria.
Supongamos que queremos crear una matriz de tamaño 5
int array [5] = [2,3,5,9,8]
dejemos que el primer elemento de la matriz apunte a la ubicación 100
y consideremos que la indexación comienza desde 1 no desde 0.
ahora tenemos que encontrar la ubicación del primer elemento con la ayuda del índice
(recuerde que la ubicación del primer elemento es 100)
ya que el tamaño de un entero es de 4 bits,
por lo tanto -> considerando el índice 1, la posición sería el
tamaño del índice (1) * tamaño del entero (4) = 4,
por lo que la posición real que nos mostrará es
100 + 4 = 104
lo cual no es cierto porque la ubicación inicial era 100.
Debería apuntar a 100, no a 104,
esto está mal
Supongamos que hemos tomado la indexación desde 0,
entonces la
posición del primer elemento debe ser el
tamaño del índice (0) * tamaño del entero. (4) = 0
por lo tanto -> la
ubicación del primer elemento es 100 + 0 = 100
y esa fue la ubicación real del elemento,
esta es la razón por la cual la indexación comienza en 0;
Espero que aclare tu punto.
Soy de un fondo Java. He presentado la respuesta a esta pregunta en el diagrama a continuación que he escrito en un papel que se explica por sí mismo.
Pasos principales:
Nota : Los bloques que se muestran en la imagen son representaciones de la memoria.
En primer lugar, debe saber que las matrices se consideran internamente como punteros porque el "nombre de la matriz contiene la dirección del primer elemento de la matriz".
ex. int arr[2] = {5,4};
considere que la matriz comienza en la dirección 100, por lo que el primer elemento estará en la dirección 100 y la segunda en 104 ahora, considere que si el índice de la matriz comienza en 1, entonces
arr[1]:-
esto se puede escribir en la expresión de punteros como esta:
arr[1] = *(arr + 1 * (size of single element of array));
considere el tamaño de int es 4bytes, ahora,
arr[1] = *(arr + 1 * (4) );
arr[1] = *(arr + 4);
como sabemos, el nombre de la matriz contiene la dirección de su primer elemento, así que arr = 100 ahora,
arr[1] = *(100 + 4);
arr[1] = *(104);
lo que da,
arr[1] = 4;
Debido a esta expresión, no podemos acceder al elemento en la dirección 100, que es el primer elemento oficial,
ahora considere que el índice de matriz comienza desde 0, entonces
arr[0]:-
esto se resolverá como
arr[0] = *(arr + 0 + (size of type of array));
arr[0] = *(arr + 0 * 4);
arr[0] = *(arr + 0);
arr[0] = *(arr);
ahora, sabemos que el nombre de la matriz contiene la dirección de su primer elemento, entonces,
arr[0] = *(100);
que da el resultado correcto
arr[0] = 5;
por lo tanto, el índice de matriz siempre comienza desde 0 en c.
referencia: todos los detalles están escritos en el libro "El lenguaje de programación C de brian kerninghan y dennis ritchie"
En la matriz, el índice indica la distancia desde el elemento inicial. Entonces, el primer elemento está a 0 distancia del elemento inicial. Entonces, es por eso que la matriz comienza desde 0.
Es porque address
tiene que apuntar a la derecha element
en la matriz. Asumamos la siguiente matriz:
let arr = [10, 20, 40, 60];
Consideremos ahora el inicio de la dirección 12
y el tamaño del element
ser 4 bytes
.
address of arr[0] = 12 + (0 * 4) => 12
address of arr[1] = 12 + (1 * 4) => 16
address of arr[2] = 12 + (2 * 4) => 20
address of arr[3] = 12 + (3 * 4) => 24
Si no fuera así zero-based
, técnicamente nuestra primera dirección de elemento en el array
sería la 16
que está mal como es su ubicación 12
.
El nombre de la matriz es un puntero constante que apunta a la dirección base. Cuando usa arr [i], el compilador lo manipula como * (arr + i). Dado que el rango int es -128 a 127, el compilador piensa que -128 a -1 son los números negativos y del 0 al 128 son números positivos, por lo que el índice de matriz siempre comienza con cero.
int
requiere un tipo para admitir al menos un rango de 16 bits, y en la mayoría de los sistemas actualmente admite 32 bits. Creo que su lógica es defectuosa, y su respuesta realmente no mejora en las otras respuestas ya proporcionadas por otras personas. Sugiero eliminar esto.