Zacznijmy od konstrukcji:
int tab[n];
to jest to poprawne, od standardu C99, i nazywa się VLA. Nie ma takiego czegoś dla ANSI/ISO C (C89/C90). Także żadna wersja C++ nie definiuje VLA. Lepiej jednak tego unikać - nie każdy kompilator to obsługuje, no i zupełnie nie działa tak, jak Ci się wydaje, i próbujesz to zastosować w przedstawionym kodzie.
Jeżeli chodzi o tablicę na zero elementów. To już nie jest poprawne.
Link: http://stackoverflow.com/questions/9722632/what-happens-if-i-define-a-0-size-array-in-c-c
Jednak skoro na gcc działa, spójrzmy na sizeof():
int tab[0];
printf("%d", sizeof(tab));
wyświetla 0! W ten sposób nie masz pamięci w ogóle. Nie możesz pod tym adresem nic pisać.
Dalej. Zmiana wartości zmiennej n nie wpływa w żaden sposób na zadeklarowaną wcześniej tablicę. Nadal masz pamięć tylko na 0 elementów. Tablica została już zadeklarowana, przydzielono jej pamięć ze stosu - “stało się”. Teraz jej rozmiaru już zmienić się nie da. Zmiana wartości zmiennej, która posłużyła do utworzenia tej tablicy nic nie da.
int a = 3;
int b = 4;
int c = a+b;
a = 99;
To jest tak, jakbyś oczekiwał tutaj, że po zmianie wartości zmiennej “a” w czwartej linii ulegnie zmianie także suma “c”, obliczona linię wcześniej. Bez sensu, prawda?
Podsumowując - “dlaczego działa?” - otóż NIE DZIAŁA! Działa całkiem przypadkiem. Piszesz po pamięci, która nie jest Twoja - wykraczasz poza przydzieloną pamięć, czego robić nie wolno. Przy odpowiednio dużym zakresie na pewno w końcu program się wysypie - natrafisz na pamięć chronioną przez system i skończy się to crashem.
Jak będziesz miał pecha to stanie się tak bardzo szybko.
Jeżeli więc zachodzi potrzeba posiadania tablicy, którą można rozszerzyć szukać należy w innym kierunku. To już inny temat. Hasła kluczowe tutaj to: “dynamiczne alokowanie pamięci”, “zarządzanie pamięcią”, “dynamiczny przydział pamięci”. Interesujące funkcje: malloc, calloc, realloc, free.
Jeżeli potrzebujesz pamięć, której wielkość nie jest znana w momencie kompilacji także raczej skorzystaj z dynamicznej alokacji, zamiast używać VLA. Nawet jak nie potrzebujesz przydzielonego rozmiaru pamięci później zmieniać.
Więcej o VLA i różnicy pomiędzy tym, a dynamiczną alokacją: http://gynvael.coldwind.pl/?id=300