Funkcje
Argumenty
Programowanie strukturalne -
Idea funkcji
Jeśli program ma
wyznaczać:
To znacznie łatwiej!!!
określić funkcję f(x) i
wyznaczyć jej wartość
Realizacja w C/C++
#include <stdio.h>
#include <math.h>
main()
{ int i; double y,al,be,ga,de,ep;
double f(double);
// zapowiedź-prototyp
printf(”Podaj liczbę rzeczywistą”); scanf(”%lf”,&y);
printf(”Podaj całkowitą”); scanf(”%d”,&i);
//obliczenia
al=f(y); be=(6.4+y)*f(y); ga=sin(y)*f(y*y);
de=f(sin(y)); ep=f((double)i)*3.2;
printf(”Wyniki: %lf %lf %lf %lf %lf\n”,al.,be,ga,de,ep);
}
//teraz właściwa funkcja f
double f(duble x)
{ return (1/(x*x+sqrt(1+2*x+3*x*x))); }
Definicja i deklaracja funkcji,
argumenty
Na definicję składają się:
typ nazwa_funkcji(lista argumentów)
{
……….. Treść funkcji …………..
}
W naszym przykładzie:
Funkcja wyznacza wartość double – jest typu double
Funkcja ma jeden parametr x typu double,
argument formalny
Instrukcje treści są wykonywane, gdy funkcja
zostanie wywołana
Wywołanie ma postać:
nazwa_funkcji(lista argumentów aktualnych)
Jak działa (nasza) funkcja?
Zmienna x przyjmuje
wartość
argumentu
(a więc wartość wyrażenia użytego podczas
wywołania)
Wykonane zostają instrukcje treści funkcji,
w tym jako ostatnia instrukcja
sterująca return
zwracająca do miejsca
wywołania wartość wyrażenia, tym samym
spełnione jest zadanie funkcji – zwrot
wartości określonego typu
Kilka uwag o naszej funkcji
Nazwa funkcji jest znana od miejsca jej
deklaracji do końca bloku
W przykładzie, definicja funkcji występuje po
definicji main, zatem wywołanie bez
dodatkowych informacji nie byłoby możliwe
Ta dodatkowa informacja to prototyp - tu jest
deklaracją lokalną (obowiązuje tylko w funkcji
main)
To deklaracja a nie definicja (ta występuje w
innym miejscu tekstu) i umożliwia kompilację ze
sprawdzeniem poprawności wywołania
Wiele funkcji
Program na ogół składa się z wielu funkcji
Definicje funkcji mogą występować w dowolnej
kolejności
Funkcje mogą odwoływać się do innych funkcji
(lub do siebie – wówczas mamy do czynienia z
rekurencją)
Należy zadbać, by (w tekście) przed każdym
wywołaniem pojawiła się definicja wywoływanej
funkcji lub jej prototyp
Definicje funkcji nie mogą być zagnieżdżone
Obszary działania zmiennych
Zmienne deklarowane wewnątrz funkcji,
są tylko w niej znane (ich nazwy są
lokalne)
Pamięć dla zmiennych lokalnych (w tym
parametrów formalnych) jest
przydzielana w czasie wywołania i tylko
na czas wywołania
Pamięć zmiennych lokalnych jest
zwalniana po zakończeniu funkcji
Instrukcja return
Ma postać:
return wyrażenie;
return przerywa działanie funkcji,
Zwraca sterowanie do miejsca
wywołania,
Do funkcji wywołującej zwraca wartość
wyrażenia
Powoduje likwidację skutków
zasobowych wywołania
Dotychczasowe wiadomości:
Funkcja „otrzymuje” wartość argumentu
jako początkową wartość parametru
Funkcja działa na zmiennych lokalnych
(o chwilowych instancjach – miejscach)
Zmiany zmiennych lokalnych nie są
dostępne na zewnątrz funkcji
Funkcja zwraca pojedynczą wartość
(typu funkcji)
Uwagi o przekazywaniu
parametrów
W powyższym przykładzie wyznaczona (tuż przed
wywołaniem) wartość argumentu – w postaci
wyrażenia stosownego typu staje się początkową
wartością lokalnej zmiennej – parametru
formalnego funkcji
Takie połączenie między środowiskiem wywołania a
środowiskiem wykonania funkcji nosi w
programowaniu nazwę połączenia przez wartość
W języku C jest to jedyny znany mechanizm
połączeń
Uwagi o przekazywaniu
parametrów
Typ wyrażenia będącego argumentem
musi być zgodny (w sensie przypisania
szeroko rozumianego) z typem
parametru formalnego
Lista parametrów formalnych jest
podobna w swoim działaniu do
deklaracji zmiennych, z jednym
wyjątkiem – każdy parametr formalny
deklarujemy osobno!
Parametry domyślne
UWAGA TYLKO W C++
Jeśli na liście parametrów formalnych
umieścimy przypisanie (jak w deklaracji z
nadaniem wartości początkowej), to ten
argument aktualny można pominąć – użyta
zostanie wartość z definicji funkcji
Uwaga : działa zero-jedynkowo – gdy opuścisz
argument to konsekwentnie wszystkie
następne też musisz opuścić
Warto na tę konsekwencję zwrócić uwagę przy
definicji – lista parametrów powinna zawierać
rzadko używane na końcu
Wskaźniki w argumentach
Należy obliczyć „więcej niż jedną wartość”
np. obwód i pole koła o promieniu r, za
pomocą jednej funkcji
Zadanie można wykonać stosując
odpowiednie parametry – do funkcji
trzeba przekazać adresy zmiennych w
których mają być umieszczone wyniki
W C/C++ można deklarować zmienne,
których wartościami są adresy
O zmiennych adresowych
operatory * i & i typie void
Użycie w deklaracji zmiennej, operatora *
(przed) nazwą zmiennej powołuje zmienną,
której wartościami mogą być adresy
int a=5,*b=&a; //w b znalazł się adres a
*b=20; printf(”%d”,a); // wypisze 20
Zmienne adresowe zajmują tyle samo bajtów,
niezależnie od typu na jaki wskazują
Występująca w instrukcji podstawienia
konstrukcja *b nazywa się L wartością a sam
operator * nazywa się wskazaniem pośrednim
Po lewej stronie instrukcji podstawienia może
wystąpić wyrażenie, o ile jest L wartością
Typ void (C++)
Funkcjom, które nie zwracają żadnej
wartości nadaje się typ void. Stają się
wówczas podobne do pascalowych
procedur i nie ma obowiązku używania
w niej instrukcji return. Uwaga: jeśli
funkcji nie nadamy typu to jest
domyślnie jest to typ int
A teraz funkcja kolo
Postać tej funkcji:
void kolo(double r,double *obw, double
*pole)
{
*obw=2*3.14*r;
*pole=3.14*r*r;
}
A wywołanie:
kolo(pr, &obwod, &pow);
A jak to działa
W chwili wywołania, wyrażenia z
operatorem & (adresu) powodują
przekazanie parametrom formalnym obw i
pole (lokalnym zmiennym czterobajtowym)
– adresów zewnętrznych zmiennych obwod
i pow
L wyrażenie *obw i *pole umożliwia
wstawienie wyniku we wskazane
(zewnętrzne) miejsce
W ten sposób realizowana w C jest
namiastka połączenia przez nazwę
Tablice znakowe
W poprzednich przykładach często
używaliśmy stałych ujętych w
cudzysłów
Kompilator języka C umieszcza taki ciąg
znaków w odpowiedniej grupie bajtów,
dokładając na końcu znak o kodzie 0
Jeśli zachodzi konieczność, programowo
znak o kodzie 0 wstawiamy jako ‘\0’
Tablice tekstowe
Do pamiętania ciągu znaków należy
zarezerwować ciąg bajtów (dłuższy o jeden od
przewidywanej długości tekstu, bowiem musi
tam się zmieścić znak końca \0)
Definicja tablicy znaków ma postać:
char d[maxline];
i rezerwuje maxline kolejnych bajtów, a
elementy tablicy są ponumerowane od 0 do
maxline-1
Rozmiar tablic w definicjach musi być stałą
(dokł. „wyrażeniem stałym”)
Tablice tekstowe
W każdym elemencie tablicy można
zmieścić jeden znak, stąd:
d[0]=‘A’;d[1]=‘l’;d[2]=‘a’;
//d - TO NIE JEST JESZCZE TEKST
d[3]=‘\0’; // a teraz już jest
Definicja tablicy przypisuje
identyfikatorowi adres elementu zerowego
(początku) tablicy
&d[0] i d to adresy początku tablicy
*(d+1) to element d[1]
Przykład
main()
{ /*ile razy a występuje w tekście? */
char d[81],*dd;
int l=0;
dd=gets(d);
while (*dd!=‘\0’)
{ if (*dd==‘a’)l++; dd++; } //NIE d++ bo d jest
stałą
printf(”w:%s \njest %d liter a”,d,l);
}
Maniera skracania – wersja
krótsza
main()
{ /*ile razy a występuje w tekście? */
char d[81],*dd;
int l=0;
dd=gets(d);
while (*dd)
if (*dd++==‘a’)l++;
printf(”w:%s \njest %d liter a”,d,l);
}
Tablice w argumentach
funkcji
Wersja z tablicą
int ile_1(char t[])
{int l=0,i=0;
while (t[i++])
if (t[i]==‘a’)l++;
return l;
}
Wersja ze
wskaźnikiem
int ile_1(char *t)
{int l=0;
while (*t)
if (*t++==‘a’)l++;
return l;
}
Pamiętać należy, że działania na parametrach formalnych to działania
na kopiach argumentów (przekazywanie przez wartość)
Tablice wielowymiarowe
Definicja:
typ nazwa[rozmiar_1][rozmiar_2];
Elementy tablicy „ułożone” w pamięci
wierszami
Odwołanie też w tylu nawiasach ilu
użyto w definicji
Wskaźnik a tablica
Zwiększenie o jeden wskaźnika
pokazującego na typ inny niż
jednobajtowy oznacza zwiększenie
adresu o liczbę bajtów zajmowanych
przez zmienną tego typu A NIE
ZWIĘKSZENIE WSKAŹNIKA (adresu) O
JEDEN (bajt)