C Language
Inicjalizacja
Szukaj…
Inicjalizacja zmiennych w C
W przypadku braku wyraźnej inicjalizacji gwarantuje się, że zmienne zewnętrzne i static
zostaną zainicjowane na zero; zmienne automatyczne (w tym zmienne register
) mają nieokreślone 1 (tj. śmieci) wartości początkowe.
Zmienne skalarne mogą być inicjowane, jeśli są zdefiniowane przez podążanie za nazwą ze znakiem równości i wyrażeniem:
int x = 1;
char squota = '\'';
long day = 1000L * 60L * 60L * 24L; /* milliseconds/day */
W przypadku zmiennych zewnętrznych i static
inicjatorem musi być stałe wyrażenie 2 ; inicjalizacja jest wykonywana raz, koncepcyjnie, zanim program rozpocznie wykonywanie.
W przypadku zmiennych automatycznych i register
inicjator nie ogranicza się do stałej: może to być dowolne wyrażenie obejmujące wcześniej zdefiniowane wartości, nawet wywołania funkcji.
Na przykład zobacz fragment kodu poniżej
int binsearch(int x, int v[], int n)
{
int low = 0;
int high = n - 1;
int mid;
...
}
zamiast
int low, high, mid;
low = 0;
high = n - 1;
W rezultacie inicjalizacja zmiennych automatycznych jest tylko skrótem dla instrukcji przypisania. Wybór preferowanej formy jest w dużej mierze kwestią gustu. Zazwyczaj używamy jawnych przypisań, ponieważ inicjalizatory w deklaracjach są trudniejsze do zauważenia i znajdują się dalej od miejsca użycia. Z drugiej strony zmienne powinny być deklarowane tylko wtedy, gdy mają być użyte, o ile to możliwe.
Inicjowanie tablicy:
Tablicę można zainicjować, postępując zgodnie z jej deklaracją za pomocą listy inicjatorów zamkniętych w nawiasy klamrowe i oddzielonych przecinkami.
Na przykład, aby zainicjować tablicę dni liczbą dni w każdym miesiącu:
int days_of_month[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
(Uwaga: w tej strukturze styczeń jest zakodowany jako miesiąc zero).
Gdy pominie się rozmiar tablicy, kompilator obliczy długość, zliczając inicjatory, których w tym przypadku jest 12.
Jeśli dla tablicy jest mniej inicjatorów niż podany rozmiar, pozostałe będą zerowe dla wszystkich typów zmiennych.
Błędem jest mieć zbyt wiele inicjatorów. Nie ma standardowego sposobu na określenie powtarzania inicjalizatora - ale GCC ma do tego rozszerzenie .
W C89 / C90 lub wcześniejszych wersjach C nie było sposobu na zainicjowanie elementu w środku tablicy bez podania wszystkich poprzednich wartości.
W wersji C99 i wyższej wyznaczone inicjalizatory umożliwiają inicjowanie dowolnych elementów tablicy, pozostawiając niezainicjowane wartości jako zera.
Inicjowanie tablic postaci:
Tablice znaków są szczególnym przypadkiem inicjalizacji; zamiast nawiasów klamrowych i przecinków można zastosować ciąg znaków:
char chr_array[] = "hello";
jest skrótem od dłuższego, ale równoważnego:
char chr_array[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
W takim przypadku rozmiar tablicy wynosi sześć (pięć znaków plus kończące '\0'
).
1 Co dzieje się z zadeklarowaną niezainicjowaną zmienną w C? Czy to ma wartość?
2 Zauważ, że stałe wyrażenie jest zdefiniowane jako coś, co można ocenić w czasie kompilacji. Tak więc int global_var = f();
jest nieważny. Innym częstym błędem jest myślenie o const
zmiennej kwalifikowanej jako wyrażenie stałej. W C const
oznacza „tylko do odczytu”, a nie „stałą czasową kompilacji”. Globalne definicje, takie jak const int SIZE = 10; int global_arr[SIZE];
i const int SIZE = 10; int global_var = SIZE;
nie są legalne w C.
Inicjowanie struktur i tablic struktur
Struktury i tablice struktur można inicjować za pomocą szeregu wartości zawartych w nawiasach klamrowych, po jednej wartości na element konstrukcyjny.
struct Date
{
int year;
int month;
int day;
};
struct Date us_independence_day = { 1776, 7, 4 };
struct Date uk_battles[] =
{
{ 1066, 10, 14 }, // Battle of Hastings
{ 1815, 6, 18 }, // Battle of Waterloo
{ 1805, 10, 21 }, // Battle of Trafalgar
};
Zauważ, że inicjalizacja tablicy może być napisana bez wewnętrznych nawiasów klamrowych, aw przeszłości (powiedzmy przed 1990 rokiem) często byłaby napisana bez nich:
struct Date uk_battles[] =
{
1066, 10, 14, // Battle of Hastings
1815, 6, 18, // Battle of Waterloo
1805, 10, 21, // Battle of Trafalgar
};
Chociaż to działa, nie jest to dobry nowoczesny styl - nie powinieneś próbować używać tej notacji w nowym kodzie i powinieneś naprawić ostrzeżenia kompilatora, które zwykle daje.
Zobacz także wyznaczone inicjalizatory .
Korzystanie z wyznaczonych inicjatorów
C99 wprowadził koncepcję wyznaczonych inicjatorów. Pozwalają one określić, które elementy tablicy, struktury lub unii mają zostać zainicjowane przez następujące wartości.
Wyznaczone inicjalizatory elementów tablicy
Dla prostego typu, takiego jak zwykły int
:
int array[] = { [4] = 29, [5] = 31, [17] = 101, [18] = 103, [19] = 107, [20] = 109 };
Termin w nawiasach kwadratowych, który może być dowolnym stałym wyrażeniem całkowitym, określa, który element tablicy ma zostać zainicjowany przez wartość terminu po znaku =
. Nieokreślone elementy są domyślnie inicjowane, co oznacza, że zdefiniowane są zera. Przykład pokazuje wyznaczone inicjatory w kolejności; nie muszą być w porządku. Przykład pokazuje luki; te są uzasadnione. W przykładzie nie pokazano dwóch różnych inicjalizacji tego samego elementu; to też jest dozwolone (ISO / IEC 9899: 2011, §6.7.9 Inicjalizacja, ¶19 Inicjalizacja powinna odbywać się w kolejności listy inicjalizacyjnej, każdy inicjator przewidziany dla określonego podobiektu przesłaniającego wcześniej wymieniony inicjator dla tego samego podobiektu ).
W tym przykładzie rozmiar tablicy nie jest jawnie zdefiniowany, więc maksymalny indeks określony w wyznaczonych inicjatorach dyktuje rozmiar tablicy - która w tym przykładzie wynosiłaby 21 elementów. Jeśli rozmiar został zdefiniowany, zainicjowanie pozycji poza końcem tablicy byłoby jak zwykle błędem.
Wyznaczone inicjatory struktur
Możesz określić, które elementy struktury są inicjowane za pomocą .
notacja element
:
struct Date
{
int year;
int month;
int day;
};
struct Date us_independence_day = { .day = 4, .month = 7, .year = 1776 };
Jeśli elementów nie ma na liście, są one domyślnie inicjowane (zerowane).
Wyznaczony inicjator dla związków
Możesz określić, który element unii jest inicjowany za pomocą wyznaczonego inicjatora.
Przed standardem C nie było możliwości zainicjowania union
. Standard C89 / C90 pozwala zainicjować pierwszego członka union
- więc wybór pierwszego członka jest najważniejszy.
struct discriminated_union
{
enum { DU_INT, DU_DOUBLE } discriminant;
union
{
int du_int;
double du_double;
} du;
};
struct discriminated_union du1 = { .discriminant = DU_INT, .du = { .du_int = 1 } };
struct discriminated_union du2 = { .discriminant = DU_DOUBLE, .du = { .du_double = 3.14159 } };
Zauważ, że C11 pozwala ci używać anonimowych członków związku wewnątrz struktury, więc nie potrzebujesz nazwy du
w poprzednim przykładzie:
struct discriminated_union
{
enum { DU_INT, DU_DOUBLE } discriminant;
union
{
int du_int;
double du_double;
};
};
struct discriminated_union du1 = { .discriminant = DU_INT, .du_int = 1 };
struct discriminated_union du2 = { .discriminant = DU_DOUBLE, .du_double = 3.14159 };
Wyznaczone inicjatory tablic struktur itp
Konstrukty te można łączyć dla tablic struktur zawierających elementy, które są tablicami itp. Zastosowanie pełnych zestawów nawiasów gwarantuje, że notacja jest jednoznaczna.
typedef struct Date Date; // See earlier in this example
struct date_range
{
Date dr_from;
Date dr_to;
char dr_what[80];
};
struct date_range ranges[] =
{
[3] = { .dr_from = { .year = 1066, .month = 10, .day = 14 },
.dr_to = { .year = 1066, .month = 12, .day = 25 },
.dr_what = "Battle of Hastings to Coronation of William the Conqueror",
},
[2] = { .dr_from = { .month = 7, .day = 4, .year = 1776 },
.dr_to = { .month = 5, .day = 14, .year = 1787 },
.dr_what = "US Declaration of Independence to Constitutional Convention",
}
};
Określanie zakresów w inicjalizatorach tablicowych
GCC zapewnia rozszerzenie, które pozwala określić zakres elementów w tablicy, które powinny otrzymać ten sam inicjator:
int array[] = { [3 ... 7] = 29, 19 = 107 };
Potrójne kropki muszą być oddzielone od liczb, aby jedna z kropek nie była interpretowana jako część liczby zmiennoprzecinkowej ( reguła maksymalnego chrupnięcia ).