Você está pronto para se juntar ao mundo majestoso de C e C++ da programação? Você quer questionar sua existência depois de algumas linhas simples de C++? Se sua resposta for "Yeh!", "Yep" ou "Why not?" - bem-vindo para testar seu conhecimento. Você receberá várias perguntas relacionadas a C ou C++. Por favor, encontre respostas e explicações corretas no final da história. Boa sorte! 1. O menor programa main; O que acontecerá se você tentar compilar este programa usando o compilador C? não irá compilar irá compilar, não irá vincular irá compilar e irá vincular 2. O garfo #include <iostream> #include <unistd.h> int main() { for(auto i = 0; i < 1000; i++) std::cout << "Hello world!\n"; fork(); } Quantas linhas este programa imprimirá? 1000 menos de 1000 mais de 1000 3. Tudo o que você precisa são índices #include <iostream> int main() { int array[] = { 1, 2, 3 }; std::cout << (4, (1, 2)[array]) << std::endl; } O que este programa imprimirá? 1 2 3 4 não irá compilar indefinido 4. Expressões regulares #include <regex> #include <iostream> int main() { std::regex re("(.*|.*)*O"); std::string str("0123456789"); std::cout << std::regex_match(str, re); return 0; } Quanto tempo levará para que essa expressão regular corresponda a essa string de entrada? 1 mês 1 segundo 1 minuto 1 hora 1 ano para sempre 5. Movimentos e lambdas #include <iostream> struct Foo { Foo() { std::cout << "Foo()\n"; } Foo(Foo&&) { std::cout << "Foo(Foo&&)\n"; } Foo(const Foo&) { std::cout << "Foo(const Foo&)\n"; } }; int main() { Foo f; auto a = [f = std::move(f)]() { return std::move(f); }; Foo f2(a()); return 0; } A última linha a ser impressa por este programa é… Foo() Foo(Foo&&) Foo(const Foo&) 6. X e barra #include <iostream> int x = 0; int bar(int(x)); int main() { std::cout << bar; } O que este programa imprimirá? 0 1 0x0 não irá compilar não vai ligar 7. Construtores #include <iostream> struct Foo { Foo() { std::cout << "Foo()\n"; } Foo(const Foo&) { std::cout << "Foo(const Foo&)\n"; } Foo(int) { std::cout << "Foo(int)\n"; } Foo(int, int) { std::cout << "Foo(int, int)\n"; } Foo(const Foo&, int) { std::cout << "Foo(const Foo&, int)\n"; } Foo(int, const Foo&) { std::cout << "Foo(int, const Foo&)\n"; } }; void f(Foo) {} struct Bar { int i, j; Bar() { f(Foo(i, j)); f(Foo(i)); Foo(i, j); Foo(i); Foo(i, j); } }; int main() { Bar(); } A última linha a ser impressa por este programa é… Foo(int, int) Foo(const Foo&, int) Foo(int, const Foo&) Foo(int) Em vez de conclusão Espero que você nunca encontre um desses fragmentos peculiares na natureza. Respostas O menor programa Este é um código C legal. Ele irá travar se você tentar executá-lo. - é uma variável global. Ele será compilado e vinculado com sucesso. main; No código C, você pode omitir muitas coisas. Por exemplo, você pode omitir o tipo de uma variável global. Por padrão, o compilador assumirá que esse tipo é um . Também não há em C (ao contrário de C++), então, ao vincular, não há como distinguir a variável da função . int confusão de nomes main main Assim, o compilador compilará um código válido e o vinculador encontrará algo chamado no arquivo objeto para vincular um programa. main O garfo Este é mais um recurso POSIX do que um recurso C ou C++. Implementações de operações de IO usam buffers para otimizar o desempenho. Quando você invoca , o SO criará uma duplicata copy-on-write da memória do processo, os buffers de IO provavelmente também serão duplicados e strings em buffer . fork provavelmente serão impressas mais de 1000 vezes Tudo o que você precisa são índices A resposta é 3 Para entender esse código, vamos dar uma olhada mais de perto em como os índices em C e C++ funcionam: , é o mesmo que , é o mesmo que e o mesmo que . array[index] *(array + index) (index + array) index[array A segunda pista é o operador . Seu operador binário, ele descarta o argumento esquerdo e retorna o argumento direito. , Expressões regulares É o que vai acontecer! O comportamento depende da implementação. impossível prever No meu ambiente, este programa gera a exceção The complexity of an attempted match against a regular expression exceeded a pre-set level. Outras opções prováveis são surpreendentemente longas ou funcionam como esperado. É porque há duas abordagens possíveis para implementar expressões regulares. Primeiro - transforme expressões regulares em autômatos finitos (n - comprimento do padrão), combine a string (m - comprimento da string). Essa abordagem não suporta O(n**2) O(m) backtracking. Segundo - abordagem gananciosa + DFS, suporta retrocesso, mas é propenso à complexidade de tempo exponencial em certos padrões. Movimentos e lambdas A resposta é . Lambdas são imutáveis por padrão, todos os valores capturados em lambda com são implicitamente . Isso desbloqueia o comportamento para lambdas. Foo(const Foo&) [] const idempotente Quando você move você cria . é um tipo estranho, então o compilador apenas copia f const Foo&& const Foo&& Foo Há duas maneiras de corrigir isso: Criar lambda mutável auto a = [f = std::move(f)]() mutable { return std::move(f); }; Declarar construtor Foo(const Foo&&) X e barra . O programa imprimirá 1 — é uma maneira estranha de declarar uma função, é igual a . int bar(int(x)); int bar(int x); Se você confundiu com conversão de tipo, - isso é conversão de tipo. int bar((int(x))); Então tentamos converter implicitamente o endereço da função para , o resultado dessa conversão é sempre . bool true A função nunca foi usada, o que nos permite evitar erros de símbolos não referenciados durante a vinculação. bar() Construtores A última linha é . Foo(const Foo&, int) é uma declaração de variável, o mesmo que . Portanto, o membro de classe sob o nome de está oculto neste escopo. Foo(i) Foo i i