Тестовое задание C++ win
От: amberovsky  
Дата: 30.11.09 11:17
Оценка:
Здравствуйте.
При попытке устроится в одну фирму прислали "удалённое" тестовое задание.



Какие проблемы Вы видите в этих фрагментах кода и как предлагаете их решать?
1.
void g( char *, char *, size_t );
void f( size_t n )
{
 char *a = new char[n];
 char *b = new char[n];
 g( a, b, n );
 delete [] b;
 delete [] a;
}

2.
int main(int argc, char* argv[])
{
 if( argc > 1 )
  printf( argv[1] );
 return 0;
}


Я ответил так:
1. new может не сработать, нужно добавить, например, try/catch. Кроме того, g может "испортить" указатели (как тут просто решить я не знаю)
2. В аргументе командной строки может встретиться символ % или \, что будет расценено printf как специальный символ.
Если следующие символы совпадут с какой-либо спецификацией формата (для % или \), то в данном случае для % — UB, для \ — произойдёт подстановка.
Решение — printf("%s", argv[1]);
Ещё можно проверить что printf действительно напечатало нужное количество символов.


В итоге мне отказали.
В чём я ошибся или чего важного не указал?

07.05.10 02:19: Перенесено из 'C/C++'
Re: Тестовое задание C++ win
От: std.denis Россия  
Дата: 30.11.09 11:40
Оценка: +2
A>1.
Подозрительно как-то — создаются два массива, передаются в функцию без какой-либо инициализации, и после того как она отработает просто прибиваются, опять-таки без использования значений в массивах. Вопрос — зачем всё это?
Re: Тестовое задание C++ win
От: remark Россия http://www.1024cores.net/
Дата: 30.11.09 11:42
Оценка:
Здравствуйте, amberovsky, Вы писали:

A>2. В аргументе командной строки может встретиться символ % или \, что будет расценено printf как специальный символ.

A>Если следующие символы совпадут с какой-либо спецификацией формата (для % или \), то в данном случае для % — UB, для \ — произойдёт подстановка.
A>Решение — printf("%s", argv[1]);

Тут да, неизвестные строки всегда надо выводить как printf("%s", str).


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: Тестовое задание C++ win
От: remark Россия http://www.1024cores.net/
Дата: 30.11.09 11:46
Оценка: +1 -4
Здравствуйте, amberovsky, Вы писали:

A>
A>Какие проблемы Вы видите в этих фрагментах кода и как предлагаете их решать?
A>1.
A>void g( char *, char *, size_t );
A>void f( size_t n )
A>{
A> char *a = new char[n];
A> char *b = new char[n];
A> g( a, b, n );
A> delete [] b;
A> delete [] a;
A>}
A>


A>Я ответил так:

A>1. new может не сработать, нужно добавить, например, try/catch. Кроме того, g может "испортить" указатели (как тут просто решить я не знаю)

Если вылетит исключение при выделении памяти под b, то память для a не будет освобождена -> утечка память.
Ну и плюс в целом ручное управление памятью чревато проблемами при поддержке, поэтому кошерно будет:

void f( size_t n )
{
 std::auto_ptr<char> a (new char[n]);
 std::auto_ptr<char> b (new char[n]);
 g( a.get(), b.get(), n );
}


Если доступен scoped_ptr<>, то лучше использовать его.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: Тестовое задание C++ win
От: Smal Россия  
Дата: 30.11.09 11:52
Оценка: 4 (2) +6
Здравствуйте, remark, Вы писали:

R>Здравствуйте, amberovsky, Вы писали:


A>>
A>>Какие проблемы Вы видите в этих фрагментах кода и как предлагаете их решать?
A>>1.
A>>void g( char *, char *, size_t );
A>>void f( size_t n )
A>>{
A>> char *a = new char[n];
A>> char *b = new char[n];
A>> g( a, b, n );
A>> delete [] b;
A>> delete [] a;
A>>}
A>>


A>>Я ответил так:

A>>1. new может не сработать, нужно добавить, например, try/catch. Кроме того, g может "испортить" указатели (как тут просто решить я не знаю)

R>Если вылетит исключение при выделении памяти под b, то память для a не будет освобождена -> утечка память.

R>Ну и плюс в целом ручное управление памятью чревато проблемами при поддержке, поэтому кошерно будет:

R>
R>void f( size_t n )
R>{
R> std::auto_ptr<char> a (new char[n]);
R> std::auto_ptr<char> b (new char[n]);
R> g( a.get(), b.get(), n );
R>}
R>


Тут UB.

R>Если доступен scoped_ptr<>, то лучше использовать его.


Ну, тогда уж
void f( size_t n )
{
 std::vector<char> a (n);
 std::vector<char> b (n);
 g( &a[0], &b[0], n );
}


или

void f( size_t n )
{
 boost::scoped_array<char> a (new char[n]);
 boost::scoped_array<char> b (new char[n]);
 g( a.get(), b.get(), n );
}
С уважением, Александр
Re: Тестовое задание C++ win
От: Bell Россия  
Дата: 30.11.09 11:53
Оценка:
Здравствуйте, amberovsky, Вы писали:

A>
A>Какие проблемы Вы видите в этих фрагментах кода и как предлагаете их решать?
A>1.
A>void g( char *, char *, size_t );
A>void f( size_t n )
A>{
A> char *a = new char[n];
A> char *b = new char[n];
A> g( a, b, n );
A> delete [] b;
A> delete [] a;
A>}

A>2.
A>int main(int argc, char* argv[])
A>{
A> if( argc > 1 )
A>  printf( argv[1] );
A> return 0;
A>}

A>


A>Я ответил так:

A>1. new может не сработать, нужно добавить, например, try/catch. Кроме того, g может "испортить" указатели (как тут просто решить я не знаю)
new может кинуть исключение, g тоже может кинуть исключение, соответственно могут возникнуть утечки. В g невозможно проверить "валидность" указателей и длину блоков. Насчет второго можно возразить, что ответственность лежит на пользователе функции g, но ИМХО assert в функции не помешал бы.
Обе эти проблемы можно решить, если в качестве параметров g использовать std::vector<char>.

Не понятно, что означает фраза

g может "испортить" указатели



A>2. В аргументе командной строки может встретиться символ % или \, что будет расценено printf как специальный символ.

A>Если следующие символы совпадут с какой-либо спецификацией формата (для % или \), то в данном случае для % — UB, для \ — произойдёт подстановка.
A>Решение — printf("%s", argv[1]);

В общем верно.



A>В итоге мне отказали.

A>В чём я ошибся или чего важного не указал?
Любите книгу — источник знаний (с) М.Горький
Re: Тестовое задание C++ win
От: landerhigh Пират  
Дата: 30.11.09 12:00
Оценка: 3 (3) +10 :))) :)))
Здравствуйте, amberovsky, Вы писали:

A>
A>Какие проблемы Вы видите в этих фрагментах кода и как предлагаете их решать?
A>


Главная проблема — это не тест по C++
www.blinnov.com
Re: Тестовое задание C++ win
От: Caracrist https://1pwd.org/
Дата: 30.11.09 12:03
Оценка:
Здравствуйте, amberovsky, Вы писали:

A>Здравствуйте.

A>При попытке устроится в одну фирму прислали "удалённое" тестовое задание.



A>
A>Какие проблемы Вы видите в этих фрагментах кода и как предлагаете их решать?
A>1.
A>void g( char *, char *, size_t );
A>void f( size_t n )
A>{
A> char *a = new char[n];
A> char *b = new char[n];
A> g( a, b, n );
A> delete [] b;
A> delete [] a;
A>}


A>


A>Я ответил так:

A>1. new может не сработать, нужно добавить, например, try/catch. Кроме того, g может "испортить" указатели (как тут просто решить я не знаю)

ничего g не может испортить.

A>В итоге мне отказали.

A>В чём я ошибся или чего важного не указал?
~~~~~
~lol~~
~~~ Single Password Solution
Re: Тестовое задание C++ win
От: SaZ  
Дата: 30.11.09 12:08
Оценка: 1 (1) +1
Здравствуйте, amberovsky, Вы писали:

A>Здравствуйте.

A>При попытке устроится в одну фирму прислали "удалённое" тестовое задание.

A>2. В аргументе командной строки может встретиться символ % или \, что будет расценено printf как специальный символ.


Про обратный слэш \ — не правда. Эти вещи обрабатываются компилятором. Если из командной строки передать обратный слэш, то он так и выведется, т.е. аргумент "\n" не приведёт к переводу командной строки, т.к. будет эквивалентен "\\n" с точки зрения компилятора.
Re[2]: Тестовое задание C++ win
От: alexander_st Россия  
Дата: 30.11.09 12:23
Оценка:
Здравствуйте, Caracrist, Вы писали:

C>Здравствуйте, amberovsky, Вы писали:


C>ничего g не может испортить.


правда? а если попробовать так:

g(char*a , char* b, size_t)
{
    delete a;
    delete[] b;
}

ПыСы: разные варьянты delete от нечего делать, но понятно что при выходе из ф-и g и попытке сделать очередной delete будет маленькая попа
Re[3]: Тестовое задание C++ win
От: amberovsky  
Дата: 30.11.09 12:34
Оценка:
Здравствуйте, alexander_st, Вы писали:

C>>ничего g не может испортить.


_>правда? а если попробовать так:


_>
_>g(char*a , char* b, size_t)
_>{
_>    delete a;
_>    delete[] b;
_>}
_>


Да, это я и имел ввиду под "испортить"
Re[3]: Тестовое задание C++ win
От: remark Россия http://www.1024cores.net/
Дата: 30.11.09 12:35
Оценка: +1
Здравствуйте, Smal, Вы писали:

R>>
R>>void f( size_t n )
R>>{
R>> std::auto_ptr<char> a (new char[n]);
R>> std::auto_ptr<char> b (new char[n]);
R>> g( a.get(), b.get(), n );
R>>}
R>>


S>Тут UB.


Да-да, точно, есть такая фигня. Ну тогда стандартными средствами лучше всего наверное std::vector<>.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: Тестовое задание C++ win
От: amberovsky  
Дата: 30.11.09 12:35
Оценка:
Здравствуйте, landerhigh, Вы писали:

L>Главная проблема — это не тест по C++


Это удалённый пре-тест для отсева.
Re[3]: Тестовое задание C++ win
От: amberovsky  
Дата: 30.11.09 12:39
Оценка:
Здравствуйте, Smal, Вы писали:

R>>Если доступен scoped_ptr<>, то лучше использовать его.


S>Ну, тогда уж

S>
S>void f( size_t n )
S>{
S> std::vector<char> a (n);
S> std::vector<char> b (n);
S> g( &a[0], &b[0], n );
S>}
S>


Насколько это естественно? По-моему это слишком сложно для обычной передачи параметров.

S>или


S>
S>void f( size_t n )
S>{
S> boost::scoped_array<char> a (new char[n]);
S> boost::scoped_array<char> b (new char[n]);
S> g( a.get(), b.get(), n );
S>}
S>


Использовать boost в таких заданиях нормально?

p.s. На второй вопрос я ответил правильно, в первом так себе. Почему же отказали?
Re[4]: Тестовое задание C++ win
От: SaZ  
Дата: 30.11.09 12:57
Оценка:
Здравствуйте, amberovsky, Вы писали:

A>p.s. На второй вопрос я ответил правильно, в первом так себе. Почему же отказали?


Если задание удалённое — то неправильно. А на собеседовании попросили бы аргументировать. Почему — написано ниже.
Re: Тестовое задание C++ win
От: любой  
Дата: 30.11.09 13:46
Оценка: 17 (4) +2
Здравствуйте, amberovsky, Вы писали:

A>[ccode]

A>Какие проблемы Вы видите в этих фрагментах кода и как предлагаете их решать?
A>1.
A>void g( char *, char *, size_t );
A>void f( size_t n )
A>{
A> char *a = new char[n];
A> char *b = new char[n];
A> g( a, b, n );
A> delete [] b;
A> delete [] a;
A>}

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

char *a = new char[n*2];
char *b = a + n;
g( a, b, n );
delete [] a;
художников никогда не обижал
Re[2]: Тестовое задание C++ win
От: srggal Украина  
Дата: 30.11.09 13:49
Оценка: +2 :)
Здравствуйте, любой, Вы писали:

Л>Тут по существу уже сказали. А меня в таком коде всегда прикалывает, почему два блока нельзя за раз выделить:


Л>char *a = new char[n*2];

Л>char *b = a + n;
Л>g( a, b, n );
Л>delete [] a;
несчастный_труженик_проекта>delete [] b;
Re[4]: Тестовое задание C++ win
От: SergeyT. США http://sergeyteplyakov.blogspot.com/
Дата: 30.11.09 14:03
Оценка:
Здравствуйте, amberovsky, Вы писали:


S>>Ну, тогда уж

S>>
S>>void f( size_t n )
S>>{
S>> std::vector<char> a (n);
S>> std::vector<char> b (n);
S>> g( &a[0], &b[0], n );
S>>}
S>>


A>Насколько это естественно? По-моему это слишком сложно для обычной передачи параметров.


Это не очень красивая, но совершенно стандартная идиома.
Скотт Мейерс, Эффективное использование STL, Item 16

Item 16. Know how to pass vector and string data to legacy APIs.

Since C++ was standardized in 1998, the C++ elite haven't been terribly subtle in their attempt to nudge programmers away from arrays and towards vectors. They've been similarly overt in trying to get developers to shift from char* pointers to string objects. There are good reasons for making these changes, including the elimination of common programming errors (see Item 13) and the ability to take full advantage of the power of the STL algorithms (see. e.g., Item 31).
Still, obstacles remain, and one of the most common is the existence of legacy C APIs that traffic in arrays and char* pointers instead of vector and string objects. Such APIs will exist for a long time, so we must make peace with them if we are to use the STL effectively.
Fortunately, it's easy. If you have a vector v and you need to get a pointer to the data in v that can be viewed as an array, just use &v[0]. For a string s, the corresponding incantation is simply s.c_str(). But read on. As the fine print in advertising often points out, certain restrictions apply.
Given
vector<int> v;


the expression v[0] yields a reference to the first element in the vector, so &v[0] is a pointer to that first element. The elements in a vector are constrained by the C++ Standard to be stored in contiguous memory, just like an array, so if we wish to pass v to a C API that looks something like this.
void doSomething(const int* pInts, size_t numlnts);
we can do it like this:
doSomething(&v[0], v.size());

Maybe. Probably. The only sticking point is if v is empty. If it is, v.size() is zero, and &v[0] attempts to produce a pointer to something that does not exist. Not good. Undefined results. A safer way to code the call is this:
if (!v.empty()) {
doSomething(&v[0], v.size());
}

If you travel in the wrong circles, you may run across shady characters who will tell you that you can use v.begin() in place of &v[0], because (these loathsome creatures will tell you) begin returns an iterator into the vector, and for vectors, iterators are really pointers. That's often true, but as Item 50 reveals, it's not always true, and you should never rely on it. The return type of begin is an iterator, not a pointer, and you should never use begin when you need to get a pointer to the data in a vector. If you're determined to type v.begin() for some reason, type &*v.begin(), because that will yield the same pointer as &v[0], though it's more work for you as a typist and more obscure for people trying to make sense of your code. Frankly, if you're hanging out with people who tell you to use v.begin() instead of &v[0], you need to rethink your social circle.

...

Re: Тестовое задание C++ win
От: rusted Беларусь  
Дата: 30.11.09 14:33
Оценка: 1 (1)
Здравствуйте, amberovsky, Вы писали:

A>[ccode]

A>Какие проблемы Вы видите в этих фрагментах кода и как предлагаете их решать?
A>1.
A>void g( char *, char *, size_t );
A>void f( size_t n )
A>{
A> char *a = new char[n];
A> char *b = new char[n];
A> g( a, b, n );
A> delete [] b;
A> delete [] a;
A>}

Проблема в том, что есть функция с ничего не говорящим именем g, для которой нет не то что комментария чего она делает, но даже названий параметров.
Re: Тестовое задание C++ win
От: Кодт Россия  
Дата: 30.11.09 14:38
Оценка: 19 (5)
Здравствуйте, amberovsky, Вы писали:

A>1. new может не сработать, нужно добавить, например, try/catch.

Лучше не try-catch (это слишком громоздко), а RAII — любой умный указатель или контейнер.

A> Кроме того, g может "испортить" указатели (как тут просто решить я не знаю)

Паранойя. Чтобы испортить указатели, функция должна расстрелять стек. А это никакими средствами не лечится.
А вот метнуть исключение функция g() может запросто.

Решение
void f(size_t n)
{
    if(n!=0)
    {
        std::vector<char> a(n), b(n);
        g(&a.front(), &b.front(), n);
    }
    else // если мы ничего не знаем про логику g(), попробуем максимально близко воспроизвести ситуацию
    {
        char a,b;
        g(&a,&b,0); // передаём два уникальных ненулевых адреса! ибо new char[0] != NULL
        
        // хотя, возможно, было бы достаточно
        g(NULL,NULL,0);
    }
    // или, в обобщённом виде
    std::vector<char> a(max(n,1)), b(max(n,1)); // гарантируем непустоту и уникальность
    g(&a.front(), &b.front(), n);
}


A>2. В аргументе командной строки может встретиться символ % или \, что будет расценено printf как специальный символ.

A>Если следующие символы совпадут с какой-либо спецификацией формата (для % или \), то в данном случае для % — UB, для \ — произойдёт подстановка.

Про бэкслеш — фантазия. Для принтфа спецсимволом является только %.
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.