funkcje
postać, przekazywanie parametrów
argumenty funkcji main()
funkcje rekurencyjne
funkcje przeciążone
zasięg deklaracji zmiennych
przesłanianie zmiennych
Funkcje są jedynymi elementami strukturalnymi w języku C i podstawowym budulcem klas w C++.
Funkcje są podprogramami które separują pewien fragment kodu od pozostałej części programu.
Posiadają identyfikator (nazwę), oraz jest dla nich określany sposób przekazywania parametrów (argumentów) i zwracania rezultatów działania, czyli interfejs.
Raz napisana funkcja może być wielokrotnie wykorzystana poprzez wywołanie z parametrami aktualnymi (wywołania).
parametry
rezultat
funkcja
Ogólna postać funkcji jest następująca:
typ_rezultatu nazwa_funkcji( lista_parametrów)
{
ciało funkcji, czyli instrukcje
return wynik;
}
W pierwszym wierszu definicji funkcji następuje określenie typu rezultatu zwracanego przez funkcję, nazwy funkcji oraz określenie argumentów (parametrów) stanowiących dane wymagane przez funkcję do prawidłowego wyznaczenia rezultatu działania funkcji. Instrukcje wykonywane w ramach funkcji są ujęte w nawiasy programowe. Wynik działania funkcja zwraca wykonując instrukcję return.
Instrukcja return kończy działanie funkcji. Wartość zwracana poleceniem return musi być zgodna z typem rezultatu określonym w pierwszym wierszu definicji funkcji. Pominięcie określenia typu rezultatu zwracanego przez funkcję oznacza przyjęcie domyślnego typu int. Lista parametrów zawiera listę deklaracji zmiennych (tzw. parametrów formalnych funkcji). Poszczególne jej elementy są separowane przecinkiem.
Przykład . Funkcja na obliczanie silni liczby.
parametr
formalny
long int silnia(int liczba)
{
long int silnia=1;
for(int i=2;i<=liczba;i++) silnia*=i;
return silnia; //zwrócenie wyniku przez funkcję
}
main()
{
int n;
long int r;
r=silnia(n); // wywołanie funkcji
return 0;
}
przykład
parametr aktualny
W momencie wywołania funkcji parametry aktualne „kojarzone” są z parametrami formalnymi.
Przekazywanie parametrów do funkcji
Poprawnie zdefiniowana funkcja nie korzysta ze zmiennych globalnych (zadeklarowanych poza funkcjami).
Wszystkie potrzebne dane funkcja powinna otrzymywać przez listę parametrów.
Wyróżnia się trzy sposoby przekazywania parametrów do funkcji: 1.
przez wartość
2.
przez adres (wskaźnik)
3.
przez referencję
Przekazywanie parametrów przez wartość umożliwia jedynie przekazanie wartości zmiennych, funkcja w tym przypadku nie może modyfikować wartości zmiennych przekazywanych jako parametry.
Aby funkcja mogła zmieniać zawartość zmiennej musi otrzymać jej adres lub zmienna musi być przekazana przez referencję.
Przekazywanie parametrów przez wartość
float suma(float a,float b)
{
a=a+b;
return a;
}
main()
{
float x=3.4,y=4.6,z;
z=suma(x,y);// po wywołaniu funkcji wartość zmiennej
//nie uległa zmianie i wynosi nadal x=3.4
return 0;
}
przykład
Przekazywanie parametrów przez adres (zmienną wskaźnikową)
void suma(float *a,float b) //wynik zwracany przez
// pierwszy składnik
{
*a=*a+b;
}
main()
{
float x=2.4,y=4.7;
suma(&x,y);
// w wywołaniu funkcji przekazywany jest
//adres zmiennej w której znajdzie się wynik
return 0;
przykład
Zmienne referencyjne
W języku C++ został wprowadzony tzw. typ referencyjny umożliwiający kojarzenie zmiennych ze zmiennymi referencyjnymi w takim sensie, że operacja na zmiennej referencyjnej powoduje natychmiastową modyfikację zmiennej z nią skojarzonej i nadanie jej takiej samej wartości.
W linii deklaracji zmiennej referencyjnej należy skojarzyć z nią zmienna.
Deklaracja zmiennej referencyjnej:
int x, &r=x; // r zmienna referencyjna
r=20;
cout<<x;
przykład
Przekazywanie parametrów przez referencję
void suma(float &a,float b) //wynik zwracany przez
// pierwszy składnik
{
a=a+b;
}
main()
{
float x=2.4,y=4.7;
suma(x,y);
// wynik w zmiennej x
return 0;
}
przykład
Przekazywanie tablic do funkcji - tablice jednowymiarowe
W przypadku przekazywania funkcjom tablic jednowymiarowych (także wielowymiarowych) nie jest możliwe przekazanie tablicy przez wartość.
Podczas wywołania funkcji należy przekazać adres pierwszego elementu tablicy (wskaźnik do początku tablicy).
Parametr formalny (w definicji funkcji) można zadeklarować jako: wskaźnik,
tablicę o określonym rozmiarze,
tablicę o nieokreślonym rozmiarze.
W każdym z przypadków informację o długości tablicy należy przekazać niezależnie.
W funkcji do elementów tablicy odwoływać się można dwojako: przez wskaźnik lub przez operator [].
przykład
Przekazywanie tablic jednowymiarowych do funkcji przez wskaźnik do typu elementu (odwoływanie do elementu przez wskaźnik)
#include <conio.h>
#include <iostream>
#define N 5
double srednia(int *w,int n)
{
double wynik;
for (int i=0;i<n;i++) wynik+=*(w+i);
return wynik/n;
}
main ()
{
int wek[N]={1,2,3,4,5};
double x;
x=srednia(wek,N);
cout<<"srednia elementów: "<<x;
getch();
return(0);
}
przykład
Przekazywanie tablic jednowymiarowych do funkcji przez wskaźnik do typu elementu (odwoływanie do elementu przez operator [])
#include <conio.h>
#include <iostream>
#define N 5
double srednia(int *w,int n)
{
double wynik;
for (int i=0;i<n;i++) wynik+=w[i];
return wynik/n;
}
main ()
{
int wek[N]={1,2,3,4,5};
double x;
x=srednia(wek,N);
cout<<"srednia elementów: "<<x;
getch();
return(0);
}
przykład
Przekazywanie tablic jednowymiarowych do funkcji przez deklarację wskaźnika do tablicy (określony rozmiar)
#include <conio.h>
#include <iostream>
#define N 5
double srednia(int w[5], int n)
{
double wynik;
for (int i=0;i<n;i++) wynik+=w[i];
return wynik/n;
}
main ()
{
int wek[N]={1,2,3,4,5};
double x;
x=srednia(wek,N);
cout<<"srednia elementów: "<<x;
getch();
return(0);
}
przykład
Przekazywanie tablic jednowymiarowych do funkcji przez deklarację wskaźnika do tablicy ( nieokreślony rozmiar)
#include <conio.h>
#include <iostream>
#define N 5
double srednia(int w[], int n)
{
double wynik;
for (int i=0;i<n;i++) wynik+=w[i];
return wynik/n;
}
main ()
{
int wek[N]={1,2,3,4,5};
double x;
x=srednia(wek,N);
cout<<"srednia elementów: "<<x;
getch();
return(0);
}
przykład
Przekazywanie tablic jednowymiarowych do funkcji przez deklarację wskaźnika do tablicy (nieokreślony rozmiar) odwołanie przez wskaźnik
#include <conio.h>
#include <iostream>
#define N 5
double srednia(int w[], int n)
{
double wynik;
for (int i=0;i<n;i++) wynik+=*(w+i);
return wynik/n;
}
main ()
{
int wek[N]={1,2,3,4,5};
double x;
x=srednia(wek,N);
cout<<"srednia elementów: "<<x;
getch();
return(0);
}
Przekazywanie tablic do funkcji - tablice wielowymiarowe
W przypadku przekazywania tablic wielowymiarowych jeżeli
parametr formalny został zadeklarowany jako wskaźnik, to w
funkcji do elementów tablicy odwoływać się można jedynie przez wskaźnik (odpowiednio obliczając adres w oparciu o indeksy
tablicy.
Jeżeli natomiast, jako parametr formalny zadeklarowana została tablica to musi ona posiadać określone wszystkie wymiary poza ostatnim (określonym tuż za nazwą tablicy). Można oczywiście
podać wszystkie wymiary. Podanie wymaganych wymiarów jest
konieczne aby w funkcji można było odwoływać się do
elementów przez indeksy (przez []).
Przekazywanie tablic do funkcji - tablice wielowymiarowe
W wywołaniu funkcji jako parametr aktualny podać należy:
-
adres pierwszego elementu np. &TAB[0][0], jeśli w liście
parametrów formalnych zadeklarowany został wskaźnik,
-
nazwę tablicy np. TAB, jeśli w liście parametrów formalnych
zadeklarowana została tablica. Wynika to z faktu, że &TAB[0][0]
jest adresem pierwszego elementu tablicy, a TAB jest wskaźnikiem do tablicy (zawiera informację o wymiarach), co przy tablicy o wymiarach 2x3 można zapisać:
int (*wsk)[2][3] .
przykład
Przekazywanie tablicy dwuwymiarowej do funkcji przez wskaźnik do typu elementu tablicy
#include <conio.h>
#include <iostream>
#define N 2
#define M 3
double srednia(int *w,int n,int m)
{
double wynik;
for (int i=0;i<n;i++)
for (int j=0;j<m;j++) wynik+=*(w+i*m+j);
return wynik/(n*m);
}
main ()
{
int tab[N][M]={1,2,3,4,5,6};
double x;
x=srednia(&tab[0][0],N,M); // x=srednia(tab,N,M); - błąd cout<<"srednia elementów: "<<x;
getch();
return(0);
}
przykład
Przekazywanie tablicy dwuwymiarowej do funkcji przez deklarację wskaźnika do tablicy
#include <conio.h>
#include <iostream>
#define N 2
#define M 3
double srednia(int w[][M],int n,int m)
{
double wynik;
for (int i=0;i<n;i++)
for (int j=0;j<m;j++) wynik+=w[i][j];
return wynik/(n*m);
}
main ()
{
int tab[N][M]={1,2,3,4,5,6};
double x;
x=srednia(tab,N,M); // x=srednia(&tab[0][0],N,M); - błąd cout<<"srednia elementów: "<<x;
getch();
return(0);
}
C/C++ - funkcje
Przekazywanie struktur do funkcji
Struktury do funkcji przekazuje się jak zmienne typu prostego, czyli przez: wartość, wskaźnik, referencję.
Przykład. Przekazywanie struktury przez wartość.
#include <iostream>
#include <math.h>
struct zespolona {
double re, im;
};
double modul(zespolona x)
{
return sqrt((x.re)*(x.re++)+(x.im)*(x.im));
// x.re zwiekszono o 1
}
int main()
{
zespolona zz={3.0,4.0}; // zainicjowanie zmiennej zespolonej double y=modul(zz);
cout<<"abs("<<zz.re<<"+j"<<zz.im<<")="<<y;
// zz.re nie ulegla zmianie
return 0
}
przykład
Przekazywanie struktur do funkcji
Przykład. Przekazywanie struktury przez wskaźnik.
#include <iostream>
#include <math.h>
struct zespolona {
double re, im;
};
double modul(zespolona *x)
{
return sqrt((x->re)*(x->re++)+(x->im)*(x->im));
// x->re zwiekszono o 1
}
int main()
{
zespolona zz={3.0,4.0}; // zainicjowanie zmiennej zespolonej double y=modul(zz);
cout<<"abs("<<zz.re<<"+j"<<zz.im<<")="<<y;
// zz.re została zmodyfikowana
return 0
}
przykład
Przekazywanie struktur do funkcji
Przykład. Przekazywanie struktury przez referencję.
#include <iostream>
#include <math.h>
struct zespolona {
double re, im;
};
double modul(zespolona &x)
{
return sqrt((x.re)*(x.re++)+(x.im)*(x.im));
// x->re zwiekszono o 1
}
int main()
{
zespolona zz={3.0,4.0}; // zainicjowanie zmiennej zespolonej double y=modul(zz);
cout<<"abs("<<zz.re<<"+j"<<zz.im<<")="<<y;
// zz.re została zmodyfikowana
return 0
}
Przekazywanie argumentów funkcji main()
W języku C/C++ możliwe jest przekazywanie parametrów
aplikacji . W tym celu należy w liście argumentów funkcji
main() umieścić dwa elementy. Pierwszy przekazuje liczbę
argumentów a drugi wskaźnik do tablicy łańcuchów którymi
są poszczególne parametry. Pierwszym argumentem
obligatoryjnie staje się nazwa programu.
Argumenty aplikacji (z wiersza poleceń) zadaje się po nazwie programu separując spacjami.
C/C++ - funkcje
Przekazywanie argumentów funkcji main()
#include <iostream>
#include <conio.h>
int main(int argc, char *argv[])
{int a,b;
cout<< argc<<'\n';
for (int i=0;argv[i];i++)
cout<< argv[i]<<'\n';
// a=argv[1]; // błąd
a=atoi(argv[1]);// atoi() – konwersja łańcucha na liczbę int
cout<<a+1<<'\n';
getch();
return 0;
}
Funkcje rekurencyjne
Funkcje rekurencyjne są funkcjami, które w swoim ciele wywołują samą siebie.
Należy wiedzieć, iż przy wywołaniu funkcji rekurencyjnej dochodzi do jej wielokrotnego wywołania bez kończenia wywołań poprzednich. Idzie za tym konieczność wielokrotnego składowania parametrów na stosie, co może prowadzić do jego przepełnienia.
Zaletą funkcji rekurencyjnych jest duża szybkość wykonywania.
Ogólna postać funkcji rekurencyjnej
int funkcja_rek (int parametr)
{
...
liczba= funkcja_rek( parametr);
...
return 0;
}
Funkcje rekurencyjne
Przykład. Iteracyjna i rekurencyjna postać funkcji na obliczanie silni long double SilniaIteracyjna(int liczba)
{
long double silnia=1;
for(int i=1; i<=liczba; i++)
silnia*=i;
return silnia;
}
long double SilniaRekurencyjna(int liczba)
{
if (liczba==0)
return 1;
else
return liczba*SilniaRekurencyjna(liczba-1);
}
przykład
Funkcje przeciążone
W języku C++ istnieje możliwość deklarowania funkcji o tej
samej nazwie i różnych interfejsach, czyli różnej liczbie
argumentów, różnych ich typach, odmiennym sposobie
zwracania wyników. Funkcje takie noszą nazwę
przeciążonych lub przeładowanych.
Oczywiście funkcje przeciążone będą różniły się także ciałami.
W przypadku funkcji przeciążonych kompilator rozpoznaje
funkcję po nazwie, liście argumentów i typie rezultatu.
Funkcje przeciążone
Przykład. Funkcja przeciążona na obliczanie modułu liczby: całkowitej, rzeczywistej i zespolonej.
struct complex{
double re,im;
};
int main(){
double abs(double x)
complex s={-2,4};
{
cout<<abs(-12.39)<<"\n";
return x>0?x:-x;
cout<<abs(35)<<"\n";
}
cout<<abs(s)<<"\n";
int abs(int i)
getch();
{
return 0;
return i>0?i:-i;
}
}
double abs(complex z)
{
return sqrt(z.re*z.re+z.im*z.im);
}
przykład
C/C++ - zasięg deklaracji zmiennych
1.
W języku C/C++ nie ma obowiązku deklarowania zmiennych w określonym miejscu. Pamiętać jednak, że od miejsca deklaracji zmiennej zależy jej zasięg.
2.
Zmienne globalne (deklarowane poza funkcjami) posiadają domyślną klasę pamięci static i są widoczne w każdym miejscu w programie o ile nie zostały przesłonięte przez zmienne lokalne funkcji. Zmienne lokalne (deklarowane w funkcjach) są widoczne widoczne tylko wewnątrz funkcji w których zostały zadeklarowane.
3.
Zmienne zadeklarowane wewnątrz funkcji posiadają domyślną klasę auto i są usuwane z pamięci po zakończeniu działania funkcji. Deklaracja zmiennej klasy static wewnątrz funkcji powoduje, że pozostaje ona w pamięci po zakończeniu działania funkcji.
4.
Zmienne zadeklarowane w liście parametrów funkcji są zmiennymi lokalnymi funkcji.
5.
Zmienne zadeklarowane w bloku są widoczne tylko w jego wnętrzu (w tym w jego zagnieżdżeniach).
C/C++ - zasięg deklaracji zmiennych
Zmienne globalne są widoczne w każdym miejscu w programie.
#include <conio.h>
#include <iostream>
int zmienna_globalna=44444; // deklaracja zmiennej globalnej
void funkcja()
{
cout<<zmienna_globalna; //użycie zmiennej globalnej
}
int main()
{
cout<<zmienna_globalna; // użycie zmiennej globalnej
getch();
return(0);
}
przykład
C/C++ - zasięg deklaracji zmiennych
Zmienne lokalne są widoczne tylko w funkcji gdzie zostały
przykład
zadeklarowane (również te klasy static).
#include <conio.h>
#include <iostream>
void funkcja()
{
int zm_lok_1=333; //zmienna klasy auto
static int zm_lok_2=444; // zmienna klasy static
}
int main()
{
funkcja();
cout<<zm_lok_1; //błąd - zmienna lokalna funkcji "funkcja"
cout<<zm_lok_2; //błąd - zmienna lokalna funkcji "funkcja"
return(0);
}
C/C++ - zasięg deklaracji zmiennych
przykład
Zmienne zadeklarowane w liście parametrów funkcji są zmiennymi lokalnymi funkcji
#include <iostream>
#include <conio.h>
double trojkat(float &a,float b, float c)
{
double y;
y=a+b+c;
a=(a*b)/2;
return y;
}
main()
{
//float
a=3,b=4,c=5;
// błąd -niezadeklarowane zmienne
cout<<"obwod trojkata wynosi "<<trojkat(a,b,c); cout<<"\na jego pole: "<<a;
return 0;
}
C/C++ - zasięg deklaracji zmiennych
przykład
Zmienne zadeklarowane w bloku są widoczne tylko w jego wnętrzu (w tym w jego zagnieżdżeniach).
#include <conio.h>
#include <iostream>
#include "losowanie.c"
main ()
{ const int N=2, M=3;
int tab[N][M],p;
randomize;
for ( int i=0;i<N;i++)
// zmienna i jest zmienną lokalną pętli for
for ( int j=0;j<M;j++){// zmienna j jest zmienną lokalną pętli for p=random(100);
// wewnętrznej, tu są widoczne obie zmienne
tab[i][j]=p;
// i oraz j
}
i=2;j=3;
// poza pętlami zmienne i oraz j nie są widoczne,
getch();// zostały już zniszczone a pamięć im przydzielona zwolniona return(0);
}
C/C++ - przesłanianie zmiennych
W języku C, tak jak w innych językach programowania, nie jest możliwe zadeklarowanie dwóch zmiennych o identycznych nazwach w tym samym bloku. Nie może być zatem dwóch zmiennych
globalnych o tej samej nazwie, podobnie w jednej funkcji nie może być dwóch zmiennych lokalnych o tym samym identyfikatorze, a
także w jednej pętli (w jednym bloku).
Można jednak deklarować zmienne o tej samej nazwie, o ile są
zmiennymi lokalnymi różnych funkcji lub znajdują się w różnych blokach tego samego poziomu (bloki nie są zagnieżdżone).
Można w funkcji zadeklarować zmienną (lokalną) o takiej samej nazwie jak zmienna globalna. Wówczas w funkcji zmienna
lokalna przesłania zmienną globalną i to na niej są wykonywane operacje realizowane w ramach funkcji.
C/C++ - przesłanianie zmiennych
przykład
Przykład
#include <conio.h>
#include <iostream>
int x=444; // deklaracja zmiennej globalnej o nazwie x
void funkcja()
{
int x=222;
// deklaracja zmiennej o nazwie x
cout<<x<<'\n'; //operacja zużyciem zmiennej lokalnej
}
// zmienna lokalna przesłoniła zmienną globalną
int main()
{ cout<<x<<'\n'; // użycie zmiennej globalnej
funkcja();
cout<<x;
getch();
return(0);
}