chapter-3

C++ Primer第三章!

#include "stdafx.h"
#include
#include        //vector可以容纳着其他对象,简称容器。
#include        //string表示可变长的字符序列。
#include   //泛型算法!

using namespace std;

int main()
{
    //定义和初始化string
    string s1;
    string s2 = s1;             //拷贝初始化
    string s3 = "hello world";            //c风格字符串
    string s4(10, 'a');                         //构造函数!
    string s5(s1);              //直接初始化

    //string包含的方法
    cout << s3 << endl;
    cin >> s2>> s1;             //string自动忽略开头空白(空格符、换行、制表),直到遇见下一处空白
    getline(cin, s1);           //遇见换行符就结束操作,触发返回的换行符实际被丢弃
    //s.empty();        s为空则返回true,否则返回false
    //s.size();         返回s中字符的个数,string::size_type为无符号类型,足够放下任何string对象的大小。
    //s[n];             返回第N个字符的引用
    //s1+s2;            s1和s2连接,也可以将字面值与string相加,但必须确保两侧至少有一个string对象。(在c++中,字面值字符串为字符指针,而与string不同类型)
    //s1=s2;
    //s1 == s2;         长度和字符相等则相等!
    //s1!=s2;
    //<,<=,>,>=;        1、长度,2、第一对相异字符。
    
    //cctype头文件,针对字符操作!
    //isalnum(c)        当c是字母或数字为真。
    //isalpha(c)        字母
    //iscntrl(c)        控制字符
    //isdigit(c)        数字
    //isgraph(c)        不是空格但可打印
    //islower(c)        小写字母
    //isprint(c)        可打印(空格和可视形式)
    //ispunct(c)        标点符号(不是控制、数字、字母、可打印空白)
    //isspace(c)        空白(空格,制表符、回车符、换行符、进纸符)
    //isupper(c)        大写字母
    //isxdigit(c)       十六进制数字
    //tolower(c)        大写转小写
    //toupper(c)        小写转大写

    //范围for
    for (auto &c : s3)  //c是一个引用,将s3字符串全部改为大写字符串。
        c=toupper(c);
    cout << s3 << endl;

    //string可以使用下标运算符,建议设置string下标的类型为string:size_type(能确保下标不会小于0),而下标值要小于size().
    const string hexdigits = "0123456789ABCDEF";
    cout << "Enter a series of numbers between 0 and 15:";
    string result;
    string::size_type n;
    cin >> n;
    result = hexdigits[n];          //  建议对下标进行检查,必须确保下标合法。
    cout << result << endl;

    //标准库类型vector,容器
    vector ivec;
    vector svec1;
    vector svec2(svec1);
    vector svec3 = svec1;
    vector svec4(10, "love");
    vector svec5 = { "hello","world","!" };
    vector svec6{ "hello","world","!" };        //提供初始元素值的列表,只能使用花括号,列表初始化。

    //向vector对象中添加元素
    svec6.push_back(" hello c++!");

    //其他vector操作
    //v.empty();        如果v中不含任何元素,则返回真。
    //v.size();         返回v中元素个数,类型为vector<内置类型>::size_type。
    //v.push_back(t);   尾端插入元素
    //v[n];             下标运算符,对v中第N个位置上元素的引用,而试图访问不存在元素将发生溢出错误。另外,不能使用下标添加元素。
    //v1=v2;            拷贝
    //v1={...}          列表初始化
    //v1 == v2;         元素数量,对应位置元素值
    //v1!=v2;
    //<,<=,>,>=;

    //迭代器,所有标准库容器都可以使用迭代器,但是只有少数才同时支持下标运算符。
    auto b = svec6.begin(), e = svec6.end();    //end返回尾后迭代器,如果容器为空,则都为尾后迭代器。
    //迭代器运算符
    //*iter         解引用迭代器,并返回迭代器所指元素的引用
    //iter->mem     解引用并返回该元素的mem成员,等价于(*iter).mem
    //++iter        令迭代器iter指向下一元素
    //--iter
    //iter1==iter2  两个迭代器是否指向相同元素?
    //iter1!=iter2

    string siter("hello world");//string也有迭代器操作!
    if (siter.begin() != siter.end())
    {
        auto it = siter.begin();
        *it = toupper(*it);
    }
    cout << siter << endl;

    for (auto it = siter.begin(); it != siter.end() && !isspace(*it); ++it)
        *it = toupper(*it);
    cout << siter << endl;

    //迭代器类型
    vector::const_iterator it1;        //迭代器分为iterator和const_iterator,const类型只能读元素,不能写元素。
    vector::iterator it2;
    //如果对象只读而不写则应该定义为const_iterator类型
    auto it_iterator = svec6.cbegin();

    //迭代器运算
    //iter+n            加上数值还是迭代器
    //iter-n;
    //iter += n;
    //iter-=n;
    //iter1-iter2;      返回类型为difference_type,带符号整型。
    //>,>=,<,<=;

    //二分法搜索
    vector text_num{ 3,1,2,4,5,6,9,8,7 };
    int find_num = 9;

    sort(text_num.begin(), text_num.end());
    auto beg = text_num.cbegin();
    auto end = text_num.cend();
    auto mid = text_num.cbegin() + (end - beg) / 2;
    while(mid != end)
    {
        if (*mid == find_num)
        {
            cout << "Find numbers!" << endl;    //  二分法搜索,如果找到数值就输出find numbers!
            break;
        }

        if (find_num < *mid)
        {
            end = mid;
        }
        else
        {
            beg = mid + 1;
        }
        mid = beg + (end - beg) / 2;
    }

    //数组,是一种类似于标准库类型vector,数组大小固定!
    int arr1[10];                   //含有10个整数的数组
    int *parr1[10];                 //含有10个整型指针的数组。int (*p)[10]指向含有10个整数数组的指针!主要应用于指向二维数组!
    int arr2[] = { 1,2,3 };     
    int arr3[5] = { 1,2,3 };
    char a1[] = { 'c','c' };
    char a2[] = "cc";
    //char a3[2]="cc";              没有足够的空间放下'\0'
    //int arr4 = arr2;              不能用一个数组初始化令一个数组。数组会自动转为首元素指针!
    //arr1=arr2;                    不能把一个数组直接赋值给另一个数组
    int (*parr2)[10]= &arr1;        //parr2指向一个包含10个整数的数组。
    int (&parr3)[10] = arr1;        //parr3引用一个含有10个整数的数组。
    int *(&parr4)[10] = parr1;      //parr4是数组的引用,该数组包含10个指针
                                    //默认情况,类型修饰符从右至左依次绑定(而括号则改为由内向外),数组必须指定类型,不允许用auto推断类型!
    constexpr unsigned sz = 10;
    string strs[sz];                //sz必须为常量表达式!

    for (auto i : arr2)
    {
        cout << i << " ";           //arr2数组也支持下标运算符,下标运算符类型为size_t,无符号类型。建议检查下标的值,避免缓冲区溢出错误。
    }
    cout << endl;

    //指针和数组关系密切,在c++中,编译时会将数组转换成指针。
    string nums[] = { "one","two","three" };
    string *p1_nums = &nums[0];
    string *p2_nums = nums;         //p1等价于p2

    //数组有,标准库函数begin和end。类似于容器的迭代器操作!
    int ia[] = { 0,1,2,3,4,5,6,7,8,9 };
    int *beg_ia = begin(ia);
    int *end_ia = std::end(ia);     //由于前文定义了迭代器变量end,因此此处只有使用作用域符!(避免使用c++内置声明符)

    //指针也是迭代器,指针相减返回类型ptrdiff_t,带符号类型,定义在头文件cstddef中。
    //c++支持c风格字符串,也定义了c_str等转换函数,但是最好不要用c风格字符串!
    //使用指针和数组容易出错,推荐使用vector和迭代器,还有string!

    //多维数组,是数组的数组!
    int ia_multi1[3][4];            //大小为3的数组,每个元素是含有4个整数的数组。
    int ia_mulit2[3][4] = { 0 };    //将所有元素初始化为0
    int ia_mulit3[3][4] = { {1,2,3,4},{5,6,7,8} };
    int ia_mulit4[3][4] = { 1,2,3,4,5,6,7,8 };
    int(&row)[4] = ia_multi1[1];    //把row绑定到ia的第二个4元素数组上
    decltype(ia_multi1) ia_mulit5;  //decltype返回类型是多维数组,而不是指针!auto推断为指针,所以数组嵌套for外层必须为引用!

    //范围for处理多维数组,也可以用for嵌套
    for (const auto &row : ia_mulit3)   //除了最内层循环,其他所有循环的控制变量都应该是引用!如果非引用auto &row=ia_mulit3,则auto将自动推断为指针!
    {
        for (auto col : row)
            cout << col << "-";
        cout << endl;
    }

    //指针和多维数组
    int(*p_mulit2)[4] = ia_mulit3;      //*p_mulit2为指针,指向含有4个整数的数组
    int *ip[4];                         //4个指向整型对象的数组!
    using int_arry = int[4];            //类型别名
    int_arry *ia_mulit6 = ia_mulit3;    //等价于*p_mulit2

    //for循环,使用auto,可以不用在数组前面加指针类型声明!
    for (auto p = ia_mulit2; p != ia_mulit2 + 3; ++p)
    {
        for (auto q = *p; q != *p + 4; ++q)
        {
            cout << *q << " ";
        }
        cout << endl;
    }
    //使用begin和end函数,更加简洁易懂
    for (auto p = begin(ia_mulit2); p != std::end(ia_mulit2); ++p)
    {
        for (auto q = begin(*p); q != std::end(*p); ++q)
        {
            cout << *q << "+";
        }
        cout << endl;
    }


    cin.ignore();
    return 0;
}

//1、使用拷贝初始化时,只能提供一个初始值;2、如果类提供了类内初始值,则只能用拷贝初始化或者列表初始化(直接和拷贝);3、如果容器提供初始元素值的列表,则只能用列表初始化。
//1、不能在范围for循环中向vector对象添加元素,另一个限制是任何可能改变vector对象容量的操作,如push_back,都会使vector对象的迭代器失效。
//第三章主要介绍vector,string,数组,顺带提到了C++对于C的支持(C风格字符串,及相互转换方法)。在介绍vector和string时引出了迭代器的概念,讲解了其基本用法。在介绍数组时引出了指针的概念和用法,同时穿插讲解了auto、decltype、范围for等等!作者重点提到,推荐使用vector、string、迭代器,避免繁琐和错误!

你可能感兴趣的:(chapter-3)