关于C++中vector数组的首地址问题

原文地址:http://www.cctry.com/thread-278452-1-1.html

近期的几个项目用到了C++标准模板库STL中的vector容器,即:动态数组,感觉也挺方便好用,跟MFC中的CArray不相上下,而且还跨平台,还是非常不错的。当前的几个项目都是用VS2013编译开发的,用着 vector 也都不错的。我举个小例子:


  1. #include "stdafx.h"
  2. #include <vector>
  3. using namespace std;

  4. int main(int argc, char **argv)
  5. {
  6.         vector <int> arr_ints;
  7.         for (int idx = 0; idx < 100; ++idx)
  8.         {
  9.                 arr_ints.push_back(idx);
  10.         }

  11.         return 0;
  12. }
复制代码


这个例子很简单,就是先定义一个 vector 动态数组,成员的类型是 int 整型,之后用个 for 循环把 100个数字放到动态数组 arr_ints 中,如此而已。
接下来呢,比如有个函数 add_value,其功能就是对指定的数组内部元素的值+1,第一个参数 pArrInts 传递的是 int 型数组的首地址,第二个参数 nArrLen 传递的是数组的大小,代码如下:
  1. void add_value(int *pArrInts, int nArrLen)
  2. {
  3.         if (!pArrInts || nArrLen <= 0) return;
  4.         for (int idx = 0; idx < nArrLen; ++idx)
  5.         {
  6.                 pArrInts[idx] += 1;
  7.         }
  8. }
复制代码


下面呢,我想调用函数 add_value,参数传递刚刚在 main 函数中定义的动态数组 arr_ints。我直接在 main 函数中这样调用肯定不行:add_value(arr_ints, arr_ints.size()); 编译都不通过。第二个参数是 arr_ints.size(),即vector动态数组的大小,这个没问题。那么第一个参数呢,add_value 想要的是数组的首地址,你直接传递 arr_ints 肯定是不行了,普通的数组:int arr_name[10]; 的名字 arr_name 可以代表数组的首地址,但是 vector 不行,他是一个对象,不是首地址。

于是我就找啊找,找到了 vector 提供了 data() 成员函数,使用它就可以了,直接返回数组内部成员的首地址,如果 vector 为空,即没有成员节点的话,那么 data() 返回 NULL,所以函数的调用改成如下就可以了:
add_value(arr_ints.data(), arr_ints.size()); 一点问题没有。

在以后的项目中我也一直使用 data() 方法来得到 vector 内部的数组的首地址。但最近有个朋友的项目要使用vs2008来开发编译,期间呢就遇到了个问题。这里面还以上面的代码为例,在 vs2008中编译呢就直接报错了,说 data() 方法不是 vector 的成员函数,说 arr_ints 对象引用不了 data() 方法。哎呀。。。怪了,之前的代码在 vs2013 上面一点问题没有,怎么到 vs2008 中就犯病了呢。忽然想到是不是 C++11 标准的事儿,因为 vs2013 本身开始全面支持 C++11,vs2008肯定不支持了。于是到网上一查,确实是这么回事:
http://en.cppreference.com/w/cpp/container/vector/data
vector 的 data 方法是在C++11中才被支持的。所以vs2008肯定用不了了。问题就来了,我就是要得到 vector 中数组元素的首地址该怎么办呢?

到网上又是百度,又是谷歌。。。还真是找到了点方法提供给大家。
vector 他本身是动态数组,所以也肯定是数组,那么内存模型就要遵循数组的形式,不然就犯规了。所以其内存空间必定是连续的。所以数组的首地址也就是数组中第1个元素的地址,也就是数组中索引为0的元素的地址。有了这个保证动态数组 arr_ints 的首地址也就是:&arr_ints[0] 对吧?我们来调试代码验证一下:
  1. int main(int argc, char **argv)
  2. {
  3.         vector <int> arr_ints;
  4.         for (int idx = 0; idx < 100; ++idx)
  5.         {
  6.                 arr_ints.push_back(idx);
  7.         }

  8.         int *p_data_1 = arr_ints.data();
  9.         int *p_data_2 = &arr_ints[0];

  10.         add_value(arr_ints.data(), arr_ints.size());

  11.         return 0;
  12. }
复制代码


没错,p_data_1 和 p_data_2 的值是相等的,也验证了我们的想法。所以,我们也可以这样调用 add_value 函数:add_value(&arr_ints[0], arr_ints.size()); 结果也是没问题的。

知道了原理之后,获得 vector 动态数组的首地址总共有以下几种写法:
  1. int *p_data_1 = arr_ints.data();
  2. int *p_data_2 = &arr_ints[0];
  3. int *p_data_3 = &arr_ints.at(0);
  4. int *p_data_4 = &arr_ints.front();
复制代码


有个问题要注意下,不能使用:
int *p_data_5 = arr_ints.begin(); 编译不通过,另外 begin 返回的迭代器,不是元素的地址,所以肯定不行,但是可以这样做:
  1. int *p_data_6 = &*arr_ints.begin();
复制代码
就可以啦!

总结一下,获得 vector 动态数组的内部元素首地址总共有 6 种方法,其中第 5 种是错误的,所以还剩下 5 种:

  1. int *p_data_1 = arr_ints.data();
  2. int *p_data_2 = &arr_ints[0];
  3. int *p_data_3 = &arr_ints.at(0);
  4. int *p_data_4 = &arr_ints.front();
  5. int *p_data_6 = &*arr_ints.begin();
复制代码


原文地址:http://www.cctry.com/thread-278452-1-1.html

猜你喜欢

转载自blog.csdn.net/net_syc/article/details/79629842
今日推荐