C++ Primer学习笔记8 数组和指针

C++提供了两种类似于vector和迭代器的低级复合操作--数组和指针。与vector类似,数组也可以保存某种类型的一组对象;而它们的区别在于,数组的长度是固定的。数组一经创建,就不允许添加新的元素。指针则可以像迭代器一样用于遍历和检查数组中的元素。

C++中尽量使用vector和迭代器,而避免使用低级的数组和指针。

1、数组

在定义数组时可以为其提供一组用逗号分隔的初值,这些初值用花括号{}括起来,称为初始化列表:

const unsigned array_size=3;
	int ia[array_size]={1,2,3};

如果没有显示提供元素初值,则数组元素会像普通变量一样初始化:

、在函数体外定义的内置数组,其元素初始化为0

、在函数体内定义的内置数组,其元素无初始化;

ƒ、不管数组在哪里定义,如果其元素为类类型,其自动调用该类的默认构造函数进行初始化,如果该类没有默认构造函数,则必须为该数组的元素提供显示初始化。

显示初始化的数组不需要指定数组的维数,如 

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

如果指定了数组维数,那么初始化列表提供的元素个数不能超过维数值。如果维数大于元素初始值个数,则只初始化前面的数组元素;剩下的其他元素,若是内置类型初始化为0,若是类类型则调用该类的默认构造函数进行初始化。

特殊的字符数组

字符数组既可以用字符进行初始化,也可以用字符串字面值进行初始化。注意这两种形式并不完全相同,字符串字面值包含一个额外的空字符(null)用于结束字符串。

char ca1[]={'c','+','+'};         //no null,3维
	char ca2[]={'c','+','+','\n'};    //no null,4维
	char ca3[]="c++";                 //null terminator added automatically,4维

vector不同,一个数组不能用另一个数组初始化,也不能将一个数组赋值给另一个数组。

 int ia[ ]={1,2,3};
	int ia2[](ia);         //error

vector元素一样,数组元素可用下标操作符来访问,数组元素也是从0开始计数。

vector使用vector::size_type作为下标类型,而数组下标正确的类型则是size_t

for循环遍历数组的10个元素,并以下标值作为各个元素的初始值:

<pre name="code" class="cpp"><pre name="code" class="cpp">#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	const size_t array_size=10;  
    int ia[array_size];         //已分配内存,不为空,未初始化 
	cout<<"ia[10]={";
    for(size_t ix=0;ix!=array_size;++ix)  
    {  
        ia[ix]=ix;  
		cout<<ia[ix];
		if(ix!=9)
			cout<<",";

    }  
	cout<<"}";
	system ("pause");
	return 0;
}


 
 

int main()
{
	vector<int> ivec;     //ivec为空
	for(vector<int>::size_type   ix=0;ix!=ivec.size();++ix)
	{
		ivec[ix]=0;   //正确
	}	
	system("pause");
	return 0;
}

ƒvector添加10个元素

 int main()
{
	vector<int> ivec;     //ivec为空
	for(vector<int>::size_type   ix=0;ix!=10;++ix)
	{
		ivec[ix]=ix;   //错误,不能用下标为vector添加元素
        ivec.push_back(ix);      //正确,用push_back为vector添加元素
	}	
	system("pause");
	return 0;
}

2、指针

vector的遍历使用下标和迭代器,同理可以使用下标和指针遍历数组。

指针用于指向对象,与迭代器一样,指针提供对其所指对象的间接访问,与迭代器不同的是,指针指向单个对象,而迭代器只能用于访问容器内的元素。

 string s("hello world");
	 string *sp=&s;      //sp为指向string类型的指针,指向s

指针的定义

string *sp;     
	int *ip1,*ip2;
	vector<int>   *pvec;

另一种定义形式:

string* sp;        //和上面的形式是一样的意思,此形式容易引起误解
string* sp,sp1;    //sp为指向string类型的指针,sp1为string类型变量

避免使用未初始化的指针,建议在使用之前初始化所有的变量,尤其是指针。如果可能的话,除非所指向的对象已经存在,否则不要先定义指针。如果必须分开定义指针和其指向的对象,则将指针初始化为0.

int *ip=0;

void*类型的指针可以保存任何类型对象的地址:

 double obj=3.14;
	double *pf=&obj;
	void *pv=&obj;

void*表明该指针与一地址相关,但不清楚存储在该地址上的对象的类型。

与对迭代器进行解引用一样,对指针进行解引用可以访问它所指向的对象。

 string s("hello world");
	string *ps=&s;
	cout<<*ps;       //print hello world

给指针赋值和通过指针进行赋值区别:如果对左操作数进行解引用,则修改的是指针所指对象的值;如果没有使用解引用操作,则修改的是指针本身的值。

 string s1("some thing");
	string *sp1=&s1;
	
	string s2("another");
	string *sp2=&s2;

	*sp1="a new value";    //修改的是sp1所指向的对象s1的值,s1="a new value"

	sp1=sp2;               //修改的是sp1的值,sp1指向s2

指针和引用的比较:

引用总是指向某个对象,定义时必须初始化

给引用赋值修改的是该引用所关联的对象的值

ƒ引用一经初始化,始终指向同一个对象。指针可以改变所指向的对象。

int ival=1024,ival2=2048;
	int *pi=&ival,*pi2=&ival2;
	 pi=pi2;

以上程序修改了pi指针的值,使pi指向ival2;而ival的值没变。

int ival=1024,ival2=2048;
	int &ri=ival,&ri2=ival2;
	 ri=ri2;

以上程序修改了ival的值,ival=ival2=2048

指针访问数组

在表达式中使用数组名时,该名字会自动转换为指向数组第一个元素的指针:

 int ia[]={0,2,4,6,8};
	 int *ip=ia;        //ip=&ia[0]
	 int *ip2=ia+4;     //ip2=&ia[4]

指针加上一个整数值其结果仍然是指针,允许在这个结果上直接进行解引用操作。

 int last=*(ia+4);        //last=ia[4]
 int last=*ia+4;        //last=ia[0]+4

解引用的优先级比加法操作符要高。

数组的超出末端指针:数组名+数组长度

vector类型提供end操作返回超出末端的一个迭代器,类似地,可以计算数组的超出末端指针,不允许对超出末端指针进行解引用操作。

const size_t array_size=5;
	 int arr[array_size]={0,2,4,6,8};
	 int *ip=arr;        //ip=&ia[0]
	 int *p2=ip+array_size;      //p2为超出末端指针

输出数组元素:

 const size_t array_size=5;
	 int arr[array_size]={0,2,4,6,8};
	 for(int *pbegin=arr,*pend=arr+array_size;pbegin!=pend;++pbegin)
	 {
		 cout<<*pbegin<<" ";
         }

指向const对象的指针

指向const对象的指针也必须具有const特性。

const double *cptr;

cptr是一个指向double类型const对象的指针,const限定了cptr指针所指向的对象类型,而非cptr本身。就是说cptr本身并不是const。在定义时不需要初始化,如果需要可以对cptr重新赋值,使其指向另一个const对象,但是不能通过cptr修改其所指向的对象的值。

 const double pi=3.14;
	double *ptr=&pi              //error 
	const double *cptr=&pi       //ok

允许把非const对象的地址赋值给指向const对象的指针

double dval=3.14;
	const double *cptr=&dval; 

尽管dval不是const对象,但不能通过cptr指针修改dval的值。

const指针

const指针其本身的值不能修改:

int errNumb=0;
	int *const curErr=&errNumb;

curErr是指向int型变量的const指针。与其他const量一样,const指针的值不能修改,不能使curErr指向其他对象,在定义时必须初始化。


创建动态数组

       数组有三个重要限制:数组长度固定不变,在编译时必须知道其长度,数组只在定义它的块语句内存在。

       动态数组不必在编译时知道其长度,可以在运行时才确定数组长度。动态数组创建后将一直存在,直到程序显示释放它为止。c++使用new和delete实现创建动态数组和释放。

      创建动态数组时,只需要指定类型和数组长度,不必为数组对象命名,new表达式返回指向新分配数组的第一个元素的指针:

      

int *pia=new int[10];
此new表达式分配了一个含有10个int型元素的数组,并返回指向该数组第一个元素的指针,此返回值初始化了指针pia

size_t  n=getsize();
int *p=new int[n];

动态空间的释放

动态分配的内存最后必须进行释放,否则,内存最终将会逐渐耗尽。

delete  [] pia;
该语句回收了pia所指向的数组,把相应的内存返回给自由存储区。在关键字delete和指针之间的方括号是必不可少的,它告诉编译器 该指针指向的是自由存储区中的数组,而并非单个对象。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值