Zmienne, stałe i komentarze
Program bez pamięci potrafi tylko wypisać z góry ustalony tekst. Zmienne to pudełka, w których program przechowuje dane w trakcie działania — i od nich zaczyna się prawdziwe programowanie. Poznasz też stałe, komentarze i zasięg, czyli zasadę mówiącą, gdzie zmienna w ogóle istnieje.
Czego się dziś nauczysz
- Zadeklarujesz zmienną i przypiszesz jej wartość
- Wyjaśnisz różnicę między deklaracją, inicjalizacją a przypisaniem
- Użyjesz
vari wskażesz, kiedy nie wolno go użyć - Utworzysz stałą i wyjaśnisz, czym różni się od zmiennej
- Opiszesz zasięg zmiennej i wskażesz, gdzie przestaje ona istnieć
- Napiszesz komentarz, który wnosi coś do kodu
Czym jest zmienna
Zmienna to nazwane miejsce w pamięci komputera, w którym program przechowuje jakąś wartość. Wartość można odczytywać i zmieniać — stąd nazwa.
Analogia: pudełko z etykietą
Wyobraź sobie regał z pudełkami. Każde ma etykietę (nazwa zmiennej) i coś w środku (wartość). Etykieta mówi też, co wolno w nim trzymać (typ) — w pudełku podpisanym „liczby całkowite” nie schowasz zdania.
Gdy program potrzebuje wartości, mówi „daj mi zawartość pudełka wiek„. Gdy chce ją zmienić — wkłada do tego samego pudełka coś innego, a stara zawartość przepada.
W C# każda zmienna ma typ, który ustala się raz i już się nie zmienia. Poniżej cztery typy, których użyjemy w tej lekcji; wszystkim przyjrzymy się dokładniej w lekcji 06.
| Typ | Co przechowuje | Przykład |
|---|---|---|
int | liczbę całkowitą | int wiek = 17; |
double | liczbę z częścią ułamkową | double srednia = 4.25; |
string | tekst | string imie = "Anna"; |
bool | prawdę albo fałsz | bool czyZdal = true; |
Kropka, nie przecinek
W kodzie część ułamkową oddziela się kropką: 4.25. Przecinek ma w C# zupełnie inne znaczenie — rozdziela argumenty. Zapis double x = 4,25; to błąd kompilacji.
Uwaga, bo to bywa mylące: program wypisze tę liczbę jako 4,25, bo przy wyświetlaniu obowiązują polskie ustawienia regionalne. W kodzie piszemy kropkę, na ekranie widzimy przecinek.
Deklaracja, inicjalizacja, przypisanie
Trzy słowa, które często myli się ze sobą, a oznaczają trzy różne rzeczy.
int wiek; // DEKLARACJA — mówimy: będzie pudełko na liczbę o nazwie wiek
wiek = 17; // INICJALIZACJA — pierwszy raz coś do niego wkładamy
wiek = 18; // PRZYPISANIE — wymieniamy zawartość na nową
int rok = 2026; // deklaracja i inicjalizacja w jednej linii (tak robi się najczęściej)
| Nazwa | Co się dzieje |
|---|---|
| Deklaracja | Podajemy typ i nazwę. Od tej chwili nazwa jest znana kompilatorowi, ale nie ma jeszcze żadnej wartości. |
| Inicjalizacja | Pierwsze nadanie wartości. |
| Przypisanie | Zapis wartości do zmiennej; może być pierwszym nadaniem albo późniejszą zmianą. |
Zmiennej bez wartości nie wolno użyć
To jedna z ważniejszych rzeczy do zapamiętania na początku:
int wiek;
Console.WriteLine(wiek); // CS0165: Użyto niezainicjowanej zmiennej lokalnej „wiek"
Zwróć uwagę: zmienna nie zawiera zera ani żadnej innej wartości domyślnej. Ona po prostu nie ma jeszcze wartości, a kompilator w ogóle nie pozwoli takiego programu zbudować. To dobra wiadomość — w wielu językach taki kod się uruchomi i wypisze przypadkową liczbę.
Znak = to nie znak równości
W matematyce x = 5 stwierdza fakt. W programowaniu to polecenie: „weź wartość z prawej strony i włóż ją do pudełka po lewej”. Czytaj to jako strzałkę w lewo.
int licznik = 5;
licznik = licznik + 1; // w matematyce bez sensu, w programowaniu: weź 5, dodaj 1, włóż z powrotem
Console.WriteLine(licznik); // 6
Słowo kluczowe var
Jeśli od razu nadajesz zmiennej wartość, kompilator sam potrafi rozpoznać typ. Zamiast pisać go dwa razy, można użyć var.
var imie = "Anna"; // kompilator widzi tekst → string
var wiek = 17; // widzi liczbę całkowitą → int
var srednia = 4.25; // widzi liczbę z kropką → double
var czyZdal = true; // widzi prawda/fałsz → bool
var to NIE jest „zmienna dowolnego typu”
To najczęstsze nieporozumienie. var nie znaczy „typ nieokreślony” — znaczy „kompilatorze, ustal typ sam”. Typ zostaje ustalony raz, na etapie kompilacji, i dalej działa dokładnie tak samo jak wpisany ręcznie.
var wiek = 17; // od tej chwili wiek jest typu int
wiek = "osiemnaście"; // CS0029: Nie można niejawnie przekonwertować typu „string" na „int"
Kiedy var nie zadziała
| Zapis | Dlaczego nie |
|---|---|
var x; | Brak wartości, więc kompilator nie ma z czego odczytać typu. |
var x = null; | null nie mówi nic o typie. |
var jako typ pola klasy | Działa tylko dla zmiennych lokalnych, wewnątrz metod. |
Kiedy używać, a kiedy nie
Używaj var, gdy typ i tak widać z prawej strony: var lista = new List<string>(); — powtarzanie nazwy typu nic nie wnosi.
Wpisuj typ wprost, gdy z prawej strony go nie widać: int liczba = int.Parse(tekst); czyta się lepiej niż var liczba = ..., bo od razu wiadomo, co dostajemy.
W tym kursie w przykładach dla początkujących będziemy zwykle pisać typ wprost — żeby było widać, z czym pracujemy.
Stałe — wartości, które nie mogą się zmienić
Czasem chcemy mieć pewność, że wartość nigdy się nie zmieni: liczba dni w tygodniu, stawka VAT, maksymalna liczba graczy. Służy do tego słowo const.
const int DniWTygodniu = 7;
const double StawkaVat = 0.23;
const string NazwaSzkoly = "ZSMI Lębork";
Console.WriteLine($"Tydzień ma {DniWTygodniu} dni.");
// DniWTygodniu = 8; // CS0131: Lewa strona przypisania musi być zmienną
| Zasada | Wyjaśnienie |
|---|---|
| Wartość od razu | Stałą trzeba zainicjalizować w tej samej linii, w której ją deklarujesz. const int x; to błąd. |
| Wartość znana przy kompilacji | Można napisać const double Pi = 3.14;, ale nie const DateTime Teraz = DateTime.Now; — czas uruchomienia nie jest znany podczas kompilacji. |
| Nazwa jak dla klasy | Stałe nazywamy od wielkiej litery: StawkaVat, a nie stawkaVat. Więcej o tym w następnej lekcji. |
Po co w ogóle stałe, skoro można użyć zwykłej zmiennej?
Z dwóch powodów. Po pierwsze kompilator pilnuje, żeby nikt jej przez pomyłkę nie nadpisał. Po drugie, i ważniejsze — nazwa tłumaczy liczbę. Porównaj:
double doZaplaty = cena * 1.23; — skąd się wzięło 1.23?
double doZaplaty = cena * (1 + StawkaVat); — od razu wiadomo.
Liczby wpisane wprost w kod nazywa się „magicznymi”. Gdy stawka VAT się zmieni, w pierwszej wersji trzeba przeszukać cały program; w drugiej — poprawić jedną linię.
Jak wolno nazywać zmienne
To są zasady techniczne — kompilator ich pilnuje. O tym, jak nazywać, żeby było czytelnie, jest cała następna lekcja.
// Poprawne nazwy
int wiekUcznia = 17;
string imie2 = "Anna";
double _tymczasowa = 1.5;
// Niepoprawne — każda z tych linii to błąd kompilacji
// int 2wiek = 17; nazwa nie może zaczynać się od cyfry
// string imie ucznia; nazwa nie może zawierać spacji
// double cena-netto; nazwa nie może zawierać myślnika
// int class = 5; class to słowo kluczowe języka
| Zasada | Szczegóły |
|---|---|
| Litery, cyfry, podkreślenie | Tylko te znaki. Bez spacji, myślników i znaków działań. |
| Nie zaczyna się od cyfry | liczba1 tak, 1liczba nie. |
| Słowo zarezerwowane wymaga prefiksu @ | class, int, for i pozostałe słowa zarezerwowane przez język są zajęte; można jednak zapisać identyfikator np. @class. W ćwiczeniach wybieramy zwykłe opisowe nazwy. |
| Wielkość liter ma znaczenie | wiek, Wiek i WIEK to trzy różne zmienne. To najczęstsze źródło błędu CS0103. |
Polskie znaki: wolno, ale nie rób tego
C# dopuszcza znaki narodowe w nazwach, więc double wartość = 5; się skompiluje. Mimo to w tym kursie nazw z ogonkami nie używamy, i nie powinieneś ich używać w swoim kodzie.
Powody są praktyczne: nazwy z polskimi znakami psują się przy kopiowaniu między systemami o różnym kodowaniu, utrudniają pracę w zespole i sprawiają kłopot przy wyszukiwaniu w kodzie. Piszemy więc wartosc, sredniaOcen, liczbaUczniow — a polskie znaki zostawiamy dla tekstów wyświetlanych użytkownikowi i dla komentarzy.
Komentarze
Komentarz to tekst, który kompilator całkowicie pomija. Jest wyłącznie dla ludzi — dla współpracowników i dla ciebie za pół roku.
// Komentarz jednoliniowy — od dwóch ukośników do końca linii
int cena = 100; // można też dopisać na końcu linii z kodem
/* Komentarz wieloliniowy.
Ciągnie się aż do znaku zamykającego,
więc mieści się w nim dowolnie długi tekst. */
/// <summary>
/// Komentarz dokumentacyjny — trzy ukośniki.
/// Visual Studio pokaże ten opis w podpowiedzi,
/// gdy ktoś najedzie myszą na nazwę metody.
/// </summary>
Skrót, który oszczędza czas
Zaznacz kilka linii i naciśnij Ctrl + K, potem Ctrl + C — Visual Studio zamieni je w komentarz. Ctrl + K, Ctrl + U cofa tę operację. Bardzo przydatne przy szukaniu błędu: wyłączasz fragment kodu, nie kasując go.
Dobry komentarz wyjaśnia DLACZEGO, nie CO
// ✗ Zbędny — kod mówi dokładnie to samo
int wiek = 17; // przypisanie 17 do zmiennej wiek
// ✓ Wnosi coś, czego z kodu nie widać
int wiek = 17; // wiek minimalny do kursu na kat. AM
// ✓ Ostrzeżenie dla następnej osoby
// UWAGA: kolejność ma znaczenie — walidacja musi być przed zapisem
// ✓ Notatka na przyszłość
// TODO: dodać sprawdzanie, czy plik istnieje
Jeśli czujesz, że fragment kodu koniecznie wymaga opisu, bo inaczej nikt go nie zrozumie — często lepszym rozwiązaniem jest zmiana nazw zmiennych albo podzielenie kodu na mniejsze części, niż dopisywanie komentarza.
Zasięg — gdzie zmienna istnieje
Zmienna nie istnieje w całym programie. Żyje tylko wewnątrz bloku, w którym została zadeklarowana — czyli między klamrami { }, w których ją utworzono.
int liczba = 10; // istnieje od tej linii do końca programu
if (liczba > 5)
{
string komunikat = "Duża liczba"; // istnieje tylko w tym bloku
Console.WriteLine(komunikat); // ✓ jesteśmy w środku
Console.WriteLine(liczba); // ✓ blok zewnętrzny też jest widoczny
}
// Console.WriteLine(komunikat); // ✗ CS0103: nazwa nie istnieje w tym kontekście
Zasada jednym zdaniem
Z wnętrza bloku widzisz wszystko na zewnątrz, ale z zewnątrz nie widzisz niczego, co powstało w środku. Poza blokiem ich nazwy nie są dostępne. Zasięg nazwy nie określa momentu zwolnienia pamięci; obiekt może nadal istnieć, jeśli pozostały do niego referencje.
Wygląda to na ograniczenie, ale jest ułatwieniem: dzięki temu tę samą nazwę można spokojnie użyć w różnych miejscach programu, a zmienne pomocnicze nie zaśmiecają reszty kodu.
Kalkulator zakupów
Program liczy wartość zamówienia: cenę netto, podatek i kwotę do zapłaty po rabacie. Wszystko, co poznaliśmy w tej lekcji, w jednym miejscu.
// Stałe — wartości ustalone raz dla całego programu
const double StawkaVat = 0.23; // 23%
const double ProgRabatu = 500.0; // od tej kwoty przysługuje rabat
const double Rabat = 0.10; // 10%
// Dane zamówienia
string nazwaProduktu = "Klawiatura mechaniczna";
int sztuk = 3;
double cenaNetto = 249.99;
// Obliczenia
double wartoscNetto = sztuk * cenaNetto;
double podatek = wartoscNetto * StawkaVat;
double wartoscBrutto = wartoscNetto + podatek;
// Rabat naliczamy tylko powyżej progu
double doZaplaty = wartoscBrutto;
if (wartoscBrutto > ProgRabatu)
{
double kwotaRabatu = wartoscBrutto * Rabat; // istnieje tylko w tym bloku
doZaplaty = wartoscBrutto - kwotaRabatu;
Console.WriteLine($"Przyznano rabat: {kwotaRabatu:F2} zl");
}
Console.WriteLine($"Produkt: {nazwaProduktu}");
Console.WriteLine($"Sztuk: {sztuk}");
Console.WriteLine($"Wartosc netto: {wartoscNetto:F2} zl");
Console.WriteLine($"VAT: {podatek:F2} zl");
Console.WriteLine($"Brutto: {wartoscBrutto:F2} zl");
Console.WriteLine($"DO ZAPLATY: {doZaplaty:F2} zl");
Przyznano rabat: 92,25 zl
Produkt: Klawiatura mechaniczna
Sztuk: 3
Wartosc netto: 749,97 zl
VAT: 172,49 zl
Brutto: 922,46 zl
DO ZAPLATY: 830,22 zl
Omówienie
| Fragment | Dlaczego tak |
|---|---|
const double StawkaVat = 0.23; |
Wartość, która nie ma prawa zmienić się w trakcie działania. Nazwa tłumaczy, czym jest liczba 0,23 — bez niej w kodzie pojawiłaby się „magiczna” liczba. |
double doZaplaty = wartoscBrutto; |
Zmienną deklarujemy przed instrukcją if, bo ma być widoczna także po niej. Gdyby powstała w środku bloku, ostatnia linia programu by się nie skompilowała. |
double kwotaRabatu = ... |
Ta z kolei celowo istnieje tylko w bloku — poza nim jest niepotrzebna. Tak działa zasięg i tak należy z niego korzystać. |
{kwotaRabatu:F2} |
Zapis po dwukropku to format. F2 oznacza „liczba stałoprzecinkowa z dwoma miejscami po przecinku”. Bez tego zobaczylibyśmy 92,2460000000001. |
| Wynik z przecinkiem | W kodzie napisaliśmy 249.99 z kropką, a program wypisał 249,99 z przecinkiem. To nie błąd — przy wyświetlaniu obowiązują ustawienia regionalne systemu. |
Do pieniędzy nie używa się typu double
Ten przykład jest uproszczony dla czytelności. W prawdziwym programie kwoty przechowuje się w typie decimal, bo double potrafi po wielu działaniach zgubić grosz. Dlaczego tak się dzieje, pokażemy w lekcji 06.
Na co uważać
| Kod | Problem |
|---|---|
int wiek; |
CS0165 — użycie zmiennej bez wartości. Zmienna lokalna nie ma wartości domyślnej; kompilator nie pozwoli jej odczytać. |
int Wiek = 17; |
CS0103 — inna wielkość litery na początku. Dla kompilatora to dwie różne nazwy. |
double x = 4,25; |
Przecinek zamiast kropki. W kodzie część ułamkową oddziela kropka. |
int wiek = "17"; |
CS0029 — po prawej jest tekst, po lewej pudełko na liczbę. Cudzysłów robi z liczby napis. |
int liczba = 5; |
CS0128 — zmienna o tej nazwie już istnieje. Za drugim razem nie podajemy typu: samo liczba = 8;. |
const int X; |
Stała musi dostać wartość w linii deklaracji. |
var x; |
Nie ma z czego odczytać typu. var wymaga wartości od razu. |
Pułapka: zmienna zadeklarowana w bloku
To bardzo częsty błąd przy pierwszych programach z instrukcją if:
// ✗ ŹLE
if (punkty > 50)
{
string ocena = "zdany";
}
Console.WriteLine(ocena); // CS0103 — poza blokiem ocena nie istnieje
// ✓ DOBRZE — deklaracja przed blokiem
string ocena = "niezdany";
if (punkty > 50)
{
ocena = "zdany"; // tu tylko zmieniamy wartość
}
Console.WriteLine(ocena); // działa
Zadania
Zadeklaruj cztery zmienne: imię (tekst), wiek (liczba całkowita), średnia ocen (liczba z ułamkiem) i informację, czy jesteś pełnoletni (prawda/fałsz). Wypisz je w czytelnej formie.
Masz dwie zmienne: int a = 5; i int b = 9;. Zamień ich wartości miejscami tak, aby na końcu a miało 9, a b miało 5. Wypisz wartości przed i po zamianie.
Poniższy program działa, ale jest nieczytelny. Zamień liczby wpisane wprost na nazwane stałe i dodaj komentarze tam, gdzie naprawdę są potrzebne.
double p = 249.0;
double w = p * 0.23;
double c = p + w;
double k = c * 0.9;
Console.WriteLine(k);
Nie uruchamiając programu, zapisz na kartce, co wypisze. Dopiero potem sprawdź w Visual Studio.
int x = 10;
int y = x;
x = 20;
Console.WriteLine(x);
Console.WriteLine(y);
W poniższym kodzie jest pięć błędów. Znajdź je wszystkie, nazwij i popraw.
const double Pi;
int 2liczba = 5;
double cena = 19,99;
string Imie = "Ala";
Console.WriteLine(imie);
int suma;
Console.WriteLine(suma);
Co trzeba zapamiętać
- Zmienna ma nazwę, typ i przypisaną wartość. Kompilator pilnuje zgodności typów.
- Deklaracja wprowadza zmienną, inicjalizacja nadaje wartość początkową, a przypisanie zapisuje wartość.
- Zmienna lokalna musi mieć przypisaną wartość przed odczytem. Pola i elementy tablic otrzymują wartości domyślne.
- = oznacza przypisanie, a == porównanie.
- var zleca kompilatorowi ustalenie typu; nie pozwala później zmieniać typu zmiennej.
- const wymaga wartości znanej podczas kompilacji.
- Zasięg określa, gdzie dostępna jest nazwa. Nie jest obietnicą natychmiastowego zwolnienia pamięci po wyjściu z bloku.
- C# rozróżnia wielkość liter. W kodzie literały ułamkowe zapisujemy z kropką; format wyświetlania zależy od kultury.