Aqui está minha opinião sobre isso:
O desenvolvimento da linguagem C oferece alguns insights sobre a evolução do tipo de array em C:
Vou tentar delinear a coisa do array:
Os precursores B e BCPL de C não tinham um tipo de array distinto, uma declaração como:
auto V[10] (B)
or
let V = vec 10 (BCPL)
declararia que V é um ponteiro (não digitado) que é inicializado para apontar para uma região não utilizada de 10 "palavras" de memória. B já utilizado *
para dereferencing ponteiro e teve a []
notação mão curta, *(V+i)
significava V[i]
, assim como hoje C / C ++. Porém, V
não é um array, é ainda um ponteiro que deve apontar para alguma memória. Isso causou problemas quando Dennis Ritchie tentou estender B com tipos de estrutura. Ele queria que os arrays fizessem parte dos structs, como em C hoje:
struct {
int inumber;
char name[14];
};
Mas com o conceito B, BCPL de matrizes como ponteiros, isso exigiria que o name
campo contivesse um ponteiro que deveria ser inicializado em tempo de execução para uma região de memória de 14 bytes dentro da estrutura. O problema de inicialização / layout foi eventualmente resolvido dando aos arrays um tratamento especial: O compilador rastreia a localização dos arrays nas estruturas, na pilha, etc. sem realmente exigir que o ponteiro para os dados se materializem, exceto em expressões que envolvem os arrays. Esse tratamento permitiu que quase todo o código B ainda rodasse e é a fonte da regra "arrays convertidos em ponteiro se você olhar para eles" . É um hack de compatibilidade, que acabou sendo muito útil, pois permitia arrays de tamanho aberto etc.
E aqui está o meu palpite de por que array não pode ser atribuído: como arrays eram ponteiros em B, você poderia simplesmente escrever:
auto V[10];
V=V+5;
para rebase uma "matriz". Isso agora não tinha sentido, porque a base de uma variável de matriz não era mais um lvalue. Portanto, essa atribuição foi rejeitada, o que ajudou a capturar os poucos programas que faziam essa rebase nas matrizes declaradas. E então essa noção pegou: como os arrays nunca foram projetados para serem citados de primeira classe no sistema de tipo C, eles foram tratados como bestas especiais que se tornam ponteiros se você usá-los. E de um certo ponto de vista (que ignora que C-arrays são um hack malfeito), desabilitar a atribuição de array ainda faz algum sentido: um array aberto ou um parâmetro de função de array é tratado como um ponteiro sem informações de tamanho. O compilador não tem as informações para gerar uma atribuição de array para eles e a atribuição do ponteiro foi necessária por motivos de compatibilidade.
typedef int vec[3];
void f(vec a, vec b)
{
vec x,y;
a=b;
x=y;
a=x;
x=a;
}
Isso não mudou quando uma revisão de C em 1978 adicionou atribuição de estrutura ( http://cm.bell-labs.com/cm/cs/who/dmr/cchanges.pdf ). Mesmo que os registros fossem tipos distintos em C, não era possível atribuí-los no K&R C. Você tinha que copiá-los por meio de membros com memcpy e podia passar apenas ponteiros para eles como parâmetros de função. A atribuição (e a passagem de parâmetro) agora era simplesmente definida como o memcpy da memória bruta da estrutura e, como isso não poderia quebrar o código existente, foi prontamente adaptado. Como um efeito colateral não intencional, isso implicitamente introduziu algum tipo de atribuição de array, mas isso aconteceu em algum lugar dentro de uma estrutura, então isso não poderia realmente apresentar problemas com a maneira como os arrays eram usados.