Documente Academic
Documente Profesional
Documente Cultură
1. Scrie o funcție care alocă o matrice de numere întregi, folosind operatorul new. (Continental Iași)
Răspuns:
int** allocMatrix(const int rows, const int cols)
{
int **pMatrix = new int*[rows];
for(int i = 0; i < rows; i++)
{
pMatrix[i] = new int[cols];
}
return pMatrix;
}
2. Scrie o funcție care alocă o matrice de numere întregi, folosind funcția malloc. (Continental Iași)
Răspuns:
int** allocMatrix(const int rows, const int cols)
{
int **pMatrix = (int**) malloc(sizeof(int*) * rows);
for(int i = 0; i < rows; i++)
{
pMatrix[i] = (int*) malloc(sizeof(int) * cols);
}
return pMatrix;
}
3. Care sunt diferențele dintre operatorul new și funcția malloc? (Continental Iași)
Răspuns:
1. Operatorul new returnează un pointer către tipul de dată alocat, pe când, funcția malloc
returneaza un pointer către tipul de dată void (sau pointer la obiect).
2. Operatorul new deduce dimensiunea tipului alocat, pe când funcția malloc trebuie să
primească numărul total de bytes ca parametru.
3. Operatorul new după alocarea memoriei, apelează constructorul clasei. (malloc nu)
6. Care sunt diferențele dintre funcția ,,free” și operatorul ,,delete”? (Continental Iași)
Răspuns:
1. Free se folosește pentru dealocarea memoriei atunci când aceasta a fost alocată cu malloc.
2. Delete se folosește pentru dealocarea memoriei când aceasta a fost alocată cu new.
3. Pe lângă dealocarea memoriei, delete apelează destructorul clasei instanțiate.
9. Cum se declară un pointer la o funcție care returnează un int și are ca parametrii două variabile
const int? Cum se apelează funcția prin intermediul noului pointer? (Cerner Brașov)
Răspuns:
int (*pf)(const int, const int);
int data = pf(1,2);
10. Care sunt difențele dintre C și C++? (Continental Iași, Cerner Brașov)
Răspuns:
1. În C nu există clase și structurile, uniunile, nu pot conține metode, pe când în C++ structurile,
uniunile pot avea metode.
2. În C, modul de formare a semnăturii unei funcții diferă față de C++, conținând numai
denumirea funcției. În C++ semnătura funcției conține denumirea și parametrii acesteia, ceea
ce face posibil polimorfismul ad-hoc. Putem avea mai multe funcții cu același nume dar cu
parametrii diferiți.
3. În C, putem omite declararea tipul de retur din antetul funcției, fiind implicit int.
4. În C nu există static_cast, dynamic_cast, reinterpret_cast, const_cast, specificatori de acces,
moștenire, polimorfism ad-hoc, polimorfism de moștenire, namespace-uri, cast de tip
constructor: int(data).
5. În C++ există referință, în C doar pointeri.
11. Scrie o funcție care să rotească un șir de caractere? (Continental Iași)(*)oper de diferentiere
Răspuns:
void reverse(char *data)
{
const int len = strlen(data);
for(int i = 0; i < len/2; i++)
{
char temp = data[i];
data[i] = data[len-1-i];
data[len-1-i] = temp;
}
}
void reverse(char *str)
{
char *end = str;
char *start = str;
while(*end) end++;
end--;
char tmp;
while(start < end)
{
tmp = *start;
*start++ = *end;
*end-- = tmp;
}
}
12. Scrie o funcție care să afișeze elementele unui șir de numere întregi. (Continental Iași)
Răspuns:
void printArray(int data[], const int length)
{
for(int i = 0; i < length; i++)
{
cout << data[i] << " ";
}
}
Pe lângă transmiterea șirului (a unui pointer către începutul acestuia) este nevoie de transmiterea
lungimii. Dacă încercăm să aflăm lungimea șirului folosind (const int length =
sizeof(data)/sizeof(*data)) vom obține un rezultat greșit fiind că sizeof(data) este egal cu
sizeof(int*), adică, pointerul la tipul de dată array se convertește la int*. Dacă vom scrie const int
length = sizeof(data)/sizeof(*data) în același scope cu declararea șirului vom obține numărul de
elemente.
template <size_t N> void printArray(int (&data)[N])
{
for(int i = 0; i < N; i++)
{
cout << data[i] << " ";
}
}
printArray(data);
Implementarea de mai sus funcționează corect deoarece compilatorul deduce argumentul N, chiar
dacă nu este transmis explicit. În acest caz, const length = sizeof(data)/sizeof(*data) funcționează
corect.
13. Scrie o funcție care să afișeze elementele unui tablou bidimensional. (Continental Iași)
Răspuns:
void printMatrix(int *matrix, const int mRows, const int nCols)
{
for(int i = 0; i < mRows; i++)
{
for(int j = 0; j < nCols; j++)
{
cout << matrix[j + i*nCols] << " ";
}
cout << endl;
}
}
printMatrix(&matrix[0][0], mRows, nCols);
Ffuncție este corectă deoarece liniile matricii alocate pe stivă sunt memorate una după alta. Dacă
matricea ar fi fost alocată în zona de memorie heap atunci această funcție nu va funcționa corect.
15. Ce se întamplă dacă se apelează un constructor de copiere de forma ,,classname (const classname
other)”? (Luxsoft București)
Răspuns: Nimic, compilatorul avertizează prin eroarea ,,invalid copy constructor”, altfel
programul va intra într-o buclă infinită (testat cu mingw).
16. Câte tipuri de cast există în C++? Când se folosesc fiecare? (Continental Iași, Cerner Brașov)
Răspuns:
1. static_cast<new_type>(data) - produce o eroare în unele cazuri, eliminând astfel potențiale
buguri. Se flosește pentru conversii aritmetice, pointer to pointer și nu pointer to non-pointer
sau const pointer la pointer. Este agreat pentru conversiile pe care compilatorul le poate
verifica.
2. const_cast<new_type>(data) – pentru a elimina atributul const sau volatile al tipului de date
către care pointează.
3. dynamic_cast<new_type>(data) – funcționează doar pentru pointeri sau referințe către
obiecte polimorfice. Dacă se face up-cast și obiectul către care pointează nu este de tipul la
care se face cast, va returna null.
4. reinterpret_cast<new_type>(data) – pot face cast la orice mai puțin ce face const_cast. Se
folosesc aceste tipuri de cast pentru ca fac verificări în plus și deci sunt mai sigure (cu
excepția lui reinterpret_cast).
17. Cine poate avea acces la metodele și membrii ,,private”? (Continental Iași)
Răspuns: Funcțiile și clasele friend sau clasa care le declară.
18. Poti inițializa variabilele membre ale unei clase în momentul declarării în C++98?
Răspuns: Da, doar dacă sunt const.
class MyClass
{
public:
const int data = 3;
};
In C++ 11 sau 14 se pot inițializa membrii unei clase în momentul declarării ({}, =).
int a{3}; /* sau */ int b = 3; //in C++11, C++14
21. Cum se citește un vector de la tastatură? Cum se ordonează un vector? (Continental Iași)
Răspuns:
int main()
{
vector<int> myVector;
int size = 0;
cout << "Dati numarul de elemente: ";
cin >> size;
myVector.reserve(size);
for(int i = 0; i < size; i++)
{
int number = 0;
cin >> number;
myVector.push_back(number);
}
sort(myVector.begin(), myVector.end());
return 0;
}
22. Poți să faci upcast între obiecte aflate într-o relație de moștenire?
Răspuns: Da, este des întâlnită această operație.
class Base
{
public: Base(){}
};
O clasă care conține o metodă pur virtuală se numește clasă abstractă și nu poate fi instanțiată.
Corpul metodei pur virtuale (dacă se dorește instanțierea) trebuie definit în clasa derivată.
26. Care este diferența dintre o clasă pur virtuală și o clasă virtuală? (Continental Iași)
Răspuns: O clasă polimorfă poate fi instanțiată, pe când o clasă pur virtuală nu.
27. Care sunt specificatorii de acces și ce vizibilate au? (Cerner Brașov, Continental Iași)
Răspuns:
Specificator Clasa curentă Clasa derivată Accesibil prin obiect
public DA DA DA
protected DA DA NU
private DA NU NU
28. Care sunt diferențele dintre structură și clasă în C++? (Continental Iași, Cerner Brașov)
Răspuns:
1. Membrii unei clase sunt implicit ,,private”, iar la structură sunt ,,public”.
2. Într-o relație de moștenire, specificatorul de acces (: <specificator> Base) implicit în cazul
claselor este private iar în cazul structurilor este public.
35. Cum poți afla tipul unui obiect la runtime? (Cerner Brașov)
Răspuns: Cu funcția typeid(<obiect>). (Pentru ierarhii de clase: dacă obiectul este polimorfic).
class Animal
{
public:
Animal(){};
virtual ~Animal(){};
};
class Cat : public Animal{};
class Dog : public Animal{};
39. Care este diferența dintre typename și class în declararea argumentelor template?
Răspuns: Cuvântul typname indică compilatorului să trateze data ca un tip și nu ca o clasă, deci
nu o să apeleze vreun constructor.
template<class T> class X
{
public:
T data[];
typename T::id xid;
};
class Y
{
public: int id;
};
int main()
{
vector<Test> tests;
tests.push_back(Test()); //(1) - move constructor
Test result;
result = makeOperations(result); //(2) - move assignment operation
return 0;
}
Move constructor și move assignment operator sunt adăugați în C++11 pentru a reduce
numărul de copii temporare. Unele compilatoare optimizează aceste operații (constructor
elission).
Constructorul de copiere, se apelează la (1) și garantează apelul constructorului Test() o singură
dată evitând astfel crearea altor obiecte temporare.
Operatorul move assignment operator se apelează la (2) și garanteaza apelul
constructorului Test() o singură dată, evitând astfel crearea altor obicete. În C++98, în acest caz
se crea un obiect temporar(newTest pe stivă) și se apela constructorul de copiere.
46. Care este valoarea lui 0x2F în decimal? Dar a lui 14 (dec) în binar? (Continental Iași)
Răspuns: Reprezentarea lui 14 în binar este 00001110. 0x2F în dec este 47.
47. Scrie o funcție care să realizeze transformările în hex/octal/bin? (Continental Iași)
Răspuns:
int convertFromBase(string number, int base)
{
if(base < 2 || (base > 10 && base != 16)) return -1;
int length = number.size();
int result = 0;
for(int i = length-1; i >= 0; i--)
{
int digit = number[i] - '0';
if(digit < 0 || digit >= base) return -1;
int exp = length-1-i;
result += digit * pow(base, exp);
}
return result;
}
cout << convertFromBase("0110", 2) << endl;
cout << convertFromBase("0110", 8) << endl;
48. Scrie o funcție care să calculeze cel mai mare divizor comun și cel mai mare multiplu comun.
Răspuns:
unsigned getCmmdc(unsigned a, unsigned b)
{
while(b != 0)
{
int rem = a%b;
a = b;
b = rem;
}
return a;
}
unsigned getCmmmc(unsigned a, unsigned b)
{
return (a*b)/getCmmdc(a,b); //
}
49. Fie următoarele informații într-un byte: 00101101, considerând biții 5 și 4 ca fiind 10. Care este
LSB? (Continental Iași)
Răspuns: 00101101.
50. Ce face următoarea secvență de cod? (Continental Iași)
int x = 0;
while(x < 5)
{
printf("x=%d\n", x);
x++;
}
Care este valoarea pe care x o are la sfârșitul programului? Scrie valorile lui x la fiecare pas.
Răspuns: Secvența de cod afișează numerele de la 0 la 4 (inclusiv). La sfârșit x este 5.
Pas Afișare Valoare x
1 x=0 1
2 x=1 2
3 x=2 3
4 x=3 4
5 x=4 5
51. Care sunt valorile variabilelor mixerproduct și Tvproduct dacă datele de intrare au valorile -10, 4,
100, 999, 1000, 1001, 3500, 7000? Specifică valorile celor 2 variabile pentru fiecare input.
(Continental Iași)
if(mixerproductcost > 0 && mixerproductcost <= 100)
{
mixerproduct = "mixerlowcost";
}
if(mixerproductcost >= 100 && mixerproductcost <= 350)
{
mixerproduct = "mixerhightcost";
}
if(TVproductcost >= 1000 && TVproductcost <= 2000)
{
Tvproduct = "TVLowcost";
}
if(TVproductcost > 2000 && TVproductcost <= 3500)
{
Tvproduct = "TVHightcost";
}
Răspuns:
mixerproductcost TVproductcost mixerproduct Tvproduct
-10 -10 - -
4 4 mixerlowcost -
100 100 mixerhightcost -
999 999 - -
1000 1000 - TVLowcost
1001 1001 - TVLowcost
3500 3500 - TVHighcost
7000 7000 - -
52. Ce face următoarea secvență de cod? Care sunt valorile pentru variabilele factorial și counter la
sfârșitul programului? (Continental Iași)
int counter = 7;
int factorial = 1;
do
{
factorial = factorial * counter;
counter = counter-1;
}while(counter > 0);
printf("factorial of 7 is %d\n", factorial);
Răspuns:
Secvența de cod calculează factorial de 7. La sfârșitul programului, variabila factorial va avea
valoarea 5040 și counter va avea valoarea 0.
II Cunoștințe specifice algoritmilor și structurilor de date
1. Scrie o funcție care să codifice 09.09.2009 în format BCD. Cum o să arate rezultatul și care va fi
dimensiunea lui? (“.” nu se ia în considerare) (Continental Iași)
Răspuns: Dimensinea rezultatului va fi de 4 bytes – 1 int.
Rezultatul va arăta: 0000(0) 1001(9) 0000(0) 1001(9) 0010(2) 0000(0) 0000(0) 1001(9)
int getDigit(char c)
{
return c >= '0' && c <= '9' ? c - '0' : -1;
}
int toBcd(const char *data)
{
int len = strlen(data);
int shifter = 0;
int bcd = 0;
for(int i = len-1; i >= 0; i--)
{
int digit = getDigit(data[i]);
if(digit == -1) continue;
bcd |= (digit << shifter);
shifter += 4;
}
return bcd;
}
2. Scrie o funcție care să sorteze crescător o listă simplu înlănțuită.
Răspuns: Pentru cazul în care se dorește o sortare modificând valorile listei.
Node *getMiddle(Node *start, Node *end)
{
if(end == nullptr || start->next == end) return start;
În cazul în care avem un șir de numere care se află într-un interval bine definit relativ mic, vom
folosi în aceeași manieră ca cea de mai sus, un șir care să memoreze frecvența fiecărui număr.
int getMostFrequentRange(const vector<int> & array)
{
if(array.size() == 0) return -1;
7. Scrie o funcție care să scrie 0 pe linia și pe coloana unde este 0, într-o matrice de numere întregi.
(Continental Iași)
Răspuns: De la început, observăm că parcurgând matricea, dacă atunci când întâlnim valoarea 0,
scriem 0 pe linia și pe coloana aferentă, vom face ca următoarele valori să fie 0. Pentru a evita
acest lucru putem memora liniile și coloanele aferente valorilor 0 din matrice, urmând apoi să
scriem 0 parcurgând valorile liniilor și coloanelor memorate. Făcând acest lucru, în cel mai rău
caz, vom avea nevoie de o memorie egală cu memoria alocată pentru matrice. Putem reduce
memoria folosită, memorând doar liniile și coloanele pe care apare valoarea 0 (nu coordonatele
fiecărui 0). Mai mult de atât, putem folosi matricea pentru a nota liniile și coloanele unde este
întâlnită valoarea 0. Adică, dacă întâlnim valoarea 0 pe [2][2], vom scrie 0 pe [2][0] și [0][2],
marcând astfel pe marginea matricei linia care va conține 0. Făcând acest lucru, pentru a nu scrie
0 pe linia 0 și coloana 0, neconținând valoarea 0 ințial, vom seta două valori bool care să indice
dacă linia 0 și coloana 0 conțineau 0 înainte de prelucrare.
void nullifyRow(int **m, int cols, int row)
{
for(int i = 0; i < cols; i++)
m[row][i] = 0;
}
void nullifyColumn(int **m, int rows, int col)
{
for(int i = 0; i < rows; i++)
m[i][col] = 0;
}
void nullify(int **m, int rows, int cols)
{
if(m == nullptr || rows <= 0 || cols <= 0) return;
regex reg("[\\s,\\t]+");
sregex_token_iterator it(str.begin(), str.end(), reg);
sregex_token_iterator itEnd;
int wordCount = 0;
for(; it != itEnd; it++)
{
wordCount++;
}
return wordCount;
}
9. Fie următoarele perechi caracter-frecvență a(15) b(7) c(6) d(6) e(5). Să se determine codurile lor
folosind algoritmul Huffman (Amazon Iași – wiki intern).
Răspuns:
class HuffNode
{
public:
HuffNode *left = nullptr;
HuffNode *right = nullptr;
string name;
int frequency;
HuffNode(string n, int f) : name(n), frequency(f){}
HuffNode(HuffNode *l, HuffNode *r)
{
name = l->name + r->name;
frequency = l->frequency + r->frequency;
this->left = l;
this->right = r;
}
};
HuffNode* buildHuffTree(MinHeap &minHeap)
{
while(minHeap.getSize() > 1)
{
HuffNode *left = minHeap.poll();
HuffNode *right = minHeap.poll();
HuffNode *root = new HuffNode(right, left);
minHeap.add(root);
}
return minHeap.poll();
}
string getEncodings(HuffNode *node, string prefix)
{
if(node->left == nullptr && node->right == nullptr)
{
return node->name + ": " + prefix + "\n";
}
string str;
if(node->left != nullptr)
{
str += getEncodings(node->left, prefix + "0");
}
if(node->right != nullptr)
{
str += getEncodings(node->right, prefix + "1");
}
return str;
}
string getEncodings(HuffNode *root)
{
return getEncodings(root, "");
}
10. Având un string, returnează cel mai lung substring care se repetă. (Amazon Iași – wiki intern)
Răspuns:
string getLingestDupSubstr(string text)
{
string suffix = "";
const int len = text.size();
Node root("");
for(int i = len-1; i >= 0; i--)
{
suffix = text.substr(i) + "$";
root.insert(suffix);
}
return root.getLongDupSubstr();
}
string getLongestDupSubstrNaive(string data)
{
string longest = "";
unordered_map<string, int> counts;
for(unsigned c = 1; c < data.size(); c++)
{
for(unsigned j = 0; j <= data.size()-c; j++)
{
string sub = data.substr(j, c);
auto it = counts.find(sub);
if(it == counts.end())
{
counts.insert(make_pair(sub, 1));
}
else
{
counts[sub]++;
if(counts[sub] > 1 && longest.size() < sub.size())
{
longest = sub;
}
}
}
}
return longest;
}
class Node
{
public:
int descendents = 0;
std::string suffix;
std::list<Node*> branches;
Node(std::string s) : suffix(s) {}
void insert(std::string newSuffix)
{
if(newSuffix == "") return;
descendents++;
if(branches.empty())
{
branches.push_back(new Node(newSuffix));
return;
}
for(auto &node : branches)
{
int pos = getFirstDiff(node->suffix, newSuffix);
if(pos > 0)
{
std::string left = node->suffix.substr(0, pos);
std::string right = newSuffix.substr(pos);
std::string remaining = node->suffix.substr(pos);
node->suffix = left;
node->insert(remaining);
node->insert(right);
return;
}
}
branches.push_back(new Node(newSuffix));
}
std::string getLongDupSubstr()
{
if(branches.size() == 0) return "";
Node *suffRoot = branches.front();
for(auto &node : branches)
{
if(suffRoot->descendents < node->descendents)
{
suffRoot = node;
}
}
return getLongDupSubstr(suffRoot);
}
private:
std::string getLongDupSubstr(Node *node)
{
std::string result = node->suffix;
for(auto &sub : node->branches)
{
if(sub->branches.size() > 1)
{
result += getLongDupSubstr(sub);
}
}
return result;
}
int getFirstDiff(std::string first, std::string second)
{
unsigned i = 0;
while(i < first.size() && i < second.size())
{
if(first[i] != second[i]) break;
i++;
}
return i;
}
};
11. Scrie o funcție care să returneze reprezentarea romană a unui întreg. (Amazon Iași)
Răspuns:
string getRoman(int number, unordered_map<unsigned, string> &map)
{
if(number == 0) return "";
if(map.find(number) != map.end()) return map[number];
int factor = round(pow(10, (int)log10(number)));
int dif = number-factor;
int sum = number+factor;
if(map.find(sum) != map.end())
map[number] = map[factor]+map[sum];
else
map[number] = getRoman(dif, map) + map[factor];
return map[number];
}
string getRoman(int number)
{
static auto map = buildRomanTable();
string result;
int factor = 1;
while(number != 0)
{
int n = (number%10) * factor;
if(n != 0)
{
string strRoman = getRoman(n, map);
result.insert(0,strRoman.c_str());
}
factor *= 10;
number /= 10;
}
return result;
}
unordered_map<unsigned,string> buildRomanTable()
{
unordered_map<unsigned,string> numberMap;
numberMap[1] = "I";
numberMap[5] = "V";
numberMap[10] = "X";
numberMap[50] = "L";
numberMap[100] = "C";
numberMap[500] = "D";
numberMap[1000] = "M";
return numberMap;
}
III Cunoștințe specifice programării orientată pe obiect
4. Ce este un singleton?
Răspuns: Singleton este un șablon de proiectare care asigură faptul că nu vom avea mai mult de
o instanță a unui obiect. În C++ acest șablon poate fi implementat cu variabile statice.
class Restaurant
{
Restaurant(){};
Restaurant(const Restaurant &){};
void operator=(const Restaurant &){};
public:
Restaurant& getInstance()
{
static Restaurant instance;
return instance;
}
};
5. Ce este o clasă factory?
Răspuns: O clasă factory este o clasă care se ocupă de crearea obiectelor.
enum GameType{Poker, BlackJack};
class CardGame{};
class PokerGame : public CardGame{};
class BlackJackGame : public CardGame{};
class GameCreator
{
public:
static CardGame* createCardGame(GameType type)
{
if(type == Poker)
{
return new PokerGame();
}
else if(type == BlackJack)
{
return new BlackJackGame();
}
return NULL;
}
};
IV Cunoștințe generale de design și tehnologii
1. Care este diferența dintre Application Server și Web Server? (Cerner Brașov)
Răspuns: Web server se ocupă de conținutul HTTP (requesturi, pagini HTML statice și nu
numai, JSP, Pearl, etc). Application server-ul nu este limitat doar de conținuturi HTTP și poate
avea suport pentru protocoale precum RMI/RPC.
Application server-ul poate avea, integrat Web Server. În plus App Server poate conține
componente specifice Application service precum tranzacții, servicii de mesagerie (între
componente software).
În principu, Web server-ul conține elemente specifice Presentation Layer-ului (web content, JSP
pages, html, javascript, etc.). Application Server expune funcționalitățile Bussines Layerului, dar
nu este limitat la aceasta.
2. Cum ai proceda pentru a insera foarte multe înregistrări într-un tabel? (Cerner Brașov)
Răspuns: Pentru a nu bloca accesul la tabelă, voi împărți volumul inițial de date în bucăți mai
mici și le voi insera pe rând.
5. Care este diferența dintre INNER JOIN, LEFT JOIN, RIGHT JOIN? (Cerner Brașov)
Răspuns: INNER JOIN face o selecție a datelor din tabele cât timp există o potrivire a coloanei
pe baza căruia se face operația.
LEFT JOIN face o selecție a datelor din tabelul stâng și a datelor care se potrivesc cu tabelul
drept. Dacă nu există o potrivire atunci rezultatul va fi NULL din tabelul drept.
RIGHT JOIN face o selecție a datelor din tabelul drept și a datelor care se potrivesc cu tabelul
stâng. Dacă nu există o potrivire atunci rezultatul din tabelul stâng va fi NULL.