Na początek należy przedstawić dwa pojęcia: deklaracji i definicji.
Deklaracja polega na stworzeniu symbolu w kodzie źródłowym o pewnej widoczności. Może to być nazwa zmiennej, ale również funkcji, klasy itp. Jest ona potrzebna jedynie w trakcie budowania programu.
Definicja zaś, jak sama nazwa wskazuje, definiuje zawartość. Może to być definicja zmiennej, funkcji, klasy. W przypadku zmiennych alokowana jest wtedy również pamięć. Jeśli napiszemy
void funkcja() {
int i;
}
to zadeklarujemy i zdefiniujemy jednocześnie zmienną `i`. Jeśli napiszemy
void funkcja() {
extern int i;
}
to jedynie zadeklarujemy zmienną `i`. Nie będzie ona stworzona w pamięci.
Zmienne lokalne (czyli zadeklarowane w funkcji, bez słowa `static`) są alokowane na stosie, w trakcie wejścia programu do funkcji. Nie ma więc znaczenia, gdzie zdefiniujesz zmienną: w pętli czy poza nią. Wygenerowany kod maszynowy będzie identyczny.
Sytuacja nieco się komplikuje, gdy definiujesz obiekt klasy w pętli. W trakcie definiowania takiej zmiennej wywoływany jest konstruktor, a po wyjściu z zakresu zmiennej, destruktor. Możliwe, że kompilator odpowiednio optymalizuje kod, aby niepotrzebnie nie wywoływać tych funkcji (jeśli przyjmują identyczne wartości za każdym obiegiem), ale nie jestem tego pewien.