Przejdź do treści
INF.04Kategorie
A1

Formatowanie i wcięcia

Warunek zaliczenia

Umiem, gdy w kodzie pisanym na czas nie ma ani jednej linii z dwiema instrukcjami, a wcięcia zagnieżdżeń są konsekwentne.

Warto wiedzieć

Kryteria R.1.1 i R.1.2. Wystarczy, że cecha jest zastosowana w 90 procentach przypadków.

Co dokładnie sprawdza egzaminator

Cytaty dosłowne z zasad oceniania. Brzmienie sprawdzone w 24 plikach zasad z sesji 2021 do 2026.

R.1.1

Kod źródłowy zapisano w sposób czytelny: instrukcje w osobnych liniach, stosowane spacje pomiędzy operatorami, konsekwentnie stosowana wybrana konwencja dla nawiasów klamrowych instrukcji blokowej

zasady oceniania INF.04-02-23.06-SG, arkusz kalkulacyjny CKEOd sesji Zima 2024 pierwsze słowa brzmią „Kod źródłowy zapisany” zamiast „zapisano”. Reszta zdania jest identyczna we wszystkich 24 przejrzanych plikach zasad.

R.1.2

Kod zapisano z wcięciami dla zagłębień bloków

zasady oceniania INF.04-02-23.06-SG, arkusz kalkulacyjny CKEW arkuszach od 2024 roku zamiast „zagłębień” stoi „zagnieżdżeń”. Znaczenie to samo, kryterium to samo.

Trzy uwagi ogólne, które zmieniają czytanie

Tolerancja
Wystarczy, że sprawdzaną cechę zastosowano dla większości (90%) przypadków w kodzie
Zakres
Kryteria dotyczą wyłącznie samodzielnie napisanego kodu
Zastępstwo
kryteria należy odnieść do aplikacji konsolowej, jeżeli ta nie istnieje, kryteria 1.1 do 1.6 zastosować do aplikacji mobilnej

Po co to jest

To są dwa kryteria z dwudziestu arkuszy na dwadzieścia. Nie ma sesji, w której by ich nie było, i nie ma wariantu, który by je pomijał.

Razem z pozostałymi kryteriami rezultatu 1 dają one od 20 do 21 procent punktów arkusza, a nie wymagają ani jednej linijki algorytmu. Dostaje się je za sposób zapisu, nie za to, co program liczy. Przy progu 75 procent, gdzie brakujące dwa kryteria potrafią zdecydować o wyniku, są to najtańsze punkty na całym egzaminie.

Katalog strat punktowych wymienia ten błąd jako E.5: kilka instrukcji w linii, brak spacji przy operatorach, mieszane klamry, brak wcięć. Wszystkie cztery naraz kosztują dwa kryteria, a każde z nich da się usunąć jednym skrótem klawiszowym w środowisku, które i tak stoi na stanowisku egzaminacyjnym.

Pojęcie

Słowo „czytelnie” brzmi jak sprawa gustu i to jest pierwsza rzecz, którą trzeba tu odrzucić. Kryterium R.1.1 nie mówi „ładnie”. Wymienia trzy sprawdzalne cechy, a R.1.2 dokłada czwartą. Egzaminator nie ocenia wrażenia, tylko zaznacza T albo N przy każdej z nich.

Pierwsza: instrukcje w osobnych liniach. Jedna instrukcja, jedna linia. Dwa przypisania rozdzielone średnikiem w tej samej linii łamią kryterium, nawet gdy są krótkie i oczywiste.

Druga: spacje pomiędzy operatorami. Chodzi o operatory dwuargumentowe: przypisanie, porównanie, działania arytmetyczne, w C++ także strumienie. Zapis a=b+c łamie kryterium, zapis a = b + c je spełnia.

Trzecia: konsekwentnie stosowana wybrana konwencja dla nawiasów klamrowych. To jest miejsce, w którym najwięcej osób się myli, bo czyta je jako „poprawna konwencja”. Nic takiego w zdaniu nie stoi. CKE nie ma zdania na temat tego, czy klamra otwierająca ma stać w tej samej linii co nagłówek, czy w następnej. Kryterium sprawdza, czy wybrałeś jedną i trzymałeś się jej. Plik, w którym połowa funkcji ma klamrę w tej samej linii, a połowa w następnej, łamie kryterium, choć każda z tych form osobno jest poprawna.

Czwarta, z kryterium R.1.2: wcięcia dla zagnieżdżeń bloków. Każdy blok wchodzący do środka innego bloku przesuwa się o jeden poziom w prawo. Ciało funkcji o jeden, ciało pętli wewnątrz funkcji o dwa, ciało warunku wewnątrz pętli o trzy. To nie jest ozdoba: głębokość wcięcia jest jedyną informacją o tym, gdzie kończy się blok, kiedy czyta się kod, a nie kompiluje.

Do tego dochodzi tolerancja, o której trzeba wiedzieć, żeby nie wpaść w panikę przy oddawaniu: uwaga ogólna do rezultatu 1 mówi, że wystarczy zastosować cechę w większości, czyli w 90 procentach przypadków. Jedna zapomniana spacja w stulinijkowym pliku nie kosztuje kryterium. Cała funkcja napisana bez wcięć już tak, bo to zwykle więcej niż jedna dziesiąta kodu.

Zobacz to dwa razy

Ten sam program, ten sam algorytm, te same nazwy zmiennych. Różni się wyłącznie zapis. Zadanie pochodzi z arkusza INF.04-01-23.01-SG, czyli z tego, na którym stoi pierwszy kamień planu.

Zapis, który łamie oba kryteria
#include <iostream>using namespace std; int nwd(int pierwsza,int druga){while(druga!=0){int reszta=pierwsza%druga;pierwsza=druga;druga=reszta;}return pierwsza;} int main(){int pierwsza,druga;cout<<"Podaj pierwsza liczbe: ";cin>>pierwsza;cout<<"Podaj druga liczbe: ";cin>>druga;cout<<"NWD wynosi: "<<nwd(pierwsza,druga)<<endl;return 0;}
  • ! linia 4Klamra otwierająca stoi w tej samej linii co nagłówek funkcji, a w linii 12 ta sama klamra stoi w linii osobnej. Dwie konwencje w jednym pliku łamią kryterium R.1.1, choć każda z nich osobno jest poprawna.
  • ! linia 5Brak spacji wokół operatora różności i po słowie kluczowym pętli.
  • ! linia 6Trzy instrukcje w jednej linii. Kryterium żąda instrukcji w osobnych liniach.
  • ! linia 8Cała funkcja jest bez wcięć: ciało funkcji, ciało pętli i instrukcja zwrotu stoją na tym samym poziomie. To kryterium R.1.2.
  • ! linia 14Brak spacji wokół operatorów strumienia oraz dwie instrukcje w jednej linii.
Ten sam program, zapis spełniający oba kryteria
#include <iostream> using namespace std; int nwd(int pierwsza, int druga){    while (druga != 0)    {        int reszta = pierwsza % druga;        pierwsza = druga;        druga = reszta;    }     return pierwsza;} int main(){    int pierwsza;    int druga;     cout << "Podaj pierwsza liczbe: ";    cin >> pierwsza;     cout << "Podaj druga liczbe: ";    cin >> druga;     cout << "NWD wynosi: " << nwd(pierwsza, druga) << endl;     return 0;}
  • + linia 6Klamra otwierająca w osobnej linii. Ta sama forma wraca w liniach 8 i 18, więc konwencja jest w całym pliku jedna.
  • + linia 7Spacja po słowie kluczowym i wokół operatora różności.
  • + linia 9Dwa poziomy wcięcia: pierwszy za wejście do ciała funkcji, drugi za wejście do ciała pętli.
  • + linia 10Jedna instrukcja w linii. Trzy przypisania, które w złym zapisie stały w linii 6, stoją tu w trzech osobnych liniach.

Mostek: zdanie kryterium wobec linii kodu

Fragment kryteriumGdzie się łamieGdzie jest spełniony
instrukcje w osobnych liniachlinia 6 (trzy instrukcje) i linia 14 (dwie instrukcje)linie 9 do 11 oraz 22 i 23, po jednej instrukcji na linię
stosowane spacje pomiędzy operatoramidruga!=0 w linii 5 oraz cout<<"..." w linii 14druga != 0 w linii 7 oraz cout << "..." w linii 22
konsekwentnie stosowana wybrana konwencja dla nawiasów klamrowychlinia 4 ma klamrę w tej samej linii, linia 12 w osobnejlinie 6, 8 i 18 mają klamrę w osobnej linii, bez wyjątku
wcięcia dla zagłębień bloków (kryterium R.1.2)linie 5 do 9 stoją przy lewej krawędzi, mimo dwóch poziomów zagnieżdżenialinia 9 ma dwa poziomy wcięcia, bo siedzi w pętli wewnątrz funkcji

Granice

Kod, którego nie napisałeś, się nie liczy. Uwaga ogólna mówi wprost: kryteria dotyczą wyłącznie samodzielnie napisanego kodu. Pliki wygenerowane przez środowisko, czyli szkielet projektu w Android Studio, pliki pośrednie Qt czy zawartość katalogu z zależnościami, nie są oceniane ani na plus, ani na minus. Nie ma sensu ich formatować i nie ma się czego bać, gdy wyglądają inaczej niż Twój kod.

Brak aplikacji konsolowej nie ratuje przed tymi kryteriami. Uwaga ogólna przenosi kryteria od 1.1 do 1.6 na aplikację mobilną, desktopową albo webową, zależnie od tego, co jest w arkuszu. Nie da się ich uniknąć, rezygnując z części pierwszej: przeniosą się na tę część, którą oddasz.

To nie jest kryterium o nazwach. Nazewnictwo funkcji i zmiennych to R.1.3 i R.1.4, czyli osobny dział A2. Kod z fatalnymi nazwami, ale wzorowo sformatowany, dostaje T przy R.1.1 i R.1.2, i odwrotnie. Przy nauce warto te dwie sprawy trzymać osobno, bo osobno są punktowane.

To nie jest kryterium o działaniu programu. R.1.1 i R.1.2 sprawdza się w pliku źródłowym. Program, który się nie kompiluje, nadal może dostać oba te punkty, a program działający bez zarzutu może ich nie dostać.

Nie-przykład, który mylnie wygląda na ten sam problem: kod poprawnie sformatowany, ale pozawijany przez edytor przy wąskim oknie. Zawinięcie widoku nie jest wcięciem w pliku i nie ma wpływu na kryterium. Znaczenie ma to, co jest w pliku, a nie to, jak wygląda na ekranie.

W czterech językach

Arkusz dopuszcza C++, C#, Javę i Pythona. Kryterium jest jedno, ale w każdym z nich wygląda trochę inaczej.

C++
Operatory strumieni też są operatorami: cout << x, nie cout<<x. Uważaj na i++ w pętli, tam spacje nie są potrzebne, bo to operator jednoargumentowy.
C#
Visual Studio formatuje dokument skrótem Ctrl+K, Ctrl+D i domyślnie stawia klamrę w osobnej linii. Nie zmieniaj tego ustawienia w trakcie pracy, bo połowa pliku zostanie w starej konwencji.
Java
Android Studio i IntelliJ formatują skrótem Ctrl+Alt+L, domyślnie klamra w tej samej linii. Ta konwencja jest równie dobra, o ile jest jedyna w pliku.
Python
Wcięcie jest tu częścią składni, więc kryterium R.1.2 spełnia się samo. Zostają dwa pozostałe żądania: jedna instrukcja w linii, czyli bez średników sklejających, oraz spacje wokół operatorów. Klamr nie ma, więc trzeci fragment kryterium nie ma zastosowania.

Procedura

Cztery żądania kryterium przekładają się na cztery przebiegi po kodzie plus jedno domknięcie skrótem klawiszowym. Kolejność ma znaczenie: konwencję klamr wybiera się przed napisaniem pierwszej linii, a formatowanie automatyczne uruchamia jako ostatnie.

  1. 1

    Zanim napiszesz pierwszą linię, wybierz konwencję klamr i zapisz ją sobie na kartce.

    to konwencja, bo kryterium sprawdza konsekwencję, a nie wybór, więc obie formy są dozwolone; decyzja podjęta w połowie pliku zostawia za sobą drugą połowę w starej formie.

  2. 2

    Pisz jedną instrukcję w linii, także wtedy, gdy gałąź warunku ma tylko jedną instrukcję.

    wolno tak, bo zapis if (x) return; mieści dwie instrukcje w jednej linii, a kryterium nie robi wyjątku dla instrukcji krótkich.

  3. 3

    Wstaw spacje po obu stronach każdego operatora dwuargumentowego.

    wolno tak, bo kryterium wymienia spacje między operatorami wprost, a operatory jednoargumentowe, jak i++, nie są nimi objęte.

  4. 4

    Każde wejście do bloku przesuwa kod o jeden poziom wcięcia w prawo.

    wolno tak, bo wcięcie jest jedyną informacją o zagnieżdżeniu przy czytaniu pliku, a egzaminator czyta plik, nie uruchamia go.

  5. 5

    Zanim zrobisz zrzut ekranu, uruchom formatowanie automatyczne na każdym pliku źródłowym.

    wolno tak, bo to jedyne miejsce w całym egzaminie, gdzie jeden skrót naprawia oba kryteria w całym pliku naraz; skróty to Ctrl+K, Ctrl+D w Visual Studio, Ctrl+Alt+L w IntelliJ i Android Studio, Shift+Alt+F w Visual Studio Code.

Co widzę, więc co robię

WidzęRobię
W linii stoi więcej niż jeden średnik kończący instrukcjęRozbij na tyle linii, ile jest instrukcji
Operator dwuargumentowy dotyka z obu stron argumentówWstaw spację z każdej strony
Klamra otwierająca raz stoi w tej samej linii, raz w następnejWybierz jedną formę i popraw wszystkie pozostałe wystąpienia
Blok wewnątrz bloku zaczyna się na tej samej kolumniePrzesuń go o jeden poziom w prawo
Kod jest gotowy i za chwilę robisz zrzutUruchom formatowanie automatyczne całego pliku

Ostatni wiersz stoi na końcu, a nie na początku, bo formatowanie automatyczne uruchomione w połowie pracy zostanie zepsute przez kod dopisany po nim.

Ćwiczenia

Trzy stopnie, w każdym mniej pomocy niż w poprzednim. Odpowiedź jest schowana celowo: zajrzyj do niej po własnej próbie, nie przed.

  1. 1Przykład z omówieniem

    Przeczytaj fragment i wypisz, które z czterech żądań kryterium są tu złamane. Uwaga: nie wszystkie.

    Fragment sita Eratostenesa z arkusza INF.04-01-23.06-SG
    void sito(bool tablica[],int rozmiar){for(int i=2;i*i<rozmiar;i++){if(tablica[i]){for(int j=i*i;j<rozmiar;j+=i)tablica[j]=false;}}}
    Pokaż odpowiedź

    Złamane są trzy z czterech: brak spacji przy operatorach, więcej niż jedna instrukcja w linii trzeciej oraz brak wcięć dla dwóch poziomów zagnieżdżenia. Konwencja klamr jest tu akurat konsekwentna, bo każda klamra otwierająca stoi w tej samej linii co nagłówek, więc tego fragmentu kryterium ten kod nie łamie.

    Pokaż rozwiązanie w kodzie
    Ten sam fragment po poprawieniu
    void sito(bool tablica[], int rozmiar) {    for (int i = 2; i * i < rozmiar; i++) {        if (tablica[i]) {            for (int j = i * i; j < rozmiar; j += i) {                tablica[j] = false;            }        }    }}
    • + linia 1Konwencja klamry w tej samej linii została zachowana, bo w oryginale już taka była. Zmiana jej przy okazji poprawek byłaby niepotrzebnym ryzykiem.
  2. 2Znajdź resztę sam

    Ten fragment ma poprawne wcięcia i jedną konwencję klamr. Znajdź dwa pozostałe uchybienia i podaj numery linii.

    int main(){    int liczba;    cout << "Podaj liczbe: "; cin >> liczba;     if (liczba>0)    {        cout << "Liczba dodatnia" << endl;    }     return 0;}

    Wskazówka: Przejdź plik dwa razy, raz szukając średników w środku linii, raz szukając znaków operatorów bez spacji obok.

    Pokaż odpowiedź

    Linia 4: dwie instrukcje w jednej linii, wypisanie monitu i wczytanie. Linia 6: brak spacji wokół operatora większości, powinno być liczba > 0. Wcięcia i konwencja klamr są tu poprawne, więc poza tymi dwoma miejscami nie ma czego zmieniać.

  3. 3Zadanie

    Przepisz poniższy fragment tak, żeby spełniał oba kryteria. Nie zmieniaj ani jednej nazwy i ani jednej instrukcji: zmieniasz wyłącznie zapis. Potem porównaj z rozwiązaniem i postaw sobie T albo N przy R.1.1 i R.1.2.

    Sortowanie bąbelkowe z arkusza INF.04-02-23.06-SG, zapisane w jednej linii
    void sortuj(int tablica[],int rozmiar){for(int i=0;i<rozmiar-1;i++){for(int j=0;j<rozmiar-1-i;j++){if(tablica[j]>tablica[j+1]){int tmp=tablica[j];tablica[j]=tablica[j+1];tablica[j+1]=tmp;}}}}
    Pokaż odpowiedź

    Powinno wyjść dziewięć albo dziesięć linii, w zależności od wybranej konwencji klamr, z czterema poziomami wcięcia w najgłębszym miejscu. Jeżeli Twoja wersja różni się od poniższej wyłącznie położeniem klamr, jest równie poprawna.

    Pokaż rozwiązanie w kodzie
    Jedno z poprawnych rozwiązań, konwencja klamry w tej samej linii
    void sortuj(int tablica[], int rozmiar) {    for (int i = 0; i < rozmiar - 1; i++) {        for (int j = 0; j < rozmiar - 1 - i; j++) {            if (tablica[j] > tablica[j + 1]) {                int tmp = tablica[j];                tablica[j] = tablica[j + 1];                tablica[j + 1] = tmp;            }        }    }}
    • + linia 5Cztery poziomy wcięcia: funkcja, pętla zewnętrzna, pętla wewnętrzna, warunek. Zmienna `tmp` jest tu dozwolona, bo zasady oceniania wymieniają ją jako wyjątek przy kryterium nazewnictwa.

Laboratorium

Popraw poniższy fragment tak, żeby przeszedł oba kryteria, i sprawdź go przyciskiem. Możesz też wyczyścić pole i wkleić własny kod ze środowiska, w którym ćwiczysz: sprawdzarka pracuje na dowolnym kodzie w C++, C#, Javie albo Pythonie.

Sprawdzenie rusza dopiero po naciśnięciu przycisku, nie przy pisaniu. Na egzaminie takiego narzędzia nie będzie, więc próba ma być najpierw własna.

Edytor wczytuje się w przeglądarce.

Pułapka

Formatowanie to kwestia gustu, a gustu nikt nie punktuje. Dopóki mój program się kompiluje i daje poprawny wynik, egzaminator nie ma podstawy, żeby postawić mi N przy zapisie kodu.

Ta reguła jest błędna i kosztuje dwa kryteria w każdym arkuszu, czyli od 5 do 7 procent punktów.

Poniższy kod kompiluje się bez ostrzeżeń i sortuje tablicę poprawnie. Dostaje N przy R.1.1 i N przy R.1.2, bo ma wszystkie instrukcje w jednej linii, zero spacji przy operatorach i zero wcięć. Działanie programu nie jest tu żadnym argumentem.

Program poprawny algorytmicznie, dwa kryteria stracone
void sortuj(int t[],int n){for(int i=0;i<n-1;i++)for(int j=0;j<n-1-i;j++)if(t[j]>t[j+1]){int p=t[j];t[j]=t[j+1];t[j+1]=p;}}

Reguła poprawna

R.1.1 i R.1.2 są kryteriami inspekcyjnymi: egzaminator sprawdza je w pliku źródłowym, patrząc na zapis, a nie na wynik uruchomienia. Działa to w obie strony i druga strona jest dobrą wiadomością. Program, który się nie kompiluje, może dostać oba te punkty w całości, o ile kod jest zapisany czytelnie.

Sprawdź się

Odpowiadaj na głos albo na kartce, zanim odsłonisz. Odtworzenie z pamięci jest tym, co buduje trwałość, a przeczytanie odpowiedzi tylko przypomina, że się ją widziało.

  1. 1

    Wymień cztery cechy zapisu, które sprawdzają kryteria R.1.1 i R.1.2.

    z pamięci

    Pokaż odpowiedź

    Instrukcje w osobnych liniach, spacje pomiędzy operatorami, jedna konsekwentnie stosowana konwencja nawiasów klamrowych oraz wcięcia dla zagnieżdżeń bloków.

  2. 2

    Ile odstępstw od reguły wolno mieć w kodzie, zanim kryterium przepadnie?

    z pamięci

    Pokaż odpowiedź

    Uwaga ogólna do rezultatu 1 mówi, że wystarczy zastosować cechę w większości, czyli w 90 procentach przypadków. Pojedyncze odstępstwa się pomija, ale cała funkcja napisana inaczej niż reszta pliku zwykle przekracza tę granicę.

  3. 3

    W Twoim pliku połowa funkcji ma klamrę otwierającą w tej samej linii co nagłówek, a połowa w linii następnej. Które kryterium jest zagrożone i co robisz?

    wykonanie i uzasadnienie

    Pokaż odpowiedź

    Zagrożone jest R.1.1, fragment o konsekwentnie stosowanej wybranej konwencji. Obie formy są dopuszczalne, więc nie ma znaczenia, którą wybierzesz; wybierasz jedną i poprawiasz wszystkie wystąpienia drugiej, najszybciej formatowaniem automatycznym całego pliku.

  4. 4

    Zabrakło Ci czasu i nie napisałeś aplikacji konsolowej. Czy kryteria R.1.1 i R.1.2 przepadają razem z nią?

    wykonanie i uzasadnienie

    Pokaż odpowiedź

    Nie. Uwaga ogólna przenosi kryteria od 1.1 do 1.6 na aplikację mobilną, desktopową albo webową, zależnie od arkusza. Zapis kodu, który oddajesz, będzie oceniony tak samo, więc formatowanie części drugiej ma dokładnie tę samą wartość punktową.

  5. 5

    Twój program nie kompiluje się z powodu jednego błędu, którego nie umiesz znaleźć. Czy warto jeszcze formatować kod przed oddaniem?

    wykonanie i uzasadnienie

    Pokaż odpowiedź

    Tak, i to jest wtedy najlepiej opłacalna rzecz, jaką możesz zrobić. R.1.1 i R.1.2 sprawdza się w pliku źródłowym, niezależnie od tego, czy kod się uruchamia, więc te dwa kryteria są nadal do wzięcia w całości.

Kiedy umiem

Warunki obserwowalne. Dopóki któryś nie jest spełniony, dział zostaje w toku, nawet jeżeli materiał wydaje się oczywisty.

  • Na kodzie pisanym na czas, trzy razy pod rząd, przeglądam plik i nie znajduję ani jednej linii z dwiema instrukcjami.
  • Wymieniam z pamięci cztery cechy zapisu z kryteriów R.1.1 i R.1.2, bez zaglądania do tej lekcji.
  • Znam skrót formatowania w środowisku, w którym będę zdawał, i używam go bez szukania w menu.
  • Po co najmniej siedmiu dniach od tej lekcji, przy zamkniętym materiale, poprawiam podany fragment kodu i moja poprawka nie pomija żadnej z czterech cech.
  • Po próbie arkusza stawiam sobie T przy R.1.1 i R.1.2 oraz wskazuję w kodzie konkretną linię, która to uzasadnia.

Źródła

  • Zasady oceniania CKE do arkuszy INF.04, sesje 2021 do 2026, 24 pliki; brzmienie kryteriów R.1.1 i R.1.2 sprawdzone w każdym z nich
  • Uwagi ogólne do rezultatu 1: tolerancja 90 procent, zakres samodzielnie napisanego kodu, przeniesienie kryteriów przy braku aplikacji konsolowej
  • Katalog strat punktowych E.5 z pliku wiedzy 01, sekcja 10
  • Treści zadań z arkuszy INF.04-01-23.01-SG, INF.04-01-23.06-SG i INF.04-02-23.06-SG