With C++ as my hammer, everything looked like a nail ~ Lex Fridman
https://youtu.be/YgCq0Y6Mhh0?si=__Z29HpbGd-2U2kr
Other Resources:
- Do Leetcodes, then go to ChatGPT and say:
Prompt: "You are a senior developer. Critique my code." - Glossary
Write a function to print Hello world to the console in C++.
# include <iostream>
int main () {
std::cout << "Helo World" <<std::endl;
return 0;
}Explain the steps required to compile and run a C++ program called money_machine.cpp on a Unix system
- Write your program,
money_machine.cpp - Use a compiler such as
g++to compile the code:g++ -o program money_machine.cpp.-ostands for ‘Output Filename’ ./programwhere./denoted the current directory.
Sexyiness
std::cout << "hello world" << std::endl;I mean how sexy is this. You’re inserting words into the stream
Knowing another language is good.
C++ is a compiler based, low level, object oriented programming language
But seriously, we’ve covered python for ML, we’ve covered algorithms, C++ will be used to cover the rest of computer science basics, due to being a more low level language (closer to machine code, but not quite as close as other languages)
Python tends to be more concise and higher-level, while C++ provides more control and efficiency, especially for system-level programming.
We’ll cover stuff like the heap vs the stack, pointers, memory management, typing.
it’s good if you want to be that applicant who also really gets computer science + knows another languagfe, and is a bit more of a programmer than a scripter.
Python was made for Machine Learning. But for programming… we return to our true love: C++. Note: this is obviously just a personal preference. There are many low-level programming languages to choose from; C, C++, C#, Rust…
- I mean
long long? Sold.
#6 0x7fc3c16c5082 (/lib/x86_64-linux-gnu/libc.so.6+0x24082)
Shadow bytes around the buggy address:
0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff8000: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
=>0x0c047fff8010: fa fa 00 00[fa]fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03
By far the best way to teach C++ to test the basics of computer science;
- bits, bytes
- what the compiler is
- operating systems 101
- hexadecimal
- pointers
- memory
- the stack and the heap
It’s good to know more than one language, and if you had to know one other one, it’d be C++ Many applications are built with C++. It’s the sexiest programming language It will make python seem so simple in comparison.
For you beautiful Pythonic programmers, here’s a little primer to make you feel more welcome:
| Python | C++ | |
|---|---|---|
| Declaring a variable | x = 10 | int x = 10; |
| Making a list | my_list = [1, 2, 3] | std::vector<int> my_list = {1, 2, 3}; |
| A for loop | for i in range(10): | for (int i = 0; i < 10; i++) { |
| Checking if an element is in a set | if element in my_set: | if (my_set.find(element) != my_set.end()) { |
| The max() function | max_value = max(my_list) | int max_value = *std::max_element(my_list.begin(), my_list.end()); |
| Reading input from console | input_value = input() | std::string input_value; std::cin >> input_value; |
| Appending to a list | my_list.append(4) | my_list.push_back(4); |
Operators
- Arithmetic Operators:
+,-,*,/,% - Relational Operators:
==,!=,>,<,>=,<= - Logical Operators:
&&,||,! - Bitwise Operators:
&,|,^,~,<<,>> - Assignment Operators:
=,+=,-=,*=,/=,%=,<<=,>>=,&=,^=,|= - Increment and Decrement:
++,-- - Member Access and Dereference:
.,->,*,& - Others:
sizeof,typeid,new,delete,throw,?:(ternary operator)
Special Characters and Punctuation
- Braces and Brackets:
{},[],(),<> - Semicolon and Comma:
;,, - Scope Resolution:
:: - Pointer/Reference:
*,& - Other Special Characters:
#(preprocessor),\:,',"
Keywords
- Control Flow:
if,else,switch,case,default,while,do,for,break,continue,goto,return - Access Specifiers:
public,protected,private - Data Types:
int,char,float,double,void,bool,short,long,signed,unsigned - Class/Struct/Union/Enum:
class,struct,union,enum - Modifiers:
const,static,extern,volatile,mutable - Error Handling:
try,catch,throw - Other Keywords:
namespace,using,template,this,virtual,inline,dynamic_cast,static_cast,reinterpret_cast,const_cast,friend,operator,typeid,new,delete,nullptr
Preprocessor Directives
#include,#define,#if,#ifdef,#ifndef,#else,#elif,#endif,#error,#pragma
Comments
- Single line:
// - Multi-line:
/* ... */
What do you like most about the C++ programming language?
-
If it comes to time-critical systems where every millisecond counts. Use C++.
-
If performance matters, use C++
-
Performance and Efficiency: C++ is known for its high performance and efficient use of resources, making it an excellent choice for applications where speed and memory management are critical, such as game development, real-time systems, and high-performance computing.
-
Low-Level Manipulation: C++ provides features that allow programmers to manipulate hardware resources directly. This includes direct memory management and the use of pointers, which can lead to highly efficient and optimized code.
-
Object-Oriented Programming (OOP): C++ supports OOP, which helps in organizing complex programs through classes and objects. This makes the code more modular, reusable, and scalable.
-
Standard Template Library (STL): The STL is a powerful feature of C++ that provides ready-to-use, efficient implementations of common data structures and algorithms.
-
Compatibility with C: C++ is almost fully compatible with C, allowing for code written in C to be used in C++ applications. This is particularly useful for integrating legacy code or for situations where certain parts of a project require low-level C-style programming.
-
Wide Range of Application: C++ is used in a variety of fields, from embedded systems and operating systems to large-scale applications and high-performance server/client applications.
-
Control Over System Resources: C++ provides a high degree of control over system resources, which is crucial for systems where hardware efficiency is essential.
-
Multi-paradigm Language: Besides supporting object-oriented programming, C++ also supports procedural, generic, and functional programming styles, making it a versatile choice for various types of applications.
-
Large Community and Resource Availability: Being one of the older programming languages, C++ has a large community of developers. There are many resources available for learning and troubleshooting, as well as a vast number of libraries and tools.
-
Continuous Evolution: The C++ language is continuously evolving with regular updates to the standard. These updates aim to make the language more user-friendly, secure, and efficient while maintaining backward compatibility.
- Object-Oriented Programming
- Low-level manipulation
- Standard template library
- Multiple inheritance
- Operator overloading
- Memory management
- Function overloading
- Exception handling
Please write a C++ program to print hello world to the console.
# include <iostream>
int main () {
std::cout << "hello world";
}↳ Why does every C++ program need a main () function?
☞ main () is just the first function to be called by default. It provides an entry point to the program, once it is executed from the runtime environment.
☞ From this entry point, the rest of the program emerge.
☞ This is sort of a universal convention across all programming languages.
☞ The main () function facilitates interaction with the operating system (OS), because when the program finishes executing, the main () function returns 0 if everything went well, and any other return value signals that something may have gone wrong.
↳ What parameters does main () have?
☞ main () can accept the command line arguments argc and argv, if given.
☞ argc: The count (number) of arguments given.
☞ argv: The arguments themselves, as a vector.
Command Line Arguments
- Command line arguments are simply arguments which come from the command line, when the program is initially run, in the exact same way you would supply a function with arguments when calling it.
- This allows the program to receive input parameters from the user/environment it is being run in.
- See here for parameters vs arguments.
↳ How would you define the main () function to accept command line arguments?
int main (int argc, char *argv[])↳ What is char *argv[]?
In this context, argv stands for ‘argument vector (array)’, and is itself an array of pointers, where each pointer pointers to an array of characters (a string).
This could written equivalently as char** argv, which makes it clear that argv is a pointer to a pointer to char.
What’s a pointer?
If you can’t answer this, watch this.
Classes vs Structs
What is a member in C++?
Member
Members are the attributes (variables) and methods (functions) of a class.
What are the three main access specifiers in C++?
Success Public
Attributes or methods declared as ’
public’ are accessible from outside the class. They can be accessed or modified.
Success Private
Attributes or methods declared as ’
private’ are only accessible within the class itself. They cannot be accessed or modified directly from outside the class, which is crucial for encapsulation, allowing the class to control the integrity of its internal state.
Success Protected
Attributes or methods declared as ’
protected’ are similar to private, but they can also be accessed in derived classes. This means that while they are not accessible directly from outside the class or unrelated functions, subclasses that inherit from the class have access to them. This specifier is often used in inheritance to ensure a level of protection while still allowing functionality in child classes.
Rewrite the expression myNode->val using * and .
This is equivalent to (*myNode).val
What is a constructor in C++?
A constructor is a member function that is automatically called when an object of a class is created.
For example, let’s say you want to create a ‘fruit’ class
What does this output?
#include <iostream>
int main () {
int pi;
std::cout << pi;
}The output of this program is unpredictable, since the variable pi has been declared but not initialized with a value yet.
One potential output:
>>> 334201973It could print any arbitrary integer value, or it could potentially cause a runtime error, depending on what is currently in the areas of memory where pi is allocated.
What is a 32-bit integer? How are integers stored in computer memory?
Cmon, you’re a data scientist. This is data in it’s most pure digital form.
Integers in computer memory are represented using a binary number system, where bits are either 0 or 1.
-
Binary Representation: A 32-bit integer is represented using 32 binary digits (0s and 1s).
-
Range of Values:
- Signed 32-bit Integer: If the integer is signed (can represent both positive and negative values), it typically uses the two’s complement notation. The range of values it can represent is from -2,147,483,648 to 2,147,483,647. The most significant bit (MSB) is used as the sign bit. If the MSB is 0, the number is positive; if it’s 1, the number is negative.
- Unsigned 32-bit Integer: If the integer is unsigned (can only represent non-negative values), it can represent values from 0 to 4,294,967,295. All 32 bits are used for the value, allowing for a wider positive range than signed integers.
-
Memory Usage: Each 32-bit integer consumes 4 bytes (32 bits / 8 bits per byte) of memory.
↳ How many different values can 8 bits represent?
however this is the number of different values; is included.
↳ What is the largest number that can be represented by 8 bits?
Unsigned Integers: 255 (since the maximum binary number would be 1111 1111 = 255)
Signed Integers: 127
☞ Signed integers can go from: [-128, 127] with 8 bits.
☞ In this case, one bit is used to represent the sign (positive/negative)
Two's complement representation (for signed integers)
- Represent the number in binary as if it were positive.
- For negative numbers only, flip each bit, so that
0becomes1- Then add 1 to the number, e.g
10000000 -> 10000001- Given that you followed the steps, the first bit will be
0if the number is positive, and1if negative.- Two’s compliment is the number that comes after the first bit, and an easy way to remember it, is it is the number you need to add to the positive version (7 bits), to get to (for 8 bit integers)
So then how do you read negative binary numbers? You flip all the bits then add 1. It’s the same process.
↳ Explain how to convert the binary number 101011 into a decimal (normal base 10) number.
Going from left to right:
↳ What’s the largest number that can be represented by 32 bits (an int32 datatype)
Following the rule, bits can represent different values, and thus the largest number able to be represented is , since we must reserve 00000...000 for the value of 0.
↳ When would you use a smaller datatype?
- Hyperperformant system
- If you know the max size of the number at compile time.
Unless you have a good reason to, stick to the following types:
boolstringintuint32byterunefloat64complex128
WHEN SHOULD I USE A MORE SPECIFIC TYPE?
When you’re super concerned about performance and memory usage.
That’s about it. The only reason to deviate from the defaults is to squeeze out every last bit of performance when you are writing an application that is resource-constrained. (Or, in the special case of uint64, you need an absurd range of unsigned integers).
You can read more on this subject here if you’d like, but it’s not required.
Translate 0x7fc3c16c5082 into decimal.
0x: This prefix indicates that the number following it is in hexadecimal format.
-
Break into digits
7, f, c, 3, c, 1, 6, c, 5, 0, 8, 2
-
Convert each hexadecimal digit to its decimal equivalent:
7, 15, 12, 3, 12, 1, 6, 12, 5, 0, 8, 2(Note: In hexadecimal, ‘a’=10, ‘b’=11, ‘c’=12, ‘d’=13, ‘e’=14, ‘f’=15)
-
Multiply each decimal digit by
16raised to the power of its position index, starting from the right (position 0): -
Add up all these values to get the final decimal number.
How many bits are in a byte?
Byte
A bit is the smallest unit of computing. One byte is made up of 8 bits.
What is the difference between a class and struct in C++?
They are functionally equivalent in C++, however:
- Struct
- In a struct, members are public by default.
- Primary purpose is to hold data
- Class
- In a class, members are private by default.
- Used for objects with more complex behaviour, encapsulating both functions and data
Both have constructors, destructors, member functions and support inheritance and polymorphism.
Class hierarchy for a zoo
Imagine you’re designing software for a zoo to monitor and track different types of animals. Using
C++, create a class hierarchy that represents various animals in the zoo. You should start with a base class ’Animal’. The base class should have common attributes like ‘name’, ‘age’, ‘weight’, and a method to display these attributes.
class Animal {
protected:
std::string name;
int age;
double weight;
public:
Animal(std::string n, int a, double w) : name(n), age(a), weight(w) {}
virtual void display() {
std::cout << "Name: " << name << ", Age: " << age << ", Weight: " << weight << " kg" << std::endl;
}
};⚘ Now, explain how you can use polymorphism to derive a ‘Fish’ type
Since we have specified the base class Animal we can use polymorphism to extend our hierarchy. Let’s derive a ‘Fish’ class from ‘Animal’
class Fish : public Animal { // inherit from Animal
std::string waterType; // std::string is a string in the standard namespace
public:
Fish(std::string n, int a, double w, std::string wt) : Animal(n, a, w), waterType(wt) {}
void swim() {
std::cout << name << " is swimming!" << std::endl;
}
void display() override {
std::cout << "Fish - ";
Animal::display();
std::cout << "Water Type: " << waterType <, std::endl;
}
};The Stack vs. The Heap
Automatic allocation vs. Dynamic allocation
Automatic allocation (stack)
Definition: Automatic allocation occurs when memory for variables is allocated on the stack at the moment the variable is declared. The memory is automatically managed: it’s allocated when entering the scope where the variable is declared and deallocated when leaving that scope.
- Advantage: No manual memory management required.
- Disadvantage: Limited to the scope of the block in which it’s declared.
void function() {
int a = 5; // 'a' is automatically allocated on the stack
} // 'a' is automatically deallocated hereIn this example, a is an automatic variable allocated on the stack. Its lifespan is tied to the function’s scope.
Dynamic allocation (heap)
Definition: Dynamic allocation is the manual allocation of memory during runtime, typically on the heap. It is done using
newin C++, and the allocated memory remains until it’s explicitly deallocated withdelete.
- Advantage: Allows for dynamic and persistent memory management.
- Disadvantage: Requires manual handling, potential for memory leaks.
int* ptr = new int(10); // Dynamically allocate an integer on the heap
// Use 'ptr'
delete ptr; // Manually deallocate the memoryHere, ptr is a pointer to an integer allocated on the heap. Its lifespan is not limited to a particular scope and must be manually managed.
TLDR
Automatic allocation is easy and scope-bound with auto-cleanup, while dynamic allocation offers flexibility and persistence but needs careful memory management.
| Python | C++ |
|---|---|
len(s) for length of strings, lists, etc. | s.length() for strings; s.size() for STL containers like std::vector, std::string; for arrays, sizeof(arr)/sizeof(arr[0]) |
for item in iterable: (for each loop) | for (auto& item : iterable) { } (range-based for loop in C++11) |
for i in range(len(iterable)): | for (size_t i = 0; i < iterable.size(); ++i) { } |
while condition: | while (condition) { } |
if condition: | if (condition) { } |
elif | else if |
def func(): (function definition) | void func() { } (function definition) |
class MyClass: | class MyClass { }; |
# Comment | // Comment or /* Comment */ |
import module | #include <header> |
None (null value) | nullptr (C++11), NULL (older C++) |
dict for dictionaries | std::map or std::unordered_map |
list for lists | std::vector |
set for sets | std::set |
str for strings | std::string |
Exceptions with try, except | Exceptions with try, catch |
with open('file') as f: for file operations | std::fstream or std::ifstream/std::ofstream |
| List comprehensions | No direct equivalent; closest is using algorithms with functors or lambdas |
Generators (yield) | No direct equivalent; closest are functions returning std::next or custom iterator classes |
| Dynamic typing | Static typing |
| Garbage collection | Manual memory management or RAII with smart pointers (std::shared_ptr, std::unique_ptr) |
| Global interpreter lock | Multi-threading with std::thread and no global interpreter lock |
| Indentation defines scope | Braces { } define scope |
What is the difference between runtime and compile time?
Compile time
Compile-time is the step when source code is translated from C++/C into a new file, written in machine code, by a compiler.
Runtime
When you actually execute the program on a computer. This is when the code you have written actually ‘happens’, as opposed to just being translated.
What is homebrew?
Homebrew
Homebrew is an open-source package management system for macOS and Linux that simplifies the installation, update, and management of software from the command line. It allows users to easily install thousands of programs and tools that are not included in the default operating system installation.
Explain the difference between STL and std.
☞ STL is a library, while std is a namespace.
Standard Template Library (STL)
- Is a collection of
C++classes that provide data structures and functions such as vectors, lists, stacks, queues, and algorithms like sort, search, etc.
std
stdis a namespace part of theC++Standard Library, which includes the STL along with other elements likeiostream, localization, threading, and more.
Lists
std::list
std::vector
std::forward_list
Sets
std::set
std::set <data_type> set_name;
Dictionaries
std::map
std::unordered_map
Priority queues
Nodes
What is 0/2 in C++?
Define a singly linked List struct
If you try to use curr_node.next in your code, where curr_node is a pointer to a ListNode, it would result in a compilation error in C++. This is because the dot operator (.) is used for accessing members of a structure or class when you have an actual object (or a reference to an object), not a pointer to an object.
In your code, curr_node is declared as a pointer to a ListNode:
ListNode* curr_node = head;Given that curr_node is a pointer, you must use the arrow operator (->) to access its members. The correct way to access the next member of the ListNode pointed to by curr_node is curr_node->next.
If curr_node were not a pointer but an actual ListNode object or a reference to a ListNode object, then you would use the dot operator. For example, if you had the following:
ListNode aNode;In this case, aNode is an object, not a pointer. So, you would use aNode.next to access its next member.
↳ When to use struct
do {}, while ()
Identical to a while loop, but the first iteration of the loop is guaranteed to run.
What is the difference between & and &&?
& is a bitwise AND operator.
int a = 5; // binary representation: 0101
int b = 9; // binary representation: 1001
int result = a & b; // result is 1, binary representation: 0001&& is a logical AND operator.
bool x = true;
bool y = false;
if (x && y) {
// This block will not execute because y is false.
}How to find the length of a string in C++?
string s = "ruhroh"
// In this context, both functions are identical
s.size()
s.length()In the code snippet you provided, int myInt = i + 3; is inside the loop block of the for loop. Here’s what happens:
-
Scope of
myInt: The variablemyIntis declared inside the loop, which means it has a local scope to each iteration of the loop. Its existence is limited to a single iteration of the loop. -
Creation and Destruction: On each iteration of the loop,
myIntis indeed created anew. When each iteration ends,myIntgoes out of scope and is destroyed. Then, on the next iteration, a newmyIntis created. -
Memory Efficiency: Modern compilers are quite efficient, and they may optimize this kind of code under the hood. The creation and destruction of
myInton each iteration are typically very fast and not a significant performance concern in most cases. However, if the variable does not need to be reinitialized each time and can maintain its value between iterations, it’s often better practice to declare it outside the loop to avoid potential confusion and to make the intent of the code clearer.
Also, note that there’s a typo in your loop: for (int i=0; I<5; I++) should be for (int i = 0; i < 5; i++) with lowercase ‘i’ for consistency.
Doesn’t work as in Python
int alpha, beta;
alpha, beta = x, y;- The statement
alpha, beta = x, y;does not correctly assign the values ofxtoalphaandytobeta. In C++, the comma operator,has the lowest precedence and is a sequence point. This statement is equivalent to(alpha), (beta = x), (y);. What happens here is:alphais evaluated and the result is discarded.betais assigned the value ofx.yis evaluated and the result is discarded.
- Therefore, after this statement,
betawill have the value ofx, butalphawill remain unchanged.