Funkcje. Deklaracja funkcji: KURS C/C++ WYKŁAD 8 #include<stdio.h> //deklaracje funkcji: printf(...), scanf(...) #include<math.h> //double sqrt (double ) #include<conio.h> //void clrscr (void) void main (){ float liczba, wynik; double kwadrat; clrscr(); scanf ("%f", &liczba); if (liczba>0) wynik = sqrt (liczba); //konwersja typu else wynik = pow (liczba, 3)); Deklaracja funkcji: typ_funkcji nazwa_funkcji (lista typów argumentów); Deklaracja funkcji informuje komplilator jaką wartość funkcja będzie zwracała i jakiego typu są jej argumenty. float fun( int a); float fun( int); Nazwy argumentów w deklaracjach nie są istotne dla kompilatora i można je pominąć. void fun(char *); int fun(void); char *fun (char tab[]); void fun (float&); Definicja funkcji Definicja jest deklaracją, w której jest przedstawiona treść funkcji. Każda funkcja wywoływana w programie musi być zdefiniowana, tylko raz. long dodaj(int, int ); // deklaracja funkcji, prototyp funkcji main() { long wynik; int i=9; float f=3.45; wynik = dodaj (2, 5); //wywołanie funkcji wynik = dodaj(3, i); wynik = dodaj(i, f); //konwersja float do int long dodaj(int a, int b){//definicja funkcji
long w; w=2*a+2*b; return (w); // return (2*a+2*b); return jest instrukcją powrotu Przy przekazywaniu argumentów, sprawdza się typ argumentów i tam gdzie trzeba dokonuje się niejawnej i jawnej konwersji typów argumentów. int index (char *, char); // deklaracja funkcji, prototyp funkcji main() { int idx; char tab[]= Informatyka, znak; idx = index (tab, f ); //wywołanie funkcji cout<<idx; //... znak= x ; idx=index (tab, znak); cout<<idx; //... int index (char *str, char znak);{ //definicja funkcji int *adr; adr=str; while ((*str!= NULL) && (*str!= znak)) str++; if (*str) return (str adr) else return -1; 1. Funkcja może zwracać wartość, wtedy przed jej nazwą umieszczamy typ zmiennej zwracanej przez funkcję, 2. Jeśli funkcja nie zwraca wartości jej nazwę poprzedzamy słowem void, 3. Funkcja może być wywoływana z argumentami, wtedy lista argumentów umieszczana jest po nazwie funkcji w nawiasach, 4. Jeśli funkcja wywoływana jest bez argumentu to deklarujemy: int f(void) lub int f(), Przekazywanie argumentów do funkcji Podczas wywoływania funkcji przydziela się pamięć dla jej argumentów formalnych, a następnie każdemu argumentowi formalnemu przypisuje się odpowiadający mu parametr aktualny. Sprawdza się przy tym zgodności typów i w razie potrzeby dokonuje się konwersji. void func(int par) { par += 5; //par = par+5; zmienna par to tzw. parametr formalny funkcji.
W funkcji main() wywołujemy ją w nastepujący sposób: void main(){ int a1=5; func(a1); // a1 to jest parametr aktualny funkcji. Argumenty przekazujemy: - przez wartość - przez wskaźnik - przez referencję (przezwisko) Przekazywanie parametrów przez wartość Funkcja pracuje na kopii zmiennej (parametru aktualnego), więc funkcja nie ma możliwości modyfikowania go. Parametr aktualny służy jedynie do modyfikacji parametru formalnego przechowywanego tymczasowo na stosie. int func(int par) { par = par + 5; cout<<"\nfunkcja: par="<<par; return (par); zmienna par to argument (parametr) formalny funkcji. void main(){ int w, a1=5; cout<<"\nparametr aktualny przed wywolaniem: a1 = "<<a1; w = func(a1); cout<<"\nparametr aktualny po wywolaniu: a1 = "<<a1; cout<<"\nwynik = "<<w; // Ekran: Parametr aktualny przed wywolaniem: a1 = 5 funkcja: par=10 Parametr aktualny po wywolaniu: a1=5 Wynik = 10 Przekazywanie parametrów przez wskaźnik Przy przekazywaniu parametru przez adres do funkcji przesyłany jest adres zmiennej (parametru aktualnego), na stosie tworzona jest kopia adresu. void func(int *par) { *par = *par + 5; cout<<"\nfunkcja: par="<<*par; zmienna par to argument (parametr) formalny funkcji.
void main(){ int a1=15; cout<<"\nparametr aktualny przed wywolaniem: a1 = "<<a1; func(&a1); cout<<"\nparametr aktualny po wywolaniu: a1 = "<<a1; Ekran: Parametr aktualny przed wywolaniem: a1 = 15 funkcja:par=20 Parametr aktualny po wywołaniu: a1=20 Przykład 2. struct st{ int licznik; char text[100]; ; void ustaw (st *, int); int sprawdz (st *p1, int w); void main() { int było; struct st p1 = {12, Dawid Lynch ; cout<< \n <<p1.licznik; //12 ustaw (&p1, 17); cout<< \n << p1.licznik; // 17 bylo = sprawdz (&p1, 12); void ustaw (st *p1, int w){ p1->licznik=w; strcpy (p1->text, Nowy licznik ); int sprawdz (const st *p1, int w){//obiekt jest stały if (p1->licznik = = w ) return (1); else return (0); Aby zabezpieczyć obiekty przed przypadkową zmianą argument specyfikujemy jako const. int sprawdz (const st *p1, int w){//obiekt jest stały if (p1->licznik = = w ) { p1->licznik = w+1; return (1); else return (0); //błąd modyfikacja obiektu stałego
Deklaracja argumentu wskaźnikowego jako const jest informacją, że wartość obiektu wskazywanego przez ten argument nie jest zmieniana przez funkcję. Przez referencję Przy przekazywaniu parametru przez referencje do funkcji przesyłany jest adres zmiennej. Operacje przeprowadzane są bezpośrednio na zmiennej, której referencje przesłano do funkcji lub na zmiennej tymczasowej gdy występuje niezgodność typu referencyjnego i argumentu. void func(int a, int &b) { a = a+5; b = b+6; cout<<"funkcja: parametr po modyfikacji: a = "<<a; cout<<"funkcja: parametr po modyfikacji: b = "<<b; main (){ int a1=5, b1=15; func (a1,b1); cout<<"parametr po wywolaniu funkcji: a1 = "<<a1; cout<<"parametr po wywolaniu funkcji: b1 = "<<b1; EKRAN: funkcja: parametr po modyfikacji: a = 10 funkcja: parametr po modyfikacji: b = 21 Parametr po wywolaniu funkcji: a1 = 5 Parametr po wywolaniu funkcji: b1 = 21 Po zakoñczeniu funkcji kopia zmiennej a1 przechowywana na stosie jest ze stosu usuwana - zmienna a1 - nie zostanie zmieniona. Drugi argument przesyłany jest przez referencje, na stosie przechowywany jest adres zmiennej, więc funkcja działa bezpośrednio na zmiennej, co powoduje że wartość zmiennej b1 jest zostaje zmieniona. Wywołanie funkcji dla parametrów przekazywanych przez wartość i referencję nie różni się od siebie. Może to prowadzić do błędów. Są również pewne niebezpieczeñstwa przy parametrach przekazywanych przez referencję: #include <stdio.h> void o_dwa (float &f){ f=f +2;
void main (){ int i=3; float f=3.0; o_dwa (i); //generowany ostrzeżenie o niezgodnośći parametrów. o_dwa (f); printf ("i=%d f=%3.1f ", i, f); Ekran: i=3 f=5.0 Niezgodność typu referencyjnego powoduje, że operacje wykonywane są na zmiennej tymczasowej. Przykład funkcji z parametrem przekazywanym przez wartość, wskaźnik i referencję: void fun_war (float ); //przez wartość void fun_wsk (float *); //przez wskaźnik void fun_ref (float &); //przez referencje void main() { float obl, nr =12; obl=fun_war (nr); cout<<obl; //-100 cout<<nr; //nr =12; fun_wsk (&nr); cout<<nr; //nr=120 fun_ref (nr); cout<<nr; //nr=130 float fun_war (float par) { par=3; return (-103 + par); //przez wartość void fun_wsk (float *par) {*par=120; //przez wskaźnik void fun_ref (float &par) {par=130;; //przez referencje Przekazywanie tablic (argumenty tablicowe) Jeśli argumentem funkcji jest tablica, to do funkcji jest przekazywany wskaźnik do jej pierwszego elementu. TABLICE NIE MOGą BYĆ PRZEKAZYWANE PRZEZ WARTOśĆ. Przyklad 1- tablica jednowymiarowa:
void f1 (int*wsk1, int n); void f2 (int tab[], int n); void f3 (int tab[4]); const r=4; void main(){ int i; int tablica[r] = {1,2,3,4; f1(tablica,r); f2(tablica,r); f3(tablica); void f1(int *wsk1, int n){ for(int i = 0; i<n; i++) *wsk++=3; //lub wsk[i]=3; void f2(int tab[],int n){ for(int i = 0; i<n; i++) tab[i]=5; //lub *tab++=5; void f3(int tab[4]){ for(int i = 0; i<4; i++) tab[i]=5; //lub *tab++=5; Przykład 2- tablica dwuwymiarowa: #include<math.h> const w=3, k=5; void f1 (int [w][k]); void f2 (int [][k], int) ; //void f3 (int [][], int, int); // poprawnie: void f3 (int **t, int, int );
void main(){ int tablica[w][k] = {1,2,3,4,5, 1,2,3,4,5; int t[2][5] = {1,2, 3,4, 5,1, 2,3, 4,5; f1 (tablica); f2 (tablica, w); f2 (t, 2); f3 ( (int **) t, 2, 5); void f1 (int t[w][k]){ for(int i=0; i<w; i++) for(int j=0; j<k; j++) cout<<t[i][j]; void f2 (int t[][k], int wym1){ for(int i=0; i<wym1; i++) for(int j=0; j<k; j++) cout<<t[i][j]; //void f3 (int t[][], int wym1, int wym2); // poprawnie: void f3 (int **t, int wym1, int wym2){ for (int i=0; i<wym1; i++) for (int j=0; j<wym2; j++) cout<< ((int*)t)[i*wym2+ j]<<endl;