Ecco la mia opinione:
Lo sviluppo del linguaggio C offre alcune informazioni sull'evoluzione del tipo di array in C:
Proverò a delineare la cosa dell'array:
I precursori di C B e BCPL non avevano un tipo di array distinto, una dichiarazione come:
auto V[10] (B)
or
let V = vec 10 (BCPL)
dichiarerebbe che V è un puntatore (non tipizzato) inizializzato per puntare a una regione inutilizzata di 10 "parole" di memoria. B già utilizzato *
per la dereferenziazione del puntatore e aveva la []
notazione a mano abbreviata, *(V+i)
intesa V[i]
proprio come in C / C ++ oggi. Tuttavia, V
non è un array, è ancora un puntatore che deve puntare a un po 'di memoria. Ciò ha causato problemi quando Dennis Ritchie ha cercato di estendere B con i tipi di struttura. Voleva che gli array facessero parte delle strutture, come in C oggi:
struct {
int inumber;
char name[14];
};
Ma con il concetto B, BCPL di array come puntatori, ciò avrebbe richiesto che il name
campo contenesse un puntatore che doveva essere inizializzato in fase di esecuzione su una regione di memoria di 14 byte all'interno della struttura. Il problema di inizializzazione / layout è stato infine risolto dando agli array un trattamento speciale: il compilatore avrebbe tracciato la posizione degli array nelle strutture, nello stack ecc. Senza effettivamente richiedere che il puntatore ai dati si materializzasse, tranne che nelle espressioni che coinvolgono gli array. Questo trattamento ha permesso a quasi tutto il codice B di funzionare ancora ed è la fonte della regola "gli array si convertono in puntatori se li si guarda" . È un trucco di compatibilità, che si è rivelato molto utile, perché consentiva array di dimensioni aperte ecc.
Ed ecco la mia ipotesi sul motivo per cui l'array non può essere assegnato: poiché gli array erano puntatori in B, potresti semplicemente scrivere:
auto V[10];
V=V+5;
per rebase un "array". Questo ora non aveva più senso, perché la base di una variabile array non era più un lvalue. Quindi questa assegnazione non è stata consentita, il che ha aiutato a catturare i pochi programmi che hanno fatto questo rebasing su array dichiarati. E poi questa nozione è rimasta bloccata: poiché gli array non sono mai stati progettati per essere citati in prima classe dal sistema di tipo C, sono stati per lo più trattati come bestie speciali che diventano puntatori se vengono utilizzati. E da un certo punto di vista (che ignora che gli array C sono un trucco mal riuscito), non consentire l'assegnazione di array ha ancora un senso: un array aperto o un parametro di funzione di array viene trattato come un puntatore senza informazioni sulla dimensione. Il compilatore non dispone delle informazioni per generare un'assegnazione di matrice per loro e l'assegnazione del puntatore era richiesta per motivi di compatibilità.
typedef int vec[3];
void f(vec a, vec b)
{
vec x,y;
a=b;
x=y;
a=x;
x=a;
}
Ciò non cambiò quando una revisione di C nel 1978 aggiunse l'assegnazione della struttura ( http://cm.bell-labs.com/cm/cs/who/dmr/cchanges.pdf ). Anche se i record erano tipi distinti in C, non era possibile assegnarli all'inizio di K&R C. Bisognava copiarli a livello di membro con memcpy e si potevano passare solo puntatori ad essi come parametri di funzione. L'assegnazione (e il passaggio di parametri) era ora semplicemente definita come la memcpy della memoria grezza della struttura e poiché questo non poteva rompere il codice esistente, veniva prontamente adattata. Come effetto collaterale non intenzionale, questo ha implicitamente introdotto una sorta di assegnazione di array, ma è successo da qualche parte all'interno di una struttura, quindi questo non poteva davvero introdurre problemi con il modo in cui venivano usati gli array.