Przekazywanie parametrów przez wartość i referencję

Transkrypt

Przekazywanie parametrów przez wartość i referencję
Podstawy Informatyki – Referencje i tablice (17/01/2014)
mgr inż. Tomasz Jaworski
Przekazywanie parametrów przez wartość i referencję
Przekazywanie danych do funkcji, w języku C/C++, można wykonać na co najmniej dwa
sposoby: za pomocą wartości i za pomocą referencji.
W przypadku wywołania funkcji z przekazywaniem argumentu przez wartość, wykonywana jest kopia lokalna tego argumentu. Wywołana funkcja wykonuje swoje operacje na
utworzonej kopii. Po zakończeniu działania funkcji, kopia lokalna jest niszczona1. Przykład przekazywania dwóch parametrów przez wartość ilustruje funkcja f1:
void f1(int a, float b)
{
a = 10;
b = 20;
}
W przypadku przekazywania argumentu prze referencje, kopia lokalna nie jest wykonywana, za to funkcja otrzymuje referencję od oryginalnej zmiennej. Oznacza to, że funkcja
wykonując operacje na takim argumencie, operuje na jego wartości oryginalnej. Zatem
po zakończeniu zmieniona wartość pozostaje dostępna do dalszego wykorzystania. Przekazywanie parametrów przez wartość (a) i referencję (b) ilustruje funkcja f2:
void f2(int& a, float& b)
{
a = 10;
b = 20;
}
Należy pamiętać, że przez referencję można przekazywać jedynie zmienne. Wywołanie
funkcji f2(c,d) jest poprawne, ale f2(c,25) już nie. Poniższa funkcja main przedstawia
przykład wywołania funkcji f1 i f2:
int main(void)
{
int c;
float d;
c = 100;
d = 200;
f1(c, d);
printf("c=%d; d=%f\n", c, d);
f2(c, d);
printf("c=%d; d=%f\n", c, d);
return 0;
}
1
Kopie lokalne znajdują się na stosie wywołania funkcji
Przekazywanie tablic
Do funkcji można przekazywać również tablice. Przekazywanie tablic odbywa się zawsze przez referencje – funkcja otrzymuje adres pierwszego elementu przekazywanej tablicy. Przykład funkcji wyświetlającej tablicę o dowolnej długości ilustruje funkcja f3:
void f3(float tab[], int N)
{
for (int i = 0; i < N; i++)
printf("%d=%f\n", i, tab[i]);
printf("\n");
}
int main(void)
{
float A[] = {9,8,7,6,5,4,3.4,2,1,0.15};
f3(A, 10);
return 0;
}
Modyfikowanie tablic przekazywanych przez referencje
Ponieważ tablice przekazywane są automatycznie (i zawsze) przez referencje, możliwa
jest modyfikacja dowolnego elementu tablicy przekazanej do funkcji. Ilustruje to funkcja
f4. Przeprowadza ona dodawanie wartości skalarnej do wektora:
A+c
void f4(float tab[], int N, float X)
{
for (int i = 0; i < N; i++)
tab[i] = tab[i] + X;
}
void f4_a(float tab[], int N, float X, float tab_wy[])
{
for (int i = 0; i < N; i++)
tab_wy[i] = tab[i] + X;
}
int main(void)
{
float A[] = {9,8,7,6,5,4,3.4,2,1,0.15};
float B[10];
f3(A, 10);
f4(A, 10, 100);
f4_a(A, 10, 200, B);
f3(A, 10);
f3(B, 10);
return 0;
}
Druga funkcja f4_a realizuje to samo działanie matematyczne. Różnica polega na zapisywaniu wyników do wektora wyjściowego (tab_wy) zamiast modyfikacji istniejącego
wektora (tab).
Operacje dwuwymiarowe na tablicach jednowymiarowych
Każdą tablicę dwuwymiarową (i dalej) można przedstawić za pomocą tablicy jednowymiarowej. Należy jednak przyjąć sposób przedstawienia: wierszowy lub kolumnowy2.
Poniżej omówiono przykład z wierszową reprezentacją tablicy dwuwymiarowej.
Przykładowa tablica dwuwymiarowa posiada 3 wiersze i 4 kolumny, co daje 12 elementów (numerowanych od 0 do 11).
0
0
1
2
1,1 (0)
2,1 (4)
3,1 (8)
1
1,2 (1)
2,2 (5)
3,2 (9)
2
1,3 (2)
2,3 (6)
3,3 (10)
3
1,4 (3)
2,4 (7)
3,4 (10)
W przypadku reprezentacji wierszowej, tabela jednowymiarowa tworzona jest poprzez
ustawienie wierszy w jednej linii. Kolorem czerwonym oznaczono wartości komórek,
kolorem zielonym – indeksy w tabeli jednowymiarowej.
0
1
2
3
4
5
6
7
8
9
10
11
1,1
1,2
1,3
1,4
2,1
2,2
2,3
2,4
3,1
3,2
3,3
3,4
2
Reprezentacja kolumnowa wykorzystywana jest w programach do automatyzacji obliczeń matematycznych, np. Matlab czy Octave.
Przy takiej reprezentacji adres komórki w tabeli jednowymiarowej można wyznaczyć z
poniższej zależności:
adres_1D = numer_wiersza*LICZBA_KOLUMN + numer_kolumny
gdzie: LICZBA_KOLUMN to liczba kolumn w tablicy dwuwymiarowej. W powyższym
przykładzie będzie to 4. numer_wiersza i numer_kolmny to współrzędne elementu tablicy dwuwymiarowej, do której chcemy się odwołać.
Przykład:
Wiersz 1 i kolumna 2 określają element o wartości 2,3. Wprowadzona zależność pozwala
na wyznaczenie numeru komórki w tabeli jednowymiarowej:
adres = 1 * 4 + 2 = 6
Poniższy przykład pokazuje jak utworzyć tablicę o wymiarach 4 wiersze/5 kolumn a następnie wyświetlić ją. Liczba wierszy przekazywana jest do funkcji wyświetl jako argument LW, liczba kolumn jako LK.
void wyswietl(float tab[], int LW,
{
for(int w = 0; w < LW; w++)
{
for(int k = 0; k < LK;
{
int nr_komorki =
printf("%5.2f ",
}
printf("\n");
}
}
int main(void)
{
float A[4*5] =
{
1, 2, 3,
5, 6, 7,
9, 10, 11,
13, 14, 15,
};
4,
8,
12,
16,
int LK)
k++)
w * LK + k;
tab[nr_komorki]);
100,
200,
300,
400,
wyswietl(A, 4, 5);
return 0;
}
Jak widać, tablica A jest tablicą jednowymiarową. Na dowolny, wizualny sposób zapisu
(po 5 elementów w jednym wierszu kodu) pozwala kompilator języka C.
Warto wspomnieć, że w przypadku reprezentacji wierszowej, do wyznaczania indeksu
komórki tablicy jednowymiarowej wykorzystywana jest LICZBA_KOLUMN (aby
określić szerokość jednego wiersza).
Zadania
Uwaga.
• We wszystkich zadaniach funkcje operujące na wektorach/macierzch nie mogą
zakładać ich wymiarów. np. funkcja wyswietl ma działać dla wektorów/macierzy
o dowolnych wielkościach.
• Jeśli nie podano inaczej, to długości/wymiary wektorów/macierzy oraz ich wartości można podać bezpośrednio w kodzie programu, bez stosowania funkcji wprowadzania danych od użytkownika.
1. Napisz program, który wyznacza iloczyn wartości skalarnej c i wektora A o dowolnej
długości. Mnożenie oraz wyświetlanie wektorów ma być wykonane przez oddzielne
funkcje. Wynikiem wyświetlonym w konsoli mają być wartości dwóch wektorów:
A, Ac .
2. Napisz program, który wyznacza sumę dwóch wektorów o jednakowej długości i dowolnych wartościach. Sumowanie oraz wyświetlanie wektorów ma być wykonane przez
→
oddzielne funkcje. Wynikiem na konsoli mają być trzy wektory: A, B, A + B .
3. Napisz program, który wyznacza iloczyn skalarny dwóch wektorów o jednakowej długości i dowolnych wartościach. Program ma posiadać oddzielne funkcje do wyświetlania
wektorów i wyznaczania ich iloczynu:
il _ sk = a 1 b1 + a 2 b 2 + a 3 b 3 + + a n b n
4. Napisz program który posiada funkcję dodającą do każdego elementu wektora wartość
stałą c. Dodawanie należy zrealizować oddzielnej funkcji. Wynik dodawania w postaci
wartości wektora wynikowego ma zostać wyświetlony na ekranie.
5. Napisz program wyświetlający macierz o dowolnie wybranych wartościach oraz rozmiarze.
6. Napisz program dodający do siebie dwie macierze o jednakowych wymiarach. Na
ekranie mają być wyświetlone trzy macierze: A, B, A+B. Dodawanie i wyświetlanie należy zrealizować w oddzielnych funkcjach.
7. Napisz program który posiada funkcję wyświetlającą dowolny wiersz i kolumnę z macierzy. Numer wiersza/kolumny ma być wybierany przez użytkownika i znajdować się w
zadanym przez programistę zakresie.
8. Napisz program mnożący dwie macierze. Program ma sprawdzać, czy wymiary macierzy wejściowych oraz wyjściowej, podane przez programistę są spójne. Mnożenie i wyświetlanie zrealizować w oddzielnych funkcjach. Na ekranie mają być wyświetlone wartości trzech macierzy: A, B, A × B .
-Zadania (17/01/2014):
1. Liczby Fibonacciego definiowane są następująco:
x1= 2, x2= 5,
xn = 2xn-2 + xn-1, n = 3,4,5,...
a. Napisz funkcję, która wyznacza n pierwszych liczb Fibonacciego.
b. Napisz program, który oblicza liczby Fibonacciego w dowolnym przedziale <k,l>
wpisanym z klawiatury.
2. Napisz program szukający liczb bliźniaczych w zadanym przedziale <x1,x2>. Liczby
bliźniacze to 2 liczby pierwsze oddalone od siebie o 2, np: 3,5; 5,7. Zaimplementuj to
przy pomocy funkcji:
void blizniacze(int x1, int x2);
//funkcja ta znajduje i wypisuje liczby bliźniacze. wewnątrz niej następuje wywołanie
funkcji pierwsze.
3. Napisz program, który w zadanym przedziale <x1, x2> znajduje liczby pierwsze3. Zaimplementuj wyznaczanie liczb pierwszych przy pomocy funkcji:
int pierwsze(int a);
a - liczba wysłana do funkcji sprawdzającej czy jest liczbą pierwszą. Funkcja
zwraca wartość 0 gdy liczba nie jest liczbą pierwsza, 1 w przeciwnym przypadku
(gdy jednak jest).
3
liczby pierwsze - liczby, które dzielą się bez reszty tylko przez wartość 1 oraz przez samą siebie