原文地址:http://www.cctry.com/thread-278452-1-1.html
近期的几个项目用到了C++标准模板库STL中的vector容器,即:动态数组,感觉也挺方便好用,跟MFC中的CArray不相上下,而且还跨平台,还是非常不错的。当前的几个项目都是用VS2013编译开发的,用着 vector 也都不错的。我举个小例子:
- #include "stdafx.h"
- #include <vector>
- using namespace std;
- int main(int argc, char **argv)
- {
- vector <int> arr_ints;
- for (int idx = 0; idx < 100; ++idx)
- {
- arr_ints.push_back(idx);
- }
- return 0;
- }
这个例子很简单,就是先定义一个 vector 动态数组,成员的类型是 int 整型,之后用个 for 循环把 100个数字放到动态数组 arr_ints 中,如此而已。
接下来呢,比如有个函数 add_value,其功能就是对指定的数组内部元素的值+1,第一个参数 pArrInts 传递的是 int 型数组的首地址,第二个参数 nArrLen 传递的是数组的大小,代码如下:
- void add_value(int *pArrInts, int nArrLen)
- {
- if (!pArrInts || nArrLen <= 0) return;
- for (int idx = 0; idx < nArrLen; ++idx)
- {
- pArrInts[idx] += 1;
- }
- }
下面呢,我想调用函数 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] 对吧?我们来调试代码验证一下:
- int main(int argc, char **argv)
- {
- vector <int> arr_ints;
- for (int idx = 0; idx < 100; ++idx)
- {
- arr_ints.push_back(idx);
- }
- int *p_data_1 = arr_ints.data();
- int *p_data_2 = &arr_ints[0];
- add_value(arr_ints.data(), arr_ints.size());
- return 0;
- }
没错,p_data_1 和 p_data_2 的值是相等的,也验证了我们的想法。所以,我们也可以这样调用 add_value 函数:add_value(&arr_ints[0], arr_ints.size()); 结果也是没问题的。
知道了原理之后,获得 vector 动态数组的首地址总共有以下几种写法:
- int *p_data_1 = arr_ints.data();
- int *p_data_2 = &arr_ints[0];
- int *p_data_3 = &arr_ints.at(0);
- int *p_data_4 = &arr_ints.front();
有个问题要注意下,不能使用:
int *p_data_5 = arr_ints.begin(); 编译不通过,另外 begin 返回的迭代器,不是元素的地址,所以肯定不行,但是可以这样做:
- int *p_data_6 = &*arr_ints.begin();
总结一下,获得 vector 动态数组的内部元素首地址总共有 6 种方法,其中第 5 种是错误的,所以还剩下 5 种:
- int *p_data_1 = arr_ints.data();
- int *p_data_2 = &arr_ints[0];
- int *p_data_3 = &arr_ints.at(0);
- int *p_data_4 = &arr_ints.front();
- int *p_data_6 = &*arr_ints.begin();