Oto moje spojrzenie na to:
Rozwój języka C oferuje pewien wgląd w ewolucję typu tablic w języku C:
Spróbuję zarysować tablicę:
Prekursory C, B i BCPL, nie miały odrębnego typu tablicy, deklaracja taka jak:
auto V[10] (B)
or
let V = vec 10 (BCPL)
zadeklarowałby V jako (bez typu) wskaźnik, który jest zainicjowany, aby wskazywać na nieużywany obszar 10 „słów” pamięci. B już używany *
dla wskaźnika dereferencing i miał []
zapis krótkiej strony, *(V+i)
oznaczałoV[i]
, tak jak dzisiaj C / C ++. Jednak V
nie jest tablicą, to nadal jest wskaźnikiem, który musi wskazywać na jakąś pamięć. Spowodowało to problemy, gdy Dennis Ritchie próbował rozszerzyć B za pomocą typów struktur. Chciał, aby tablice były częścią struktur, tak jak dzisiaj w C:
struct {
int inumber;
char name[14];
};
Ale z koncepcją B, BCPL tablic jako wskaźników, wymagałoby to, name
aby pole zawierało wskaźnik, który musiałby być zainicjowany w czasie wykonywania do obszaru pamięci 14 bajtów w strukturze. Problem inicjalizacji / układu został ostatecznie rozwiązany przez nadanie tablicom specjalnego traktowania: kompilator śledziłby położenie tablic w strukturach, na stosie itp. Bez konieczności materializacji wskaźnika do danych, z wyjątkiem wyrażeń, które obejmują tablice. To traktowanie pozwoliło na to, aby prawie cały kod B nadal działał i jest źródłem reguły „tablice konwertowane na wskaźnik, jeśli na nie spojrzysz” . Jest to hack kompatybilności, który okazał się bardzo przydatny, ponieważ pozwalał na tablice o otwartym rozmiarze itp.
A oto moje przypuszczenie, dlaczego nie można przypisać tablicy: Ponieważ tablice były wskaźnikami w B, możesz po prostu napisać:
auto V[10];
V=V+5;
aby zmienić bazę „tablicy”. To było teraz bez znaczenia, ponieważ podstawa zmiennej tablicowej nie była już lwartością. Więc to przypisanie było niedozwolone, co pomogło wyłapać kilka programów, które dokonały tego ponownego bazowania na zadeklarowanych tablicach. I wtedy to pojęcie utknęło: ponieważ tablice nigdy nie były zaprojektowane tak, aby były pierwszej klasy cytowane w systemie typu C, były one głównie traktowane jako specjalne bestie, które stały się wskaźnikami, jeśli ich użyjesz. I z pewnego punktu widzenia (który ignoruje fakt, że tablice C to nieudany hack), zakazanie przypisywania tablicy nadal ma sens: otwarta tablica lub parametr funkcji tablicy są traktowane jako wskaźnik bez informacji o rozmiarze. Kompilator nie ma informacji do wygenerowania przypisania tablicy dla nich, a przypisanie wskaźnika było wymagane ze względu na zgodność.
typedef int vec[3];
void f(vec a, vec b)
{
vec x,y;
a=b;
x=y;
a=x;
x=a;
}
Nie zmieniło się to, gdy wersja C w 1978 roku dodała przypisanie struktury ( http://cm.bell-labs.com/cm/cs/who/dmr/cchanges.pdf ). Mimo że rekordy były odrębnymi typami w C, nie było możliwe przypisanie ich we wczesnym K&R C. Trzeba było je kopiować według elementów członkowskich za pomocą memcpy i można było przekazywać do nich tylko wskaźniki jako parametry funkcji. Przypisanie (i przekazywanie parametrów) zostało teraz po prostu zdefiniowane jako memcpy surowej pamięci struktury, a ponieważ nie mogło to zepsuć istniejącego kodu, zostało łatwo zaadoptowane. Jako niezamierzony efekt uboczny, to pośrednio wprowadziło jakiś rodzaj przypisania tablicy, ale miało to miejsce gdzieś wewnątrz struktury, więc nie mogło to wprowadzić problemów ze sposobem używania tablic.