Wyklad 09


KURS C/C++
WYKAAD 9
Przekazywanie wartości z funkcji
Z funkcji która nie jest zadeklarowana jako void trzeba przekazać wartość, określa się ją w
instrukcji return (instrukcja powrotu).
W funkcji może wystąpić więcej niż jedna instrukcja powrotu.
int f() { } //błąd
void f() { } //dobrze
W instrukcji return sprawdza się zgodność typu z typem zwracanym przez funkcję i jeżeli
zachodzi potrzeba dokonuje się konwersji typów.
double potega (float liczba, int stopien) {
int i; double w=1;
if (stopien<=0) return -1; //niejawna konwersja 1 do double
for (i=1; i<=stopien; i++) w = w * liczba;
return (w);
}
#include
#include //double pow (double x, double y); //double pow10 (int x);
void main (){
int wynik;
wynik=potega (2, 4); //nadanie wartości zmiennej wynik
cout< wynik=pow (2, 4); //funkcja biblioteczna
wynik=pow10 (3); //funkcja biblioteczna
cout< }
JEST BŁDEM PRZEKAZYWANIE NA ZEWNąTRZ WSKAzNIKA DO ZMIENNEJ
LOKALNEJ, WSKAZYWANA WARTOSC ZMIENI SI NIEPRZEWIDYWALNIE.
Podczas każdego wywołania funkcji jest tworzona nowa kopia jej argumentów i zmiennych
automatycznych. Zużyta pamięć jest odzyskiwana po powrocie z funkcji.
int *f(){
int lokalna =1;
//.....
return &lokalna; //błąd przekazywania adresu do zmiennej lokalnej
}
int *f (int a){
//.....
return &a; // błąd przekazywania adresu do zmiennej lokalnej
}
Powyższe kody funkcji są niepoprawne, ale będą kompilowane bez błędów.
Przykład
#include
#include
char * f(char text[], char znak){
while ((*text !=znak) && ( *text != NULL)) text++;
return (*text ? text : NULL);
}
void main(){
char tab []="teresa";
char *adr;
clrscr ();
adr = f (tab, 'e');
cout<<"\n"<<*adr<<" "<getch();
}
Zwracanie wskaznika do lokalnej zmiennej static jest poprawne.
int *f(){
static int lokalna =1;
//.....
return &lokalna; //poprawnie
}
Przekazywanie referencji do zmiennej lokalnej jest błędem i jest sygnalizowane.
int& fun (){
int lokalna =1;
return (lokalna); //błąd, przekazywanie referencji do zmiennej lokalnej a
}
int& fun (int a){
...
return a; //błąd, przekazywanie referencji do zmiennej lokalnej a
}
int& fun (int &a){
...
return a; // poprawnie
}
Przykład
#include
#include
struct test{
int a;
char napis[100];
}bo={1,"PKO"};
char &zmien (test &a, int nr){
return (a.napis[nr]);
}
/* char &zmien (test a, int nr){ //zmiana nie będzie widoczna
return (a.napis[nr]);
}*/
void main(){
clrscr();
cout<zmien(bo,2)='P';
cout<getch();
}
Zwracanie referencji do lokalnej zmiennej static jest poprawne.
int& fun (){
static int lokalna =0;
lokalna ++; //ilość wywołań funkcji
return (lokalna);
}
Przeciążanie nazw funkcji
C++ dopuszcza użycie tej samej nazwy dla kilku funkcji.
void screen (int);
void screen (int, int);
Obie te funkcje mimo tej samej nazwy różnią się jednak od siebie, mają inne parametry
wywołania. Kompilator rozpoznaje funkcje nie tylko po nazwie, ale także po liście argumentów
funkcji. Zjawisko to nazywamy właśnie przeciążaniem nazw funkcji.
Funkcje przeciążone, mają tę samą nazwę, ale różnią się liczbą lub typem zmiennych , bądz
dla tej samej liczby argumentów kolejnościa typów ich występowania. To, która funkcja zostanie
wywołana zależy od kontekstu, czyli od towarzyszących jej argumentów wywołania.
Błędem jest próba definicji dwóch funkcji o identycznej nazwie i tej samej liście
argumentów. Przy przeładowaniu istotna jest tylko lista argumentów, natomiast typ zwracany przez
funkcje nie jest brany pod uwagę.
Poniższe pary funkcji są nie do odróżnienia przez kompilator:
(1)
void screen(int &);
void screen(int );
(2)
void screen(int );
float screen(int );
Funkcje z argumentami domyślnymi
Wartości argumentom nadaje się w prototypie funkcji:
void system (int liczba, int system = 10);
void main(){
system (12); // domyslnie ustawiane jest 10;
system (12,10);
system (12,16);
system (12,8);
}
Funkcja wyswietla liczbę w dowolnym systemie liczbowym, choć zakłada, że najczęściej używa się
systemu 10-tkowego.
Argumentami domyślnymi moga być ostatnie argumenty funkcji:
int funkcja(int, int =0, char * = 0); //OK
int funkcja(int=0, int =0, char *); //BŁAD
int funkcja(int = 0, int, char * = NULL); //BŁAD
* = pomiędzy tymi znakami musi być odstęp, ponieważ
*= to operator przypisania:
Funkcje rekurencyjne
Funkcje języka C mogą być wywoływane rekurencyjnie, tzn. funkcja może wywoływac sama siebie
zarówno bezpośrednio jak i pośrednio. Najprostszym przykładem funkcji rekurencyjnej może byc
funkcja obliczająca wartość silni dowolnej liczby naturalnej.
double silnia_rec (unsigned n) double silnia(unsigned n)
{ {
if(n > 0) long sil=1;
sil = n * silnia_rec(n-1); int i;
else for(i = 1;i<=n;i++)
sil = 1; sil = sil *i;
return sil; return sil;
} }
double silnia (unsigned n){
return n ? n*silnia (n-1) : 1;
}
// przekształcenie zapisu dziesiętnego na binarny
void drukujbity (unsigned liczba){
if ((liczba / 2 ) != 0) drukujbity (liczba /2 );
cout<<(liczba %2)
}
Funkcje inline.
Każdorazowe wywołanie funkcji w programie wymaga umieszczenia argumentów na stosie
i wykonania skoku pod odpowiedni adres.
Żeby uniknąć narzutu związanego z wywołaniem funkcji stosujemy konstrukcję inline.
Funkcję o niewielkich rozmiarach możemy zdefiniować używając specyfikatora inline, który
oznacza, że skompilowana treść funkcji ma być umieszczana w miejscu wywołania.
Sposób definiowania takiej funkcji jest prosty:
inline int max (int a, int b){ (a>b) ? return a : return b;}
inline int min(int a, int b) { (a void main (){
int maximum, minimum;
maximum = max (2,3);
//(a>b) ? return a : return b;
minimum = min (2,3);
//(a }
Ilekroć w programie umieścimy nazwę funkcji tylekroć kompilator umieści jej treść w linii
w której to wywołanie nastąpiło. Nie będzie więc żadnych dodatkowych działań ze strony
procesora. Definicje funkcji tego typu w przeciwieństwie do standardowych funkcji muszą być
umieszczane na początku programu. Treść funkcji musi być znana kompilatorowi już na etapie
kompilacji.
Uwaga:
 Funkcje z atrybtem inline są dostępne tylko wewnątrz modułu, w którym są zdefiniowane.
 Funkcje z atrybutem inline nie powinny zawierać słów kluczowych: do, while, for, goto,
switch, break, continue, ich użycie powoduje, że kopilatorowi nie będzie ich traktował jako
inline.
Funkcja main () z argumentami.
Wcześniej mówiliśmy, że main() jest taką samą funkcja jak inne, w związku z tym może
wystepować z argumentami.
W środowisku języka C/C++, do uruchamianego programu można przekazać parametry
wywołania, w wierszu polecenia wywołujacego program.
Działanie programu rozpoczyna się wtedy wywołaniem funkcji main() z dwoma
argumentami.
void main (int argc, char *argv[])
Pierwszemu argc zostanie przypisana liczba parametrów znajdujących się w wierszu komendy
Drugi argument argv (argument vector) zawiera:
 argv[0] - nazwa programu wraz z pełną sieżką dostępu
 wskazniki do łańcuchów zawierających kolejne parametry wywołania
Przykład:
#include
#include
void main (int argc, char *argv[]){
clrscr();
cout<<"argc="<int licznik=0;
while (licznik cout<<"licznik="< cout< licznik++
}
}
Program został zapisany w pliku test.cpp -> test.exe
Wywołanie:
test Cienka czerwona linia
Ekran:
argc = 4
licznik = 0 C:\CPP\TEST.EXE
licznik = 1 Cienka
licznik = 2 czerwona
licznik = 3 linia
Jeżeli nie podamy argumentów w linii komend to argc=1 i argv[0] zawiera nazwa programu wraz z
pełną sieżką dostępu
Wskazniki do funkcji
Wskaznikami możemy pokazywać na różne obiekty np.:
char *adr; char z = 'b'; char tz[] = "c++";
adr = &z; adr = tz; adr = &tz[1];
Obiektami mogą to być również funkcje. Ponieważ wskaznik zawiera adres, wskaznik do funkcji
wskazuje na obszar gdzie zaczyna się kod będący instrukcjami żądanej funkcji.
int dodaj (); - deklaracja funkcji bezparametrowej
zwracającej obiekt typu int.
int odejmij (); - deklaracja funkcji bezparametrowej
zwracającej obiekt typu int.
int (*wsk_fun) (); - deklaracja wskaznika do funkcji bezparametrowj
zwracającej obiekt typu int.
Wskaznik nazywa się wsk_fun, można mu na przykład przypisać adres funkcji .
Adresem funkcji jest jej nazwa.
wskaznik = nazwa_funkcji;
Można więc dokonać przypisania:
wsk_fun=dodaj; wsk_fun=odejmij;
int *fun1 (int); - deklaracja funkcji z parametrem typu int
zwracającej adres do obiektu typu int.
int *(*wsk_fun1) (int); - deklaracja wskaznika do funkcji z parametrem typu
int zwracającej adres do obiektu typu int.
Można dokonać przypisania:
wsk_fun1=fun1;
Należy pamiętać, że typ wskaznika do funkcji musi się zgadzać z typem funkcji.
Błędem będzie podstawienie wsk_fun1=dodaj;
Przykład:
void wypisz_tekst (char p[]){ //definicja funkcji
cout < }
void main(){
void (*adres_fun) (char []);//wskaznik do funkcji
char znaki[]="Kosmos";
adres_fun = wypisz_tekst;// adres_fun wskazuje na funkcje wypisz_test
// lub
wypisz_tekst (znaki); // wywołanie funkcji przez jej nazwę
(*adres_fun) ( znaki); // wywołanie funkcji przez jej adres
//lub
adres_fun (znaki);
}
Na wskaznikach do funkcji nie wolno wykonywać żadnych operacji arytmetycznych.
Kiedy więc przydają się wskazniki do funkcji:
1) przy przekazywaniu funkcji jako argumentu do innej funkcji
Przykład 1.
float wzor1 (int nr, int k){
float w;
w = sqrt (nr) + sgrt (k) + 5.3;
return (w);
}
float wzor2 (int nr, int k){
float w;
w = sqrt (nr) - k * 7.2;
return (w);
}
float oblicz (float (*wsk_f) (int, int), int a, int b ) {
float wynik;
wynik = wsk_f (a, b);
return wynik;
}
void main(){
float wynik_f;
int los1, los2;
los1=random (100); los2= random (10);
if (los1>50)
wynik_f = oblicz (wzor1, los1, los2);
else
wynik_f = oblicz (wzor2, los1, los2)
}
2) do tworzenia tablic wskazników do funkcji
#include
#include
int f1 (int x) {return x+1;}
int f2 (int x) {return x+2;}
int f3 (int x) {return x+3;}
void main(){
clrscr ();
int (*wsk_fun[3])(int)= {f1,f2,f3};
//lub
wsk_fun[0]=f1;
wsk_fun[1]=f2;
wsk_fun[2]=f3;
int w[3];
for (int i=0; i<3; i++)
w[i]=wsk_fun[i](i);
for (i=0; i<3; i++)
cout<getch();
}
Ekran: 1 3 5


Wyszukiwarka

Podobne podstrony:
Wyklad 09 USG
Wyklad 09 Podstawy Genetyki AI
wyklad6 09
wyklad 2 3 09
wykład 09
wyklad 09
Wyklad11 09
wykład 09
Wyklad 09 decyzja ustanawiajaca Eurojust
fizjologia zwierzat wyklad 09
Wyklad 09 decyzja wzmacniajaca Eurojust
Wyklad13 09
wyklady 09
Wykladowka 2 09

więcej podobnych podstron