Wejściówka
Napisz program w języku C++, który stworzy dwuwymiarową tablicę (NxM) w postaci tablicy wskaźników do tablicy wartości liczb całkowitych. Napisz funkcję f1, która wypełni tą tablicę dowolnymi wartościami.
Rozwiązanie:
#include <iostream>
void f1(int **arr, int n, int m) {
for(int i = 0; i < n; ++i)
for(int j = 0; j < m; ++j)
arr[i][j] = i * j;
}
int main() {
int n, m;
std::cin >> n >> m;
int **arr = new int*[n];
for(int i = 0; i < n; ++i)
arr[i] = new int[m];
f1(arr, n, m);
for(int i = 0; i < n; ++i)
delete[] arr[i];
delete[] arr;
return 0;
}
Zadanie 1
Napisz program w języku C++, który za pomocą wskaźnika do funkcji wywoła dwie funkcje: add i sub. Funkcja add powinna dodawać dwie liczby, zaś funkcja sub odejmować dwie liczby. Zaimplementowany program powinien sprawdzić poprawność działania tych funkcji.
Rozwiązanie:
#include <iostream>
int add(int a, int b) {
return a + b;
}
int sub(int a, int b) {
return a - b;
}
int main() {
int (*fun)(int, int);
fun = add;
std::cout << fun(10, 2) << std::endl;
fun = sub;
std::cout << fun(10, 2) << std::endl;
return 0;
}
Omówienie:
Dotychczas zajmowaliśmy się sytuacją, gdy wskaźnik wskazywał na jakąś zmienną. Jednak nie tylko zmienna ma swój adres w pamięci. Oprócz zmiennej także i funkcja musi mieć swoje określone miejsce w pamięci. Z tego względu nie ma przeszkód, aby i na nią wskazywał jakiś wskaźnik.
Kod maszynowy utworzony po skompilowaniu programu odnosi się właśnie do adresu funkcji. Wskaźnik na funkcję różni się od innych rodzajów wskaźników.
Jedną z głównych różnic jest jego deklaracja. Zwykle wygląda ona następująco:typ_zwracanej_wartości (*nazwa_wskaźnika)(typ1 argument1, typ2 argument2);
Należy zwrócić uwagę na dwie rzeczy:
– przypisując nazwę funkcji bez nawiasów do wskaźnika, automatycznie informujemy kompilator, że chodzi nam o adres funkcji,
– wskaźnika używamy tak, jak normalnej funkcji, na którą on wskazuje.
Zadanie 2
Napisz program w języku C++, który wczyta od użytkownika dwie liczby zmiennoprzecinkowe a i b, a następnie nieujemną liczbę całkowitą o. Program, w zależności od podanej nieujemnej liczby całkowitej, powinien wyświetlić wynik odpowiedniego działania:0 – dodawanie,1 – odejmowanie,2 – mnożenie,3 – dzielenie.
Do rozwiązania zadania wykorzystaj wskaźniki na funkcje.
Rozwiązanie:
#include <iostream>
float add(float a, float b) {
return a + b;
}
float sub(float a, float b) {
return a - b;
}
float mul(float a, float b) {
return a * b;
}
float div(float a, float b) {
return a / b;
}
int main() {
unsigned int o;
float a, b;
float (*f_ptr[4])(float, float) = {add, sub, mul, div}; // tablica wskaźników na funkcje
std::cin >> a >> b >> o;
std::cout << f_ptr[o](a, b) << std::endl;
return 0;
}
Zadanie 3
Wykorzystując wskaźniki na funkcje napisz program w języku C++, który w zależności od wywołania funkcji f znajdzie w tablicy liczb całkowitych wartość minimalną lub maksymalną.
Rozwiązanie:
#include <iostream>
int min(int a, int b) {
return a < b ? a : b;
}
int max(int a, int b) {
return a > b ? a : b;
}
int f(int arr[], int n, int (*fun)(int,int)) {
int ex = arr[0];
for(int i = 1; i < n; ++i)
ex = fun(ex, arr[i]);
return ex;
}
int main() {
int arr[] = {1, 2, 3, 5, 15, 0, 12, 13, 5, 7};
std::cout << f(arr, 10, min) << std::endl;
std::cout << f(arr, 10, max) << std::endl;
return 0;
}
Omówienie:
int f(int arr[], int n, int (*fun)(int,int)) //można zamienić na: typedef int (*p_fun)(int, int); int f(int arr[], int n, p_fun fun)
Zadanie 4
Napisz program w języku C++, który posortuje tablicę dowolnych liczb rzeczywistych arr1 malejąco oraz tablicę dowolnych liczb całkowitych arr2 rosnąco. Do sortowania wykorzystaj algorytm Quick Sort z pliku nagłówkowego cstdlib.
Rozwiązanie:
#include <cstdlib>
#include <iostream>
int min(const void *a, const void *b) {
float av = *(float *)a;
float bv = *(float *)b;
if(av > bv) return -1;
else if(av == bv) return 0;
else return 1;
//lub
//return *(float*)b - *(float*)a < 0 ? -1 : 1;
//powyższy zapis wynika z konwersji liczb zmiennoprzecinkowych na liczbę całkowitą np. float 0.2 -> int 0 itd.
}
int max(const void *a, const void *b) {
int av = *(int *)a;
int bv = *(int *)b;
if(av < bv) return -1;
else if(av == bv) return 0;
else return 1;
//lub
//return *(int*)a - *(int*)b;
}
int main() {
float arr1[] = {1.f, 2.f, 3.f, 5.f, 15.f, 0.f, 12.f, 13.f, 5.f, 7.f};
int arr2[] = {1, 2, 3, 5, 15, 0, 12, 13, 5, 7};
qsort(arr1, 10, sizeof(float), min);
for(int i = 0; i < 10; ++i)
std::cout << arr1[i] << " ";
std::cout << "\n";
qsort(arr2, 10, sizeof(int), max);
for(int i = 0; i < 10; ++i)
std::cout << arr2[i] << " ";
std::cout << "\n";
return 0;
}
Zadanie 5
Napisz program w języku C++, który posortuje malejąco tablicę napisów za pomocą funkcji qsort.
Rozwiązanie:
#include <cstdlib>
#include <iostream>
#include <cstring>
int str_cmp(char str_0[], char str_1[]) {
unsigned int i = 0;
while(str_0[i] && (str_0[i] == str_1[i])) ++i;
return str_0[i] - str_1[i];
}
int compar(const void *p1, const void *p2) {
return -str_cmp((char *)p1, (char *)p2);
//return -strcmp((const char *)p1, (const char *)p2); - jeżeli korzystamy z pliku nagłówkowego cstring
}
int main() {
char arr[5][100] = {
"tygrys syberyjski",
"krokodyl nilowy",
"panda wielka",
"tygrys azjatycki",
"chomik europejski"
};
qsort(arr, 5, 100, compar);
for(int i = 0; i < 5; ++i)
std::cout << arr[i] << std::endl;
return 0;
}
Zadanie 6
Napisz program w języku C++, który wczyta od użytkownika liczbę, jako napis. Liczba powinna mieć co najwyżej 10 cyfr. Następnie program powinien zwiększyć tą liczbę o 10 i ją wyświetlić.
Rozwiązanie:
#include <cstdio>
#include <cstdlib>
#include <iostream>
int main() {
char str[11] = {0}, *ptr = nullptr;
scanf("%10s", str);
int value = strtol(str, &ptr, 10) + 10;
std::cout << std::to_string(value) << std::endl;
return 0;
}
Zadanie 7
Zaprojektuj funkcję w języku C++, która zwróci indeks szukanej wartości w posortowanej tablicy liczb całkowitych. Funkcja powinna zwrócić -1, jeśli nie uda się znaleźć takiej wartości w tablicy. Rozwiązanie powinno wykorzystywać algorytm Binary Search. Napisz program w języku C++, który przetestuje działanie tej funkcji.
Rozwiązanie:
#include <iostream>
#include <cstdlib>
int binarySearch(int *arr, int l, int r, int x) {
int mid = (l + r) / 2;
if(mid <= r && mid >= l) {
if(arr[mid] == x) return mid;
else if(arr[mid] > x) return binarySearch(arr, l, mid - 1, x);
else return binarySearch(arr, mid + 1, r, x);
}
return -1;
}
int compare(const void *ap, const void *bp) {
return *(int*)ap - *(int*)bp;
}
int main() {
int arr[] = {1, 2, 3, 4, 10, 22, 23, 42};
int x = 4;
int n = sizeof(arr) / sizeof(arr[0]);
int result = binarySearch(arr, 0, n - 1, x);
int *p = (int *) bsearch(&x, arr, n, sizeof(arr[0]), compare);
std::cout << (result == -1 ? "Brak" : std::to_string(result)) << std::endl;
std::cout << (p ? std::to_string(p - arr) : "Brak") << std::endl;
return 0;
}
Zadanie 8
Napisz funkcję w języku C++, która przyjmuje w argumencie tablicę liczb całkowitych (wskaźnik na kwadratową macierz) oraz jej rozmiar N. Funkcja powinna wypełnić przekazaną w argumencie macierz tabliczką mnożenia. Macierz jest spójnym obszarem pamięci.
Rozwiązanie:
#include <iostream>
void fill_matrix(int *matrix, int n) {
for(int i = 0; i < n; ++i)
for(int j = 0; j < n; ++j)
matrix[i * n + j] = (i + 1) * (j + 1);
}
void print_matrix(int *matrix, int n) {
for(int i = 0; i < n; ++i) {
for(int j = 0; j < n; ++j)
std::cout << matrix[i * n + j] << " ";
std::cout << "\n";
}
}
int main() {
int n = 10;
int *arr = new int[n * n];
fill_matrix(arr, n);
print_matrix(arr, n);
delete[] arr;
return 0;
}
Zadanie 9
Napisz funkcję w języku C++, która otrzymuje w argumencie jednowymiarową tablicę liczb zmiennoprzecinkowych, dwie liczby całkowite będące wymiarami obszaru reprezentowanego przez tablicę podaną w pierwszym argumencie. Funkcja powinna wypełnić krawędzie obszaru zerami, a następnie zwrócić dwuwymiarową tablicę z tak zmodyfikowanymi danymi. Napisz program w języku C++, który sprawdzi działanie tej funkcji.
Rozwiązanie:
#include <iostream>
void f(float *arr, int n, int m, float **result) {
for(int i = 0; i < n; ++i)
for(int j = 0; j < m; ++j)
if(i == 0 || j == 0 || i == n - 1 || j == m - 1)
result[i][j] = 0.f;
else
result[i][j] = arr[i * m + j];
}
void print_arr(float **arr, int n, int m) {
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j)
std::cout << arr[i][j] << " ";
std::cout << "\n";
}
}
int main() {
const int n = 3, m = 5;
float arr[n * m] = {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f};
float **result = new float*[n];
for(int i = 0; i < n; ++i)
result[i] = new float[m];
f(arr, n, m, result);
print_arr(result, n, m);
for(int i = 0; i < n; ++i)
delete[] result[i];
delete[] result;
return 0;
}
Zadanie 10
Napisz program w języku C++, który wczyta od użytkownika dwie liczby całkowite n i x, a następnie stworzy dwie n-elementowe tablice liczb całkowitych. Następnie program powinien uzupełnić tablicę kolejnymi wartościami zaczynając od x i ustawić te wartości w losowej kolejności (wymieszać). Na koniec program powinien wyświetlić obie tablicę, sumę wartości w tablicach oraz wynik iloczynu skalarnego dwóch tak zdefiniowanych wektorów. Spróbuj rozwiązać zadanie wykorzystując głównie algorytmy i funkcje biblioteczne np. iota z pliku nagłówkowego numeric.
Rozwiązanie:
#include <iostream>
#include <numeric>
#include <algorithm>
void print_arr(int *b, int *e) {
for(int *i = b; i < e; ++i)
std::cout << *i << " ";
std::cout << "\n";
}
int main() {
int n, x, init = 0, *t1 = nullptr, *t2 = nullptr;
std::cin >> n >> x;
t1 = new int[n];
t2 = new int[n];
std::iota(t1, t1 + n, x);
std::iota(t2, t2 + n, x);
std::random_shuffle(t1, t1 + n);
std::random_shuffle(t2, t2 + n);
print_arr(t1, t1 + n);
print_arr(t2, t2 + n);
std::cout << std::accumulate(t1, t1 + n, init) << std::endl;
std::cout << std::inner_product(t1, t1 + n, t2, init) << std::endl;
delete[] t1;
delete[] t2;
return 0;
}
Zadanie 11
Napisz program w języku C++, który wczyta od użytkownika maksymalnie 100 znakowe słowo. Następnie program powinien stworzyć odwrócony odpowiednik napisu wprowadzonego przez użytkownika za pomocą arytmetyki wskaźników.
Rozwiązanie:
#include <cstdio>
#define MAX_SIZE 100
int main() {
char str[MAX_SIZE + 1] = {0}, reverse[MAX_SIZE + 1] = {0};
char *s = str;
char *r = reverse;
scanf("%100s", str);
int len = 0;
while(*(s++)) len++;
s--;
while(len >= 0) {
*(r++) = *(--s);
len--;
}
*r = '\0';
printf("Original: %s\n", str);
printf("Reverse: %s\n", reverse);
return 0;
}
Omówienie:
Ciekawy przykład arytmetyki na wskaźnikach:
#include <iostream>
using namespace std;
int main()
{
int num[5];
int* p;
p = num;
*p = 10;
p++;
*p = 20;
p = &num[2];
*p = 30;
p = num + 3;
*p = 40;
p = num;
*(p + 4) = 50;
for (int i = 0; i < 5; i++)
cout << num[i] << ", ";
return 0;
}
Zadanie 12
Wykorzystaj funkcję qsort do posortowania tablicy liczb całkowitych rosnąco pod względem liczebności cyfry 0 w liczbach.
Rozwiązanie:
#include <iostream>
#include <cstdlib>
int num_zeros(int value) {
int result = 0;
do if(!(value % 10)) ++result; while(value /= 10);
return result;
}
int cmp_num_zeros(const void *a, const void *b) {
return num_zeros(*(int *)a) - num_zeros(*(int *)b);
}
void print_arr(int *arr, int n) {
for(int i = 0; i < n; ++i)
std::cout << arr[i] << " ";
std::cout << "\n";
}
int main() {
const int n = 6;
int arr[n] = {10, 1000, 1010, 100000, 101010, 100};
print_arr(arr, n);
qsort(arr, n, sizeof(arr[0]), cmp_num_zeros);
print_arr(arr, n);
return 0;
}
Zadanie 13
Zmodyfikuj poprzednie rozwiązanie tak, aby wykorzystało funkcję std::sort. Użyj jej zamiast qsort.
Rozwiązanie:
#include <iostream>
#include <algorithm>
int num_zeros(int value) {
int result = 0;
do if(!(value % 10)) ++result; while(value /= 10);
return result;
}
bool cmp_num_zeros(int &a, int &b) {
return num_zeros(a) < num_zeros(b);
}
void print_arr(int *arr, int n) {
for(int i = 0; i < n; ++i)
std::cout << arr[i] << " ";
std::cout << "\n";
}
int main() {
const int n = 6;
int arr[n] = {10, 1000, 1010, 100000, 101010, 100};
print_arr(arr, n);
std::sort(arr, arr + n, cmp_num_zeros);
print_arr(arr, n);
return 0;
}
Zadanie 14
Napisz funkcję w języku C++, która przyjmie dwa parametry liczbę całkowitą x oraz liczbę całkowitą d, w której zapisana będzie cyfra. Funkcja powinna zwrócić liczbę wystąpień cyfry d w liczbie x. W implementacji tej funkcji nie używaj pętli.
Rozwiązanie:
#include <iostream>
int count_occurrences_of_digit(int x, int d) {
if(!x) return 0;
int tmp = 0;
if(x % 10 == d) tmp = 1;
return count_occurrences_of_digit(x / 10, d) + tmp;
}
int main() {
int x = 156113, d = 1;
std::cout << count_occurrences_of_digit(x, d) << std::endl;
return 0;
}
Przygotuj się na kolejne laboratorium!
W celu przygotowania się na kolejne zajęcia, spróbuj wykonać poniższe zadania samodzielnie.
Zadanie 1
Napisz program w języku C++, który stworzy n-elementową tablicę liczb całkowitych, a następnie wypełni tę tablicę dowolną wartością wykorzystując funkcję fill z biblioteki .
Zadanie 2
Napisz funkcję w języku C++, która przyjmuje wskaźnik na void oraz liczbę całkowitą ptrsize. ptrsize jest liczbą bajtów, która reprezentuje zmienną. Funkcja powinna odpowiednio zrzutować zmienną i wyświetlić jej wartość (obsłuż typ char oraz int).
Zadanie 3
Zapoznaj się z innymi algorytmami znajdującymi się w bibliotece (find, generate, transform, etc).
