Najczęstsze uwagi co do zadań

  1. Zestaw 3:
    1. Sprawdzenie, czy podano bok nieujemny -najlepiej zrobić funkcję do wczytywania
    2. Proponuję stosowanie stałej nazwanej zamiast gołego 3.14
  2. Zestaw 4:
    1. Sprawdzenie, czy nie dzielimy przez 0
    2. 4.2: proszę o stałe np. zakresOd i zakresDo, nie chcę widzieć „magic numbers” wielokrotnie
  3. Zestaw 5:
    1. W miarę możliwości proszę stosować pętle.
    2. Rozmiar tablicy jako argument funkcji.
    3. Wymiar macierzy w funkcjach ogólnych takich jak wyświetlanie czy losowanie również jako argument funkcji.
    4. 5.1: Proszę użytkownikowi nie wyświetlać tylko wyniku porównania na zasadzie -1, 0, 1, ale proszę napisać mu który czas jest większy, najlepiej w formie czas XX:YY:ZZ jest wiekszy niż AA:BB:CC
    5. 5.1: jeśli porównujemy w pętli nie chcę widzieć 3 w funkcji, ma być używa stała
  4. Zestaw 6:
    1. Proszę pamiętać, że luty ma czasami 29 dni, ale nie co każde 4 lata
    2. Informacje o dniach w miesiącu polecam wyliczać w oddzielnej funkcji
    3. Polecam do zamiany miejscami napisanie funkcji np. void zamien(int* a, int* b);
    4. 6.3: Te funkcje mają być ogólne, czyli działające na tablicy o dowolnym rozmiarze, dlatego proszę o przekazywanie do każdej z tych funkcji tablicy i jej rozmiaru.
      1. Nie chcę też widzieć „magic numbers”, proszę o użycie stałych
  5. Zestaw 7:
    1. 7.3:
      1. Nie chcę widzieć „magic numbers”, proszę użyć stałej jako rozmiar tablicy
      2. Funkcje mają przyjmować rozmiar tablicy
      3. Na wyświetlanie tablic również proszę o oddzielną funkcję
  6. Zestaw 8:
    1. 8.2:
      1. Proszę o porządne, spójne, czytelne nazwy typów w enumie
      2. Zmienne lokalne, których nie modyfikujemy proszę jako const
      3. Naszą funkcję wyświetlającą proszę rozbić na wiele funkcji -po jednej dla każdego z typów
      4. Proszę nie za każdym razem rzutować, tylko mieć zmienne pomocnicze np:
        const char argumentChar = *(char*)argument;
  7. Zestaw 11:
    1. Jak to sortować? Ogólnie mamy liczby całkowite z przedziału [0, 1000] i mamy je posortować przy założeniu, że się nie zmieszczą w pamięci. Można to zrobić w taki sposób, że mamy tablicę 1001 elementów i zliczamy ile razy występuje dana liczba, dzięki temu tak naprawdę nie musimy sortować tych liczb, a jedynie je zliczyć.

PK: Wstęp do programowania – kolokwium

Przed rozpoczęciem pracy niestety muszą Państwo skonfigurować sobie środowisko np. Code:Blocks aby udało się uruchomić testy, testy są napisane przy użyciu biblioteki gtest , aby ta biblioteka zadziałała w Code:Blocks konieczne jest zaktualizowanie kompilatora, instrukcja:

KonfiguracjaMinGW

Kompilator:
https://www.gg.pl/dysk/bBZuMthfLctrbRZuMthfrMQ/mingw530_32.zip
alternatywnie jakby powyższy link nie działał:
https://www.dropbox.com/s/c8uo5g800ce2r0q/mingw530_32.zip?dl=0
alternatywnie:
http://eclipse.elektron.pk.edu.pl/~gbazior/doku.php?id=dydaktyka:informatyka:wdp

Dla nudzących się na zajęciach (tzn. bardziej zaawansowanych niż reszta)

 

  1. Najczęstsze błędy w C++ http://www.horstmann.com/cpp/pitfalls.html
  2. Jak można zaimplementować foreach zanim było to możliwe: http://www.artima.com/cppsource/foreach.html
  3. Filmy ze Scottem Mayersem (guru od wydajnego programowania w C++): http://www.aristeia.com/videos.html
  4. Egzaminy z C++ dr Przygody: http://hades1.if.uj.edu.pl/cplusplus/index.php/wyklady/category/1-wyklady
  5. Pytania z rozmowy kwalifikacyjnej do google:
    http://weblog.infopraca.pl/2012/01/15-pytan-rekrutacyjnych-zakazanych-w-google/
    (z proponowanymi odpowiedziami)
  6. Ciekawe linki polecane przez informatyka z powołania -Kamila N. (szczególnie sekcja Linki z którymi każdy programista powinien się zapoznać…):
    https://dydaktykakn.wordpress.com/
  7. Strona na której można rozwiązywać przykładowe zadania i otrzymywać punkty za nadesłania, ponoć mając dużo punktów łatwiej o pracę:
    http://pl.spoj.com/

Jak programować -styl programowania

„Zawsze programuj tak, jakby człowiek, który będzie zajmował się konserwacją twojego kodu, był agresywnym psychopatą i wiedział, gdzie mieszkasz.”,

cytat Johna F. Woodsa, wpis z grupy dyskusyjnej comp.lang.c++ 1991 r., tłumaczenie wzięte z książki „Czysty kod w C++17 Oprogramowanie łatwe w utrzymywaniu”, Stephana Rotha, tłumaczenia Tomasza Walczaka

Czego się czepiam w programach od strony technicznej:

  1. Musi bezwzględnie się kompilować -jak się nie kompiluję, daję 0 punktów i nie sprawdzam nic więcej!
  2. Program musi działać -polecam przetestowanie go metodą białej skrzynki w taki sposób aby sterowanie weszło do każdego rozgałęzienia. Jak wykryję niedziałający program to nie sprawdzam dalej tylko przyznaję tyle punktów ile bym przyznał gdyby w miejscu znalezienia błędu kończył się program (co często może dać 0).
  3. Żadnych warningów kompilacji w Państwa kodzie, czyli ma mi się program skompilować z flagami: -Wall -pedantic -Wextra -Werror. Można zastosować jako ułatwienie inne flagi, np. -std=c99 lub -std=c11 dla języka C, lub dla C++: -std=c++11 -std=c++14 -std=c++17, a dla hardcorów -Weffc++.
  4. W razie konieczności użycia którejś z flag proszę o informacje o tym w komentarzu w pliku na samej górze.

Czego się czepiam od strony estetycznej:

W skrócie żeby kod był ładny,  czytelny, zrozumiały, aby się go czytało (prawie) jak książkę) a dokładniej przykładowe aspekty „czystości kodu”:

  1. Najważniejsza wytyczna każdego ze stylów programowania: KONSEKWENCJA! Styl możemy mieć dowolny, ale się tego konsekwentnie trzymajmy!
  2. Po drugie: musisz rozumieć co się dzieje w Twoim kodzie!
  3. Dobre rozbicie programu na funkcje:
    1. Żeby każda funkcja wykonywała jedną rzecz.
    2. Żeby nazwa funkcji mówiła co dana funkcja robi.
    3. Żeby funkcja była możliwie krótka (wyjątek jak mamy jednego- długiego switcha), zasady mówiące o długości funkcji są takie:
      1. „Funkcje mają być możliwie najkrótsze”
      2. „Funkcja mają być krótsze niż są”
    4. Krótka funkcja main().
    5. [Język C] Jeśli nie przyjmuje argumentów żeby przyjmowała void.
    6. Każda czynność, którą można sensownie nazwać jest kandydatem do utworzenia z niej funkcji.
    7. Każde powtórzenie kodu sygnalizuje, że powinna to być funkcja.
    8. Proszę nie stosować skrótów w nazwach funkcji (zmiennych raczej też nie)-gdyż nie każdy może je znać.
    9. W funkcjach spada czytelność gdy ma ona zbyt wiele argumentów, im mniej tym lepiej, chociaż oczywiście pewne rzeczy musimy przesyłać jako argumenty (celem uniknięcia zmiennych globalnych).
  4. Czytelne zmienne:
    1. Ich nazwa musi zdradzać cel (z wyjątkiem pętli).
    2. Proszę unikać zmiennych globalnych.
    3. Proszę zwrócić uwagę na zainicjowanie zmiennych przed użyciem.
    4. Mimo dawnego podejścia języka C, aby definiować wszystkie zmienne na samym początku zakresu polecam jednak stosować je w momencie użycia, ewentualnie tuż przed użyciem.
  5. Zasoby
    1. Pamięć dynamiczna powinna być ZAWSZE zwalniana, przy każdym scenariuszu działania programu.
    2. Wszystkie zasoby powinny być uwalniane po zakończeniu pracy (pliki powinny być zamykane).
  6. Komentarze
    1. Stosować wyłączenie jeśli są konieczne do zrozumienia kodu, a kod powinien być samo-opisujący.
    2. Dobrze jest stosować komentarze na zakończenie dużych zakresów, np.:
      #endif /* PLIK_HPP */
      } /* while */
    3. Polecam podpisywać się na samej górze pliku w komentarzu.
  7. Preprocesor:
    1. Starać się nie stosować makrodefinicji -chyba, że jest ku temu jakiś konkretny cel.
    2. Każdy plik musi mieć strażników! (#ifndef, #define, … #endif lub #pragma once)!
    3. Stałe proszę używać przez const, a nie #define (jeśli język C to w miarę możliwości też używać const)
  8. Wcięcia -są bardzo ważne:
    1. W momencie wchodzenia do zakresu lub wchodzenia do ifa stosujemy wcięcia.
    2. Wcięcia muszą być konsekwentne, stylu nie narzucam, ale ten co stosujemy abyśmy konsekwentnie stosowali.
    3. Proszę nie stosować TABów, zamiast tego spacje (wyjątkiem są pliki makefile).
    4. Polecam stosowanie pustych linii między niespokrewnionymi linijkami. Czasami możemy wstawić dwie białe linie jedna za drugą, ale więcej niż dwie następujące po sobie białe linie to już za dużo.
    5. Odstępy warto stosować nie tylko na wysokość, ale też na szerokość, np. spacje po argumentach funkcji.
    6. Wcięcia powinny być rozsądne, czyli 1 spacja to jednak za mało, ale np. 10 spacji to już za dużo.
    7. Warto stosować spacje dla podkreślenia priorytetów operatorów np.:
      3 + 4*8
  9. Ogólnie:
    1. Kod ma być prosty i czytelny. Kod ma się czytać jak dobrą książkę-z góry na dół i wiemy o co chodzi.
    2. Ma się czytać jak dobra książka -idziemy od góry do dołu i wszystko wiemy.
    3. Jedna instrukcja w jednej linii (chyba, że logiczniej i czytelniej jest nie stosować tej zasady).
    4. Nie należy mieszać wewnątrz jednej funkcji wielu poziomów abstrakcji.
  10. Wywołanie systemowe system(„”):
    1. Starać się nie stosować Windowsowego system(„pause”);, lepiej zastosować getchar(); [w C] lub np. std::cin.get() [w C++].
    2. Ogólnie należy w miarę możliwości unikać wywołania systemowego, gdyż to nam robi lukę zabezpieczeń w programie, najczęściej konkretne wywołanie systemowe działa tylko na jednym systemie, więc czemu by nie użyć funkcji systemowych, które dostarczają tę funkcjonalność. Oczywiście jeśli mamy taką możliwość należy stosować rozwiązania standardowe, które zadziałają na wszystkich systemach.
  11. Pliki:
    1. Nazwa pliku musi odzwierciedlać co jest w tym pliku, oczywiście nazwa plików nie może być przesadnie długa, np.:
      programLiczacyLiczbyNaturalne.c, obliczanieLiczbNaturalnych.c.
    2. Konsekwentne nazewnictwo plików (jeśli stosujemy takieNazwy.c w jednym pliku to w innym nie stosujmy takich_nazw.c)
    3. W projektach zaliczeniowych lub w razie łączenia wielu zadań w jeden program proszę o stosowanie wielu plików.
    4. Funkcje obecne w jednym pliku powinny by jakoś ze sobą powiązane, niepowiązane z niczym polecam wrzucić do pliku np. utilities.h
    5. Proszę unikać spacji i innych białych znaków w nazwach plików.
    6. Plik nagłówkowy i odpowiadający mu plik źródłowy powinny mieć takie same nazwy.
    7. Warto stosować wiele plików, w każdym pliku funkcje i typy powinny być ze sobą jakoś tam powiązane, jeśli nie są -to kolejny plik.
    8. Plik z funkcją main() nie powinien być bardzo obszerny.
    9. Jak mamy wiele powiązanych plików, to warto umieścić je w katalogu.
  12. Klasy [C++]:
    1. Dobra nazwa klasy -czyli taka po której wiemy do czego służy dana klasa (~=typ użytkownika).
    2. Klasa jak to klasa -do czegoś służy, ale jak służy do wszystkiego to jest do … . A teraz na poważnie jedna klasa służy do określonych czynności, nie do wszystkiego, ma być odpowiedzialna za jedną rzecz.
    3. W klasie powinna być kolejność od najważniejszych do mniej ważnych, czyli innymi słowy to co publiczne powinno być najpierw, dobrze jest też nie mieszać definicji pól z metodami, tylko wpierw metody, potem pola.
    4. Mimo iż nazwy metod mają mówić co dana metoda robi, to nazwy publicznych metod powinny być w miarę możliwości krótkie.
    5. Modyfikatory: jeśli dana metoda nie zmienia składowych klasy to powinna być zakończona słówkiem const, jeśli nie używa składowych niestatycznych klasy to powinna być poprzedzona słówkiem static (nie dotyczy funkcji, dla których występuje polimorfizm). Jeśli klasa pochodna przeciąża metody koniecznie słówko override.
    6. Piszemy definicje metod poza klasą, chyba że jest to jedna prosta instrukcja (np. getter, setter, pusta funkcja). Definiując własną wersję metody generowanej z automatu możemy napisać = default;
    7. Klasa ma zawierać tylko metody, które potrzebuję, im więcej metod i pól tym ciężej się połapać -miej tyle metod ile jesteś w stanie ogarnąć!
  13. Polimorfizm [C++]:
    1. Jeśli planujemy dziedziczyć po danej klasie i używać polimorfizmu to koniecznie virtualny destruktor.
    2. Minimalny interfejs -tylko to co potrzeba, metody virtualne tylko te, które potrzeba. Jeśli jakaś metoda nie ma sensu dla niektórych klas pochodnych to nie powinna być w klasie bazowej.
  14. Inne uwagi co do C++:
    1. Przestrzenie nazw -warto je stosować. Lepiej mieć przestrzeń nazw z funkcjami niż klasę z samymi statycznymi funkcjami.
    2. Enum class zamiast enum.
    3. Inteligentne wskaźniki zamiast zwykłych.
    4. Jeśli możesz używaj deklaracji w plikach nagłówkowych zamiast włączania nagłówków.

Text User Interphace (TUI) – tekstowa komunikacja z użytkownikiem:

  1. Z użytkownikiem trzeba jak z głupkiem -łopatologicznie mu wszystko wyjaśnić, żeby nic się nie musiał domyślać, żeby wszystko miał ładnie napisane. Prosta rada ale bardzo praktyczna, proszę mi wierzyć.
  2. Wczytując dane od użytkownika warto je jakoś weryfikować, użytkownik nie musi być złośliwy, żeby nam wszystko popsuć.
  3. Należy unikać wyświetlania na raz zbyt dużej ilości linijek -tylko to co konieczne w danej chwili.
  4. Jeśli użytkownik ma do wpisania konkretne opcje to warto mu dokładnie je wylistować.

Wiedza programistyczna (Informatyk z założenia jest leniwy i to ma swoje plusy):

  1. Nie odkrywajmy koła na nowo, jeśli coś jest dostarczone przez bibliotekę standardową warto tego użyć zamiast pisać od początku samodzielnie.
    1. Starajmy się używać funkcji z biblioteki standardowej (chyba że na tym ucierpiała by znacznie czytelność).
    2. Używajmy struktur danych dostępnych w bibliotece standardowej zamiast pisania własnych.
    3. Używajmy stałych, które są w bibliotece standardowej zamiast definiować własne.
    4. Warto znać aliasy typów z biblioteki standardowej.
    5. Dokumentacja powinna być pod ręką: Cplusplus, Cppreference, C++0x.
  2. Używajmy nowych rzeczy, które czynią kodowanie wygodniejszym i kod czytelniejszym (typu możliwości C++14,17,… oraz C99,11,…).
  3. Nigdy nie przestawaj się uczyć programowania i śledzić nowości w technologii informatycznej: „Jak nie idziesz do przodu to się cofasz”!!!

Czego ponadto się czepiam w programach zaliczeniowych

  1. Program musi posiadać Makefile (lub inny system budowy), lub plik projektu środowiska programistycznego.
    1. jeśli Makefile chciałbym mieć komendy:
      1. make compile
      2. make run
      3. make clean
  2. Posiadać jakiś opis czym jest ten program, na jakąś platformę, jakich bibliotek używa, jak go najszybciej zbudować (czy przez make’a czy przy użyciu środowiska programistycznego)
  3. Aby użyte biblioteki poza standardem były załączone do paczki (o ile jest taka możliwość, oraz o ile nie zajmują bardzo dużo), w razie niemożliwości proszę o informacje jakie biblioteki były użyte i dlaczego nie dało się ich załączyć.

Testy programów (pod względem danych użytkownika)

  1. Liczby – czy nie będziemy dzielić przez 0, czy nie utworzymy tablicy zerowej lub ujemnej wartości, czy nie wyjdziemy poza zakres tablicy.
  2. Stdin – czy na pewno użytkownik podał to co chcieliśmy, czy się udało wczytać ([C]: scanf zwraca informacje ile danych udało się wczytać, [C++]: std::cin również można sprawdzić czy się udało wczytywanie)
  3. Nazwa pliku -nie wszystkie znaki są dozwolone na różnych systemach w nazwach plików (więcej informacji).
  4. Czy nie podano opcji, której nie oferuje menu.
  5. Czy udało się otworzyć plik.
  6. Czy udało się dokonać dynamicznej alokacji pamięci.
  7. Nazwy testów jednostkowych (zacytowany z książki Czysty kod w C++17):
    <testowanaJednostka>:<warunekWstępnyIStanTestowanejJednostki>_<TestowanaCzęśćApi>_<OczekiwaneDziałanie>

Co warto wiedzieć stosując repozytorium

  1. Nie wrzucamy tam własnych plików binarnych, plików skompilowanych, plików kopii zapasowych (o kopię zatroszczy się repozytorium)
  2. Nie wrzucamy śmieci, które tworzy środowisko, a nie są potrzebne (katalogi Debug, obj, baza indeksów).
  3. Wrzucamy plik z projektem środowiska programistycznego (jeśli używamy takowego).
  4. Branche -używa się tego, ale oddając do oceny wszystko ma być na branchu master.
  5. Katalogowanie -jeśli w katalogu ma być jeden plik i nic więcej to czemu by uniknąć posiadania tego katalogu?
  6. Biblioteki zewnętrzne -można je wrzucić do repozytorium, dzięki temu inny użytkownik po ściągnięciu repozytorium nie będzie musiał ściągać wymaganych bibliotek.
  7. Nie pozbywajmy się bez poważnych powodów historii z repozytorium (np. stosujmy git mv zamiast git rm + git add).

Bibliografia:

  1. Czysty kod w C++17. Oprogramowanie łatwe w utrzymani, Stephan Roth
  2. Czysty kod. Podręcznik dobrego programisty, Robert C. Martin
  3. Język C++. Standardy kodowania. 101 zasad, wytycznych i zalecanych praktyk; Andrei Alexandrescu, Herb Sutter
  4. Standardy kodowania firm w których pracowałem.

Istniejące, popularne standardy programowania:

Osoby chcące z automatu poprawić wcięcia na szybko mogą użyć clang-formatter.
Należy się wystrzegać antywzorców.

„We wszystkich dobrych praktykach programistycznych chodzi o to, żeby zmniejszyć zależności”
(zaczerpnięte z książki nr „Język C++. Standardy kodowania…”).