Polinom — nađi grešku
Klasa Polinom čuva koeficijente polinoma
- Prevesti i pokrenuti program bez sanitajzera. Šta se ispisuje, a šta je očekivano?
- Prevesti sa sanitajzerom i pročitati izveštaj: tip greške, gde je memorija pročitana i gde je oslobođena.
- Objasniti šta se dešava pri pozivu
izvod(p)i pri dodeliq = p. - Ispraviti klasu tako da program ispiše očekivane vrednosti.
g++ -std=c++17 -Wall -Wextra -g main.cpp -o program
g++ -std=c++17 -Wall -Wextra -g -fsanitize=address,undefined main.cpp -o program
Pitanje za razmišljanje: Program počinje da radi i ako se parametar funkcije izvod promeni u const Polinom&. Da li je greška u funkciji izvod ili u klasi? Šta je sa dodelom q = p?
Ko nema sanitajzer: postaviti prekidnu tačku u destruktor i pratiti vrednost pokazivača koef — ista adresa se oslobađa dva puta.
Dodatno: Napisati klasu Polinom tako da koeficijente čuva u nizu tipa DinamickiNiz<int>. Da li su tada potrebni destruktor, konstruktor kopije i operator dodele?
Ulaz
Program nema ulaz.
Izlaz
p(2) = 29
d(2) = 38
p(0) = 1
Postavka
main.cpp
// POCETNI KOD ("nadji gresku").
// Program se prevodi bez upozorenja, ali ne radi ispravno. Zasto?
//
// g++ -std=c++17 -Wall -Wextra -g main.cpp -o program && ./program
// g++ -std=c++17 -g -fsanitize=address main.cpp -o program && ./program
#include <cstddef>
#include <iostream>
// Polinom a0 + a1 x + ... + an x^n; koeficijenti u dinamicki alociranom nizu.
class Polinom {
private:
int* koef;
std::size_t stepen_;
public:
explicit Polinom(std::size_t stepen)
: koef(new int[stepen + 1]), stepen_(stepen)
{
for (std::size_t i = 0; i <= stepen_; ++i)
koef[i] = 0;
}
~Polinom()
{
delete[] koef;
}
std::size_t stepen() const { return stepen_; }
int& operator[](std::size_t i) { return koef[i]; }
int operator[](std::size_t i) const { return koef[i]; }
long long vrednost(long long x) const
{
long long rez = 0; // Hornerova sema
for (std::size_t i = stepen_ + 1; i > 0; --i)
rez = rez * x + koef[i - 1];
return rez;
}
};
Polinom izvod(Polinom p)
{
Polinom d(p.stepen() > 0 ? p.stepen() - 1 : 0);
for (std::size_t i = 1; i <= p.stepen(); ++i)
d[i - 1] = static_cast<int>(i) * p[i];
return d;
}
int main()
{
Polinom p(3); // p(x) = 1 + 2x + 3x^3
p[0] = 1;
p[1] = 2;
p[3] = 3;
Polinom d = izvod(p); // d(x) = 2 + 9x^2
std::cout << "p(2) = " << p.vrednost(2) << std::endl; // ocekivano 29
std::cout << "d(2) = " << d.vrednost(2) << std::endl; // ocekivano 38
Polinom q(1);
q = p;
q[0] = 100;
std::cout << "p(0) = " << p.vrednost(0) << std::endl; // ocekivano 1
return 0;
}
Rešenje
main.cpp
#include <cstddef>
#include <iostream>
// Polinom a0 + a1 x + ... + an x^n; koeficijenti u dinamicki alociranom nizu.
class Polinom {
private:
int* koef;
std::size_t stepen_;
public:
explicit Polinom(std::size_t stepen)
: koef(new int[stepen + 1]), stepen_(stepen)
{
for (std::size_t i = 0; i <= stepen_; ++i)
koef[i] = 0;
}
~Polinom()
{
delete[] koef;
}
// Podrazumevani konstruktor kopije i operator dodele kopiraju samo
// pokazivac koef, pa bi dva objekta delila (i dva puta oslobodila) isti
// blok. Klasa sa destruktorom koji oslobadja memoriju mora da definise
// i kopiranje (pravilo trojke).
Polinom(const Polinom& drugi)
: koef(new int[drugi.stepen_ + 1]), stepen_(drugi.stepen_)
{
for (std::size_t i = 0; i <= stepen_; ++i)
koef[i] = drugi.koef[i];
}
Polinom& operator=(const Polinom& drugi)
{
if (this == &drugi)
return *this;
// Novi blok se obezbedjuje i popunjava pre oslobadjanja starog.
int* novi = new int[drugi.stepen_ + 1];
for (std::size_t i = 0; i <= drugi.stepen_; ++i)
novi[i] = drugi.koef[i];
delete[] koef;
koef = novi;
stepen_ = drugi.stepen_;
return *this;
}
std::size_t stepen() const { return stepen_; }
int& operator[](std::size_t i) { return koef[i]; }
int operator[](std::size_t i) const { return koef[i]; }
long long vrednost(long long x) const
{
long long rez = 0; // Hornerova sema
for (std::size_t i = stepen_ + 1; i > 0; --i)
rez = rez * x + koef[i - 1];
return rez;
}
};
Polinom izvod(Polinom p)
{
Polinom d(p.stepen() > 0 ? p.stepen() - 1 : 0);
for (std::size_t i = 1; i <= p.stepen(); ++i)
d[i - 1] = static_cast<int>(i) * p[i];
return d;
}
int main()
{
Polinom p(3); // p(x) = 1 + 2x + 3x^3
p[0] = 1;
p[1] = 2;
p[3] = 3;
Polinom d = izvod(p); // d(x) = 2 + 9x^2
std::cout << "p(2) = " << p.vrednost(2) << std::endl; // ocekivano 29
std::cout << "d(2) = " << d.vrednost(2) << std::endl; // ocekivano 38
Polinom q(1);
q = p;
q[0] = 100;
std::cout << "p(0) = " << p.vrednost(0) << std::endl; // ocekivano 1
return 0;
}