2013-03-09 13 views
6

Mieliśmy projekt szkolny, każdy system informacyjny używający C. Aby zachować listę rekordów studentów o dynamicznym rozmiarze, wybrałem strukturę danych z listą linków. Dziś rano mój przyjaciel pozwolił mi zobaczyć jego system. Byłem zaskoczony jego listy rekordów:C globalna niezasilana tablica?

#include <stdio.h> 
/* and the rest of the includes */ 

/* global unsized array */ 
int array[]; 

int main() 
{ 
    int n; 
    for (n=0; n < 5; n ++) { 
     array[n] = n; 
    } 


    for (n=0; n < 5; n ++) { 
     printf("array[%d] = %d\n", n, array[n]); 
    } 
    return 0; 
} 

Jak z kodem, oświadczył się niezagruntowanej tablicę, która jest globalnym (w segmencie BSS) do całego programu. Był w stanie dodawać nowych wpisów do tablicy przez nadpisanie kolejnych bloków pamięci o wartości innej niż zero, tak że może on przechodzić przez układ wygląda następująco:

for (n=0; array[n]; n++) { 
    /* do something */ 
} 

Używał (ja również przetestowane go) Turbo C v1 . Próbowałem go w Linuksie i działa.

Ponieważ nigdy wcześniej nie spotkałem się z tą techniką, przypuszczam, że jest z nią jakiś problem. Więc, tak, chcę wiedzieć, dlaczego to zły pomysł i dlaczego wolisz to od połączonej listy.

+1

Jest to to samo, co pisanie do dowolnej tablicy poza granicami - niezdefiniowane. – teppic

+0

czy to ma być C99? –

+0

1der Sprawdź aktualność aktualizacji teppic.i otwórz link do skryptu kodującego, możesz obserwować niezdefiniowane zachowanie C w kodzie. –

Odpowiedz

6
int array[]; 

technicznie znany jako tablicę z niekompletnym typu. Mówiąc najprościej jest to równoważne:

int array[1]; 

To nie jest dobre tylko dlatego, że:

  1. To powoduje zachowanie niezdefiniowane. Podstawowym zastosowaniem macierzy z niepełnym typem jest Struct Hack. Zauważ, że niekompletne typy tablic są standaryzowane w C99 i są niedozwolone wcześniej.
+0

Czy to nie tylko UB, ponieważ GCC mówi 'source.c: 4: 5: warning: array 'array' zakłada się, że ma jeden element [włączony domyślnie]' co oznaczałoby, że pisałby poza granicami tablicy idąc dalej niż 1 element? –

+2

To nie jest VLA, to po prostu zapisywanie do losowego adresu w pamięci. – teppic

+0

@teppic, Tony: Yup, zmodyfikowany tak, aby odzwierciedlał poprawność. –

3

To jest Niezdefiniowane zachowanie. Piszemy do nieprzydzielonej pamięci (poza tablicę). Aby to skompilować, kompilator alokuje co najmniej jeden element, a Ty piszesz dalej. Wypróbuj znacznie większy zakres liczb. Na przykład, jeśli uruchomię twój kod na Linuksie, to działa, ale jeśli zmienię pętlę na 50 000, ulegnie awarii.

EDIT Kod może działać dla małych wartości n, ale w przypadku większych wartości nie powiedzie się. Aby to pokazać, napisałem Twój kod i przetestowałem go pod kątem n = 1000.

Oto link do CODEPAD, i widać, że dla n = 1000 dzieje się błąd segmentacji .

Podczas gdy ten sam kod z tym samym kompilatorem działa dla n = 10, zobacz ten link CODEPAD. To się nazywa Niezdefiniowane zachowanie.

+0

Dodam trochę więcej szczegółów w twojej odpowiedzi, aby zademonstrować niezdefiniowane zachowanie dla kodu. Mam nadzieję że ci się spodoba. Jeśli nie, możesz wrócić do swojej wersji –

+0

@GrijeshChauhan: ok, po prostu dokonam niewielkiej edycji. – teppic

+0

tak, proszę bardzo. :) –

1

Jeśli używasz powiązanych list, możesz sprawdzić, czy pamięć została przydzielona poprawnie.

int *ptr; 
ptr = (int *)malloc(sizeof(int)) 
if(ptr==NULL) 
{ 
    printf("No Memory!!!"); 
} 

Ale z kodem program po prostu ulega awarii, jeśli testowany z tablicą o dużej granicy.