C++ primer 第三章-Strings, Vectors, and Arrays

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
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容