(笔记—C++ Primer) 第三章 字符串、向量、数组

  • string和vector是两种标准库类型,是内置数组的一种抽象;
  • 迭代器也是一种标准库类型,用于访问string的字符和vector的元素;
  • 内置类型如数组 和硬件密切相关,而标准库类型未能直接实现到计算机中,但同时增强了使用的灵活性;

1. 命名空间和using声明

using namespace std;   //使用std命名空间中的名字;
  • using namespace::name, 从而无需专门的前缀,就可以使用所需的名字例: using std::cin;
    • 每个名字需要独立的using声明;
    • 头文件中不应该有using声明
      • 标准库与头文件见附录A

2. String

2.1 字符串初始化

使用等号“=”的是拷贝初始化
使用括号的是直接初始化
string s1;    //默认初始化,空字符串
string s2(s1);
string s2 = s1; // 二者等价,s2是s1的副本
string s3 = "value";
string s3("value"); //二者等价,是字面值的副本
string s4(n, 'c'); 

2.2字符串操作

s.size()的返回类型为string::size_type(可以等同于 unsigned int);
字符串字面值和string不是同种类型;
这里写图片描述

2.3字符串中的字符

在头文件cctype中标准库函数处理这部分工作。
C++标准库兼容C的标准库,C的头文件形如name.h, C++的则是cname,且其中的名字隶属于命名空间std;

这里写图片描述

  • range for 语句, 遍历序列中的元素,并执行相应操作:
    for(auto c : str) cout << c << endl;逐个输出字符
  • 当只处理string中的部分字符时,不需要遍历,可以使用下标迭代器
    下标的类型为string::size_type, 其范围为 0 ( s i z e 1 ) ;
for (string::size_type i = 0; i < str.size();str[i++] = 'Y');  //机智的写法;

3. Vector

  • vector表示对象的集合,其中所有的对象是同种类型的,每个对象有对应的索引;(也称作容器container)
  • 头文件和using声明:
#include<vector>
using std::vector;
  • vector是一个类模板。根据模板创建函数和类型的过程称作实例化(instantiation);根据提供的信息创建所需的类型:
// 尖括号 <>中即提供的信息
vector<int> ivec;
vector<String> Svector;
vector<vector<String>> file; //元素为vector对象

3.1 定义和初始化vector

这里写图片描述
最常见的方式是先定义一个空的向量vector,然后逐个添加获取的元素;

//列表初始化:
vector<String> v1 = {"a", "red", "apple"};
vector<String> v2{"a", "red", "apple"};
//指定长度vector
vector<int> ivec(10, 0)   

3.2 vector中添加元素

  先定义一个空vector,再利用其成员函数push_back()逐个向其中添加元素,例:

vector<int> v1;
for(int i=0;i<100;i++)
    v1.push_back(i);
// v1中含有0-99共100个元素;
  • 若循环体内存在改变vector长度的语句,则不能使用 范围for循环;

3.3 vector其他操作

这里写图片描述

  • vector.size()返回vector的长度,其返回类型为 vector<Type>::size_type;
  • 不能用下标的形式来添加元素;使用范围for语句可以保证下标的合法;

4. 迭代器

  • 迭代器可以用于同样可以用于访问string的字符和vector的元素, 事实上,所有的标准库容器都可以使用迭代器,(String不是容器);
  • 迭代器的对象是容器的元素或string的字符,同时提供间接访问(类似于指针),迭代器有有效和无效之分;

4.1 使用迭代器

- 支持迭代器的类型拥有begin和end成员,用于返回迭代器;

auto b = v.begin();     //指向第一个元素
auto e = v.end();       //指向尾元素的下一个位置

这里写图片描述

string s("Hello");
for(auto i = s.begin(); i!= s.end(); ++i)
    *i = toupper(*i);
//for循环中使用了 !=, 而非 < , 因为在C++中,所有的标准库容器迭代器都定义了 ==和!=,而未必有<;
  • 迭代器类型为 iteratorconst_iterator, 例:
vector<int>::iterator it1;   //可读写
vector<int>::const_iterator it2;  //只可读,不可写;
  • *iter是解引用运算符。 iter->mem则将解引用和成员访问结合在一起;
  • 任何改变了vector容量的操作(如push_back()),都会使其迭代器失效;

4.2 迭代器的运算

这里写图片描述
注意: 迭代器没有定义iter1 + iter2运算;

5. 数组

5.1 数组的定义和初始化

  • 显示初始化数组元素:
    int a[3] = {1, 2, 3};
    int a[3] = {};
  • 数组的维度是已知且固定的,而vector的维度是可变的;
  • 利用字符串字面值初始化数组时, 会在结尾处含有一个空字符:char str[6] = "Hello";
  • 不能将数组的内容为其他数组初始化或赋值;
  • 复杂的数组声明:
int *ptr[10];   //含有10个指针的数组;
int &refs[10];  //wrong, 不存在引用的数组
int (*Parray)[10] = &arr;  //指向含有10个整数数组的指针;
int (&arrRef)[10] = arr;  // 引用含有10个整数的数组
//理解数组的证明,需要从内到外,而不再是从右往左;

5.2 访问数组元素

  • 与vector相同,可以利用下标访问, 其下标的类型为size_t, 定义在头文件<cstddef>中, 可以直接由C++定义;
  • 可以用范围for语句来遍历数组;

5.3 指针和数组

  • 使用数组时,编译器会将其转换为指针;
  • 多数表达式中,使用数组类型的对象其实是使用一个指向其首地址的指针;
string str[] = {"a", "an", "the"};
string *p1 = &str[0];
string *p2 = str;           //p1 和 p2是等价的
string *pe = &str[3];     //获取的是尾后指针;
  • 指针也是迭代器,可以执行表3.6和3.7中的运算;
  • 标准库函数begin和end:
int a[] = {0,1,2,3,4,5,6,7,8,9};
int *Pbegin = begin(a);
int *Pend = end(b);
  • 在指针运算过程中,其相减的结果是ptrdiff_t类型,是带符号数, 定义在<cstddef>中;
  • 下标与指针:
int a[] = {0,1,2,3,4,5,6,7,8,9};
int i1 = a[1];

int *p = a;
int i2 = *(p+1); //i1和i2是等效的;

//指针执行下标运算:
int *p2 = &a[5];
int i3 = p2[1];  //即 a[6];
int i4 = p2[-1]; //即 a[4]

5.4 C风格字符串

  • cf风格字符串不是一种类型,而是一种约定的写法,将字符串存放在字符数组中,必须以空字符\0结束,利用指针进行访问和操作;
  • 相关函数在头文件<cstring>中:
    这里写图片描述

    • 标准库string相对更安全,高效;
    • string和C风格字符串:
      string s("Hello World")
      const char *str = s.c_str()
      
  • 数组初始化 vector:

    int arr[] = {1,2, 3, 4, 5};
    vactor<int> vec(begin(arr), end(arr));
    

猜你喜欢

转载自blog.csdn.net/qq_35588560/article/details/80615602