Imię i nazwisko:                                                                                                       10 czerwca 2006

 

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ć słowem „TAK”, a odpowiedź błędną – słowem „NIE”.

 

1.        Zaleca się, by używać asercji do:

a)       Wyłapywania błędów w implementacji algorytmów.

b)       Wyłapywania błędów składniowych.

c)       Obsługi nieprawidłowego formatu danych wprowadzanych przez użytkowników programu.

d)       Wyłapywania błędów w dynamicznej alokacji pamięci.

2.        Zaleca się, by używać wyjątków do:

a)       Wyłapywania błędów w implementacji algorytmów.

b)       Wyłapywania błędów składniowych.

c)       Obsługi nieprawidłowego formatu danych wprowadzanych przez użytkowników programu.

d)       Wyłapywania błędów w dynamicznej alokacji pamięci.

3.        Koszt użycia asercji związany ze zwiększeniem czasu wykonywania programu

a)       Można zredukować do zera, definiując opcję kompilatora –DNDEBUG

b)       Można zredukować do zera, definiując opcję kompilatora –DEBUG

c)       Można znacząco zredukować, ale nigdy do zera.

d)       Jest zawsze tak mały, że w praktyce można go pomijać.

4.        Po wykonaniu programu kompilowanego kompilatorem gcc na konsoli pojawił się następujący komunikat:
/usr/local/include/c++/4.1.1/debug/list:227:

    error: attempt to access an element in an empty container.

Objects involved in the operation:

sequence "this" @ 0x0x22ee90 {

  type = N15__gnu_debug_def4listIiSaIiEEE;

}

Aborted (core dumped)
Oczywiście napis N15__gnu_debug_def4listIiSaIiEEE reprezentuje „udekorowaną” nazwę pewnego typu  użytego w programie. Aby się zorientować, co to za typ, można posłużyć się programem lub programami:

a)       make

b)       ar

c)       nm

d)        preprocesorem (gcc –E)

5.        Załóżmy, że definicja klasy X wygląda  następująco (wydruk pomija definicję konstruktora X):
class X : public Y
{

   public:

std::vector<int> _v;

int _x;

X () : _x(10), _v(_x) { /* ... jakiś kod ... */  }

};

a)       Składowa _x jest zawsze inicjowana przed _v.

b)       O tym, czy _x jest inicjowane przed _v decyduje definicja konstruktora X.

c)       Składowe _x i _v klasy X są inicjowane przed składowymi klasy bazowej Y.

d)       Definiując treść dowolnego konstruktora X można przyjąć, że klasa bazowa Y jest już w pełni zainicjowana.

6.        Wartość wyrażenia (1&2) + (1|2) + (1^2) + (1%2) + 0x12

a)       wynosi 25

b)       wynosi 26

c)       wynosi 27

d)       jest większa niż 27

7.        Koszt użycia funkcji wirtualnych związany ze zwiększeniem czasu wykonywania programu

a)       Można zredukować do zera, definiując opcję kompilatora –DFASTVIRTUAL

b)       Można znacząco zredukować, definiując wszystkie składowe wirtualne jako inline

c)       Jest zawsze tak mały, że w praktyce można go pomijać.

d)       Może być znaczący w wypadku funkcji krótkich i bardzo często wywoływanych.

8.        Tablicę tab, zdefiniowaną instrukcją
       int
tab[100];
można użyć jako argumentu następujących  funkcji:

a)       int         fa(int t[100]);

b)       void        fb(void * t);

c)       int &       fc(int * t);

d)       const int & fd(const int t[]);

 

9.        O funkcji int f(int x) wiadomo, że wyrażenie f(x) == f(x) ma zawsze wartość false.  Efekt ten można osiągnąć:

a)       przy pomocy zmiennych globalnych.

b)       przy pomocy zmiennych statycznych lokalnych w f.

c)       przy pomocy zmiennych automatycznych lokalnych w f.

d)       przy pomocy modyfikacji argumentu funkcji, czyli x.

 

10.     W poniższych instrukcjach mamy gwarancję, że funkcja g nie będzie wywołana przed f:

a)       int x = f(x) + g(x);

b)       if ( f(x) && g(x) ) continue;

c)       if ( f(x) > g(x) )  continue;

d)       bool b = f(x) || g(x);

 

11.     Rozpatrzmy funkcję o następującej sygnaturze:
std::vector::resize(unsigned n) const;
Użyte w niej słówko const

a)       modyfikuje typ wyniku funkcji;

b)       modyfikuje typ wskaźnika this (w definicji tej funkcji);

c)       modyfikuje typ argumentu funkcji (n);

d)       jest oczywistym błędem składniowym.

 

12.     Podczas testowania poprawności programu kompilowanego kompilatorem g++ warto przedsięwziąć następujące kroki:

a)       skompilować program z opcją -g

e)       skompilować program z opcją -DNDEBUG

f)        skompilować program z opcją  -D_GLIBCXX_DEBUG

g)       skompilować program z opcją -lm

13.     Z deklaracji
template<typename _InputIterator, typename _Function>
_Function
for_each(_InputIterator __first, _InputIterator __last, _Function __f)

a)       wynika, że ostatni argument przekazywany jest przez wartość;

b)       wynika, że ostatni parametr musi być funkcją.

c)       wynika, że ostatni parametr może być funktorem

d)       wynika, że for_each jest szablonem klasy.

 

14.     Żeby wyłapać dowolny wyjątek wyprowadzony przez dziedziczenie z klasy std::exception i móc później z pożytkiem wywołać jego stałą metodę virtual const char *what() const należy za blokiem try umieścić instrukcję (poprawnych jest kilka odpowiedzi):

a)       catch (std::exception)             { /*stosowny kod*/ }

b)       catch (std::exception e)           { /*stosowny kod*/ }

c)       catch (std::exception const& e)    { /*stosowny kod*/ }

d)       catch (std::exception & e)         { /*stosowny kod*/ }

 

15.     Następująca instrukcja sortuje 100 pierwszych elementów tablicy int tab[1000]:

a)       std::sort( &tab[0], &tab[100] );

b)       std::sort( tab, tab + 100 );

c)       std::sort( tab[0], tab[100] );

d)       std::sort( tab.begin(), tab.begin() + 100 );

 

16.     Rozpatrzmy funkcję f

int f(int x, unsigned int n)

{

  int y = (n % 2) ? x : 1;

 

  while (n >>= 1)

  {

    x *= x;

    if (n % 2)

      y *= x;

  }

  return y;

}

wartością f(2, 3) jest

a)       1

a)       6

b)       8

c)       liczba większa od 10 i mniejsza od 16

 

1.        W ramach deklaracji
  char
bufor[100];
  char *p = 0, 
  long int strtol (const char *string, char **tailptr, int base);
poprawna (pod względem składniowym) jest następująca instrukcja:

a)       long int n = strol(bufor, *p, 10);

b)       long int n = strol(bufor, p, 0);

c)       long int n = strol(bufor, &p, 16);

d)       long int n = strol(&bufor[0], &p, 10);

 

2.        Rozpatrzmy następujący kod,
class Foo
{
public:
   const Foo* This() const { return this; }
   /* ...
*/
} foo;
Instrukcja
std::cout << (&foo – foo.This()) << ’\n’;
wyświetli

a)       0

b)       wartość przypadkową, bo this ma wartość przypadkową.

c)       wartość przypadkową, bo  &foo ma wartość nieokreśloną.

d)       nic nie wyświetli, bo instrukcja (&foo – foo.This()) zawiera błąd składniowy.



3.        Wiadomo, że pewien program kompilowany kompilatorem gcc wymaga użycia biblioteki znajdującej się w pliku libm.a w standardowym katalogu bibliotecznym kompilatora. W tym celu:

a)       Do konsolidatora należy przekazać opcję –lm

b)       Do konsolidatora należy przekazać opcję –libm

c)       Do konsolidatora należy przekazać opcję –L lm

d)       Do konsolidatora należy przekazać opcję –L libm

 

4.        Aby przyspieszyć wykonanie programu kompilowanego kompilatorem gcc, można

a)       podczas kompilacji zastosować opcję –O2, -Os lub –O3

b)       podczas uruchamiania programu zastosować opcję –O2, -Os lub –O3

c)       podczas kompilacji zastosować opcję –DNDEBUG

d)       podczas uruchamiania programu zastosować opcję –DNDEBUG


Zadania

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.

 

  1. Dany jest ciąg liczb całkowitych (an) taki, że
    an = 0, dla n  £ 0,
    an
    +1 = 2n – 1 + an
    , dla 0 £ n < 100,
    an = –1 dla n > 100 .
    Podaj definicję funkcji f, która dla argumentu całkowitego n zwracać będzie wartość an.

  2. Poniższy program w moim komputerze działa bez końca. Wyjaśnij, co może być tego przyczyną.

 

#include <iostream>

 

int main()

{

    int v[10];

    for (int i = 0; i <= 10; ++i)

      v[i] = 0;

}

         

  1. Zdefiniuj klasę Print tak, by dla dowolnego wektora v klasy std::vector<int> instrukcja
    for_each (v.begin(), v.end(), Print(std::cout))
    powodowała wyświetlenie w strumieniu std::cout wszystkich elementów wektora v.

 

  1. Napisz program, który wczyta z klawiatury liczbę naturalną n, po czym utworzy macierz kwadratową n×n i wypełni jej elementy tak, by element (i,j) miał wartość i + j (uwaga: w powyższym opisie wiersze i kolumny numerujemy tak, jak w matematyce, czyli od 1).