Esta es mi opinión al respecto:
El desarrollo del lenguaje C ofrece una idea de la evolución del tipo de matriz en C:
Intentaré delinear lo de la matriz:
Los precursores B y BCPL de C no tenían un tipo de matriz distinto, una declaración como:
auto V[10] (B)
or
let V = vec 10 (BCPL)
declararía que V es un puntero (sin tipo) que se inicializa para apuntar a una región no utilizada de 10 "palabras" de memoria. B ya se usaba *
para desreferenciar punteros y tenía la []
notación abreviada, es *(V+i)
decir V[i]
, al igual que en C / C ++ hoy. Sin embargo, V
no es una matriz, sigue siendo un puntero que tiene que apuntar a algo de memoria. Esto causó problemas cuando Dennis Ritchie intentó extender B con tipos de estructura. Quería que las matrices fueran parte de las estructuras, como en C hoy:
struct {
int inumber;
char name[14];
};
Pero con el concepto B, BCPL de matrices como punteros, esto habría requerido que el name
campo contuviera un puntero que tenía que inicializarse en tiempo de ejecución a una región de memoria de 14 bytes dentro de la estructura. El problema de inicialización / diseño finalmente se resolvió dándole a las matrices un tratamiento especial: el compilador rastrearía la ubicación de las matrices en estructuras, en la pila, etc.sin requerir realmente que el puntero a los datos se materialice, excepto en expresiones que involucren las matrices. Este tratamiento permitió que casi todo el código B aún se ejecutara y es la fuente de la regla "las matrices se convierten en puntero si las observa" . Es un truco de compatibilidad, que resultó ser muy útil, porque permitía matrices de tamaño abierto, etc.
Y aquí está mi suposición de por qué no se puede asignar una matriz: dado que las matrices eran punteros en B, simplemente podría escribir:
auto V[10];
V=V+5;
para reajustar una "matriz". Esto ahora no tenía sentido, porque la base de una variable de matriz ya no era un lvalue. Así que esta asignación fue rechazada, lo que ayudó a capturar los pocos programas que hicieron este rebase en matrices declaradas.. Y luego esta noción se atascó: como las matrices nunca fueron diseñadas para ser citadas de primera clase del sistema de tipo C, en su mayoría fueron tratadas como bestias especiales que se convierten en punteros si las usa. Y desde cierto punto de vista (que ignora que las matrices C son un truco fallido), rechazar la asignación de matrices todavía tiene algún sentido: una matriz abierta o un parámetro de función de matriz se trata como un puntero sin información de tamaño. El compilador no tiene la información para generar una asignación de matriz para ellos y la asignación de puntero fue requerida por razones de compatibilidad.
typedef int vec[3];
void f(vec a, vec b)
{
vec x,y;
a=b;
x=y;
a=x;
x=a;
}
Esto no cambió cuando una revisión de C en 1978 agregó la asignación de estructuras ( http://cm.bell-labs.com/cm/cs/who/dmr/cchanges.pdf ). Aunque los registros fueron tipos distintos en C, no era posible asignarlos en K&R C. Tenías que copiarlos por miembros con memcpy y solo podías pasarles punteros como parámetros de función. La asignación (y el paso de parámetros) ahora se definió simplemente como la memoria en bruto de la estructura de la estructura y, dado que esto no podía romper el código existente, se adaptó fácilmente. Como efecto secundario involuntario, esto introdujo implícitamente algún tipo de asignación de matriz, pero esto sucedió en algún lugar dentro de una estructura, por lo que esto realmente no podría presentar problemas con la forma en que se usaban las matrices.