Zmienna to nazwany fragment pamięci, który przechowuje wartość, a program może ją odczytywać i zmieniać. W C zawsze z góry określasz, jaki rodzaj wartości przechowuje zmienna, i ten wybór obowiązuje przez cały czas jej życia.
Deklaracja zmiennej
Forma to typ, nazwa, średnik:
int age;
double price;
char grade;
Każda linia rezerwuje tyle pamięci, ile potrzebuje dany typ danych, i nadaje jej nazwę. Nic jeszcze nie zostało zapisane: miejsce istnieje, ale jego zawartość to to, co zostawił tam wcześniej uruchomiony kod.
Wartość możesz nadać w tym samym momencie, co nazywa się inicjalizacją:
Zwróć uwagę na specyfikatory formatu: %d dla int, %f dla double, %c dla char. printf nie sprawdza przekazanych wartości: ufa twojemu łańcuchowi formatu, więc niezgodność wypisuje bzdury zamiast zgłosić błąd.
Przypisanie po deklaracji
Gdy zmienna już istnieje, zmieniasz ją za pomocą =:
W C = to przypisanie, a nie równość. score = score + 10 czyta się jako "weź to, co jest w score, dodaj 10 i wynik z powrotem zapisz w score". Operatorem porównania jest ==, a mylenie ich to tak częsty błąd, że ma osobną sekcję na stronie o wartościach logicznych.
Skrót score += 10 robi to samo mniejszą liczbą znaków; złożone operatory przypisania obejmują całą arytmetykę.
Pułapka niezainicjowanej zmiennej
To najczęstszy błąd początkujących w C i nie powoduje on żadnego błędu kompilacji:
Uruchom to. Możesz zobaczyć 15, czyli poprawną odpowiedź. Możesz zobaczyć ogromną losową liczbę. Przy drugim uruchomieniu albo na innej maszynie możesz zobaczyć coś jeszcze innego. Każde z tych zachowań jest "poprawne", bo odczyt niezainicjowanej zmiennej lokalnej to niezdefiniowane zachowanie: standard C nie stawia żadnych wymagań co do tego, co się stanie.
W przeciwieństwie do wielu języków C nie zeruje zmiennych lokalnych. Zmienna lokalna to kawałek stosu, a stos jest pełen pozostałości po wcześniejszych wywołaniach funkcji. Czasem te pozostałości akurat są zerami i właśnie dlatego ten błąd jest tak groźny: często działa podczas testów, a zawodzi na produkcji.
Poprawka to jeden znak:
Wyrób sobie nawyk: inicjalizuj każdą zmienną w miejscu deklaracji. Jeśli naprawdę nie masz jeszcze sensownej wartości, 0 albo NULL to lepsze niż śmieci. I kompiluj z -Wall, które wyłapuje większość przypadków:
warning: 'total' is used uninitialized in this function
Wyjątkiem są zmienne globalne i static: one są automatycznie inicjalizowane zerem. Można na tym polegać, ale napisanie = 0 i tak dokumentuje twoją intencję.
Deklarowanie kilku zmiennych naraz
Zmienne tego samego typu mogą dzielić jedną deklarację, z inicjalizatorami lub bez:
To poprawne i częste przy ściśle powiązanych wartościach, takich jak x, y, z. Tu też kryje się klasyczne nieporozumienie:
int a = 0, b = 0, c = 0; /* wszystkie trzy to 0 */
int d, e, f = 0; /* tylko f to 0: d i e to śmieci */
Inicjalizator dotyczy jednej nazwy, a nie całej linii. Gdy wartości mają różne znaczenie, daj każdej osobną linię: lepiej się to czyta i daje czytelniejsze diffy.
Deklarowanie wskaźników w jednej linii ma tę samą pułapkę w ostrzejszej formie:
int *p, q; /* p to wskaźnik na int; q to zwykły int */
* wiąże się z nazwą, a nie z typem. Deklaruj wskaźniki po jednym w linii.
Zasady i konwencje nazewnictwa
Zasady kompilatora:
- Tylko litery, cyfry i podkreślenia.
- Nazwa nie może zaczynać się od cyfry:
total2jest w porządku,2totalnie. - Nie może być słowem kluczowym C: żadnej zmiennej o nazwie
int,return,forczydouble. - Wielkość liter ma znaczenie:
count,CountiCOUNTto trzy osobne zmienne. - Nazwy zaczynające się od podkreślenia albo zawierające podwójne podkreślenie są zarezerwowane dla implementacji. Nie twórz ich.
int itemCount; /* poprawne */
int item_count; /* poprawne: typowy styl C */
int _count; /* poprawne, ale zarezerwowane: unikaj */
int item-count; /* błąd: '-' to operator odejmowania */
int 3rd_place; /* błąd: zaczyna się od cyfry */
int float; /* błąd: słowo kluczowe */
Konwencje, których trzyma się większość kodu w C: snake_case dla zmiennych i funkcji, WIELKIE_LITERY dla stałych makr oraz nazwy mówiące, co oznacza wartość, a nie jakiego jest typu. elapsed_ms jest lepsze niż t; customer_count jest lepsze niż n2.
Krótkie nazwy wciąż są w porządku, gdy zasięg jest malutki: i jako licznik pętli rozumie każdy i nikt nie chce pisać for (int indeks_iteracji_petli = 0; ...).
Gdzie żyje zmienna
Miejsce deklaracji zmiennej decyduje o tym, kto ją widzi i jak długo istnieje. To zasięg, a w skrócie wygląda to tak:
Zmienna jest widoczna od swojej deklaracji do nawiasu zamykającego blok, w którym się znajduje. Zmienne globalne żyją przez cały czas działania programu i są widoczne wszędzie, co brzmi wygodnie i właśnie dlatego sprawiają kłopoty: każda funkcja może je zmienić, więc ustalenie, która to zrobiła, zamienia się w przeszukiwanie całego pliku. Wybieraj zmienne lokalne i przekazuj wartości do funkcji jako parametry.
Deklarowanie w dowolnym miejscu (C99 i nowsze)
W pierwotnym C89 każda deklaracja musiała stać przed jakąkolwiek instrukcją w bloku:
int main(void) {
int i, sum = 0; /* najpierw wszystkie deklaracje */
printf("Start\n");
for (i = 0; i < 10; i++) { sum += i; }
return 0;
}
Od C99 możesz deklarować tam, gdzie wartość jest potrzebna po raz pierwszy, także w nagłówku for:
To lepszy styl: deklaracja stoi obok pierwszego użycia, a i nie może wyciec do reszty funkcji. Skompiluj z -std=c17 (albo dowolnym ustawieniem C99+) i zadziała wszędzie.
Najczęściej zadawane pytania
Jak zadeklarować zmienną w C?
Napisz typ, potem nazwę, a na końcu średnik: int age;. Możesz od razu nadać jej wartość, int age = 30;, co nazywa się inicjalizacją i prawie zawsze jest tym, czego chcesz.
Czym różni się deklaracja zmiennej od jej inicjalizacji?
Deklaracja rezerwuje miejsce i nadaje mu nazwę (int count;). Inicjalizacja umieszcza w nim wartość w chwili utworzenia (int count = 0;). Zadeklarowana, ale niezainicjowana zmienna lokalna zawiera bajty, które akurat leżały pod tym adresem, a jej odczyt to niezdefiniowane zachowanie.
Jakie są zasady nazywania zmiennych w C?
Tylko litery, cyfry i podkreślenia; nazwa nie może zaczynać się od cyfry; nie może być słowem kluczowym, takim jak int czy for; wielkość liter ma znaczenie, więc total i Total to różne zmienne. Nazwy zaczynające się od podkreślenia są zarezerwowane: unikaj ich.
Czy zmienne można deklarować w dowolnym miejscu funkcji w C?
Od C99 tak: deklaruj każdą zmienną tam, gdzie jest potrzebna po raz pierwszy. W pierwotnym standardzie C89 każda deklaracja musiała stać na początku bloku, dlatego starszy kod ma ścianę deklaracji przed jakąkolwiek właściwą pracą.