Interesting C/C++ interview questions

User avatar
A. Fig Lee
Уже с Приветом
Posts: 12072
Joined: 17 Nov 2002 03:41
Location: английская колония

Post by A. Fig Lee »

Hamster wrote:
Mongush wrote:Есть :)
при i++ создается временная преременая.


А оптимизация на что?

Ну если оптимизация еще както.. То endl() - уж точно никаким боком - мож так задумано? :pain1:
Верить нельзя никому - даже себе. Мне - можно!
Izh
Уже с Приветом
Posts: 172
Joined: 15 Feb 2003 16:57
Location: Moscow

Re: Interesting C/C++ interview questions

Post by Izh »

roeh wrote:вот мне недавно задали вопрос, что произойдёт при попытке выполнения вот этого кода:

Code: Select all

typedef struct {
    char a;
    char b;
} someStruct;

int
main ( int, char** )
{
    someStruct     ss;
    someStruct* pSS;

     pSS = ( someStruct* ) ss;
     pSS->a = 'a';
     printf ( "%c\n", ss.a );

     return 0;
}


указания на факт, что statement pSS = ( someStruct* ) ss; в принципе -бессмыслица не принимаются. :wink:


Вообще говоря, все что угодно может произойти, поскольку вместо адреса структуры подставляется служебное значение, используемое компилятором.

Допустим имеется следующий код:

Code: Select all

typedef
struct
    {
    char a;
    } SomeStruct;

int main()
{
    SomeStruct  ss;

    printf( "ss = 0x%08x\n", &ss );

    return 0;
}


GNU C, например, генерит следующий ассемблер в случае, когда вызывается
printf( "ss = 0x%08x\n", &ss ):

Code: Select all

       ...
       leal    -2(%ebp), %eax  ; Получаем адрес ss
       pushl   %eax               ; ...и записываем его в стек
       pushl   $.LC0
       ...


Когда, же вызывается printf( "ss = 0x%08x\n", ss ), ассемблер получается такой:

Code: Select all

       ...
       pushw   -2(%ebp)        ; Совсем не то, что нужно
       pushl   $.LC0           
       ...   
User avatar
Шоколадина
Удалён за неэтичное поведение
Posts: 1860
Joined: 08 Jan 2004 19:26
Location: NJ, USA

Post by Шоколадина »

Это задачки с интервью, взято из архива моего мужа.

1. На вход программы должно поступить ((2 в 32-ой) - 1) положительных целых чисел размером 4 байта. Известно заранее, что все они разные. Задача: написать программу, использующую МИНИМУМ ПАМЯТИ, которая определяет, какое именно число (а оно, как понятно, ровно одно) НЕ поступало на вход программы.

2. Есть массив, состоящий из M+N элементов.

[A1] [A2] .... [Am] [Am+1] .... [Am+n]

Задача: за МИНИМУМ ВРЕМЕНИ и используя КОНЕЧНУЮ (т.е. не зависящую от M и N) ПАМЯТЬ, переставить части массива местами (см. рис.).

[Am+1] [Am+2] .... [Am+n] [A1] [A2] .... [Am]

3. Даны результаты выборов, на которых (10 в 9-ой) избирателей проголосовали за (10 в 6-ой) кандидатов - каждый, естественно, голосовал за кого-то одного. Есть (10 и 3-ей) свободных ячеек памяти (результаты выборов, разумеется, менять нельзя - задачка не российская). Определить кто победил в такой ситуации нельзя, но можно, ПРОЙДЯ МАССИВ (10 в 9-ой) МИНИМУМ РАЗ, узнать, выиграл ли кто-то из кандидатов уже в первом туре (т.е., проще говоря, определить, кто набрал более 50% всех голосов).

4. Есть некая операционная система, в которой определены следующие функции, ответственные за аллокацию памяти:

void* OS_alloc(unsigned int);
void OS_free(void*, unsigned int);

Надо написать оптимальную имплементацию следующих функций:

void* alloc(unsigned int);
void free(void*);

5. Дан односвязный список элементов, причем возможно, что этот список замкнут в "петлю", т.е. один из элементов списка указывает на один из предшествующих ему элементов. Используя КОНЕЧНЫЙ объем памяти, найти "соединение" этой петли или конечный элемент списка.

Если кому нужны ответы, предоставим с открытой душой.
А что это у Вас такое вкусненькое?..
SlaMin
Уже с Приветом
Posts: 176
Joined: 21 Feb 2002 10:01
Location: KZ -> KY -> WA

Post by SlaMin »

Шоколадина wrote:1. На вход программы должно поступить ((2 в 32-ой) - 1) положительных целых чисел размером 4 байта. Известно заранее, что все они разные. Задача: написать программу, использующую МИНИМУМ ПАМЯТИ, которая определяет, какое именно число (а оно, как понятно, ровно одно) НЕ поступало на вход программы.


Если следовать условиям задачи, и домыслить, что требуется найти то число, из диапазона НЕОТРИЦАТЕЛЬНЫХ чисел представимых четырмя байтами, которое не поступило на вход программы, то результат известен сразу - ноль :)

Ну а если не умничать, то МИНИМУМ ПАМЯТИ это 4-ре байта (записываем туда ноль и XORим со всеми по очереди).
Hamster
Уже с Приветом
Posts: 11475
Joined: 20 Nov 2000 10:01
Location: Escondido, CA

Post by Hamster »

2) решается рекурсией, хотя немного мутно. Три случая:
(а) m = n. Делаем m swap'ов, задача решена.
(b) m > n. Делаем n swap'ов, m' = m-n, n' = n, повторяем.
(c) m < n. Делаем m swap'ов, m' = m, n' = n-m, повторяем.
3) hash-table, два прохода.
4) Определить, есть петля или нет, можно в линейное время с фиксированным объемом памяти. А вот найти "соединение"? ... Пока вижу только решение в квадратичное время.
P.S. А, нет, можно и в линейное.
User avatar
olg2002
Уже с Приветом
Posts: 990
Joined: 27 Mar 2002 10:01
Location: Palo Alto, CA

Post by olg2002 »

Hamster wrote:2) решается рекурсией, хотя немного мутно. Три случая:
(а) m = n. Делаем m swap'ов, задача решена.
(b) m > n. Делаем n swap'ов, m' = m-n, n' = n, повторяем.
(c) m < n. Делаем m swap'ов, m' = m, n' = n-m, повторяем.


Простого цикла достаточно:
next = cur + m mod m+n;
A[idx] = A[next];
idx = next;

добавлено> OK, двух циклов: второй по 1...GCD(m,n)
Last edited by olg2002 on 13 Apr 2004 16:54, edited 1 time in total.
User avatar
Sullen
Уже с Приветом
Posts: 1823
Joined: 28 Sep 1999 09:01
Location: CA, Saratoga, USA

Post by Sullen »

ballymahon wrote:
8K wrote:
uncle_Pasha wrote:
yocto wrote:
uncle_Pasha wrote:Если класс не задумывался как базовый, почему бы не использовать struct?

Так ведь объявление типа через struct не запрещает наследование.

Оно объясняет смысл данного элемента данных.
99% что никому не прийдет в голову наследоваться от struct в дальнейшем

Неужели нельзя "запечатать" класс собственными средствами С++? Не верю.


А как интересно? Можно конечно не использовать виртуальных функций и protected членов (о чем уже упоминалось) и тогда от наследования не будет особого толку, хотя сама возможность и будет присутствовать.
Как запретить наследование от данного класса - разве что сделать все конструкторы приватными и создавать обьекты статической функцией?

Ну зачем же? Достаточно сделать private destructor.
Ваше предложение более подходит для создания singleton. Причем если верить Мейерсу для создания экземпляра класса, в этом случае, лучше использовать friend function.
Понятно, что она вне области видимости класса. Но она фактически является элементом его интерфейса, что улучшать инкапсуляцию класса.
Politicians prefer unarmed peasants.
User avatar
Sullen
Уже с Приветом
Posts: 1823
Joined: 28 Sep 1999 09:01
Location: CA, Saratoga, USA

Re: Interesting C/C++ interview questions

Post by Sullen »

awq900 wrote:Посмотрел вопросы для чайников и понял, что я даже в чайники не гожусь. xотя я пограмаю на C ++ более 5 лет и, главное, это меня кормит, приносит "башки" моей компании и удовлетворение клиентам.

Вот например, первый вопрос из http://v.psiola.ru/cpp/index.htm для чайников.


Cколько символов "A" выведет на экран следующая программа:

#include <iostream>
using namespace std;
struct A
{A(){cout << "A";}; ~A(){cout << "A";};};
struct B : public A
{B(){cout << "B";}; ~B(){cout << "B";};};
struct C : public B
{C(){cout << "C";}; ~C(){cout << "C";};};
int main() {C c;return 0;}



Я не знаю ответ, а главное и знать не хочу :mrgreen:
Я не доумеваю, для чего нужны такие тесты?! Зачем их используют при приеме на работу?
Может кто-нибудь занает ответы ...
Паша

Что бы было понятно, программирует человек хотя бы 5 месяцев на С++ или нет.
Politicians prefer unarmed peasants.
Hamster
Уже с Приветом
Posts: 11475
Joined: 20 Nov 2000 10:01
Location: Escondido, CA

Post by Hamster »

Sullen wrote:Ну зачем же? Достаточно сделать private destructor.


У private destructor будет побочный эффект - объекты можно будет создавать только динамически через new и потом удалять только через функцию-член класса.
User avatar
Sullen
Уже с Приветом
Posts: 1823
Joined: 28 Sep 1999 09:01
Location: CA, Saratoga, USA

Post by Sullen »

Hamster wrote:
Sullen wrote:Ну зачем же? Достаточно сделать private destructor.


У private destructor будет побочный эффект - объекты можно будет создавать только динамически через new и потом удалять только через функцию-член класса.

А у private constructor, никаких побочных эффектов не предвидится? :wink:
Politicians prefer unarmed peasants.
User avatar
roadman
Уже с Приветом
Posts: 707
Joined: 12 Mar 2003 22:29
Location: Moscow->Bay Area, CA

Post by roadman »

Hamster wrote:
Mongush wrote:Есть :)
при i++ создается временная преременая.


А оптимизация на что?

Если i это int, то компилятор оптимизирует. А вот если это, как в примере, целый класс - iterator, то разница большая. Посмотрите на реализацию STL контейнера list:
iterator operator++() { _ptr = _ptr->_next; return *this; }
iterator operator++(int) { iterator tmp = _ptr; _ptr = _ptr->_next; return tmp; }
происходит полная копия объекта iterator. А если Вы переопределили эти операторы для более "тяжелого" класса?
The philosophy of one century is the common sense of the next. --Henry Ward Beecher
User avatar
roadman
Уже с Приветом
Posts: 707
Joined: 12 Mar 2003 22:29
Location: Moscow->Bay Area, CA

Post by roadman »

Вот ещё пример из реальной практики
template < typename T1, typename T2, typename С >
T1 do_something(T1 var1, T2 var2)
{
С convertor;
return convertor.convert(var1, var2);
}

template < typename T1, typename T2 >
class RIntAdd
{
public:
T1 convert(T1 var1, T2 var2) { return var1 + var2; }
};

template < typename T1, typename T2 >
class RIntSub
{
public:
T1 convert(T1 var1, T2 var2) { return var1 - var2; }
};


int main()
{
int resAdd = do_something< int, int, RIntAdd< int, int > >(5, 3);
int resSub = do_something< int, int, RIntSub< int, int > >(5, 3);
return 0;
}

Вопрос, чему будут равны resAdd и resSub?
The philosophy of one century is the common sense of the next. --Henry Ward Beecher
User avatar
roadman
Уже с Приветом
Posts: 707
Joined: 12 Mar 2003 22:29
Location: Moscow->Bay Area, CA

Post by roadman »

Достоинства и недостатки двух методов обработки exception
class exep
{
public:
exep(int err) : _error(err) {}
int get_code() const { return _error; }
private:
int _error;
};

int main()
{
try
{
throw new exep(1);
}
catch (exep* x)
{
cout << x->get_code();
delete x;
}

try
{
exep x(1);
throw x;
}
catch (exep& x)
{
cout << x.get_code();
}
The philosophy of one century is the common sense of the next. --Henry Ward Beecher
User avatar
roadman
Уже с Приветом
Posts: 707
Joined: 12 Mar 2003 22:29
Location: Moscow->Bay Area, CA

Post by roadman »

Что "лучше" работает

If (x == 0)
cout << "step 0";
else if (x == 1)
cout << "step 1";
else if (x == 2)
cout << "step 2";
else if (x == 10)
cout << "step 10";
else
cout << "step unknown";

или

switch (x)
{
case 0:
cout << "step 0";
break;
case 1:
cout << "step 1";
break;
case 2:
cout << "step 2";
break;
case 10:
cout << "step 10";
break;
default:
cout << "step unknown";
}


Это любителям "C"
The philosophy of one century is the common sense of the next. --Henry Ward Beecher
User avatar
Tango
Уже с Приветом
Posts: 2099
Joined: 30 Jan 2004 07:55
Location: Orange County, CA

Post by Tango »

А я вот иногда задаю такой вопрос по C:
"How to access the n-th bit of a word?"

а после того как интервьюируемый ответит (well, если ответит :) ):
"Now, how to access the n-th bit of a word without a bit-shift operation?"

....а уже на десерт:
"How to access the n-th bit of a word without a bit-shift or mask operation?"

Return to “Работа и Карьера в IT”