Menu

Zmienne w C: deklaracja, inicjalizacja i przypisanie

Jak zadeklarować zmienną w C, czym deklaracja różni się od inicjalizacji, zasady nazewnictwa, deklarowanie kilku zmiennych naraz i dlaczego niezainicjowana zmienna to najczęstszy błąd początkujących.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

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: total2 jest w porządku, 2total nie.
  • Nie może być słowem kluczowym C: żadnej zmiennej o nazwie int, return, for czy double.
  • Wielkość liter ma znaczenie: count, Count i COUNT to 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ą.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ