Program 6 Program wykorzystujący strukturę osoba o polach: imię

Transkrypt

Program 6 Program wykorzystujący strukturę osoba o polach: imię
Program 6
Program wykorzystujący strukturę osoba o polach: imię, nazwisko, wiek. W programie
wykorzystane są dwie funkcje:
Funkcja pobierz_osobe wczytuje dane osoby podanej jako argument.
Funkcja wypisz_osobe wypisująca dane osoby podanej jako argument.
#include<iostream>
using namespace std;
struct osoba {
string imie, nazwisko;
int wiek;
};
void pobierz_osobe(osoba &o);
void wypisz_osobe(osoba o);
int main()
{
const int liczba_osob = 3;
osoba klasa[liczba_osob];
for (int i=0; i<liczba_osob; i++)
pobierz_osobe(klasa[i]);
cout << "\n\nsklad klasy: \n";
for (int i=0; i<liczba_osob; i++)
wypisz_osobe(klasa[i]);
system("pause");
}
void pobierz_osobe(osoba &o)
{
cout << "imie: "; cin >> o.imie;
cout << "nazwisko: "; cin >> o.nazwisko;
cout << "wiek: "; cin >> o.wiek;
}
void wypisz_osobe(osoba o)
{
cout << "imie: " << o.imie << "\n";
cout << "nazwisko: " << o.nazwisko << "\n";
cout << "wiek: " << o.wiek << "\n\n";
}
Omówienie programu
Definicja struktury o nazwie osoba:
struct osoba {
string imie, nazwisko;
int wiek;
};
Kilka słów o strukturach
Co to jest struktura? Struktura to typ danych, podobnie jak np. typ całkowity oznaczany int.
JeŜeli chcemy zdefiniować zmienną typu int o nazwie a robimy to następująco:
int a;
Zmienna a to jedna liczba całkowita. JeŜeli np.:
a=14;
wówczas zmiennej a nadajemy wartość 14.
Co moŜemy opisać przy pomocy jednej zmiennej całkowitej? Np. wiek, rok, numer domu,
odległość…czyli wszystko to co czego wartością moŜe być jedna liczba całkowita.
A czy moŜemy jedną liczbą całkowitą (czy rzeczywistą) opisać punkt na płaszczyźnie? Jedna
liczba to oczywiście za mało. Musimy mieć dwie liczby poniewaŜ punkt na płaszczyźnie ma
dwie współrzędne.
A iloma liczbami moŜemy opisać samochód? Takich liczb jest wiele zaleŜnie od tego jak
dokładnie chcemy opisać samochód np.: ilość miejsc, ilość drzwi, zuŜycie benzyny, prędkość
maksymalna, pojemność bagaŜnika. W opisie samochodu moŜemy wykorzystywać nie tylko
liczby, ale i ciągi znaków (typ string). Np.: marka samochodu to nie liczba…to właśnie
ciąg znaków.
A jak opisać osobę? Osoba posiada m.in. imię i nazwisko oraz wiek. A zatem aby opisać
osobę moŜemy wykorzystać liczbę (wiek) i dwa ciągi znaków (imię i nazwisko). Oczywiście
moŜemy podać inne cechy osoby: numer telefonu, numer pesel, data urodzenia etc. W
powyŜszym programie wykorzystano tylko trzy: imię (typ string), nazwisko (typ
string) i wiek (typ int).
W tworzeniu takich złoŜonych obiektów jak omówione powyŜej (punkt na płaszczyźnie,
samochód, osoba) wykorzystujemy tzw. struktury. KaŜdy z tych obiektów moŜna
zadeklarować jako strukturę.
Deklaracja struktury ma następującą postać:
struct nazwa_struktury
{
typ_pola1 nazwa_pola1;
typ_pola2 nazwa_pola2;
typ_pola3 nazwa_pola3;
. . . . . . . . . .
};
RozwaŜmy na przykład strukturę punkt:
struct punkt
{
int x;
int y;
};
[ RównowaŜnie
struct punkt
{
int x,y;
};]
Struktura punkt ma dwa pola typu int (x i y). Interpretujemy je jako współrzędne punktu.
Mając zadeklarowaną strukturę punkt moŜemy definiować zmienne (nazywane teŜ
obiektami) typu punkt podobnie jak moŜemy definiować zmienne typu int:
punkt p;
int z;
W pierwszej linijce zdefiniowaliśmy zmienną o nazwie p typu punkt. W drugiej zmienną
o nazwie z typu int.
JeŜeli chcemy nadać wartość zmiennej p robimy to następująco:
P=8;
lub
cin>>p;
Zmienna typu punkt „posiada” dwa pola całkowite (x i y). JeŜeli chcemy nadać wartości x i
y zmiennej p zdefiniowanej powyŜej robimy to następująco:
p.x=9;
p.y=13;
p.x to pole x zmiennej p, p.x to pole x zmiennej p. A zatem współrzędna x punktu p
ma wartość 9, współrzędna y punktu p ma wartość 13.
Oczywiście moŜemy zdefiniować inną zmienną typu punkt:
punkt sk;
sk.x=6;
cin>>sk.y;
Pole x (czyli współrzędna) punktu sk ma wartość 6. Wartość pola y wprowadzamy z
klawiatury.
RozwaŜmy teraz strukturę osoba z powyŜszego programu:
struct osoba {
string imie, nazwisko;
int wiek;
};
Struktura ta ma trzy pola: dwa pola będące ciągami znaków (typ string) – imie,
nazwisko i jedno pole liczbowe (typ int) – wiek. RozwaŜmy następujący program:
#include<iostream>
using namespace std;
struct osoba {
string imie, nazwisko;
int wiek;
};
int main()
{
osoba mama;
mama.imie="Maria";
mama.nazwisko="Nowak";
mama.wiek=35;
cout << "imie: " << mama.imie <<endl;
cout << "nazwisko: " << mama.nazwisko <<endl;
cout << "wiek: " << mama.wiek <<endl;
system("pause");
}
W programie tym zadeklarowana jest struktura osoba:
struct osoba {
string imie, nazwisko;
int wiek;
};
Dalej zdefiniowana jest zmienna typu osoba o nazwie mama:
osoba mama;
Pole imie zmiennej mama ma wartość Maria. Pole nazwisko zmiennej mama ma
wartość Nowak. Pole wiek zmiennej mama ma wartość 35:
mama.imie=”Maria”;
mama.nazwisko=”Nowak”;
mama.wiek=35;
Następnie mamy instrukcje, które wypisują na ekran pola imie, nazwisko i wiek
zmiennej mama (zmienna ta jest typu osoba):
cout << "imie: " << mama.imie <<endl;
cout << "nazwisko: " << mama.nazwisko <<endl;
cout << "wiek: " << mama.wiek <<endl;
Wróćmy teraz do zasadniczego (strona 1) programu. UŜyte są w nim dwie funkcje:
void pobierz_osobe(osoba &o);
void wypisz_osobe(osoba o);
Powtórzmy kilka faktów dotyczących funkcji w języku C++.
Kilka słów o funkcjach
Funkcja (procedura, podprogram) to wydzielona część programu wykonująca jakieś operacje.
Podprogramy stosuje się, aby uprościć program główny i zwiększyć czytelność kodu.
RozwaŜmy następujący program:
#include<iostream>
using namespace std;
int main()
{
cout<<" * "<<endl;
cout<<" *** "<<endl;
cout<<"*****"<<endl;
system("pause");
}
Wynikiem działania tego programu będzie choinka:
*
***
*****
Aby otrzymać trochę bardziej skomplikowaną (wyŜszą) choinkę
*
***
*****
*
***
*****
musimy następująco zmodyfikować nasz program:
#include<iostream>
using namespace std;
int main()
{
cout<<" * "<<endl;
cout<<" *** "<<endl;
cout<<"*****"<<endl;
cout<<" * "<<endl;
cout<<" *** "<<endl;
cout<<"*****"<<endl;
system("pause");
}
MoŜemy jednak postąpić inaczej. Zdefiniujmy funkcję choinka() która będzie rysowała:
*
***
*****
Za kaŜdy razem gdy będziemy chcieli uzyskać powyŜszy obrazek wywołamy funkcję
choinka(). Zobaczmy jak teraz wygląda nasz program:
#include<iostream>
using namespace std;
void choinka()
{
cout<<" * "<<endl;
cout<<" *** "<<endl;
cout<<"*****"<<endl;
}
int main()
{
choinka();
Definicja funkcji choinka()
Wywołanie funkcji choinka()
system("pause");
}
Aby uzyskać wyŜszą choinkę musimy wywołać funkcję choinka() więcej razy. JeŜeli
wywołamy funkcję choinka() 3 razy czyli wpiszemy w powyŜszym programie:
choinka();
choinka();
choinka();
otrzymamy:
*
***
*****
*
***
*****
*
***
*****
Funkcja choinka() nie posiada Ŝadnego argumentu. RozwaŜmy funkcję:
void kwadrat(int x)
{
cout<<x*x<<endl;
}
Funkcja kwadrat posiada jeden argument całkowity x (int x). Działanie funkcji
kwadrat polega na wypisaniu liczby całkowitej przesłanej do niej jako argument. Na
przykład wywołanie funkcji:
kwadrat(5);
kwadrat(3);
spowoduje wypisanie na ekranie liczby 25 (pierwsza linijka) i 9 (druga linijka). Cały program
wygląda następująco:
#include<iostream>
using namespace std;
void kwadrat(int x)
{
cout<<x*x<<endl;
}
int main()
{
kwadrat(5);
kwadrat(3);
system("pause");
}
Argumentem funkcji moŜe być dowolna zmienna takiego samego typu jak argument. Np.
int c=4;
kwadrat(c);
W efekcie na ekranie zostanie wypisana liczba 16 czyli kwadrat liczby 4 będącej wartością
zmiennej c (zauwaŜmy, Ŝe typ argumentu funkcji tzn. int jest taki sam jak typ zmiennej c).
Cały program wygląda następująco:
#include<iostream>
using namespace std;
void kwadrat(int x)
{
cout<<x*x<<endl;
}
int main()
{
int c=4;
cout<<c<<endl;
kwadrat(c);
cout<<c<<endl;
system("pause");
}
Na początku mamy definicję zmiennej c typu int i nadanie jej wartości 4:
int c=4;
Następna linijka to wypisanie wartości zmiennej c czyli 4.
W następnej linijce mamy wywołanie funkcji kwadrat(c) z argumentem c. Co się dzieje
w czasie takiego wywołania funkcji kwadrat?
Wartość zmiennej lokalnej (lokalnej bo określonej wewnątrz funkcji kwadrat) x będzie
równa wartości zmiennej c czyli 4. Na ekran zostanie wypisana wartość x*x czyli 4*4 a
zatem 16.
Na końcu zostanie wypisana znowu wartość zmiennej c czyli 4.
Czyli otrzymamy:
RozwaŜmy teraz następującą modyfikację funkcji kwadrat():
void kwadrat(int x)
{
cout<<x*x<<endl;
x=x*x;
}
Pierwsza linijka odpowiedzialna za wypisanie kwadratu argumentu funkcji x jest bez zmian:
cout<<x*x<<endl;
W drugiej linijce mamy następującą instrukcję:
x=x*x;
Oznacza to, Ŝe nowa wartości zmiennej x równa jest kwadratowi dotychczasowej wartości.
RozwaŜmy nasz program z tak zmodyfikowaną funkcją kwadrat:
#include<iostream>
using namespace std;
void kwadrat(int x)
{
cout<<x*x<<endl;
x=x*x;
}
int main()
{
int c=4;
cout<<c<<endl;
kwadrat(c);
Modyfikacja
cout<<c<<endl;
system("pause");
}
Czy zmieni się działanie naszego programu po takiej modyfikacji funkcji kwadrat?
Początek jest bez zmian - definicja zmiennej c typu int i nadanie jej wartości 4:
int c=4;
Następna linijka to wypisanie wartości zmiennej c czyli 4.
W następnej linijce mamy wywołanie funkcji kwadrat(c) z argumentem c. W efekcie na
ekranie zostanie wypisana liczba 16 (kwadrat 4) – bo w funkcji mamy pierwszą linijkę:
cout<<x*x<<endl;
PoniewaŜ druga linijka funkcji wygląda następująco:
x=x*x;
zatem nowa wartość zmiennej lokalnej x będzie wynosiła 16 (bo dotychczasowa wartość była
równa 4). Wartość ta nie jest jednak wypisana na ekranie. Na końcu zostanie wypisana znowu
wartość zmiennej c czyli 4 (bo mamy linijka: cout<<c<<endl;).
W efekcie otrzymamy:
Wprowadźmy teraz pewną waŜną modyfikację do funkcji kwadrat():
Modyfikacja – zamiast int x int &x
void kwadrat(int &x)
{
cout<<x*x<<endl;
x=x*x;
}
Zobaczmy jaki będzie wynik naszego program z tak zdefiniowaną funkcją kwadrat.
A zatem teraz w wyniku wywołania instrukcji:
cout<<c<<endl;
pojawi się nie liczba 4 ale 16! Dlaczego?
W tym przypadku zamiast wartości zmiennej c czyli liczby 4 do funkcji został wysłany adres
(adres zmiennej x to &x – patrz definicja funkcji) zmiennej c w pamięci komputera.
Ten adres funkcja sobie odebrała i stworzyła tzw. referencję czyli powiedziała sobie coś
takiego: „Dobrze, zatem komórce pamięci o przesłanym adresie nadaję pseudonim (nazwę)
x”. ZauwaŜmy, Ŝe do funkcji został przesłany adres zmiennej c bo wywołanie funkcji ma
postać:
kwadrat(c);
A zatem wewnątrz funkcji kwadrat komórka pamięci o nazwie x to ta sama komórka co
komórka o nazwie c poza funkcją. Po prostu ta sama komórka pamięci inaczej nazywa się
wewnątrz funkcji kwadrat (nazwa x) i poza nią (nazwa c). W efekcie operacja:
x=x*x;
polega na pobraniu zawartości komórki o nazwie x (czyli liczby 4 – przypomnijmy jeszcze
raz, Ŝe to jest ta sama komórka która poza funkcją kwadrat ma nazwę c) i umieszczeniu w
tej komórce nowej wartości równej 4*4 czyli 16.
W efekcie zmianie ulega wartość zmiennej c!! I dlatego na końcu wypisana jest liczba 16.
Oczywiście funkcja moŜe posiadać kilka argumentów.
Zapamiętajmy na koniec, Ŝe przesłanie argumentu do funkcji bez & nazywamy przesłaniem
przez wartość, natomiast przesłanie argumentu z & nazywamy przesłaniem przez referencję.
I wreszcie omówienie programu
Czas powrócić (wreszcie☺) do omówienia programu ze strony pierwszej.
Mamy tam zdefiniowaną strukturę osoba:
struct osoba {
string imie, nazwisko;
int wiek;
};
Mówiliśmy juŜ o niej powyŜej.
Następnie mamy deklaracje funkcji uŜytych w programie:
void pobierz_osobe(osoba &o);
void wypisz_osobe(osoba o);
Definicja funkcji pobierz_osoba wygląda następująco:
void pobierz_osobe(osoba &o)
{
cout << "imie: "; cin >> o.imie;
cout << "nazwisko: "; cin >> o.nazwisko;
cout << "wiek: "; cin >> o.wiek;
}
ZauwaŜmy, Ŝe argument funkcji typu osoba jest przesłany przez referencję. Oznacza to, Ŝe
funkcja moŜe „zmienić” wartości pól przesłanej do niej zmiennej typu osoba. I tak jest
rzeczywiście, poniewaŜ działanie funkcji pobierz_osoba polega na pobraniu z
klawiatury wartości pól imie, nazwisko i wiek zmiennej typu osoba przesłanej do
funkcji przez referencję.
Działanie funkcji wypisz_osoba:
void wypisz_osobe(osoba o)
{
cout << "imie: " << o.imie << "\n";
cout << "nazwisko: " << o.nazwisko << "\n";
cout << "wiek: " << o.wiek << "\n\n";
}
polega na wypisaniu wartości pól imie, nazwisko i wiek zmiennej typu osoba
przesłanej do funkcji przez wartość.
Funkcja main() w omawianym programie wygląda następująco:
int main()
{
const int liczba_osob = 3;
osoba klasa[liczba_osob];
for (int i=0; i<liczba_osob; i++)
pobierz_osobe(klasa[i]);
cout << "\n\nsklad klasy: \n";
for (int i=0; i<liczba_osob; i++)
wypisz_osobe(klasa[i]);
system("pause");
}
Pierwsza linijka to definicja stałego obiektu typu int o nazwie liczba_osob i nadanie mu
wartości 3:
const int liczba_osob = 3;
Słowo const oznacza, Ŝe wartość liczba_osob nie moŜe być juŜ zmieniona.
Następna linijka to definicja 3-elemetowej (3-elementowej bo liczba_osob=3) tablicy
typu osoba o nazwie klasa:
osoba klasa[liczba_osob];
(UWAGA: tak jak moŜemy definiować tablice zawierające np. liczby całkowite (int),
rzeczywiste (float) czy znaki (char) moŜemy teŜ definiować tablice zawierające osoby,
jeŜeli tylko typ osoba został zdefiniowany. W naszym przypadku typ osoba został
zdefiniowany bo mamy definicję struktury osoba)
Następnie mamy w programie pętle for dzięki której moŜemy wpisać wartości pól imie,
nazwisko i wiek w przypadku kaŜdego elementu tablicy klasa. Odbywa się to w ten
sposób, Ŝe kolejno do funkcji pobierz_osobe przesyłamy jako argument: klasa[0]
(dla i=0), klasa[1] (dla i=1), klasa[2] (dla i=2). W efekcie pętla równowaŜna jest
trzem wywołaniom funkcji pobierz_osobe:
pobierz_osobe(klasa[0]);
pobierz_osobe(klasa[1]);
pobierz_osobe(klasa[2]);
Druga pętla wygląda bardzo podobnie z tą róŜnicą, Ŝe zamiast funkcji pobierz_osobe
wywoływana jest w niej trzy razy funkcja wypisz_osobe:
wypisz_osobe(klasa[0]);
wypisz_osobe(klasa[1]);
wypisz_osobe(klasa[2]);

Podobne dokumenty