《c++ primer》贴板

变量声明和定义

c++支持分离式编译(separate compilation),程序分割成若干个文件,每个文件可独立编译。
声明(declaration):使得名字为程序所知,一个文件使用别处定义的名字必须包含对这个名字的声明。
定义(defination):创建与名字关联的实体。

例子:

extern int i; //声明i而非定义i
int j; //声明且定义j
extern double pi = 3.14; //定义

Note:变量只能被定义一次,可以多次声明。

引用

引用即本身不是一个对象,不能定义引用的引用。
引用只能绑定在对象上。
引用必须被初始化。

指向指针的引用:

int i = 42;
int *p;
int *&r = p; //r是一个对指针p的引用

const限定符

定义这样一种变量,它的值不能被改变:

const int bufSize = 512;

const对象必须初始化:

const int k; //错误

默认情况,const对象被设定为仅在文件内有效。

const的引用

对常量的引用(reference to const):把引用绑定到const对象上。

const int ci = 1024;
const int &r1 = ci;

允许一个常量引用绑定非常量对象:

int i =42;
const int &rl = i;

指针和const

指向常量的指针(pointer to const):存放常量对象的地址。

const double pi = 3.14;
const double *cptr = pi;

允许指向常量的指针指向非常量对象:

double dval = 3.14;
cptr = &dval;

const指针:指针是对象而引用不是,可以定义指针本身为常量。常量指针(const pointer)必须初始化、

int errNumb = 0;
int *const curErr = &errNumb; //curErr将一直指向errNumb

指针本身是一个常量并不意味着不能通过指针修改其所指的值,取决于所指对象的类型。

*curErr = 0; //正确,把curErr所指对象的值重置

常量表达式:值不会改变且在编译过程就能得到计算结果的表达式。

声明为constexpr的变量一定是一个常量,而且必须用常量表达式初始化:

constexpr int mf = 20;

best practices:认为变量是一个常量表达式,就声明成constexpr类型。

auto类型说明符

编程时常常要把表达式的值赋给变量,要求在声明变量的时候清楚地知道表达式的类型。
auto让编译器通过初始值推算变量的类型,auto定义的变量必须有初始值:

auto item = val1 + val2;

一条语句中声明多个变量,因为一条声明语句只能有一个基本数据类型,所以该语句中所有变量的初始基本数据类型都必须一样:

auto i=0 ,*p=&i; //正确:i是整数、p是整型指针
auto sz=0 , pi=3.14; //错误:sz、pi类型不一致。

decltype类型指示符

希望从表达式的类型推断出要定义的变量的类型:
编译器分析表达式得到它的类型,不实际计算表达式的值:

decltype(f()) sum = x; //sum的类型是f()函数的返回类型

warning: decltype((variable))的结果永远是引用,而decltype(variable)结果只有当variable本身就是引用时才是引用。

string

string对象会自动忽略开头的空白,并从第一个真正的字符读起,直到遇见下一处空白:

input  "  Hello World! "
output  "Hello"

getline读取一整行:

int main()
{
  string line;
  //每次读入一整行,直至到达文件的末尾
  while(getline(cin, line))
    cout << line << endl;
    return 0;
}
  • 注:用getline得到的string最后不包含换行符。
  • Tip:string的size方法返回类型string::size_type是unsigned,所以不要用int混淆了,因为比较s.size() < n(n是负数)时几乎都是True,n会转换为比较大的无符号值,

string和字符串字面值不是同一类,string相加至少有一个是string

string s2="world"; //s2是字面值“world”的副本
string s7 = ("hello" + ", ") + s2; //错误,字面值不能直接相加

处理字符

例子:统计string对象中的标点符号:

int main()
{
    string s("Hello World!!!");
    decltype(s.size()) punct_cnt = 0;
    for (auto c : s)
        if (ispunct(c))
            ++punct_cnt;
    cout << punct_cnt
        << " punctuation characters in " << s << endl;
    return 0;
}

处理部分字符

下标运算符[]接受输入参数string::size_type类型的值;返回值是该位置上字符的引用。
s[s.size()-1]是最后一个字符。

vector

vector是一个类模板(class template)
实例化:

vector<int> ivec; //ivec保存int类型的对象

初始化:

vector<string> v1{"a", "an", "the"}; //列表初始化
vecotr<int> ivec(10); //10个元素,每个都是0
vector<int> ivec(10, -1); //10个元素,每个都被初始化为-1

Warning:范围for语句体内不应改变其所遍历序列的大小

v.push_back(t) //尾端添加值为t的元素
v.size()
v.empty()

例子:分数段统计:

//分数段统计
int main()
{
    vector<unsigned> scores(11, 0); //11个分数段,全都初始化为0
    unsigned grade;
    while (cin >> grade) {
        if (grade <= 100)
            ++scores[grade / 10];
    }
    return 0;
}

迭代器

迭代器提供对对象的间接访问。就迭代器而言,其对象是容器中的元素或者string对象中的字符。

*iter 返回迭代器iter所指元素的引用
iter->mem 解引用iter并获取该元素的名为mem的成员,等价于(*item).mem

迭代器类型

vector<int>::iterator it; //it能读写vector<int>的元素
vector<int>::const_iterator it3; //it3只能读元素,不能写元素
  • 注:如果vector对象或string对象是一个常量,只能使用const_iterator。
  • 如果对象只需读操作而无须写操作的话最好使用常量类型。
  • cbegin、cend只返回const_iterator:
vector<int> v;
auto it3 = c.cbegin(); //it3的类型是vector<int>::const_iterator
int main()
{
    string text;
    getline(cin,text);
    for ( auto it = text.cbegin(); it != text.cend() ; ++it)
        cout << *it << endl;
    return 0;
}

迭代器失效:任何一种可能改变vector对象容器的操作,如push_back
Warning:使用了迭代器的循环体,都不要想迭代器所属的容器添加元素。

计算最接近vi中间元素的一个迭代器

auto mid= vi.begin() + vi.size() / 2;

迭代器距离的类型:difference_type

迭代器运算:

#include "stdafx.h"
#include<string>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int main()
{
    string text;
    getline(cin,text);
    sort(text.begin(), text.end());
    cout << text << endl;
    char sought = 'a';
    auto beg = text.begin(), end = text.end();
    auto mid = text.begin() + (end - beg) / 2;
    while (mid != end && *mid != sought) {
        if (sought < *mid)
            end = mid;
        else
            beg = mid + 1;
        mid = beg + (end - beg) / 2;
    }
    cout << *mid<<endl;
    return 0;
}

数组

数组的维度必须是一个常量表达式:

unsigned cnt = 42; //不是常量表达式
constexpr unsigned sz = 42; //常量表达式
string bat[cnt]; //错误。cnt不是常量表达式

tip:理解数组声明,从数组的名字开始由内向外的顺序阅读。
数组下标类型:size_t

指针

int ia[] = {0,1,2,3};
auto ia2(ia); //ia2是一个整型指针,指向ia的第一个元素
auto ia3(&ia[0]); //ia3类型是int*  与上面一样
decltype(ia) ia4 = {0,1,2,3}; //ia4是一个含有四个元素的整型数组

尾后指针,类似尾后迭代器:

int *e = &arr[10]; //指向arr尾元素的下一位置的指针

更安全的使用:标准库函数begin和end:

指针间的距离:

auto n = end(arr) - begin(arr); //arr中元素的数量

n的类型是内置的ptrdiff_t类型

解引用

int a[] = {0, 2, 4, 6, 8};
int last = *(ia + 4); //解引用等价于: ia[4]

Warning:内置的下标运算符所用的索引值不是无符号类型。

表达式

位运算符

  • 左移运算符 << : 向右侧插入值为0的二进制位;
  • 右移运算符 >> : 1.左侧运算对象是无符号类型,在左侧插入值为0的二进制位,2.左侧运算对象是带符号类型,在左侧插入符号位的副本或值为0的二进制位。
  • 位与运算符 & :
  • 位异或运算符 ^ :
  • 位或运算符 | :

整型提升:把小整数类型转换成较大的整数类型。

函数

Best Practice: 如果函数无需改变引用形参的值,最好声明为常量引用:

bool isShorter(const string &s1,const string &s2){
  return s1.size() < s2.size();
}

引用形参返回额外的信息

string::size_type find_char(const string &s, char c, string::size_type &occurs) {
    auto ret = s.size();
    occurs = 0;
    for (decltype(ret) i = 0; i != s.size(); ++i) {
        if (s[i] == c) {
            if (ret == s.size())
                ret = i;
            ++occurs;
        }
    }
    return ret;
}

猜你喜欢

转载自blog.csdn.net/nockinonheavensdoor/article/details/80754790