网站开发合同免费模板,广州培训+网站开发,哪里可以买到便宜的域名,企业网站建设难吗✨✨ 欢迎大家来到贝蒂大讲堂✨✨ #x1f388;#x1f388;养成好习惯#xff0c;先赞后看哦~#x1f388;#x1f388; 所属专栏#xff1a;C学习 贝蒂的主页#xff1a;Betty’s blog 1. C/C中的数组
1.1. C语言中的数组
在 C 语言中#xff0c;数组是一组相同类型… ✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 养成好习惯先赞后看哦~ 所属专栏C学习 贝蒂的主页Betty’s blog 1. C/C中的数组
1.1. C语言中的数组
在 C 语言中数组是一组相同类型元素的有序集合。与字符串类似它的大小在编译时就已经确定不可更改。
//大小为5的整型数组
int arr1[5] { 1,2,3,4,5 };
//大小为5的浮点型数组
double arr2[5] {0.0};1.2. C中的数组
同样与string类似C为了更加方便就引入了一个支持可动态大小数组的序列容器vecotr。其特点如下 vector是可变大小的序列容器采用连续存储空间存储元素可通过下标高效访问。与数组不同vector大小可动态改变由容器自动处理。vector本质上用动态分配数组存储元素插入新元素时可能重新分配空间即分配新数组并移动全部元素此操作时间代价高但不是每次插入都重新分配。vector会分配额外空间适应增长不同库策略不同但重新分配通常是对数增长间隔使末尾插入元素能在常数时间完成。与deque、list和forward_list相比vector访问元素及末尾添加和删除元素更高效非末尾的删除和插入操作效率低且统一的迭代器和引用更好。 //整型数组
vectorint v1;
//浮点型数组
vectordouble v2;并且注意每次使用vector都需要包含头文件#includevector。并且vector是一个模版类所以在使用时需要显示实例化。
2. vector的接口
接下来我们将介绍一些vector的常见接口因为很多接口的作用都与string的接口非常类似所以很多就不在详细说明大家具体也可以参考vector的使用。 2.1. vector的迭代器
同样的vector中也存在迭代器iterator因为定义在vector类中所以其需要通过域作用限定符访问——vector类型::iterator
下面将介绍的begin()end()rbeign()rend()的使用访问方法与string中的几乎一摸一样我们直接上实例演示
void Test1()
{vectorint v {1,2,3,4,5,6,7,8};vectorint::iterator it v.begin();cout 顺序遍历;while (it ! v.end()){cout *it ;it;}cout endl;cout 逆序遍历;vectorint::reverse_iterator rit v.rbegin();while (rit ! v.rend()){cout *rit ;rit;}
}当然vector也支持const_iterator用法也类似这里就不在赘述。
2.2. vector的初始化与销毁 同样的vector也支持多种构造函数拷贝构造以及赋值运算符重载。
void Test2()
{//1.默认构造函数初始化vectorint v1;//2.n个val初始化vectorint v2(3, 2);string s(abcd);//3.利用迭代器区间初始化vectorint v3(s.begin(), s.end());//4.拷贝构造vectorint v4(v3);//5.赋值重载v2 v3;//6.可变参数列表初始化vectorint v5 { 1,2,3,4,5 };vectorchar v6 v4;//error 不同类型不能赋值
}其中需要注意的是可变参数列表初始化这是在C11之后支持的新语法具体讲解我们之后再谈。
2.3. vector的容量操作
函数名称功能size返回数组的有效长度capacity返回数组的容量大小clear清空数组empty检查是否为空数组是则返回ture否则返回falsereserve请求改变数组的容量resize重新设置有效元素的数量超过原来有效长度则用c字符填充
2.3.1. 有效长度与容量大小
在vector类中我们同样可以通过size()容器的有效长度capacity()返回容器的容量大小。 void Test3()
{vectorint v { 1,2,3,4,5 };cout v.size() endl;cout v.capacity() endl;
}在初始化时vecotr中的size与capacity一般相同。这时我们也可以通过以下程序探究一下其扩容机制
void TestExpand()
{size_t sz;vectorint v;sz v.capacity();cout making v grow:endl;for (int i 0; i 100; i){v.push_back(i);if (sz ! v.capacity()){sz v.capacity();cout capacity changed: sz endl;}}
}在VS环境下vector一般是以1.5倍扩容。但是在Linux环境下一般就以2倍扩容。 至于clear()与empty()两个函数用法就十分简单这里就不在赘述了。
2.3.2. 有效长度与容量操作
接下来我们来使用一下vector中的resize()与reserve()。其实他们的用法与特点也是与string类中的相同我们直接上手即可 当nsz时reserve并不会发生任何改变resize会删除有效字符到指定大小。当szncapcity时reserve并不会发生任何改变resize会补充有效字符(默认为0)到指定大小。当ncapacity时reserve会发生扩容resize会补充有效字符(默认为0)到指定大小。 void Test4()
{vectorint v1 { 1,2,3,4,5 };cout v1的有效长度为 v1.size() endl;cout v1的容量大小为 v1.capacity() endl;v1.reserve(10);cout v1的有效长度为 v1.size() endl;cout v1的容量大小为 v1.capacity() endl;v1.resize(8, 10);for (auto e : v1){cout e ;}
}在这里我们需要注意一个经典错误如下列代码
void Test5()
{vectorint v;v.reserve(10);for (int i 0; i 10; i){v[i] i;}for (auto e : v){cout e ;}
}一旦运行就会发生如上错误这是为什么呢因为reserve只是改变了容量capacity并没有改变size而operator[]访问时元素时是禁止访问下标size以后的元素的一旦访问就会直接报错。
2.4. vector的访问操作
函数名称功能operator[]返回指定位置的元素越界则报错at返回指定位置的元素越界则抛异常back返回字符串最后一个元素front返回字符串第一个元素
这四个函数的用法也与string中的函数用法相同我们就直接上手示例
void Test6()
{vectorint v { 1,2,3,4,5 };for (int i0;iv.size();i){cout v[i] ;}cout endl;for (int i 0; i v.size(); i){cout v[i] ;}cout endl;cout front v.front() endl;cout back v.back() endl;
}2.4. vector的修改操作
函数名称功能push_back在数组后追加元素insert在指定位置追加元素assign使用指定数组替换原数组pop_back删除数组最后一个元素erase删除数组指定部分区间swap交换两个数组
我们首先先介绍最简单的四个函数push_back()pop_back()assign()swap()。
void Test7()
{vectorint v { 1,2,3,4,5,6 };cout back v.back() endl;//尾插v.push_back(7);//尾删cout back v.back() endl;v.pop_back();cout back v.back() endl;vectorint vv { 6,5,4,3,2,1 };//n个val赋值给原数组vv.assign(3, 2);for (int i 0; i vv.size(); i){cout vv[i] ;}cout endl;vv.swap(v);for (int i 0; i v.size(); i){cout v[i] ;}cout endl;for (int i 0; i vv.size(); i){cout vv[i] ;}
}然后我们来介绍insert()与·earse()的用法这两个函数的用法就与string中的有所不同。首先是insert()函数 void Test8()
{vectorint myvector(3, 100);vectorint::iterator it myvector.begin();//1.向指定位置插入一个元素it myvector.insert(it, 200);cout myvector contains:;for (it myvector.begin(); it myvector.end(); it)cout *it;cout endl;//2.向指定位置插入n个元素myvector.insert(it, 2, 300);cout myvector contains:;for (it myvector.begin(); it myvector.end(); it)cout *it;cout endl;//3.向指定位置插入一段迭代器区间it myvector.begin();vectorint anothervector(2, 400);cout myvector contains:;for (it myvector.begin(); it myvector.end(); it)cout *it;cout endl;it myvector.begin();myvector.insert(it 2, anothervector.begin(), anothervector.end());//4.向指定位置插入一段迭代器区间int myarray[] { 501,502,503 };myvector.insert(myvector.begin(), myarray, myarray 3);cout myvector contains:;for (it myvector.begin(); it myvector.end(); it)cout *it;cout endl;
}接下来我们继续来使用erase()函数 void Test9()
{//1.删除迭代器所指元素vectorint myvector;for (int i 1; i 10; i) myvector.push_back(i);vectorint::iterator it myvector.erase(myvector.begin() 5);it myvector.erase(it);//2.删除一段迭代器区间it myvector.erase(myvector.begin(), myvector.begin() 3);cout myvector contains:;for (int i 0; i myvector.size(); i)cout myvector[i];cout endl;
}虽然看起来vector的insert()和erase()与string的没有什么区别但是仔细观察就可以发现我们每次使用完迭代器之后都会更新这是为什么呢
主要还是因为我们每次插入数组都可能发生扩容而扩容分为就地扩容与异地扩容。如果发生的异地扩容这时的迭代器就不在指向原来的空间而就指向一块释放的内存我们一旦继续访问就会报错这种现象我们称为迭代器失效。为了避免出现这种情况所以我们在使用完迭代器之后需要更新。