Hi!这里是山幺幺的c++ primer系列。写这个系列的初衷是,虽然在学校学习了c++,但总觉得对这门语言了解不深,因此我想来啃啃著名的c++ primer,并在这里同步记录我的学习笔记。由于我啃的是英文版,所以笔记是中英文夹杂的那种。另外由于已有一定的编程基础,所以这个系列不会含有太基础的知识,想入门的朋友最好自己啃书嘻嘻~
关于using声明
using std::cin;
using namespace std;
- 头文件中不应含using声明,因为头文件中的内容会被复制到所有include它的文件中
关于string
声明
- #include <string>
- using std::string;
初始化
string s5 = "hiya"; // copy initialization
string s6("hiya"); // direct initialization
string s7(10, 'c'); // direct initialization; s7 is cccccccccc
string s8 = string(10, 'c'); // copy initialization; s8 is cccccccccc
//等价于
string temp(10, 'c'); // temp is cccccccccc
string s8 = temp; // copy temp into s8
操作
- 上图第二行:whitespace(包括空格、tab、换行等)-separated是指 cin >> s1 >> s2; 输入“ Hello World ”会让s1=Hello,s2=World
- 上图第三行:可以用 while (getline(cin, line)) 读文件,line不包含换行符
- 上图第五行:返回类型是string::size_type,是一个unsigned且足够容纳任何string的类型【所以当n是负数时,s.size() < n会返回true,因为n会转换为一个signed且值较大的数】
- 上图第七行:字符串字面量并不是string类型
string s5 = "hello" + ", "; // error: no string operand
string s6 = s1 + ", " + "world"; // ok: each + has a string operand
string s7 = "hello" + ", " + s2; // error: can't add string literals
#include <cctype>
PS:cctype是从c的ctype.h中迁移过来的
index(s[i])
- if our index has a signed type, its value will be converted to the unsigned type that string::size_type represents
关于vector
声明
- #include <vector>
- using std::vector;
vector的性质
- vector是template而不是type,实例化的vector才是type
- 引用不是对象,所以无法把vector实例化为引用
- we can (efficiently) add elements to a vector at run time
初始化
- 上图第五行:要求T是有默认初始值的类型,比如int(0)、string("")等
- list initialization
vector<string> v5{"hi"}; // list initialization: v5 has one element
vector<string> v6("hi"); // error: can't construct a vector from a string
literal
vector<string> v7{10}; // not a list initialization: v7 has ten default-initialized elements
vector<string> v8{10, "hi"}; // not a list initialization: v8 has ten elements with value "hi"
操作
- 上图第三行:注意for循环体内语句不能改变the size of the sequence over which it is iterating.
- 上图第二行:若是一个int型vector,则返回类型为vector<int>::size_type
关于迭代器
基本性质
- iterators give us indirect access to an object
- 迭代器指向的对象是:容器中的元素或者string中的char
- 若容器v是空的,则v.begin() == v.end()
- 任何改变容器大小的操作都可能使迭代器失效
操作
- 第一行:有时括号是必要的:
(*it).empty() // ok
*it.empty() // error: attempts to fetch the member named empty from it
类型
vector<int>::iterator it; // it can read and write vector<int> elements
string::iterator it2; // it2 can read and write characters in a string
vector<int>::const_iterator it3; // it3 can read but not write elements
string::const_iterator it4; // it4 can read but not write characters
auto it3 = v.cbegin(); // it3 has type vector<int>::const_iterator
string、vector迭代器支持的运算
- 第五行:返回类型是difference_type,是一个signed
- 栗子
auto mid = vi.begin() + vi.size() / 2;
if (it < mid) ...
关于array
基本性质
- 大小固定,不能增加元素
- 因为引用不是对象,所以没有元素是引用的array
初始化
unsigned cnt = 42; // not a constant expression
constexpr unsigned sz = 42; // constant expression
int arr[10]; // array of ten ints
int *parr[sz]; // array of 42 pointers to int
string bad[cnt]; // error: cnt is not a constant expression
string strs[get_size()]; // ok if get_size is constexpr, error otherwise
int a2[] = {0, 1, 2}; // an array of dimension 3
int a3[5] = {0, 1, 2}; // equivalent to a3[] = {0, 1, 2, 0, 0}
string a4[3] = {"hi", "bye"}; // same as a4[] = {"hi", "bye", ""}
int a5[2] = {0,1,2}; // error: too many initializers
char a1[] = {'C', '+', '+'}; // list initialization, no null
char a2[] = {'C', '+', '+', '\0'}; // list initialization, explicit null
char a3[] = "C++"; // null terminator added automatically
int a[] = {0, 1, 2}; // array of three ints
int a2[] = a; // error: cannot initialize one array with another
a2 = a; // error: cannot assign one array to another
PS:若array没有定义在任何函数内,则未初始化的array中的元素初始值为undefined;否则有默认初始值(比如,int初始值为0,string初始值为"")
*和&
int *ptrs[10]; // ptrs is an array of ten pointers to int
int (*Parray)[10] = &arr; // Parray points to an array of ten ints
int (&arrRef)[10] = arr; // arrRef refers to an array of ten ints
int *(&arry)[10] = ptrs; // arry is a reference to an array of ten pointers
- 第一行:从左往右读,int*表示这个array存放的元素是指向int的指针
- 第二行:先读括号,*Parray表示Parray是一个指针
- 第三行:先读括号,&arrRef表示arrRef是一个引用
index
- 可以把用作index的变量i定义为 size_t 类型,它定义在头文件cstddef中,也就是stddef.h的c++版本
- size_t 是一个unsigned类型,large enough to hold the size of any object in memory
- index也可以是负数:The library types force the index used with a subscript to be an unsigned value. The built-in subscript operator does not. The index used with the built-in subscript operator can be a negative value.
int *p = &ia[2]; // p points to the element indexed by 2
int j = p[1]; // p[1] is equivalent to *(p + 1),
// p[1] is the same element as ia[3]
int k = p[-2]; // p[-2] is the same element as ia[0]
int k = p[-3]; // error: out of range
array名是指针
int ia[] = {0,1,2,3,4,5,6,7,8,9}; // ia is an array of ten ints
auto ia2(ia); // ia2 is an int* that points to the first element in ia
// 但使用decltype时会变成array类型
decltype(ia) ia3 = {0,1,2,3,4,5,6,7,8,9};
迭代器
int arr[] = {0,1,2,3,4,5,6,7,8,9};
// 类似于begin()
int *p = arr; // p points to the first element in arr
++p; // p points to arr[1]
// 类似于end()
int *e = &arr[10]; // pointer just past the last element in arr
// 以下在iterator头文件中
int *beg = begin(arr); // pointer to the first element in ia
int *last = end(arr); // pointer one past the last element in ia
指针运算
auto n = end(arr) - begin(arr); // n is 5, the number of elements in arr
- n的类型是 ptrdiff_t ,是一个signed,定义在头文件cstddef中
- 指向同一array内元素的指针可以比较大小
关于C风格的字符串(最好别用!)
基本性质
- 以'\0'结尾
char ca[] = {'C', '+', '+'}; // not null terminated
cout << strlen(ca) << endl; // disaster: ca isn't null terminated
操作
- 以下函数均定义在头文件cstring中
用array初始化vector
int int_arr[] = {0, 1, 2, 3, 4, 5};
vector<int> ivec(begin(int_arr), end(int_arr));
// copies three elements: int_arr[1], int_arr[2], int_arr[3]
vector<int> subVec(int_arr + 1, int_arr + 4);
关于多维array:即array的array
初始化
int arr[10][20][30] = {0}; // initialize all elements to 0
int ia[3][4] = { // three elements; each element is an array of size 4
{0, 1, 2, 3}, // initializers for the row indexed by 0
{4, 5, 6, 7}, // initializers for the row indexed by 1
{8, 9, 10, 11} // initializers for the row indexed by 2
};
// equivalent initialization without the optional nested braces for each row
int ia[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
// explicitly initialize only element 0 in each row
int ia[3][4] = {{ 0 }, { 4 }, { 8 }};
// explicitly initialize row 0; the remaining elements are value initialized
int ix[3][4] = {0, 3, 6, 9};
index
int ia[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
int (&row)[4] = ia[1]; // binds row to the second four-element array in ia
遍历
for (auto &row : ia) {
for (auto &col : row) ...
}
for (const auto &row : ia) { // 即使不需要写,也要用引用,否则row的类型会推断为指向ia每行第一个元素的int*
for (auto col : row) ...
}
for (auto p = ia; p != ia + 3; ++p) {
for (auto q = *p; q != *p + 4; ++q) ...
}
for (auto p = begin(ia); p != end(ia); ++p) {
for (auto q = begin(*p); q != end(*p); ++q) ...
}
指针相关
int ia[3][4]; // array of size 3; each element is an array of ints of size 4
int (*p)[4] = ia; // p points to an array of four ints
p = &ia[2]; // p now points to the last element in ia