C++学习笔记二 C++标准库 数组及指针

C++的string跟vector库分别定义了大小可变的字符串和集合。

string跟vector往往将迭代器用作配套类型来访问string中的字符或者vector中的元素。

 

string字符串的size操作的返回值是字符串的长度,类型属于string的配套类型,即string::size_type(是一个unsigned int 或者unsigend long类型)

string类型可以通过下标操作来访问string对象中的单个字符

 

vector类型size操作的返回值是vector集合里元素的个数,类型同理是vector的配套类型vector<T>::size_type (类型同string::size_type)

此处<T>可为int,string 甚至是vector<T>类型分辨表示是一个元素类型为int,string,vector<T>的集合。

vector也可以通过下标操作来访问其中的元素。但是vector下标操作只能用来获取已经存在的元素。

 

vector元素对象还可以使用迭代器来实现。

迭代器是一种支持可用来遍历容器内的元素,并访问这些元素值操作的类型。如数组的迭代器就是指针。

每种容器都定义了自己迭代起的类型,vector的就是vector<T>::iterator

每一种容器也都定义了一队命名为begin()和end()的函数,用于返回迭代器。

如果vector不空 那么他的begin返回的迭代器就是指向第一个元素

end()函数返回的是vector的末端元素的下一个,它不指向容器里的任何一个元素,只表示我们已经处理完所有的元素

迭代器的解引用操作符(*)可以用来访问迭代器所指向的元素

 

 

如:

 

string str("some string");

vector<int> ivec(5);                                                         //定义一个5个元素的vector<int>类型

 

// 利用下标操作符分别输出str字符串中所有字符

for(string::size_type index=0;index!=str.size();++index)

        cout<<str[index]<<endl;

 

//利用下标操作分别输出vector中的各元素值

for(vector<int>::size_type index=0;index!=ivec.size();++index)

      cout<<ivec[index]<<endl;

 

//下标操作可用作左值

//利用下标操作符将str每个字符全部赋值为'a'

for(string::size_type index=0;index!=str.size();++index)

        str[index]='a'; 

 

//vector下标操作只能用于获取已经存在的元素

for(vector<int>::size_type index=0;index!=10;++index)

       ivec[index]=index;                                                         //试图将0-9分别赋值到ivec的第0到第9个元素

                                                                                             //这个是错误的,下标操作只能用于获取已经存在的元素

                                                                                             //此处ivec是只初始化5个元素个数的vector<int>类型

//正确方法应使用push_back();函数

for(vector<int>::size_type index=0;index!=10;++index)

      ivec.push_back(index);                                                   //依次在ivec后面添加新元素

 

//利用迭代器分别输出str字符串中各字符

for(string::iterator iter=str.begin();iter!=str.end();++iter)

        cout<<*iter<<endl;                                               //使用解引用操作符访问迭代器所指向元素的值

 

//利用迭代器分别输出vector中的各元素值

for(vector<int>::iterator iter=ivec.begin();iter!=ivec.end();++iter)

     cout<<*iter<<endl;                                                  //使用解引用操作符访问迭代器所指向元素的值

 

//使用迭代器将str字符串各字符赋值为'a'

for(string::iterator iter=str.begin();iter!=str.end();++iter)

     *iter='a';

 

//使用迭代器赋值容器中的各元素的值

for(vector<int>::iterator iter =ivec.begin();iter!=ivec.end();++iter)

     *iter=0;                                                                     //利用解引用操作符将容器中各元素依次赋值为0

 

iterator类型跟const_iterator

上面使用了iterator来读取或者改写其对应的值

const_iterator只能用来读取对应的值,而不能对其重新赋值

 

 

数组与指针:

数组的定义及初始化

数组的维数必须用值大于等于1的常量表达式定义,此表达式只能包含整型字面值常量(如 5),枚举常量,或者用常量表达式初始化的整型const对象。如:

const unsigned buf_size=512,max_file=20;

int staff_size=127;

const unsigned sz=get_size();                                             //调用get_size()函数获取一个const unsigned类型

char input_buffer[buf_size];                                                 //ok,因为buf_size是一个已经初始化的整型const对象

string fileTable[max_file+1];                                                 //ok,因为max_file也为一个const对象,

                                                                                             //max_file+1在运行的时候已经可以确定他的值

double salaries[staff_size];                                                  //errer staff_size不是一个const对象

int test_scores[get_size()];                                                  //errer get_size()要在程序运行的时候才能计算得它的返回值

int vals[sz];                                                                           //errer 同上

 

初始化

const size_t array_size=3;

//显式初始化

int ia1[array_size]={0,1,2};                                            //如果显式初始化个数小于维数,只初始化前面的数组元素

                                                                                        //剩余的若为内置类型则初始化为0,若是类类型就按默认构造函数初始化

int ia2[]={3,4,5,6}   ;                                                       //不指定维数,按初始化个数来确定数组长度

特殊的字符数组

char ca1[]={'C','+','+'};                                                   //ca1有3个元素

char ca2[]={'C','+','+','/0'};                                             //ca2有4个元素

char ca3[]="C++";                                                          //用字符串字面值初始化字符数组,ca3有4个元素,隐性加一个空字符

char ca4[6]="string";                                                      //错误,因为"string"有7个字符

 

不允许数组直接复制跟赋值。

 

 

数组可以使用下标对每个元素进行操作,数组下标类型为 size_t类型

//利用下标遍历数组中的各个元素,将其下标赋值给各个元素

const size_t array_size=10;

int ia[array_size];

for(size_t index=0;index!=array_size;++index)

        ia[index]=index;

 

同理可以利用下标操作加for循环将一个数组的元素赋值给另外一个同类型同数组

 

指针的定义

c++中使用*符号把一个标识符申明为一个指针

string *pstr;

指针的另一种声明风格

string* pstr;

第二种风格容易使人错以为string*是一种新类型,且在声明多个指针时容易出错。如:

string* ptr1,ptr2;

上句声明了一个字符串指针pstr跟一个字符串ptr2。

使用第一种风格就会很好的避免此类问题

string *ptr1, *ptr2;

 

避免使用未初始化的指针。

如可能的话,除非所指对象已经存在,否则不要先定义指针,这样可以避免一个未初始化的指针。

如果不需分开定义指针跟所指对象,则应将指针初始化成0;

 

指针的操作

指针提供简介操作其指向的对象,跟迭代器一样可以用解引用操作符获取指针所指向的对象。

string s1("hello world");

string s2="abcde";

string *sp=&s1;

cout<<*sp<<end;                         //用解引用操作符获取指针所指向对象的值

解引用操作符返回值可以当左值,用来改变指针所指向的对象的值。

*sp="goodbye";                           //解引用操作符用作左值来修改指针所指向的对象

给指针直接赋值也可以修改指针所指向对象的值,这样不需要使用解引用操作符

sp=&s2;

 

左操作值如果有解引用操作符,修改的是指针指向的对象的值

左操作值中没有解引用操作符,修改的是指针的本身

 

指针跟引用的比较

引用是变量的一个别名,定义引用时必须指定绑定对象,修改引用时同时修改了变量的值

指针是指向一个变量,当修改了指针本身时,并不修改原来指针所指向对象的值

 

使用指针访问数组元素:

C++中的表达式使用数组名,改名字自动转化为指向该数组第一个元素的指针

int ia[]={0,2 ,4 ,6};

int *ip=&ia;   //此时ip指向ia[0]

若要指向到其他元素,使用下标先定位在取地址符获取该元素的地址

ip=&ia[3];     //此时IP指向ia[3]

与其使用下标,使用指针的算术操作更方便。指针加上或者减去一个整型数值n等效获得一个新的指针。

2个指针的减法操作的结果是标准库类型ptrdiff_t的数据.

size_t是unsigend 类型 因为数组的下标不能为负数

ptrdiff_t是signed类型 而指针的减法操作的结果有可能是负数

 

下标跟指针

使用下标访问数组时,实际上是使用下标访问指针

int ia[]={0,2,4,6,8};

int i=ia[0];

int *p=&ia[2];

int j=p[1];     //p[1]=*(p+1),此处p[1]=ia[3]

int k=p[-2];   //p[-2]其实就是*(p-2)等效于ia[0]

 

 

利用指针遍历输出数组元素

const size_t array_size=5;

int ia[array_size]={0,1,2,3,4};

for(int *pbegin=ia,*pend=ia+array_size;pbegin!=pend;++pbegin)

   cout<<*pbegin<<endl;

 

上例中for循环定义了2个int类型的指针pbegin pend

pbegin 指向数组的第一个元素,而pend指向的是数组最后一个元素的下一个(类似vector提供的end()返回的迭代器) 

 

指针跟const限定符

C++强制要求指向const对象的指针也具有const特性

const double *cptr;  //cptr是一个指向double类型的const对象的指针,const限定了cptr指针所指向的对象类型,而非cptr本身

也就是说 cptr本身不是一个const,所以在定义时可以不初始化,后面也可以对其重新赋值,使其指向另一个const对象

但不能通过cptr修改它指向的值,如  *cptr=42;

 

指向const对象的指针理解为“自以为指向const对象的指针”

不能通过指向const对象的指针修改基础对象,然后如果该对象指向的是一个非const对象,可以通过其他方式修改其值 

 

const指针---本身不能修改的指针

int i=0;

int *const ip=&i;  //iph是指向int类型对象的const指针,它的值不能修改,且定义时必须初始化。

 

指向const对象的const指针

const double pi=3.14159;

const double *const pi_ptr=&pi;   //pi是一个指向double类型的const对象的const指针

此时pi_ptr本身不能修改,它指向的对象也不能修改

 

指针跟typedef

typedef string *pstring;

const pstring cstr;

声明const pstring cstr时const修饰的是pstring类型,它是一个指针。

所以cstr定义为一个指向string对象的const指针。等价于string *const cstr;

 

 

 

 

理解复杂的const类型的声明

阅读const类型的声明难易理解是因为const限定符既可以放在类型名前,也可以放在类型名后

const string s1;

string const s2;

s1跟s2都是一个const string类型

用typedef写const类型定义时,const放在类型名前容易对所定义的类型产生误解,

string s1;

typedef string *pstring;

const pstring cstr1=&s1;

pstring const cstr2=&s1;

string *const cstr3=&s1;

把const放在类型pstring之后,然后从右向左阅读该声明语句就会非常清楚的指导cstr2是一个const pstring类型,即指向string类型的const指针。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值