Imię i nazwisko:
13 września 2003
Uwaga: W poniższym teście w
każdym punkcie ilość poprawnych odpowiedzi wynosi od 0 do 4. Każdą z nich
należy oznaczyć symbolem „+”, a odpowiedź błędną – symbolem „–”.
1. Asercje zaleca się stosować m.in. do
a) sprawdzania, czy operator new faktycznie przydzielił potrzebną nam pamięć.
b) sprawdzania, czy użytkownik podał dane liczbowe w wymaganym przez nas zakresie.
c) sprawdzania, czy indeks tablicy nie wykracz poza dopuszczalny zakres.
d) sprawdzania, czy po wywołaniu metody klasy wciąż zachowany jest jej niezmiennik.
2.
Załóżmy, że początek definicji klasy X
wygląda następująco:
class
X : public Y
{
int _z;
std::vector<int> _wektor;
public:
X(int z) : _wektor(_z), _z(z)
{_wektor.push_back(z);}
...
};
wynika stąd, że:
a) konstruktor obiektu _wektor zostanie wywołany przed domyślnym konstruktorem klasy bazowej Y;
b) wartość z zostanie nadana składowej _z przed wywołaniem konstruktora składowej _wektor;
c) instrukcja _wektor.push_back(z) zostanie wywołana po wywołaniu konstruktora składowej _wektor;
d) w destruktorze obiektów klasy X nie można odwoływać się do składowej _wektor, gdyż składowe ulegają automatycznemu zniszczeniu tuż przed wywołaniem ciała destruktora
3.
Załóżmy, że początek definicji klasy X
wygląda następująco:
class
X
{
std::vector<int> _wektor;
public:
static int z;
static int f() {...}
...
};
wynika stąd, że:
a) jeżeli utworzę dwa obiekty klasy X i w jednym z nich nadam wartość 10 składowej z, to drugi obiekt automatycznie uzyska informację, że jego składowa z też ma wartość 10.
b) jeżeli utworzę dwa obiekty klasy X i w jednym z nich nadam wartość 10 zmiennej _wektor[0], to drugi obiekt automatycznie uzyska informację, że jego zmienna _wektor[0] też ma wartość 10.
c) w (wykropkowanej) definicji funkcji składowej f nie można używać wskaźnika this.
d) funkcja składowa f nie ma dostępu do składowej _wektor.
4. Wartość wyrażenia (6&3) + (6|3) + (6^3) + (6%3) + 0x36
a) wynosi 60
b) wynosi 62
c) wynosi 64
d) wynosi 66
5. rozpatrzmy instrukcję if (x == y == 0) x = y = 1;
a) jeśli początkowo x i y są równe 0, to po jej wykonaniu będą równe 1;
b) jeśli początkowo x i y są równe 2, to po jej wykonaniu będą równe 1;
c) jeśli początkowo x jest równe 1, a y równe jest 2, to po jej wykonaniu x i y będą równe 1;
d) instrukcja x = y = 1; wykona się wtedy i tylko wtedy, gdy początkowo x i y są jednocześnie równe 0.
6.
Rozpatrzmy następującą deklarację:
double
f(double a, double *b, double & c);
w ramach deklaracji
double
x, y, z, tab[10];
poprawne jest następujące wywołanie funkcji f:
a) f(x, *y, &z);
b) f(x, &y, *z);
c) f(x, &x, x);
d)
f(x, tab, tab[0]);
7.
Rozpatrzmy następującą makrodefinicję:
#define
max(x,y) ( ((x) > (y)) ? (x) : (y) )
Po wykonaniu ciągu instrukcji
int
x = 0, y =1;
int
z = max(x++, y++);
a) z ma wartość 2;
b) z ma wartość 3;
c) y ma wartość 2;
d) y ma wartość 3;
Uwaga: w pierwszej fazie działania operatora ?: wyznaczana jest wartość testu wraz z wszelkimi efektami ubocznymi.
8.
Rozpatrzmy następującą funkcję:
inline
int max(int x, int y) {return (x > y) ? x : y;}
Po wykonaniu ciągu instrukcji
int
x = 0, y =1;
int
z = max(x++, y++);
a) z ma wartość 2;
b) z ma wartość 3;
c) y ma wartość 2;
d)
y ma wartość 3;
9.
Rozpatrzmy następujący szablon funkcji:
template
<typename T>
inline T const& max(T const& x, T const& y) {return (x > y) ? x
: y;}
Po wykonaniu ciągu instrukcji
int
x = 0, y =1;
int
z = max(x++, y++);
a) z ma wartość 2;
b) z ma wartość 3;
c) y ma wartość 2;
d) jeżeli w definicji szablonu pominęlibyśmy modyfikatory const, to instrukcja max(x++, y++); byłaby błędem składniowym, bo implikowałby użycie referencji do obiektów tymczasowych.
10.
Rozpatrzmy następującą deklarację:
int
X::size(X& x) const;
Użyte w niej słówko const
a) modyfikuje typ wartości zwracanej przez funkcję
b) modyfikuje typ wskaźnika this (używanego w ciele funkcji X::size(X& x) const)
c) modyfikuje typ argumentu funkcji, tj. x
d) jest błędem składniowym.
11. Linker to osobny program służący głównie do
a) optymalizacji hierarchii dziedziczenia (zależności między klasami itp.)
b) optymalizacji czasu działania programu (i być może wielkości kodu wykonywalnego)
c) wyszukiwania w programie błędów składniowych
d) łączenia skompilowanych plików źródłowych z bibliotekami w celu utworzenia pliku wykonywalnego
12.
rozpatrzmy instrukcje
char*
a[200];
char*
(*b)[200];
char*
(*c)();
char*
(*d[200])();
a) a jest tablicą 200 napisów w stylu języka C
b) poprawna jest instrukcja b = &a;
c) c jest wskaźnikiem na funkcję
d) poprawna jest instrukcja d[0] = c;
13. Zamierzamy wykorzystać tablicę obiektów wyprowadzonych przez dziedziczenie z abstrakcyjnej klasy X zawierającej deklaracje interesujących nas metod wirtualnych. Możemy posłużyć się następującą definicją:
a) std::vector<X> tablica;
b) std::vector<X*> tablica;
c) X* tablica = new X [n];
d)
X tablica[100];
14. Następująca instrukcja sortuje 100 pierwszych elementów tablicy int tab[1000]:
a) std::sort( tab[0], tab[100] );
b) std::sort( &tab[0], &tab[100] );
c) std::sort( tab.begin(), tab.begin() + 100 );
d) std::sort( tab, tab + 100 );
15.
Chcemy
otworzyć plik, którego nazwa zawierać będzie wartości zmiennych całkowitych n i k; np. dla n == 10 i k == 7 plik ma mieć nazwę "n10_k7.dat". W tym celu możemy posłużyć
się następującymi instrukcjami:
#include <sstream>
#include
<fstream>
...
std::ostringstream
ostr;
ostr
<< "n" << n << "_k" << k <<
".dat";
a sam plik otwieramy instrukcją
a)
std::ofstream
F(ostr);
b)
std::ofstream
F(ostr.str());
c)
std::ofstream
F(ostr.c_str());
d)
std::ofstream
F(ostr.str().c_str());
16.
Rozpatrzmy
następujący kod:
template <typename In,
typename Out>
Out copy (In first, In last, Out result)
{
while (first != last)
*result++ = *first++;
return result;
}
a)
Słówko
In jest zdefiniowane w innej
części programu (np. przez typedef lub #define).
b)
Słówko
typename można by tu zastąpić słowem
class
c)
Pierwszy
argument funkcji copy jest iteratorem
przekazywanym przez wartość.
d)
W
ramach deklaracji
char tab[] = "ciekawostka
programistyczna";
poprawna jest instrukcja
cout << copy (tab, tab+10, tab+10);
17.
Jacek
zauważył, że po zadeklarowaniu w funkcji main() tablicy 1 000 000 liczb typu int:
int tab[1000000];
jego program przestał działać. Problem ten można obejść:
a)
przesuwając
definicję tablicy do zakresu globalnego;
b)
alokując
tę tablicę przy pomocy operatora new;
c)
posługując
się standardowym wektorem (std::vector<int>);
d)
zamieniając
tablicę jednowymiarową na tablicę dwuwymiarową (int tab[1000][1000]);
18.
a)
Jeżeli
wewnątrz pliku *.cpp umieszczę definicję funkcji typu inline, to będę mógł z niej korzystać
tylko w tym pliku.
b)
Jeżeli
definicję funkcji typu inline umieszczę
wewnątrz pliku nagłówkowego, to będę mógł z niej korzystać w każdym pliku
włączającym dany plik nagłówkowy.
c)
Jeżeli
definicję zwykłej funkcji (nie inline) umieszczę wewnątrz pliku nagłówkowego, to prawdopodobnie program
się nie skompiluje.
d)
Jeżeli
w kilku różnych plikach źródłowych zdefiniuje się obiekty globalne, to nie
wiadomo, w jakiej kolejności będą one konstruowane.
19.
Można
się spodziewać, że implementacja następującej kolekcji może być oparta jest na
drzewie czerwono-czarnym:
a)
std::vector
b)
std::list
c)
std::map
d)
std::stack
20.
Rozpatrzmy
następujący kod, w którym typ wartości stałej
metody This zastąpiono słowem RESULT:
class Foo
{
public:
RESULT This() const { return this;}
};
...
Foo foo;
std::cout << (&foo – foo.This()) << ’\n’;
Prawdziwe
są następujące zdania:
a)
jeżeli
RESULT zastąpimy słowem Foo, to kompilator zgłosi błąd składniowy;
b)
jeżeli
RESULT zastąpimy wyrażeniem Foo*, to
kompilator zgłosi błąd składniowy
c)
jeżeli
RESULT zastąpimy wyrażeniem Foo&, to
kompilator zgłosi błąd składniowy
d)
jeżeli
RESULT zastąpimy wyrażeniem const Foo*, to std::cout wyświetli pewną ściśle określoną wartość
Rozwiązania proszę najpierw napisać na brudno i po sprawdzeniu przenieść na podpisaną kartkę z wersją „finalną”. Proszę zwrócić uwagę na sposób definiowania argumentów i wartości funkcji.