How not to write code

image


Ready to plunge into the wonderful world of programming? Want to find out how unpredictably several simple lines of code can behave?


If your answer is "Yes!" - welcome under cat.


You will be waited by several entertaining puzzles in C or C ++.


The correct answer with explanation will always be hidden under the spoiler.


Good luck!


About the shortest program


main; 

What happens if you compile this program with a C compiler?


  1. Not compiled.
  2. Do not link up.
  3. Compiled and linked.

Answer:

This is a valid C code.
Why? In C, you can omit the return type of the functions and when declaring variables, by default it will be int. And in C there is no difference between functions and global variables when linking. In this case, the linker thinks that under the name main there is a function.


About fork


 #include <iostream> #include <unistd.h> int main() { for(auto i = 0; i < 1000; i++) std::cout << "Hello world!\n"; fork(); } 

How many times will Hello World! Be printed?


  1. 1000
  2. less
  3. more

Answer:

IO operations are buffered to improve performance.
Calling fork() will spawn a new process, with copy-on-write duplicate address space.
Buffered lines will be printed in each process.


About indexes


 #include <iostream> int main() { int array[] = { 1, 2, 3 }; std::cout << (4, (1, 2)[array]) << std::endl; } 

What will this code print?


  1. one
  2. 2
  3. 3
  4. four
  5. Compilation error
  6. Not defined by standard.

Answer:

The grammar prints 3.
Why is that?
First look at the index: array[index] == *(array + index) == *(index + array) == index[array]
Then we deal with the binary operator comma. It discards its left argument and returns the value of the right one.


About regular expression


 #include <regex> #include <iostream> int main() { std::regex re { "(.*|.*)*O" }; std::string str { "0123456789" }; std::cout << std::regex_match(str, re); return 0; } 

What is the minimum time for this regular season?


  1. ~ 1 ms
  2. ~ 100 ms
  3. ~ 1 sec.
  4. ~ 1 min
  5. ~ 1 hour
  6. ~ 1 year.
  7. more time life of the universe.

Answer:

Haha That is not guessed. Depends on the compiler.
On my laptop, clang shows a result of about 100 ms.
GCC 57 seconds! Minute! Seriously?!
Why is that?
There are 2 approaches for implementing regular expressions.
One is to turn the regular expression into a state machine for O(n**2) , for a regular expression of length n characters.
The complexity of matching with a string of m characters is O(m) . This regular expression does not support backtracking.
The second is something like a greedy brute-force search in depth. Supports backtracking.
And yet, the complexity of operations with regular expressions in the STL is not defined. Well at least, that in a minute managed.


About move and lambda


 #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; } 

What line will the program print last?


  1. Foo()
  2. Foo(Foo&&)
  3. Foo(const Foo&)

Answer:

Foo(const Foo&) . By default, lambdas are immutable. const is implicitly added to all values ​​specified in [] .
This allows lambdas to behave like normal functions. With the same arguments return the same values.
What happens in this case? When we try to move f from a function, we get const Foo&& .
This is a very strange thing, the compiler does not know how to work with it and copies Foo . You can fix it by declaring mutable lambda:


 auto a = [f = std::move(f)]() mutable { return std::move(f); }; 

Or make a constructor from Foo(const Foo&&) .


Pro x and bar


 #include <iostream> int x = 0; int bar(int(x)); int main() { std::cout << bar; } 

What happens if you try to compile and run it?


  1. will print 0
  2. will print 1
  3. prints 0x0
  4. will not compile
  5. does not link

Answer:

The program will print 1 .
Why is that?
int bar(int(x)); - this is a function declaration, it is equivalent to int bar(int x); .
If you want a type conversion, you need to write like this int bar((int(x))); .
Then we try to print the address of the function, it will be implicitly converted to bool, the address of the function cannot be zero, i.e. true .
The bar() function is not used. Therefore, when linking will not be unreferenced symbol.


About inline


 #include <iostream> inline size_t factorial(size_t n) { if (n == 0) return 1; return n * factorial(n - 1); } int main() { std::cout << factorial(5) << std::endl; } 

The program is compiled and linked without errors, like this: g++ -c main.cpp -o main.o && g++ foo.cpp -o foo.o && g++ foo.o main.o -o test . What happens if you run it?


  1. 120 will print.
  2. Anything can happen.

Answer:

Anything can happen. This is C ++.
The whole catch in the word inline. This is only an instruction to the compiler.
It can simply compile this function into an object file (most likely, it will do just that for recursive functions).
The linker can throw out duplicates of inline functions not embedded in the code.
In the final file usually gets the option that met in the first object file.
The program will output 0 if in foo.cpp:


 #include <cstddef> inline size_t factorial(size_t n) { if (n == 0) return 0; return 2 * n * factorial(n - 1); } int foo(size_t n) { return factorial(n); } 

About designers


 #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(); } 

What line will be printed last?


  1. Foo(int, int)
  2. Foo(const Foo&, int)
  3. Foo(int, const Foo&)
  4. Foo(int)

Answer:

The last line is Foo(const Foo&, int) .
Foo(i) is a variable declaration, it is equivalent to Foo i , which means that the field of class i will disappear from scope.


Conclusion


I hope you never see it in real code.

Source: https://habr.com/ru/post/413697/


All Articles