什么是数组? 简单来说数组代表一块连续的内存,内部包含连续的一排相同的对象, 因为内存分布连续且对象大小相同,所以我们可以高效的根据 索引随机访问和赋值。


一维数组就象一行字。 

二维数组就象一页字。 

三维数组就象一本书中的字。 

四维数组就象一套书中的字。 

五维数组就象书柜中多套书中的字。 

六维数组就象图书馆中多个书柜多套书中的字。

七维数组是一个省中的所有图书馆藏书中的字。

八维数组是一个城市的所有图书馆藏书中的字。

九维数组是一个国家的所有图书馆藏书中的字。

十维数组是一个洲所有国家的图书馆藏书中的字。

十一维数组是地球上所有国家的图书馆藏书中的字。

数组是我们平时用的最多的数据结构, 因为它很符合我们程序运行时的平坦内存布局,使用起来简单而高效。可以这样说,只要恰当的使用,数组可以满足我们工作中的大部分需要。



数组包括静态数组和动态数组, C/C++语言内置支持数组, 我们平时一般这样用:


void test() 
  
{ 
  
     
  int ar[5] = {1, 2, 3, 4, 5}; 
  
     
  int v = a[2]; 
  

     
  int* pAr =  
  new  
  int[3]; 
  
    pAr[1] = v; 
  
    delete []pAar; 
  
}




其中ar是静态数组,它分配在该线程的堆栈上, 而pAr是动态分配的,它内存分配在堆上, 详细内存分配可以看我这篇 《C++中new和delete的背后》



对于数组,我们要注意的是C++数组不支持多态, 这里他们讨论过这个问题 《C++的数组不支持多态?》



上面我们讨论的动态数组是C++语言内置支持的, 但是因为内置数组大小固定且容易越界, 另外还有上面的多态问题, C++标准库为我们提供了另一种封装vector, 我们可以这样用:


void test() 
  
{ 
  
    vector< 
  int> ar; 
  
    ar.push_back(1); 
  
    ar.push_back(2); 
  
     
  int d = ar[1]; 
  
    ar[2] = 10; 
  
}



我们可以看到, vector使用起来非常方便, 一方面我们可以像内置数组一样使用, 另一方面我们不用再担心容量问题, 因为它会在大小不够时自动增加。



vector虽然简单,但是实际上它有 不少陷井和技巧, 下面列举一些常见问题:



1。小心迭代器失效

void test() 
  
{ 
  
 vector< 
  int> ar; 
  
 ar.push_back(1); 
  
 vector< 
  int>::iterator itr = ar.begin(); 
  
  
  for( 
  int i=0; i<100; ++i) 
  
 { 
  
  ar.push_back(i); 
  
 } 
  
  
  
  
  int d = *itr; 
  
}




你看出上面代码的问题了吗? 


不错, 可能在我们push_back过程中, 内存重新分配了, 导致我们原先记录的迭代器itr已经失效, 后面再重新访问就出错了。
这种bug有时很难定位,参见 《一次痛苦的Coredump定位过程》


2。防止内存多次分配


我们知道在push_back过程中, 当数组容量不够时, 我们就会重新分配内存, 然后将已有的元素进行拷贝, 效率很低。


所以最好的方法是用reserve()方法对需要的大小进行正确的估计,然后预留足够的空间, 防止重新内存分配。



3。释放已分配空间


有些时候某个vector对象已经分配了挺大空间,当用的差不多时, 我们需要释放这些空间, 但是要保留该对象,要怎么做?


有人可能会说用成员函数clear(), 但那只能清除内容却不会释放空间, 这里有个挺实用的swap技巧:


int> vec; 
  
void test() 
  
{ 
  
     
  for( 
  int i=0; i<10000; ++i) 
  
        vec.push_back(i); 
  


    vector< 
  int> temp; 
  
    vec.swap(temp); 
  
}




4。删除某些符合条件的元素

void test() 
  
{ 
  
 vector< 
  int> ar; 
  
  
  for( 
  int i=0; i<100; ++i) 
  
 { 
  
  ar.push_back(i); 
  
 } 
  

vector< 
  int>::iterator itr = ar.begin(); 
  
  
  for(;itr != ar.end();) 
  
 { 
  
   
  if(*itr > 10) 
  
  { 
  
   itr = ar.erase(itr); 
  
  } 
  
   
  else 
  
  { 
  
   ++itr; 
  
  } 
  
 } 
  
}


上面的代码删除数组中大于10的所有item, 实际上我们可以下面更简单的方法替代:


int>(), 10)), ar.end());



从上面的一些技巧,我们可以看到, 只有真正理解了vector的内部实现原理, 我们才能规避一些使用陷井, 更简单而高效的开发程序。



上面我们讨论的vector主要针对的模拟C++内置的动态数组部分, 而对于静态数组部分,我们是不是也有相应的类? 


是的,C++11里新增的array就是做这个事的, 我们可以这样用:


void test() 
  
{ 
  
 std::array< 
  int, 10> ar = {1, 2, 3, 4};  
  
 ar[5] = 33; 
  
}


其中array<int, 10>在内部存储实际上是int data[10];



最后, 简单总结下,我们从C++的内置数组讲到标准库提供的vector, 最后谈到C++11新增的array, 数组这个最基本的数据结构在C++中终于有了完整的支持。