Rekurencja w C++, modyfikator const, wskaźniki i referencje jako

Transkrypt

Rekurencja w C++, modyfikator const, wskaźniki i referencje jako
SYSTEMY INFORMATYCZNE
M.A. Jankowska, G. Sypniewska-Kamińska
LABORATORIUM NR 02
TEMAT: REKURENCJA W C++. WYBRANE ZAAWANSOWANE ZAGADNIENIA ZWIĄZANE Z FUNKCJAMI W C++
I. Funkcje rekurencyjne
Wywołanie funkcji C++ może mieć miejsce nie tylko w innej funkcji, z czym mieliśmy do czynienia dotychczas. Wywołanie
funkcji może wystąpić także w jej własnej definicji. Funkcję, która wywołuje samą siebie nazywamy funkcją rekurencyjną.
Przepisz, skompiluj i wykonaj zamieszczony poniżej kod programu. Przeanalizuj jego działanie.
#include "stdafx.h"
#include <iostream>
using namespace std;
int silnia_rekurencja(int n);
int silnia_iteracja(int n);
int _tmain(int argc, _TCHAR* argv[])
{
cout << "Program oblicza wartosc funkcji silnia dla argumentow n <= 12" << endl;
int n = 20;
while (n >=13)
{
cout << "Podaj wartosc n z przedzialu [0,12]. n = ";
cin >> n;
}
cout << endl<< "n! = " << silnia_rekurencja(n)<< endl;
cout << endl<< "n! = " << silnia_iteracja(n)<< endl;
return 0;
}
int silnia_iteracja(int n)
{
int s = 1;
for (int i=1; i<=n; i++)
s = s*i;
return s;
}
int silnia_rekurencja(int n)
{
int s;
// zakończenie rekurencji po spełnieniu warunku
if (n == 1) return 1;
s = n*silnia_rekurencja(n-1); // wywołanie funkcji silnia_rekurencja
return s;
}
Funkcję
n ! określoną dla argumentów naturalnych można zdefiniować na dwa sposoby:
definicja 1
n !=1⋅2⋅...⋅(n−1)⋅n
definicja 2
1 !=1,
n !=n⋅(n−1)! dla n>1
Pierwsza z przytoczonych wyżej definicji funkcji n ! określa wartość funkcji w sposób bezpośredni dla każdego naturalnego
argumentu n.
Druga z definicji określa bezpośrednio wartość funkcji tylko dla pewnego argumentu, w tym przypadku dla n=1 . Wartości
funcji dla argumentów n>1 określone są poprzez odwołanie do definicji tej samej funkcji dla argumentu mniejszego o jeden.
Definicje tego typu nazywane są definicjami rekurencyjnymi.
W zamieszczonym powyżej kodzie programu zdefiniowano dwie funkcje C++ realizujące to samo zadanie obliczenia wartości
funkcji silnia. Funkcja silnia_iteracja oblicza wartość n ! według algorytmu iteracyjnego, wynikającego z definicji 1.
Funkcja silnia_rekurencja oblicza wartość n ! zgodnie z rekurencyjną definicją 2. Funkcja ta wywołuje samą siebie.
Aby ten proces nie trwał w nieskończoność, w definicji funkcji musi wystąpić przynajmniej jedna instrukcja return, realizowana po
spełnieniu określonego warunku. W powyższym przykładzie rekurencyjny proces zostaje zakończony, gdy w wyniku zmniejszania
Laboratorium 2
1
SYSTEMY INFORMATYCZNE
argumentu funkcji o jeden przyjmie on wartość
M.A. Jankowska, G. Sypniewska-Kamińska
n=1 , dla której funkcja jest określona bezpośrednio.
if (n==1) return 1;
II. Modyfikator const
Gdy stosujemy mechanizm przekazywania argumentu do funkcji przez referencję, to parametr funkcji jest traktowany jak alias
przekazywanego argumentu. Oznacza to, że przy wywołaniu funkcji parametr funkcji zostaje zainicjalizowany adresem aktualnego
argumentu. Funkcja uzyskuje bezpośredni dostęp do argumentu aktualnego, może go zatem zmieniać. Przekazywanie argumentów
przez referencję łączy w sobie zalety przekazywania prez wskaźnik, takie jak możliwość modyfikacji argumentu przez funkcję oraz
szybsze działanie (nie ma konieczności kopiowania wartości), z prostotą implementacji właściwą przekazywaniu przez wartość
(nie występują operacje adresowania i wyłuskiwania).
Poniżej zamieszczono kod programu wywołującego funkcję, która zmienia znak argumentu w przypadku, gdy argument ma
wartość ujemną.
#include "stdafx.h"
#include <iostream>
using namespace std;
float funkcja_wb(float& x);
int _tmain(int argc, _TCHAR* argv[])
{
float a;
cout << "Podaj dowolna liczbe wymierna: _ "; cin >>a;
cout << endl<<"Jej wartosc bezwzgledna = "<< funkcja_wb(a);
cout << endl<<"Po wywołaniu funkcji a = "<< a <<endl;
}
float funkcja_wb(float& x)
{
if( x < 0.0f) x = -x;
return x;
}
Próba wywołania funkcji funkcja_wb z parametrem będącym stałą zakończy się niepowodzeniem. Jeżeli na przykład w
powyższym programie umieścimy instrukcję
cout << endl<<"Wartosc bezwzgledna liczby -20.5 "<< funkcja_wb(-20.5);
to po kompilacji pojawi się komunikat o błędzie
error C2664: 'funkcja_wb' : cannot convert parameter 1 from 'float' to 'float &'
Można stosować mechanizm przekazywania parametrów przez referencję z jawną deklaracją, że argument funkcji nie zostanie
zmodyfikowany. W nagłówku funkcji należy wówczas poprzedzić typ parametru formalnego kwalifikatorem const. Kompilator
sprawdza (i ewentulnie wysyła komunikat o błędzie), czy w ciele funkcji parametr nie jest zmieniany pojawiając się jako lewa
strona instrukcji przypisania albo w instrukcjach inkrementacji i dekrementacji. Użycie modyfikatora const zabezpiecza argument
funkcji przed zmianami przy zachowaniu wszelkich zalet związanych z przekazywaniem parametrów przez referencję. W roli
argumentów mogą w takim przypadku występować także stałe.
float funkcja_wb1(const float& x)
{
float w = x;
if( x < 0.0f ) w = -x;
return w;
}
III. Wskaźniki i referencje jako wynik funkcji
W wyniku działania funkcji, z wyjątkiem funkcji typu void, w miejscu jej wywołania zostaje zwrócona pojedyncza wartość
określonego typu. Funkcja może zwracać jako wynik także wskaźnik albo referencję. Rozwiązania te stwarzają całkiem nowe
możliwości dla programisty. Między innymi zwracanie jako wyniku wskaźnika sprawia, że funkcja może przekazać dowolną ilość
danych w postaci tablicy zainicjalizowanej zwracanym wskaźnikiem. Należy zapamiętać, że przy próbie zwrócenia adresu lokalnej
zmiennej automatycznej funkcji wygenerowane zostanie ostrzeżenie, a program nie będzie działał poprawnie. Rozwiązaniem jest
utworzenie za pomocą operatora new zmiennej/zmiennych wskaźnikowej w obszarze pamięci wolnej (na stercie).
Laboratorium 2
2
SYSTEMY INFORMATYCZNE
M.A. Jankowska, G. Sypniewska-Kamińska
Poniżej zamieszczono kod programu wywołującego funkcję, która przydziela pamięć jednowymiarowej tablicy dynamicznej oraz
drukuje wartości elementów tego wektora na ekranie.
#include "stdafx.h"
#include <iostream>
#include <conio.h>
using namespace std;
double * rozlokuj_wektor (int nn);
void
wypisz_wektor
(double * x, int nn);
int _tmain(int argc, _TCHAR* argv[])
{
int n;
cout << "Okresl liczbe elemntow wektora n = ";
cin >> n;
double * w;
w = rozlokuj_wektor(n);
for (int i = 0; i<n; i++)
{
w[i] = pow(static_cast<double>(i), 1.0/3.0);
cout <<i<<" : "<< w[i] <<endl;
}
cout << endl << "Elementy wektora w:" << endl;
wypisz_wektor(w,n);
delete [] w;
_getch();
return 0;
}
double * rozlokuj_wektor (int nn)
{
double * ptab = new double[nn];
return ptab;
}
void wypisz_wektor (double * x, int nn)
{
for (int i=0; i<nn; i++)
cout << x[i] << " ";
cout << endl;
}
Laboratorium 2
3

Podobne dokumenty