• 第3章 字符串、向量、数组


    3.2 string

    初始化

    string s1;          //默认初始化,s1是一个空串
    string s2(s1);      //使用s1初始化s2
    string s2=s1;      //同上
    string s3("value"); //s3是字面值"value"的副本,但是不包括
    string s3="value";  //同上
    string s4(10,'c');  //使用10个c初始化s4

    操作

    os<<str    //将str写入输出流,并返回os
    is>>str    //将is中读取的字符串空格分割赋给str,并返回is
    getline(is, str)    //从is中读取一行赋值给str,换行符也读取了(流中的位置在换行符后),但是没有赋值给str
    str.empty()
    str.size()    //返回字符的个数
    str[n]    //返回str中第n字符的引用
    str1+str2
    str1=str2    //将str2的副本代替str1中的内容
    str1 == str2
    str1 != str2
    <, <=, >, >=

    warming

    string::size_type string::size();

    size函数返回的是size_type类型,这其实是一个无符号的类型,所以应该注意与负数的比较:

    表达式:str.size() < -1,将返回为true,因为-1需要转换成无符号进行比较。

    str1+str2

    字面值之间不能相加,比如"asd" + "1256"

    warming

    string的类型和字符串"string"的类型是不一样的,后者是char[]

    处理字符

    使用如下语句处理:

    for( auto c : str)
    {
        statement.....
    }
    isalnum(c)    //c为字母或数字时为真
    isalpha     //字母
    iscntrl       //控制字符
    isdigit       //数字
    isgraph     //不是空格,但是可以打印
    islower      //小写字母
    isprint       //可打印,包括空格
    ispunct      //标点符号
    isspace     //空白字符
    isupper     //大写字母
    isxdigit     //十六进制数字
    tolower     //变成小写
    toupper    //变成大写

    warming

    刚才的基于范围的for循环,仅仅是获取string中字符的副本,如果要改变string中的值,必须使用引用:

    for (auto &c : s)

    3.3 vector容器

    #include<vector>
    using std::vector;

    vector是一个类模板。

    模板本身不是类或者函数,它是对类或函数的说明,编译器根据说明(尖括号中的说明)创建类或者函数(这个过程叫做实例化)。

    vector能够容纳绝大数类型的对象,但是引用不是对象,不能包含进去。

    warming

    在早期版本的编译器中,vector中若存放vector,则内层尖括号需要有空格分割,如:vector< vector<int> >

    初始化

    vector<T> v1;    //v1是空vector,类型为T,执行默认初始化
    vector<T> v2(v1);    //v2中包含v1中的所有元素
    vector<T> v2 = v1;    //同上
    vector<T> v3(n, val);    //v3包含n个重复的val
    vector<T> v4(n);    //v4包含了n个重复的默认初始化的T对象,必须能够有默认的初试化的T
    vector<T> v5{a, b, c, d};    //v5包含了初始值
    vector<T> v5={a, b, c, d};    //同上

    warming

    vector<string> v_str("hello");

    这个语句是错误的,因为"hello"是char[],没有办法初始化string。

    vector<string> v_str {"hello"}

    这个是正确的,可以用列表初始化string的vector

    vector<string> v_str {10, "hello"}

    这个是正确的,初始化时时10个相同的"hello"

    vector操作

    /*注意在执行压入时,会改变v1的end判断,尤其是在范围for语句中可能出现错误*/
    v1.push_back(t);    //将t压入到v1的尾部
    
    v.empty();    //判断不含任何元素,返回真
    v.size();    //元素的个数
    v[n];    //得到第n个元素
    v1 = v2;    //使用v2的元素的拷贝替换v1中所有的元素
    v1 = {a,b,c,d};    //同上
    v1 == v2;    //当且仅当v1、v2元素个数一样,并且对应元素相同
    v1 != v2;
    <, <=, >, >=

     3.4 迭代器

    迭代器提供了对对象的间接访问。有效的迭代器指向某个元素,或者尾元素的下一个位置,其他的情况是无效的迭代器。

    for(auto iter = v.begin(); iter != v.end(); ++iter)
    {
        *iter = (*iter)+5;
    }

    迭代器运算

    v.begin();   //返回容器的第一个元素的迭代器
    v.end();    //返回容器尾元素的下一个元素的迭代器
    v.cbegin();   //返回容器的第一个元素的迭代器,常量形式不可修改
    v.cend();    //返回容器尾元素的下一个元素的迭代器,常量形式不可修改
    
    *iter;    //返回所指元素的引用
    iter->member;    //解引用,并返回其所指元素的member成员,同(*iter).member
    
    ++iter;    //指向下一个元素
    --iter;    //指向上一个元素
    iter+n;    //超出最后一个元素不会报错
    iter-n;    //超出第一个元素不会报错
    iter1 - iter2;    //两个迭代器之间的距离
    
    iter1 == iter2;    //判断是同一个元素
    iter1 != iter2;
    >, >=, <, <=    //判断所处位置的前后

    迭代器的类型分为iterator和const_iterator,如:vector<int>::iterator iter;

    迭代器的距离类型为difference_type,是一个带符号的整数型。

    如果容器为空,则begin和end返回的都是尾元素的下一个位置。
    如果容器为常量,则begin与cbegin返回的都是常量形式,end亦然.

    3.5 数组

    与vector一样,数组的元素不能是引用。复杂数组的声明

    在编译时,就需要知道数组的大小,因此,数组初始化时,维度应该为常量。

    与其他内置类型(int、double)一样,数组在函数外定义时,才会进行默认初始化;在函数内定义时,并没有初始化。为了给数组默认初始化,可以将一个空的列表赋值给数组。

    int a[]={1, 2, 3};    //显式初始化
    int a[10]={};    //显式初始化,初始化后都为0
    int d[]=a;    //错误,不能拷贝
    int size=sizeof(a)/sizeof(*a);    //获取数组的大小

    复杂数组的声明

    int *ptrs[10];    //存放10个整形指针
    int (*Parray)[10] = &arr;    //Parray指向含有10个整形的数组
    int (&arrRef)[10] = arr;    //arrRef是一个含有10个整形数组的引用
    
    int *(&arrRef)[10] = arr;    //arrRef是数组的引用,数组中有10个指针

    数组的访问

    数组下标的类型为size_t,定义在<cstddef>头文件中,它设计的足够大,可以表示内存中任意对象的大小。

    指针与迭代器

    编译器一般会将数组名当成首个元素的指针。

    在头文件<iterator>中定义了名为begin和end的函数,用于得到数组的手元素的指针和尾元素下一位置的指针。

    int a[10]={};
    for(int *pbeg=begin(a);pbeg!=end(a);pbeg++)
        cout<<(*pbeg)<<endl;

    两个指针相减,得到他们之间的距离,这两个指针也必须是指向同一个数组中元素的指针。
    这个距离是类型为ptrdiff_t,定义在<cstddef>中。

    C风格字符串

    char类型的数组中,以''字符结尾的字符序列。其所有的运算都要通过<cstring>中的函数完成。

    C++与C的接口

    //C字符串可以通过构造函数转换成string
    //string可以通过c_str()函数转换成C字符串
    char cStr[] = "字符串";
    string cppStr(cStr);
    const char *ctr = cppStr.c_str();
    
    //使用数组初始化vector,只需指明首尾数组地址
    int int_arr[]={1, 2, 3, 4, 5};
    vector<int> ivec(begin(int_arr), end(int_arr));

    3.6 多维数组

    多维数组实际上是数组的数组。在定义时,可以跟一个空的列表进行默认初始化。

    为什么多维数组还要要求每一维中的元素个数相同?因为数组要求其中存储的类型相同,数组类型起始包含了数组的长度的,所以每一个个数都要求相同。

    对于二维数组,常将第一维成为行,第二维称为列。

    warming

    在使用范围for循环遍历多维数组时,除了最内层循环其他都要用引用遍历,避免数组被自动转换为指针。

    for( auto &row : table)
        for( auto line : row)
            cout<<line<<endl;

    如果在外层for循环中,不使用auto,则需要为二维数组中的内层维度指明类型。

    例如对于int table[10][5],就需要知道内层维度为int[5],所以auto的类型应该是int[5]。但是如果写成int row[5],则每次迭代,迭代器会将table中的当前维度的副本赋值给row,由于数组不能够直接赋值,所以此处只能使用对int[5]的引用:

    for( int (*row)[5] : table)
        for( int line : row)
            cout<<line<<endl;
  • 相关阅读:
    jquery02
    jquery01
    oracle04_plsql
    oracle03
    oracle02
    oracle01
    selenium
    爬取京东商品信息并保存到MongoDB
    python pymongo操作之增删改查
    MongoDB 数据库表删除
  • 原文地址:https://www.cnblogs.com/qiusuo/p/4471321.html
Copyright © 2020-2023  润新知