Zrozumienie funkcji C: parametry, wartości zwracane i zakres

12

Większość języków programowania umożliwia dzielenie obszernego, długotrwałego kodu na schludne, nazwane fragmenty. Elementy te nazywane są funkcjami. Pozwalają na ponowne wykorzystanie kodu zamiast ciągłego przepisywania tej samej logiki. Funkcja pobiera dane wejściowe zwane parametrami i generuje wynik. W C możesz przekazać dowolną liczbę parametrów. Kompilator nie dba o kolejność deklarowania funkcji w pliku źródłowym, o ile zna nazwę funkcji przed próbą jej wykonania.

Pokrótce poruszyliśmy ten temat przy pomocy funkcji rand. Jest to najprostsza możliwa funkcja. Nie akceptuje niczego i zwraca liczbę całkowitą.

Linia int Rand() informuje kompilator, że rand jest funkcją. Nie przyjmuje żadnych parametrów i zwraca liczbę całkowitą. W tej konkretnej wersji nie ma zmiennych lokalnych. Gdyby tak było, pojawiałyby się natychmiast po otwierającym nawiasie klamrowym {. W C możesz deklarować zmienne w dowolnym miejscu po {. Istnieją aż do osiągnięcia odpowiedniego nawiasu zamykającego „}”. Potem znikają. Dopóki są „żywe”, zmienne lokalne są przechowywane na stosie systemowym.

Zauważ, że po rand() nie ma średnika. Jeśli przypadkowo to ustawisz, kompilator wygeneruje ogromną liczbę bezsensownych komunikatów o błędach. Nawet jeśli nie ma parametrów, wymagane są nawiasy. Bez nich nie deklarujesz funkcji, ale po prostu liczbę całkowitą.

Instrukcja Return i wiele punktów wyjścia

Operator powrotu ma kluczowe znaczenie dla każdej funkcji zwracającej wynik. Ustawia wartość zwracaną i natychmiast kończy funkcję. Możesz umieścić wiele instrukcji return w jednej funkcji, aby utworzyć wiele punktów wyjścia.

Jeśli zapomnisz instrukcji return w funkcji, która ma zwracać wartość, funkcja zakończy działanie po osiągnięciu nawiasu zamykającego. Zwróci losową, „śmieciową” wartość. Większość nowoczesnych kompilatorów ostrzeże Cię, jeśli zapomnisz zwrócić określoną wartość. C obsługuje zwracanie dowolnego typu: int, float, char, struct i inne.

Istnieje kilka poprawnych sposobów wywoływania funkcji rand. Najczęściej spotykane jest przypisanie:

Tutaj zmienna x pobiera wartość zwracaną przez rand. Podczas wywoływania należy uwzględnić nawiasy, nawet jeśli nie ma żadnych parametrów. Bez nich x otrzyma adres pamięci funkcji rand. Rzadko jest to to, co zamierzałeś zrobić.

Możesz także wywołać to wewnątrz warunku:

Lub po prostu zignoruj wynik:

W tym drugim przypadku funkcja jest wykonywana, ale zwracana wartość jest odrzucana. Prawdopodobnie nie powinieneś tego robić z randem, ale wiele funkcji używa zwracanej wartości jako kodu błędu. Jeśli wiesz, że błąd nie jest możliwy, dopuszczalne jest odrzucenie kodu.

Obsługa nieważnych zwrotów

Czasem nie trzeba nic zwracać. Służy do tego typ zwracany „void”.

Ta funkcja generuje tekst, ale nie zwraca żadnej wartości. You call it like this:

Ponownie umieść nawiasy. Jeśli je pominiesz, funkcja nie zostanie wywołana. Skompiluje się poprawnie na wielu systemach, ale nic to nie da.

Opcje i starszy styl kodu C

Funkcje C mogą przyjmować parametry dowolnego typu. Oto funkcja obliczająca silnię liczby:

Parametr „i” jest przekazywany jako liczba całkowita. Aby przekazać wiele parametrów, oddziel je przecinkami.

Język C ewoluował. Od czasu do czasu zobaczysz stary kod napisany w „starym stylu”. Wygląda to tak:

Musisz umieć przeczytać tę starą notację. Działa to dokładnie w ten sam sposób. To po prostu inna składnia. Powinieneś użyć „nowego stylu” znanego jako ANSI C, w którym typy są deklarowane na liście parametrów. Używaj starego stylu tylko wtedy, gdy wiesz, że wysyłasz kod do kogoś, kto ma kompilator inny niż ANSI.

Dlaczego jest to ważne dla zwykłych użytkowników?

Nie możesz pisać funkcji w C codziennie. Jednak zrozumienie ich działania zmienia sposób myślenia o oprogramowaniu. Za każdym razem, gdy klikniesz przycisk w aplikacji internetowej, funkcja prawdopodobnie obsłuży to kliknięcie, sprawdzi parametry i zwróci status. Jeśli kiedykolwiek widziałeś „błąd wykonania” lub „przepełnienie stosu”, natknąłeś się na ograniczenia tych mechanizmów.

Różnica między przekazaniem wartości a przekazaniem referencji (adresu pamięci) jest częstym źródłem błędów. Jest to często ukryte w językach wysokiego poziomu. W C jest to wyraźne. Świadomość, że „rand” bez nawiasów zwraca adres, a nie liczbę, oszczędza wiele godzin debugowania.

Debata na temat starego i nowego stylu dotyczy głównie nowych projektów. ANSI C jest standardem. Jednak starsze bazy kodów nadal istnieją. Umiejętność czytania int add(i,j) int i; int j; zapobiega utknięciu w kodzie, który wygląda źle, ale działa doskonale. To jest problem umiejętności czytania i pisania.

Czy stos naprawdę ma dla Ciebie znaczenie? Jeśli program nieoczekiwanie ulegnie awarii, jedyną wskazówką będzie ślad stosu. Zmienne lokalne znikające po osiągnięciu nawiasu zamykającego nie są błędem. To jest funkcja. Dzięki temu wykorzystanie pamięci jest przewidywalne.

Nie ma idealnego sposobu na pisanie kodu. Istnieje tylko sposób, który się kompiluje i sposób, który się nie kompiluje. Zachowaj nawiasy. Uważaj na instrukcje return. I nie zakładaj, że kompilator uchroni Cię przed własnymi błędami składniowymi. On cię nie uratuje.