Języki Programowania – Zajęcia 2
Instrukcje warunkowe, pętle, funkcje i tablice
Na poprzednich zajęciach poznaliście podstawy pracy z C++: tworzenie plików
źródłowych, kompilację programu przy użyciu g++ oraz podstawowe
typy danych i operacje na zmiennych.
Dzisiaj poznamy podstawowe konstrukcje programistyczne, które znacie już z Pythona: instrukcje warunkowe, pętle, funkcje oraz tablice. Zobaczymy, jak zapisuje się je w C++ i wykorzystamy je w jednym większym zadaniu.
1. Instrukcja warunkowa if
Instrukcja if pozwala wykonać określony fragment programu
tylko wtedy, gdy podany warunek jest spełniony.
Podstawowa składnia wygląda następująco:
if (warunek) {
// instrukcje wykonywane, gdy warunek jest prawdziwy
}
else {
// instrukcje wykonywane, gdy warunek jest fałszywy
}
Przykład:
int x = 10;
if (x > 5) {
cout << "x jest wieksze od 5" << endl;
}
else {
cout << "x nie jest wieksze od 5" << endl;
}
Możemy również sprawdzać kilka warunków za pomocą else if:
if (x > 10) {
cout << "x jest wieksze od 10" << endl;
}
else if (x > 5) {
cout << "x jest wieksze od 5, ale nie od 10" << endl;
}
else {
cout << "x jest mniejsze lub rowne 5" << endl;
}
Podstawowe operatory porównania:
| Operator | Znaczenie |
|---|---|
== | równe |
!= | różne |
> | większe |
< | mniejsze |
>= | większe lub równe |
<= | mniejsze lub równe |
= oznacza przypisanie,
natomiast == oznacza porównanie.
2. Pętla for
Pętla for pozwala wielokrotnie wykonać określony fragment programu.
Podstawowa składnia:
for (inicjalizacja; warunek; zmiana) {
// instrukcje
}
Przykład:
for (int i = 0; i < 10; i++) {
cout << i << endl;
}
Program wykona instrukcje dla i = 0, 1, 2, ..., 9.
Jest to odpowiednik znanej z Pythona konstrukcji:
for i in range(10):
print(i)
Warto zwrócić uwagę na trzy części nagłówka pętli:
int i = 0– utworzenie zmiennej i ustawienie jej wartości początkowej,i < 10– warunek wykonywania pętli,i++– zwiększenie wartościipo każdym obrocie pętli.
3. Pętla while
Pętla while wykonuje instrukcje tak długo, jak długo spełniony
jest podany warunek.
Składnia:
while (warunek) {
// instrukcje
}
Przykład:
int i = 0;
while (i < 10) {
cout << i << endl;
i++;
}
Operator ++ zwiększa wartość zmiennej o 1:
i++;
jest równoważne:
i = i + 1;
4. Tablice
Tablica pozwala przechowywać wiele wartości tego samego typu. Tablicę o określonym rozmiarze tworzymy na przykład tak:
double measurements[10];
Możemy od razu podać wartości:
double measurements[10] = {
10.2, 9.8, 10.5, 10.1, 9.9,
10.3, 11.7, 10.0, 9.6, 10.4
};
Podobnie jak w Pythonie, numerowanie elementów zaczyna się od zera:
measurements[0] // pierwszy element
measurements[1] // drugi element
measurements[9] // dziesiaty element
Elementy tablicy możemy przeglądać za pomocą pętli:
for (int i = 0; i < 10; i++) {
cout << measurements[i] << endl;
}
std::vector. Do tematu wektorów wrócimy
na kolejnych zajęciach.
5. Funkcje
Funkcja pozwala wydzielić fragment programu wykonujący określone zadanie. Funkcję możemy następnie wielokrotnie wywoływać z różnych miejsc programu.
Ogólna składnia funkcji:
typ_zwracany nazwa_funkcji(parametry) {
// instrukcje
return wartosc;
}
Na przykład:
double square(double x) {
return x * x;
}
Funkcję możemy następnie wywołać:
double result = square(3.0);
cout << result << endl;
Funkcja może również niczego nie zwracać. W takim przypadku używamy typu
void:
void printHello() {
cout << "Hello!" << endl;
}
5.1. Funkcja przyjmująca tablicę
Do funkcji możemy przekazać również tablicę. Przykładowo funkcja która zwiększa wszystkie elementy tablicy o 1 może wyglądać następująco:
void addCalibrationOffset(double measurements[], int length) {
for (int i = 0; i < length; ++i) {
measurements[i] += 1;
}
}
Funkcję możemy wywołać dla naszej tablicy:
addCalibrationOffset(measurements, 10);
6. Ćwiczenie – krótkie przykłady
Ćwiczenie 1: instrukcja warunkowa
Napiszcie program, który pobiera od użytkownika liczbę całkowitą i sprawdza, czy liczba jest dodatnia, ujemna czy równa zero.
Program powinien wykorzystać if, else if
i else.
Ćwiczenie 2: pętla
Napiszcie program, który wypisuje liczby od 1 do 10 oraz ich kwadraty.
Wykorzystajcie pętlę for.
Przykładowy fragment wyniku:
1 1
2 4
3 9
...
10 100
Ćwiczenie 3: funkcja
Napiszcie funkcję:
double suma(double x, double y)
która zwraca sumę dwóch liczb. Wywołajcie ją dla kilku wartości i wypiszcie wyniki.
7. Zadanie – analiza wyników pomiarów
Zadanie 1
Napiszcie program w C++, który analizuje wyniki 10 pomiarów pewnej wielkości fizycznej.
Wykorzystajcie następującą tablicę:
double measurements[10] = {
10.2, 9.8, 10.5, 10.1, 9.9,
10.3, 11.7, 10.0, 9.6, 10.4
};
Program powinien:
- wypisać wszystkie wyniki pomiarów na ekran,
- obliczyć i wypisać wartość średnią,
- znaleźć i wypisać wartość minimalną,
- znaleźć i wypisać wartość maksymalną,
- policzyć, ile pomiarów jest mniejszych od średniej,
- policzyć, ile pomiarów jest większych od średniej,
- wypisać wszystkie pomiary, które różnią się od średniej o więcej niż 10%.
Obliczenia powinny zostać wykonane z wykorzystaniem funkcji. Program powinien zawierać co najmniej następujące funkcje:
double average(double data[], int size);
double minimum(double data[], int size);
double maximum(double data[], int size);
int countAbove(double data[], int size, double value);
Możecie oczywiście utworzyć również dodatkowe funkcje, jeśli ułatwi Wam to rozwiązanie zadania.
std::vector.
Nie korzystajcie również z gotowych funkcji STL do obliczania minimum,
maksimum lub średniej. Celem zadania jest przećwiczenie tablic, pętli,
instrukcji warunkowych i funkcji.
8. Przykładowy wynik programu
Pomiary:
10.2 9.8 10.5 10.1 9.9 10.3 11.7 10.0 9.6 10.4
Srednia: 10.25
Minimum: 9.6
Maksimum: 11.7
Pomiary mniejsze od sredniej: 6
Pomiary wieksze od sredniej: 4
Pomiary rozniace sie od sredniej o wiecej niz 10%: 1 // ten pomiar to 11.7
9. Schemat pracy
1. Utwórz / otwórz katalog projektu
|
v
2. Utwórz plik .cpp
|
v
3. Napisz / zmodyfikuj kod (niewielkie fragmenty kodu, najlepiej po 1 funkcji na raz!)
|
v
4. Skompiluj:
g++ program.cpp -o program
|
v
5. Jeżeli kompilacja się udała:
uruchom program
|
v
6. Sprawdź działanie
|
v
7. Wprowadź poprawki i wróć do punktu 4
10. Kompilacja i uruchomienie
Program zapiszcie w pliku main.cpp.
Otwórzcie terminal w VS Code: Terminal → New Terminal.
Jeżeli terminal znajduje się w katalogu zawierającym main.cpp,
wykonajcie:
g++ main.cpp -o main
Jeżeli kompilacja zakończyła się poprawnie, uruchomcie program:
./main
Jeżeli korzystacie z Windowsa i program został utworzony jako
main.exe, może być konieczne użycie:
.\main.exe
g++ main.cpp -o main
kompiluje program, natomiast
./main
uruchamia program wynikowy.
11. Co zrobić, gdy kompilator zgłosi błąd?
Podczas pisania programu bardzo często pojawią się błędy składniowe lub logiczne. Jest to normalna część programowania.
Przykładowo, usuńcie średnik z jednej z instrukcji:
double x = 10
cout << x << endl;
Spróbujcie skompilować program i zobaczcie komunikat kompilatora. Następnie poprawcie kod i ponownie wykonajcie:
g++ main.cpp -o main
12. Czym jest std::vector?
Klasyczne tablice w C++ (np. double measurements[10]) mają stały rozmiar, ustalany w kodzie. Przekazując je do funkcji, zwykle podajemy również ich rozmiar, ponieważ sama tablica nie udostępnia go funkcji jako osobnej informacji.
std::vector to dynamiczna tablica dostępna w bibliotece standardowej C++. Aby z niej korzystać, należy dołączyć nagłówek:
#include <vector>std::vector:
- Przechowuje swój rozmiar: metodą
.size()odczytujemy liczbę elementów. - Może zmieniać rozmiar: metodą
.push_back(wartość)dodajemy element na końcu. - Udostępnia elementy przez indeks: indeksowanie zaczyna się od zera, tak jak w tablicy.
- Zarządza pamięcią automatycznie: nie trzeba samodzielnie alokować ani zwalniać pamięci.
Tworzenie wektora i dostęp do elementów
Wektor można utworzyć na kilka sposobów:
std::vector<double> a;
std::vector<double> b = {1.2, 3.4, 5.6};
std::vector<double> c(5, 0.0);ajest pustym wektorem.bzawiera trzy podane wartości.czawiera pięć elementów, każdy o wartości0.0.
Do elementów odwołujemy się za pomocą indeksów:
std::cout << b[0] << std::endl; // 1.2
std::cout << b[2] << std::endl; // 5.6
b[1] = 4.0; // zmiana drugiego elementuN elementów poprawne indeksy to 0, 1, ..., N-1. Odwołanie do indeksu spoza tego zakresu prowadzi do błędu logicznego i może powodować niezdefiniowane zachowanie.Rozmiar i dodawanie elementów
Metoda .size() zwraca liczbę elementów. Metoda .push_back() dodaje nowy element na końcu:
std::vector<double> values = {2.0, 4.0, 6.0};
std::cout << values.size() << std::endl; // 3
values.push_back(8.0);
std::cout << values.size() << std::endl; // 4Po dodaniu elementu rozmiar wektora zwiększa się automatycznie. Nie trzeba wcześniej rezerwować konkretnej liczby elementów ani ręcznie aktualizować zmiennej z rozmiarem.
Przeglądanie elementów w pętli
Jeśli potrzebujemy indeksu elementu, możemy użyć klasycznej pętli for:
for (int i = 0; i < values.size(); i++) {
std::cout << values[i] << std::endl;
}Jeśli chcemy jedynie odczytać kolejne wartości, możemy użyć pętli zakresowej:
for (double value : values) {
std::cout << value << std::endl;
}Pętla zakresowa przechodzi po wszystkich elementach wektora. Zmienna value przyjmuje kolejno wartość każdego elementu.
Przekazywanie wektora do funkcji
Wektor można przekazać do funkcji przez stałą referencję. Dzięki temu nie tworzymy kopii całego wektora, a funkcja nie może modyfikować jego elementów:
double average(const std::vector<double>& data) {
if (data.empty()) {
return 0.0;
}
double sum = 0.0;
for (double value : data) {
sum += value;
}
return sum / data.size();
}constoznacza, że funkcja nie powinna zmieniać przekazanych danych.&oznacza przekazanie przez referencję, bez kopiowania całego wektora.data.empty()sprawdza, czy wektor nie zawiera elementów.
Funkcję można wywołać dla wektorów o różnej liczbie elementów. W powyższym przykładzie zwrócenie 0.0 dla pustego wektora jest przyjętą konwencją na potrzeby ćwiczenia; w większych programach sposób obsługi pustych danych należy świadomie zaprojektować.
Zadanie 2 – analiza pomiarów z wykorzystaniem std::vector
Napisz program, który wykonuje analizę wyników podobną do tej z Zadania 1, ale zamiast klasycznej tablicy wykorzystuje std::vector<double>.
Krok 1. Przygotowanie danych
Utwórz wektor zawierający następujące wartości pierwotnie przechowywane w tablicy measurements.
Wypisz liczbę pomiarów (długość vectora), a następnie wypisz wszystkie wartości w pętli.
Krok 2. Dodawanie pomiarów
Dodaj do wektora dwa nowe pomiary. Sprawdź, czy rozmiar wektora zmienił się zgodnie z oczekiwaniami, i wypisz zaktualizowaną listę pomiarów.
Krok 3. Funkcje analizujące dane
Przygotuj funkcje obliczające średnią, minimum i maksimum. Zastosuj następujące deklaracje:
double average(const std::vector<double>& data);
double minimum(const std::vector<double>& data);
double maximum(const std::vector<double>& data);
Funkcje powinny działać dla wektorów o różnej liczbie elementów. Zastanów się, jak obsłużyć pusty wektor.
Krok 4. Analiza wyników
Korzystając z napisanych funkcji i pętli, oblicz:
- liczbę pomiarów mniejszych od średniej;
- liczbę pomiarów większych od średniej;
- wszystkie pomiary różniące się od średniej o więcej niż 10%.
Krok 5. Sprawdzenie rozwiązania
Uruchom program dla danych początkowych, a następnie dla danych uzupełnionych o dwa dodatkowe pomiary. Sprawdź, czy wszystkie obliczenia uwzględniają nowe elementy.
.size(), .push_back() oraz przekazywanie wektora do funkcji. Nie zakładaj na sztywno, że wektor zawsze zawiera dziesięć elementów. Możesz samodzielnie zaimplementować algorytmy albo skorzystać z funkcji biblioteki standardowej, jeśli potrafisz wyjaśnić ich działanie.15. Najważniejsze rzeczy z dzisiejszych zajęć
- Instrukcja if, else if i else pozwala uzależnić wykonanie kodu od warunku.
- Pętle for i while pozwalają wielokrotnie wykonywać fragment programu.
- Klasyczna tablica przechowuje wiele wartości tego samego typu, a jej indeksowanie zaczyna się od zera.
- Funkcja może przyjmować parametry, zwracać wartość i wykonywać obliczenia na tablicy lub wektorze.
- std::vector przechowuje swój rozmiar; .size() odczytuje liczbę elementów, a .push_back() dodaje element na końcu.
- std::string służy do przechowywania napisów; .length() zwraca liczbę znaków, a == pozwala porównywać napisy.
- Bloki kodu w C++ wyznaczają klamry { }, a większość instrukcji kończy się średnikiem ;.
- Po zmianie kodu źródłowego należy ponownie skompilować program.
16. Punktacja – 0–5 pkt
| Punkty | Kryterium |
|---|---|
| 0.5 pkt | Ćwiczenia: Wykonanie trzech ćwiczeń wprowadzających. |
| 0.5 pkt | Zadanie 1.1: Poprawne utworzenie i wykorzystanie tablicy oraz wypisanie jej elementów. |
| 1.5 pkt | Zadanie 1.2-4: obliczyć i wypisać wartość średnią, minimalną, maksymlaną (0.5 pkt każde). |
| 1 pkt | Zadanie 1.5-6: policzyć, ile pomiarów jest mniejszych/większych od średniej (0.5 pkt każde). |
| 0.5 pkt | Zadanie 1.7: wypisać wszystkie pomiary, które różnią się od średniej o więcej niż 10%. |
| 1.0 pkt | Zadanie 2: Powtórzenie zadania przy użyciu vector. |