Podstawy C++ [MK, 18/19]
Lekcja 8. Tablice w C++   Wskaźniki

Funkcje w C++

Funkcja jest to fragment programu, któremu nadano nazwę i który możemy wykonać poprzez podanie tej nazwy oraz ewentualnych argumentów. Funkcja może zwracać wartość lub nie.

Przykład najprostszej funkcji w języku C++, która nie przyjmuje argumentów ani nie zwraca wartości:
void funkcja_introwertyczna()
{
    // kod Twojej funkcji
}

Słowo kluczowe void oznacza, że funkcja nie zwracana wartości.

Przykład bardziej złożonej funkcji, która przyjmuje dwa argumenty i zwraca wartość:

int dodawanie(int a, int b)
{
    return a + b;
}

Funkcja może przyjmować skończenie wiele argumentów, ale zawsze zwraca tylko jedną wartość. Należy pamiętać o właściwym określaniu typów zarówno dla argumentów jak i dla wartości. Wywołanie funkcji z powyższego przykładu, może odbyć się w następujący sposób:

int wynik = dodawanie(123, 456);

Definicja a deklaracja funkcji

Jeśli w pliku zawierającym kod programu, będziemy zapisywać wiele funkcji, to dobrym rozwiązaniem jest najpierw zadeklarowanie naszych funkcji (przed obowiązkową funkcją main), a następnie pod funkcją main zapisanie definicji naszych funkcji. Przykład deklaracji i definicji funkcji:

#include <iostream>
using namespace std;
 
int max(int num1, int num2);    // deklaracja funkcji
 
int main () {
   int a = 100;    // deklaracja i inicjalizacja dwóch zmiennych lokalnych
   int b = 200;
   int ret;    // deklaracja zmiennej lokalnej
 
   ret = max(a, b);    // wywołanie funkcji max
   cout << "Wartosc maksymalna to: " << ret << endl;
 
   return 0;
}
 
int max(int num1, int num2) {    // definicja funkcji
   int result;    // deklaracja zmiennej lokalnej
 
   if (num1 > num2)
      result = num1;
   else
      result = num2;
 
   return result; 
}

Dzięki takiemu rozmieszczeniu definicji funkcji w programie, można łatwo zorientować się, co robi program, ponieważ najpierw czytamy kod funkcji main, w nim widzimy jakie funkcje są z niego wywoływane, a na końcu widzimy kod pozostałych funkcji zapisanych w pliku.

Opcjonalne argumenty funkcji

Niekiedy zdarza się, że chcemy narzucić, aby funkcja posiadała jeden lub kilka opcjonalnych argumentów na wypadek, gdyby nie zostały one podane w czasie jej wywołania. Na przykład poniższa funkcja:

int sum(int a, int b = 20) {
   int result;
   result = a + b;
  
   return (result);
}

zwróci wartość 300, jeśli wywołamy ją w standardowy sposób: sum(100, 200). Natomiast, gdy wywołamy ją kodem sum(100), to otrzymamy wynik 120 (a nie 110 jak to było napisane wcześniej).

Przekazywanie argumentów funkcji przez wartość i przez referencję

W zdecydowanej większości przypadków argumenty przekazywane do funkcji nie ulegają zmianie. Tzn. jeśli uruchomimy poniższy program:

#include <iostream>

int multiply(int z, int w)
{
    return z * w;
}
 
int main()
{
    int a = 4;
    int b = 7;
    std::cout << multiply(a, b) << '\n';
    std::cout << a << '\n';
    std::cout << b << '\n';
    return 0;
}

to otrzymamy wynik mnożenia, czyli 28 oraz składniki: 4 i 7. Jest to przykład, kiedy argumenty do funkcji przekazujemy przez wartość. Wartości zmiennych a i b nie zmieniają się w wyniku przekazania ich do funkcji multiply. Czasem jednak chcemy, aby wywołanie funkcji spowodowało zmianę argumentów, które do niej przekazujemy. Popatrzmy na poniższy kod:

void add2(int &x, int &y) {
  x += 2;
  y += 2;
}

int main() {
  int firstNum = 10;
  int secondNum = 20;

  cout << firstNum << " | " << secondNum << "\n";    // zmienne mają wartość 10 i 20

  add2(firstNum, secondNum);

  cout << firstNum << " | " << secondNum << "\n";    // teraz zmienne mają wartość 12 i 22

  return 0;
}

Tan naprawdę, to wszystko jest już wyjaśnione w komentarzach po wywołaniu funkcji add2. Parametry przekazywane do niej ulegają zmianie. W tym przykładzie są zwiększane o 2, ale nic nie stoi na przeszkodzie, aby były modyfikowane na inne sposoby. To, co informuje nas, że parametry do funkcji będą przekazywane przez referencję, to znak & (ampersand) przed nazwą argumentu funkcji.

Przeciążanie funkcji

Przeciążanie funkcji polega na utworzeniu więcej niż jednej funkcji posiadających taką samą nazwę, ale różniących się liczbą lub typem argumentów. Przeciążona funkcja może również zwracać inny typ danych, ale nie jest to warunek wystarczający. Przykłady funkcji przeciążonych:

void funkcja (int);
int funkcja (int);   // kompilator zwróci błąd, ponieważ pierwsza i druga funkcja różnią się tylko typem zwracanym
int funkcja (bool);
void funkcja (std::string);
void funkcja (std::string, std::string);

Kompilator na etapie kompilacji kodu, dodaje do nazwy każdej z przeciążonych funkcji specjalny identyfikator, który jest związany z liczbą i typem argumentów. Tak więc po etapie kompilacji wszystkie funkcje mają unikalne nazwy.

Przykład skryptu zawierającego funkcje przeciążone:

#include <iostream>

using namespace std;

int dodaj(int a, int b)
{
    return a + b;
}

double dodaj(double a, double b)
{
    return a+b ;
}

int main()
{
    int liczba1 = dodaj(3, 5);
    double liczba2 = dodaj(2.1, 6.2);
    cout << "Dodawanie liczb calkowitych: " << liczba1 << "\n";
    cout << "Dodawanie liczb rzeczywistych: " << liczba2;
    return 0;
}

Funkcje rekurencyjne

Z funkcjami rekurencyjnymi mamy do czynienia wtedy kiedy funkcja wywołuje sama siebie. Przy tworzenia takich programów należy oczywiście pamiętać, aby ciąg wywołań kiedyś się skończył. W tym celu przed wywołaniem samej siebie, funkcja powinna sprawdzać warunek. Przykład kodu zawierającego rekurencyjne wywoływanie funkcji do obliczania kolejnych liczb ciągu Fibonacciego:

#include<iostream>
using namespace std;

int fibonacci(int n);  

int main()
{
    int num, i;

    cout << "Ilu elementow ciagu Fibonacciego potrzebujesz: ";
    cin >> num;

    cout << "\n Ciag Fibonacciego: ";

    for(i = 0; i <= num; i++)
    {
        cout << " " << fibonacci(i);
    }

    cout << "\n";
    return 0;
}

int fibonacci(int n)   
{
    if(n == 0)
        return 0;
    else if (n == 1)
        return 1;
    else
        return(fibonacci(n-1) + fibonacci(n-2)); 
}

Należy pamiętać, że przy nieumiejętnym stosowaniu funkcji rekurencyjnych można szybko doprowadzić do lawinowej ilości wywołań oraz do znaczącego wydłużenia czasu obliczeń.


Zadania

Zadanie 1. #

Napisz program w języku C++, który będzie zawierał trzy funkcje. Funkcja pierwsza nie zwraca wartości, ani nie przyjmuje parametru. Funkcja druga nie zwraca wartości, ale przyjmuje parametr typu string. Funkcja trzecia zwraca dowolną wartość typu int i przyjmuje argument typu string.

Wszystkie 3 funkcje mają być wywoływane z funkcji main poprzez wybranie odpowiednich numerów: 1, 2 lub 3. Każda funkcja ma wyświetlać informację o tym, że została wywołana, jaki argument otrzymała i jaką wartość zwraca. Jeśli użytkownik wprowadzi liczbę 0, to program ma zakończyć działanie.

Przykład działania:
Wybierz 1, aby wykonac funkcje pierwsza, 2 dla drugiej i 3 dla trzeciej
Wcisnij 0, aby wyjsc z programu

Wybierz opcje 1, 2, 3 lub 0
1
Ta funkcja nie przyjmuje parametrow ani nie zwraca zadnej wartosci
Jedyne co robi, to wypisuje tekst na konsoli

Wybierz opcje 1, 2, 3 lub 0
2
Podaj argument dla drugiej funkcji, np. liczbe lub wyraz
covid
Ta funkcja nic nie zwraca, ale za to mozemy jej przekazac argument typu string
Argument tej funkcji to: covid

Wybierz opcje 1, 2, 3 lub 0
3
Podaj argument dla trzeciej funkcji, np. liczbe lub wyraz
19
Ta funkcja zwraca, wartosc typu int oraz mozemy jej przekazac argument typu string
Argument tej funkcji to: 19

Funkcja trzecia zwrocila wartosc 1
Wybierz opcje 1, 2, 3 lub 0
0

Process returned 0 (0x0)   execution time : 18.296 s

Zadanie 2. #

Napisz program, który będzie skracał ułamek zwykły. Program ma pobierać na wejściu dwie liczby całkowite jako licznik i mianownik oraz zwracać dwie liczby całkowite jako licznik i mianownik skróconego ułamka. Program powinien wykluczać możliwość wprowadzenia zera jako mianownika. Poza główną funkcją main, program ma zawierać dodatkową funkcję wyznaczającą największy wspólny dzielnik dwóch liczb całkowitych (wywoływać tą funkcję z wewnątrz main).

Przykład działania:
Podaj licznik ułamka: 12
Podaj mianownik ułamka: 64
12/64 = 3/16

Zadanie 3. #
Napisz program w języku C++, który będzie skracał ułamek zwykły. Program ma zawierać funkcję do której są przekazywane przez referencję dwa argumenty typu int (licznik i mianownik). Następnie licznik i mianownik są skracane z wykorzystaniem największego wspólnego dzielnika dla tych liczb. Funkcja main powinna wykonywać następujące zadania:
  1. Wyświetlenie informacji o tym co program robi
  2. Poproszenie o podanie licznika
  3. Poproszenie o podanie mianownika
  4. Sprawdzenie czy mianownik jest różny od zera, jeśli nie, to proszenie do skutku o właściwą liczbę
  5. Wyświetlenie ułamka w postaci nieskróconej, np.: 16/65536
  6. Wywołanie funkcji skracającej ułamek zwykły i przekazanie do niej przez referencję licznika i mianownika
  7. Wyświetlenie ułamka w postaci skróconej, np.: 1/4096

Zadanie 4. #
Napisz program w języku C++, który będzie wyznaczał największą wspólną wielokrotność dwóch liczb całkowitych. Skorzystaj z zależności: NWW(a, b) = (a * b) / NWD(a, b). Program, poza main, ma zawierać jeszcze dwie funkcje: NWD i NWW o wiadomym działaniu. Funkcje NWD i NWW mają składać się z deklaracji i definicji. Przekazywanie argumentów: przez wartość.

Zadanie 5. #
Napisz program w języku C++, który będzie zawierał przeciążenie funkcji obliczającej pole. Funkcja ta ma być zdefiniowana w trzech wersjach:
  1. Obliczanie pola kwadratu – przyjmuje jednej argument typu float i zwraca wartość typu float
  2. Obliczanie pola prostokąta – przyjmuje dwa argumenty typu float i zwraca wartość typu float
  3. Obliczanie pola koła – przyjmuje jednej argument typu double i zwraca wartość typu double

Zadanie 6. #
Napisz program w języku C++, który będzie zawierał dwie funkcje przeciążone o wspólnej nazwie oblicz. Funkcje mają wykonywać następujące obliczenia:
  • miarę kąta wewnętrznego wielokąta foremnego – funkcja przyjmuje jednej argument typu int (liczba boków) i zwraca wartość typu float
  • pole powierzchni wielokąta foremnego – przyjmuje argument typu int (liczba boków) i typu float (długość boku) a zwraca wartość typu double
Program ma wykluczać możliwość podania liczby boków mniejszej niż 3.

Zadanie 7. #
Napisz program w języku C++, który będzie zawierał funkcję obliczającą silnię dla podanej liczby naturalnej x. Dla x = 0 funkcja ma zwracać wartość 1. Z kolei dla argumentów większych od zera, funkcja powinna obliczać silnię w sposób rekurencyjny, czyli wywoływać samą siebie, zmniejszając za każdym razem argument o 1. Jeśli nie potrafisz od razu napisać programu z funkcją rekurencyjną, to zacznij od programu obliczającego silnię metodą iteracyjną przy użyciu pętli for. Przyjmij, że maksymalna wartość argumentu x wynosi 12 i użytkownik nie może podać większej liczby.

Zadanie 8. #
Napisz program w języku C++, który wyznaczy największy wspólny dzielnik dwóch liczb naturalnych, wykorzystując do tego algorytm Eukildesa. Program powinien zawierać rekurencyjną metodę postępującą zgodnie ze wzorem NWD(a, b) = NWD(b, a mod b) dopóki reszta z dzielenia a przez b jest różna od zera.

Zadanie 9. #
Napisz program w języku C++, który będzie wypisywał wszystkie liczby pierwsze znajdujące się w podanym przedziale liczb naturalnych. Za górne ograniczenie przedziału liczbowego, przyjmij liczbę 9000. Na końcu program ma podać informację ile liczb pierwszych znajduje się w tym przedziale liczbowym.

Zadanie 10. #
Napisz program w języku C++, który będzie wypisywał wszystkie liczby półpierwsze znajdujące się w podanym przedziale liczb naturalnych. Liczba półpierwsza, to liczba rozkładająca się na iloczyn dokładnie dwóch liczb pierwszych. Program ma wyświetlić liczbę półpierwszą oraz iloczyn dwóch liczb pierwszych, który daję tą liczbę. Za górne ograniczenie przedziału liczbowego, przyjmij wartość 9000. Na końcu program ma również podać informację ile liczb półpierwszych znajduje się w tym przedziale liczbowym.

2018-11-17 00:10:12 2020-04-14 23:54:06


© 2024 Młody Informatyk v. 0.1.7717