This content originally appeared on HackerNoon and was authored by Ilia
Are you ready to join majestic world of C and C++ of programming? Do you want to question your existence after few simple lines of C++?
\ If your answer is "Yeh!", “Yep“ or “Why not?“ - welcome to test your knowledge. You will be given multiple questions related to C or C++.
\ Please find correct answers and explanations in the end of the story. Good luck!
1. The smallest program
main;
\ What will happen if you try to compile this program using C compiler?
- will not compile
- will compile, will not link
- will compile and will link
2. The fork
#include <iostream>
#include <unistd.h>
int main() {
for(auto i = 0; i < 1000; i++)
std::cout << "Hello world!\n";
fork();
}
\ How many lines will this program print?
- 1000
- less than 1000
- more than 1000
3. All you need is indices
#include <iostream>
int main() {
int array[] = { 1, 2, 3 };
std::cout << (4, (1, 2)[array]) << std::endl;
}
\ What will this program print?
- 1
- 2
- 3
- 4
- will not compile
- undefined
4. Regular expressions
#include <regex>
#include <iostream>
int main() {
std::regex re("(.*|.*)*O");
std::string str("0123456789");
std::cout << std::regex_match(str, re);
return 0;
}
\ How long will it take for this regular expression to match this input string?
\
- 1 ms
- 1 sec
- 1 min
- 1 hour
- 1 year
- forever
5. Moves and 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;
}
\ The last line to be printed by this program is…
\
Foo()
Foo(Foo&&)
Foo(const Foo&)
6. X and bar
#include <iostream>
int x = 0;
int bar(int(x));
int main() {
std::cout << bar;
}
\ What will this program print?
0
1
0x0
- will not compile
- will not link
7. Constructors
#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(); }
\ The last line to be printed by this program is…
Foo(int, int)
Foo(const Foo&, int)
Foo(int, const Foo&)
Foo(int)
Instead of conclusion
I hope you will never find one of this peculiar snippets in the wild.
Answers
The smallest program
\ This is legal C code. It will compile and link successfully. It will crash if you try to run it.
main;
- is global variable.\ In C code you can omit a lot of things. For example you can omit the type of a global variable. By the default compiler will assume this type is an
int
. Also there is no name mangling in C (unlike in C++), so when linking there is no way to distinguish variablemain
from functionmain
.\ Thus compiler will compile valid code, and linker will find something named
main
in object file to link a program.\
The fork
\ This is more POSIX feature rather than C or C++ feature. Implementations of IO operations use buffers for optimising performance. When you invoke
fork
, the OS will create copy-on-write duplicate of process memory, the IO-buffers will likely duplicate as well and buffered strings likely will be printed more than 1000 times.\
All you need is indices
\ Answer is 3
\ To understand this code lets take a closer look on how indices in C and C++ work:
array[index]
, is the same as*(array + index)
, is the same as(index + array)
and the same asindex[array
. \nThe second clue is operator
,
. Its binary operator, it discards left argument and returns right argument.\
Regular expressions
\ Its impossible to predict what will happen! The behaviour is up to implementation.
\ Im my environment this program raises the exception
The complexity of an attempted match against a regular expression exceeded a pre-set level.
\ Other probable options are surprisingly long time or work as expected. It’s because there are two possible approaches to implement regular expressions.
\ First - transform regular expressions to finite automata
O(n**2)
(n - length of pattern), match stringO(m)
(m - length of string). This approach doesn’t support [backtracking.]()\ Second - greedy approach + DFS, supports backtracking but prone to exponential time complexity on certain patterns.
\
Moves and lambdas
\ Answer is
Foo(const Foo&)
. Lambdas are immutable by the default, all values captured into lambda with[]
are implicitlyconst
. This unlocks idempotent behaviour for lambdas.\ When you move
f
you createconst Foo&&
.const Foo&&
is a weird type, thus compiler just copiesFoo
\ There are two ways to fix this:
\
Create mutable lambda
auto a = [f = std::move(f)]() mutable { return std::move(f); };
\
Declare constructor
Foo(const Foo&&)
\
X and bar
The program will print
1
.\
int bar(int(x));
— is weird way to declare function, it is equal toint bar(int x);
. \nIf you confused with type cast,
int bar((int(x)));
- this is type cast.\ Than we try to implicitly cast function address to
bool
, the result of such cast is alwaystrue
.\ Function
bar()
has never been used, thats allow us to dodge unreferenced symbol error while linking.\
Constructors
The last line is
Foo(const Foo&, int)
.\
Foo(i)
is variable declaration, the same asFoo i
. Thus class member under the name ofi
is hidden in this scope.
\
This content originally appeared on HackerNoon and was authored by Ilia
Ilia | Sciencx (2024-08-09T13:46:20+00:00) Hidden Gems of C and C++ That You Probably Don’t Know. Retrieved from https://www.scien.cx/2024/08/09/hidden-gems-of-c-and-c-that-you-probably-dont-know/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.