INFORMATYKA 1 FOLIE NR 7 TEMAT: Programowanie w języku C
Transkrypt
INFORMATYKA 1 FOLIE NR 7 TEMAT: Programowanie w języku C
INFORMATYKA 1 FOLIE NR 7 Wykonanie programu rozpoczyna się od funkcji main. Gdy dochodzimy do instrukcji zawierającej funkcję add, to wywołanie tej funkcji przekazuje sterowanie do pierwszej jej instrukcji. Do funkcji przekazywane są dwa parametry typu float. Pierwszy parametr (a) otrzymuje wartość pierwszego parametru wywołania funkcji (x1), natomiast drugi parametr (b) - wartość drugiego parametru wywołania funkcji (x2). Powrót z funkcji (do miejsca zaraz po jej wywołaniu) następuje na skutek wykonania instrukcji return. Wartość zwracana przez funkcję podstawiana jest pod zmienną wynik. Po słowie return moŜe występować dowolne wyraŜenie. WyraŜenie to często umieszczane jest w nawiasach, ale nie jest to konieczne. Funkcję add moŜna zapisać w prostszy sposób: TEMAT: Programowanie w języku C/C++: Funkcje. Przekazywanie argumentów przez wartość i referencje. Funkcje W programie w języku C zawsze występuje co najmniej jedna funkcja - main - od której rozpoczyna się wykonanie całego programu. Oprócz niej mogą występować takŜe inne funkcje zdefiniowane przez uŜytkownika. Ogólna struktura funkcji w języku C jest następująca: nazwa funkcji typ wartości zwracanej przez funkcję float add(float a, float b) { return (a+b); } argumenty przekazywane do funkcji nagłówek funkcji float add(float a, float b) { instrukcja float y; ciało funkcji y = a + b; instrukcja return y; instrukcja } wartość zwracana przez funkcję wynik = add(10,20); wynik = add(x1*20+4,x1/x2); Istnieją funkcje, które nie zwracają Ŝadnej wartości, wtedy jako typ zwracanego wyniku podajemy void, np. void drukuj(int a) { printf(“Liczba a wynosi: %d \n”,a); return; } Przykład 1 (funkcja dodająca dwie liczby) #include <stdio.h> Wywołanie funkcji w programie: float add(float a, float b) { float y; y = a + b; return y; } int main() { float x1=10.0, x2=20.0, wynik; return 0; } PowyŜsza funkcja nie zwraca Ŝadnego wyniku więc wystarczy samo słowo return. Jeśli funkcja nie zwraca wyniku i nie ma w jej ciele return to sterowanie wraca do punktu wywołania na skutek zakończenia wykonania wszystkich instrukcji w bloku funkcyjnym. Mogą istnieć funkcje, do których nie przekazujemy Ŝadnych parametrów formalnych, np. Wywołanie funkcji w programie: -1- © 2008 Jarosław Forenc drukuj(-10); void linia() { printf(”----------\n”); } wynik = add(x1,x2); printf("Wynik = %f\n", wynik); Informatyka 1 W wywołaniu funkcji jako parametry mogą występować zmienne, wyraŜenia arytmetyczne lub stałe liczbowe, np. Informatyka 1 void linia(void) { printf(”----------\n”); } lub linia(); -2- - nawiasy są konieczne. © 2008 Jarosław Forenc Ale juŜ zapis: Przekazywanie parametrów do funkcji przez wartość linia(void) { printf(”----------\n”); } Przekazywanie parametrów przez wartość oznacza, Ŝe po przekazaniu sterowania do funkcji tworzone są kopie zmiennych przekazywanych do funkcji i wszystkie działania w funkcji wykonywane są na kopiach. nie jest równowaŜny powyŜszym zapisom, gdyŜ jeśli nie podamy typu zwracanej wartości przez funkcję, to domyślnie jest to typ int. Umieszczanie definicji funkcji w programie Definicje funkcji moŜna umieszczać w dowolnym miejscu programu (przed lub po main). NaleŜy jednak pamiętać o tym, Ŝe zasięg widzialności funkcji rozpoczyna się od miejsca jej deklaracji. Jeśli chcemy umieścić definicję funkcji po funkcji main, czyli po jej wywołaniu, to musimy wcześniej podać jej formalną deklarację czyli prototyp. Prototyp opisuje to samo co nagłówek, ale kończy się średnikiem. W prototypie nie musimy podawać nazw argumentów formalnych - wystarczą tylko typy. Podanie nazw argumentów ma jednak znaczenie dla czytelności programu. Dzięki prototypom kompilator ma moŜliwość sprawdzenia zgodności typów formalnych i faktycznych. Wynik działania programu: void fun(int a, int b) { printf("fun1: a=%3d, b=%3d \n",a,b); a=10; b=10; printf("fun2: a=%3d, b=%3d \n",a,b); } int main() { int a=20, b=20; printf("main1: a=%3d, b=%3d \n",a,b); fun(a,b); printf("main2: a=%3d, b=%3d \n",a,b); return 0; } main1: fun1: fun2: main2: void fun(int a, int b); void fun (int a, int b) { ... } Przekazywanie parametrów do funkcji przez referencję int main() { ... fun(a,b); ... } Przykład 3 (przekazywanie parametrów do funkcji przez referencję) lub #include <stdio.h> void fun(int, int); W programie po prawej stronie umieszczenie prototypu funkcji fun nie jest konieczne, gdyŜ definicja funkcji fun umieszczona jest przed funkcją main. Informatyka 1 -3- 20, 20, 10, 20, b= b= b= b= 20 20 10 20 Przekazywanie parametrów do funkcji przez referencję polega na tym, Ŝe do funkcji przekazywane są adresy zmiennych. Wszystkie operacje w funkcji wykonywane są zatem na zmiennych z funkcji wywołującej (poprzez adres tych zmiennych). W programie po lewej stronie funkcja fun zdefiniowana jest po funkcji main, dlatego przed funkcją main umieszczony jest jej prototyp: void fun(int a, int b); a= a= a= a= Po powrocie z funkcji fun wartości zmiennych a i b nie zmieniły się, gdyŜ w funkcji fun pracowaliśmy na ich kopiach (mających takie same nazwy). #include ... void fun (int a, int b) { ... } #include <stdio.h> #include ... int main() { ... fun(a,b); ... } Przykład 2 (przekazywanie parametrów do funkcji przez wartość) © 2008 Jarosław Forenc void fun(int *a, int *b) { printf("fun1: a=%3d, b=%3d \n",*a,*b); *a=10; *b=10; printf("fun2: a=%3d, b=%3d \n",*a,*b); } int main() { int a=20, b=20; printf("main1: a=%3d, b=%3d \n",a,b); fun(&a,&b); printf("main2: a=%3d, b=%3d \n",a,b); return 0; } Informatyka 1 -4- Wynik działania programu: main1: fun1: fun2: main2: a= a= a= a= 20, 20, 10, 10, b= b= b= b= 20 20 10 10 Po powrocie z funkcji fun wartości zmiennych a i b zostały zmienione, gdyŜ do funkcji fun przekazane zostały adresy (&a, &b) i pracowaliśmy na zmiennych poprzez ich adresy. © 2008 Jarosław Forenc W funkcji main: int a; a &a - deklaracja zmiennej typu int, - zmienna typu int, - adres zmiennej, a nie jej wartość. W funkcji fun: - deklaracja zmiennej wskaźnikowej (na typ int), - adres zmiennej typu int, - wartość zmiennej wskazywanej przez a. int *a; a *a Przekazywanie parametrów do funkcji Zmienne lokalne i zmienne globalne Zmienne zadeklarowane w funkcjach są zmiennymi lokalnymi widzianymi tylko w obrębie danej funkcji (bloku funkcyjnego) od miejsca, w którym zostały zadeklarowane. Zmienne lokalne są zmiennymi dynamicznymi. Zmienne zadeklarowane poza funkcją main są zmiennymi globalnymi widzianymi w całym programie od miejsca deklaracji (są to zmienne statyczne). Jeśli zmienna globalna i lokalna mają takie same nazwy, to zmienna lokalna przesłania widzialność zmiennej globalnej w danej funkcji. #include ... int a, b; void f1() { float a, c; zmienne a i b typu int są zmiennymi globalnymi, zmienne a i c typu float są zmiennymi lokalnymi widzianymi tylko w funkcji f1, zmienne c i d typu int są zmiennymi lokalnymi widzianymi tylko w funkcji main, zmienna globalna b widziana jest w obu funkcjach: f1 i main, zmienna globalna a widziana jest tylko w funkcji main, gdyŜ w funkcji f1 jej nazwa została przesłonięta przez zmienną lokalną a typu float. ... } int main() { int c, d; ... } Rekurencyjne wywołanie funkcji Rekurencyjne wywołanie funkcji polega na ponownym jej wywołaniu zanim skończyło się jej poprzednie wywołanie. Przykład (silnia liczby n): Wersja nierekurencyjna Wersja rekurencyjna (1) Wersja rekurencyjna (2) int silnia(int n) { int i, wynik=1; for (i=1;i<=n; i++) wynik = wynik * i; return wynik; } int silnia(int n) { Informatyka 1 int silnia(int n) { if (n<=1) return 1; else return n*silnia(n-1); } -5- Tablica jednowymiarowa (wektor). Przy przekazywaniu do funkcji wektora, w nagłówku funkcji umieszczamy typ elementów wektora, jego nazwę i same nawiasy kwadratowe lub nawiasy kwadratowe z rozmiarem wektora. W wywołaniu funkcji podajemy natomiast tylko nazwę wektora. Zatem przekazujemy do funkcji adres wektora więc wszystkie zmiany w funkcji będą uwzględnione po wyjściu z niej. Przykład: void fun(int wektor[]) { ... } lub int main() { int wektor[10]; ... fun(wektor); ... } void fun(int wektor[10]) - wywołanie funkcji. Tablica dwuwymiarowa (macierz). Przy przekazywaniu do funkcji tablicy dwuwymiarowej musimy koniecznie podać liczbę kolumn. W wywołaniu funkcji podajemy natomiast tylko nazwę tablicy. Zatem przekazujemy do funkcji adres tablicy więc wszystkie zmiany w funkcji będą uwzględnione po wyjściu z niej. Przykład: void fun(int macierz[][M]) lub { ... } int main() { int macierz[N][M]; ... fun(macierz); ... } void fun(int macierz[N][M]) - wywołanie funkcji. return n ? n*silnia(n-1) : 1; } © 2008 Jarosław Forenc Informatyka 1 -6- © 2008 Jarosław Forenc Struktury. Struktury przekazywane są do funkcji tak jak kaŜde inne zmienne podstawowych typów, czyli przez wartość. Przykład: struct punkt { int x,y; }; struct punkt fun(struct punkt p1) { ... } int main() { struct punkt p1,p2; ... p2=fun(p1); ... } Informatyka 1 - wywołanie funkcji. -7- © 2008 Jarosław Forenc