cs106l:破晓
ReadMe
看这学期能不能挤时间学一门新的课程,把我的C++的coding水平提一提,为以后上数据结构做准备。
我从大一开始一直都是写的 C++ 代码,直到学完这门课我才意识到,我写的 C++ 代码大概只是 C 语言 +
cin
/cout
而已。这门课会深入到很多标准 C++ 的特性和语法,让你编写出高质量的 C++ 代码。例如 auto binding, uniform initialization, lambda function, move semantics,RAII 等技巧都在我此后的代码生涯中被反复用到,非常实用。
值得一提的是,这门课的作业里你会实现一个 HashMap(类似于 STL 中的
unordered_map
), 这个作业几乎把整个课程串联了起来,非常考验代码能力。特别是iterator
的实现,做完这个作业我开始理解为什么 Linus 对 C/C++ 嗤之以鼻了,因为真的很难写对。总的来讲这门课并不难,但是信息量很大,需要你在之后的开发实践中反复巩固。Stanford 之所以单开一门 C++ 的编程课,是因为它后续的很多 CS 课程 Project 都是基于 C++的。例如 CS144 计算机网络和 CS143 编译器。这两门课在本书中均有收录。
就选这门cs106l了。如果这学期鸽掉,那就寒假再学吧。
课程网址:CS 106L: Standard C++ Programming (stanford.edu)
版本:2022spring
Exercises and assignments:
Types and Structs
We won’t use “using namespace std” most of the time. It’s not good style!
Types
即int, char, float, double等
C++是一种静态语言(statically typed language)
statically typed:everything with a name is given a type before runtime.
type1 function_name(type 2 variable);
type2—>type1
If we want two versions of a function for two different types, we can use polymorphism(多态).
For example:
1 | int half(int x){ |
Struct
struct: a group of names variables each with their own type. A way to bundle different types together.
For example:
1 | struct Student{ |
To initial a struct:
1 | Student s; |
Pair
std::pair An STL built-in struct with two fields of any type.
A template: You specify the types of the fields inside <> for each pair object you make.
The fields in std::pairs are named first and second.
For example:
1 | std::pair<int,string> numSuffix={1,"st"}; |
You can also use std::pair to write a function. For example:
1 | std::pair<bool, Student>lookupStudent(string name){ |
Type Deduction(类型推断) with auto
auto:Keyword used in lieu of type when declaring a variable(当申明一个变量时用来代替类型的关键词), tells the compiler to deducethe type.
auto does not mean that the variable doesn’t have a type. It means that the type is deduced by the compiler.
For example:
1 | auto a=3; |
Streams
Pay attention! Here thinks out the streams, so the single cin or cout is out of our discussion.
stream:an abstraction for input/output. Streams convert between data and the string representation of data.
std::cout is an output stream. It has type std::ostream
output streams:
- have type std::ostream
- can only send data using the << operator.(converts any type into string and sends it to the stream.)
output file streams:
- have type std::ofstream
can only send data using the << operator.(converts data of any type into string and sends it to the file stream.)
- must initialize your own ofstream object linked to your file.
std::ofstream out(“out.txt”);
out<<5<<std::endl;
Input streams
Input Streams:
- have type std::istream
- can only reveive strings using the >> operator
- receives a string from the stream and converts it to data
each >> ONLY reads util the next whitespace
-whitespace=tab, space, newline
whilespace is eaten: it won’t show up in output.
Reading using >> extracts a single “word” or type including for strings.
To read a whole line, use std::getline(istream&stream, string&line);
For example:
1 | std::string line; |
Don’t mix >> with getline!
- >> reads up to the next whitespace character and does not go past that whitespace character
- getline reads up to the next delimiter (by default, ‘\n’), and does go past that delimiter.
Input File Streams
- have type std::ifstream
- only receives strings using the >> operator
- receives strings from a file and converts it to data of any type
Stringstreams
- Input stream: std::istringstream
- Give any data type to the istringstream, it’ll store it as a string!
- Output stream: std::ostringstream
- Make an ostringstream out of a string, read from it word/type by word/type!
The same as the other i/ostreams you’ve seen!
Initialization and References
InitializationHow we provide initial values to variables.
two ways to intial a struct:
1 | Student s; |
multiple ways to initial a pair:
1 | std::pair<int, string> numSuffix1 = {1,"st"}; |
initialization of vectors:
1 | std::vector<int> vec1(3,5); |
Uniform initialization:curly bracket initialization(花括号).Available for all types, immediate initialization on declaration.
$$less common/nice for primitive types, but possible.
P.S. about vector initialization
1 | std::vector<int> vec1(3,5); |
using auto to reduce long type names
For example:
1 | std::pair<bool, std::pair<double,double>>result=quadratic(a,b,c); |
1 | auto quadratic(a,b,c); |
Reference
Reference:An alias (another name) for a names variable.
reference vs copy:
1 | void changeX(int& x){ //changes to x will persist |
1 | vector<int> original{1, 2}; |
“=” automatically makes a copy! Must use & to avoid this.
const and const references
const indicates a variable can’t be modified!
can’t declare non-const reference to const variable! For example:
1 | std::vector<int>& bad_ref=c_rec; |
use references to have multiple aliases to the same thing
use const references to avoid making copies whenever possible
Containers
Standard Template Library(STL) contains:
containers,iterators,functions,algorithms.
How to use STL?
two steps:
- Import the relevant STL feature
- Use it with “std::
“”
For example:
1 |
|
Sequence Containers
Simple
<>vector (adding + removing elements at end)
⇅ deque (adding + removing elements anywhere but end):
- 先把现有的填满,超出的可以向前向后延申。
↓ list (adding + removing elements anywhere, but no random access)
() tuple (different data types, but immutable)
- size:number of elements in a vector
- capacity:amount of space saved for a vector(开的空间大小)
summary:
- std::vector: use for almost everything
- std::deque: use if you are frequently inserting/removing at front
- std::list: use very rarely, and only if you need to split/join multiple lists
container adaptors
- stack(栈):adding/removing elements from the front
- LIFO(last-in, first-out)
- queue:adding elements from the front, removing from the back
- FIFO(first-in, first-out)
- priority_queue:adding elements with a priority, always removing the highest priority-element
Container adaptors are wrappers in C++.
It provides a different interface(接口) for sequence containers. We can choose what the underlying container is. For instance, let’s choose a deque as our underlying container, and let’s implement a queue.
Concrete examples with std::queue
1 | std::queue<int>stack_deque; //Container=std::deque |
Associative Containers
Ordered
- {} set (unique elements)
- {:} map (key value pairs)
Every std::map<K,V> is actually backed by: std::pair<const K, V>
hint: std::pair’s are just two-element tuples!
Unordered
- {} unordered_set
- {:} unordered_map
if using simple data types/you’re familiar with hash functions, use unordered associative containers.
the difference from the unordered and the ordered:
Each STL set/map comes with an unordered sibling. They’re almost the same, except:
- Instead of a comparison operator, the set/map type must have a hash function defined for it.
- unordered_map/unordered_set are generally faster than map/set.
Iterators and Pointers
Iterators
Iterations allow iterating over any container** whether ordered, unordered, sequence, or associative!
An iterator is like a “claw”, it has an “ordering” over elements.
1 | std::set<type> s={0,1,2,3,4}; |
There are a few different types of iterators, since containers are different.
- input iterators can be on the RHS (right hand side) of an =sign:
- auto elem =*it;
- output iterators can be on the LHS of =:
- *elem = value;
Container | Type of iterator |
---|---|
Vector | Random-Access |
Deque | Random-Access |
List | Bidirectional |
Map | Bidirectional |
Set | Bidirectional |
Stack | No iterator |
Queue | No iterator |
Priority Queue | No iterator |
P.S. Random access iterators support indexing by integers!
These are equivalent :
1 | auto key = (* iter).first; |
Pointers(指针)
Pointers are objects that store an address and type of a variable.
Iterators are a form of pointers.
Pointers are more generic iterators. (can point to any object, not just elements in a container)