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